Repository: aws-cloudformation/cfn-lint

Issue:
v1: E1050 'dynamic references' is too long (4)
### CloudFormation Lint Version

1.3.0

### What operating system are you using?

mac

### Describe the bug

```yaml
  MyS3Bucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      AccessControl: '{{resolve:ssm:${AWS::AccountId}/${AWS::Region}/ac}}' 
```

result in 

```
E1050 ['resolve', 'ssm', '${AWS', '', 'AccountId}/${AWS', '', 'Region}/ac'] is too long (4)
E1050 '' does not match '\\d+'
```



### Expected behavior

I thinking `:` inside `${}` should be ignored while checking this rule.

### Reproduction template

```yaml
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31

Resources:
  S3Storage:
    Properties:
      LoggingConfiguration:
        AccessControl: !Sub "{{resolve:ssm:${AWS::AccountId}/${AWS::Region}/ac}}"
```



Discussion:

Patch:
diff --git a/src/cfnlint/jsonschema/_filter.py b/src/cfnlint/jsonschema/_filter.py
index 8762323fc1..8204046465 100644
--- a/src/cfnlint/jsonschema/_filter.py
+++ b/src/cfnlint/jsonschema/_filter.py
@@ -8,7 +8,7 @@
 from dataclasses import dataclass, field, fields
 from typing import TYPE_CHECKING, Any, Sequence, Tuple
 
-from cfnlint.helpers import REGEX_DYN_REF, ToPy, ensure_list
+from cfnlint.helpers import FUNCTIONS, REGEX_DYN_REF, ToPy, ensure_list
 
 if TYPE_CHECKING:
     from cfnlint.jsonschema.protocols import Validator
@@ -106,7 +106,14 @@ def filter(self, validator: Any, instance: Any, schema: Any):
         # Lets validate dynamic references when appropriate
         if validator.is_type(instance, "string"):
             if REGEX_DYN_REF.findall(instance):
-                yield (instance, {"dynamicReference": schema})
+                # if we are in a function we can't validate
+                # dynamic references the same way
+                if not any(
+                    p in set(FUNCTIONS) - set(["Fn::If"])
+                    for p in validator.context.path.path
+                ):
+                    yield (instance, {"dynamicReference": schema})
+                    return
                 return
 
         # dependencies, required, minProperties, maxProperties


Test patch:
diff --git a/test/unit/module/jsonschema/test_filter.py b/test/unit/module/jsonschema/test_filter.py
new file mode 100644
index 0000000000..0a012e2d0e
--- /dev/null
+++ b/test/unit/module/jsonschema/test_filter.py
@@ -0,0 +1,50 @@
+"""
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: MIT-0
+"""
+
+from collections import deque
+
+import pytest
+
+from cfnlint.context import Context
+from cfnlint.context.context import Path
+from cfnlint.jsonschema import CfnTemplateValidator
+from cfnlint.jsonschema._filter import FunctionFilter
+
+
+@pytest.fixture(scope="module")
+def filter():
+    filter = FunctionFilter()
+    yield filter
+
+
+@pytest.mark.parametrize(
+    "name,instance,schema,path,expected",
+    [
+        (
+            "Don't validate dynamic references inside of function",
+            "{{resolve:ssm:${AWS::AccountId}/${AWS::Region}/ac}}",
+            {"enum": "Foo"},
+            deque(["Foo", "Test", "Fn::Sub"]),
+            [],
+        ),
+        (
+            "Validate dynamic references",
+            "{{resolve:ssm:secret}}",
+            {"enum": "Foo"},
+            deque(["Foo", "Test"]),
+            [
+                ("{{resolve:ssm:secret}}", {"dynamicReference": {"enum": "Foo"}}),
+            ],
+        ),
+    ],
+)
+def test_filter(name, instance, schema, path, expected, filter):
+    validator = CfnTemplateValidator(
+        context=Context(regions=["us-east-1"], path=Path(path)),
+        schema=schema,
+    )
+    results = list(filter.filter(validator, instance, schema))
+
+    assert results == expected, f"For test {name} got {results!r}"
diff --git a/test/unit/rules/functions/test_basefn.py b/test/unit/rules/functions/test_basefn.py
index f13d0d77d3..a4dc9dabf3 100644
--- a/test/unit/rules/functions/test_basefn.py
+++ b/test/unit/rules/functions/test_basefn.py
@@ -3,11 +3,11 @@
 SPDX-License-Identifier: MIT-0
 """
 
+from collections import deque
+
 import pytest
 
-from cfnlint.context import Context
-from cfnlint.context.context import Parameter, Resource
-from cfnlint.jsonschema import CfnTemplateValidator
+from cfnlint.jsonschema import ValidationError
 from cfnlint.rules.functions._BaseFn import BaseFn
 
 
@@ -17,11 +17,34 @@ def rule():
     yield rule
 
 
-@pytest.fixture(scope="module")
-def validator():
-    context = Context(
-        regions=["us-east-1"],
-        resources={"MyResource": Resource({"Type": "Foo", "Properties": {"A": "B"}})},
-        parameters={"MyParameter": Parameter({"Type": "String"})},
-    )
-    yield CfnTemplateValidator(context=context)
+@pytest.mark.parametrize(
+    "name,instance,schema,expected",
+    [
+        (
+            "Dynamic references are ignored",
+            {"Fn::Sub": "{{resolve:ssm:${AWS::AccountId}/${AWS::Region}/ac}}"},
+            {"enum": ["Foo"]},
+            [],
+        ),
+        ("Everything is fine", {"Fn::Sub": "Foo"}, {"enum": ["Foo"]}, []),
+        (
+            "Standard error",
+            {"Fn::Sub": "Bar"},
+            {"enum": ["Foo"]},
+            [
+                ValidationError(
+                    message=(
+                        "{'Fn::Sub': 'Bar'} is not one of "
+                        "['Foo'] when '' is resolved"
+                    ),
+                    path=deque(["Fn::Sub"]),
+                    validator="",
+                    schema_path=deque(["enum"]),
+                )
+            ],
+        ),
+    ],
+)
+def test_resolve(name, instance, schema, expected, validator, rule):
+    errs = list(rule.resolve(validator, schema, instance, {}))
+    assert errs == expected, f"{name!r} failed and got errors {errs!r}"