Repository: aws-cloudformation/cfn-lint

Issue:
cfn-lint v1 does not warn about missing mapping keys
### CloudFormation Lint Version

1.3.3 & git (b0782f87c)

### What operating system are you using?

Mac

### Describe the bug

cfn-lint v1 (1.3.3) does not warn about missing mapping keys.

This was first noticed with missing second level key, but it applies to both first and second level.

### Expected behavior

cfn-lint 0.87.7 would warn:
```
W1011 FindInMap second key "MissingName" doesn't exist in map "Map" under "Key" at Resources/Bucket/Properties/BucketName/Fn::FindInMap
map.yaml:14:11
```

I would actually expect this to be `W7xxx` or even `E7xxx`, but I'll be happy with anything other than silence 😄 

### Reproduction template

```
AWSTemplateFormatVersion: '2010-09-09'
Mappings:
  Map:
    Key:
      Name: "unused"
Resources:
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName:
        Fn::FindInMap:
        - "Map"
        - "Key"
        - "MissingName"
```


Discussion:
Rule `W1011` was removed in c7d01e9 (#3055) and is now used for a completely different warning (`Use dynamic references over parameters for secrets`)
Looking into it.  We should have still caught this but the rule would have changed so I have to see what I'm missing. 



Patch:
diff --git a/src/cfnlint/conditions/conditions.py b/src/cfnlint/conditions/conditions.py
index 27c2101b6a..a56fb77a32 100644
--- a/src/cfnlint/conditions/conditions.py
+++ b/src/cfnlint/conditions/conditions.py
@@ -19,7 +19,6 @@
 from cfnlint.conditions._equals import Equal, EqualParameter
 from cfnlint.conditions._errors import UnknownSatisfisfaction
 from cfnlint.conditions._utils import get_hash
-from cfnlint.helpers import PSEUDOPARAMS
 
 LOGGER = logging.getLogger(__name__)
 
@@ -371,20 +370,20 @@ def satisfiable(
 
         cnf = self._cnf.copy()
         at_least_one_param_found = False
+
         for condition_name, opt in conditions.items():
             for c_equals in self._conditions[condition_name].equals:
                 found_params = {}
                 for param, value in parameter_values.items():
-                    if param in PSEUDOPARAMS:
-                        continue
-
                     ref_hash = get_hash({"Ref": param})
+
                     for c_equal_param in c_equals.parameters:
                         if isinstance(c_equal_param, EqualParameter):
                             if c_equal_param.satisfiable is False:
                                 raise UnknownSatisfisfaction(
                                     f"Can't resolve satisfaction for {condition_name!r}"
                                 )
+
                     if ref_hash in c_equals.parameters:
                         found_params = {ref_hash: value}
 
diff --git a/src/cfnlint/jsonschema/validators.py b/src/cfnlint/jsonschema/validators.py
index 039b559165..0dcee07ae0 100644
--- a/src/cfnlint/jsonschema/validators.py
+++ b/src/cfnlint/jsonschema/validators.py
@@ -180,6 +180,8 @@ def resolve_value(self, instance: Any) -> ResolutionResult:
                         except UnknownSatisfisfaction as err:
                             LOGGER.debug(err)
                             return
+                    else:
+                        yield None, self, r_errs  # type: ignore
                 return
 
             # The return type is a Protocol and we are returning an instance


Test patch:
diff --git a/test/unit/module/jsonschema/test_validator_resolver.py b/test/unit/module/jsonschema/test_validator_resolver.py
new file mode 100644
index 0000000000..94feb8af26
--- /dev/null
+++ b/test/unit/module/jsonschema/test_validator_resolver.py
@@ -0,0 +1,56 @@
+"""
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: MIT-0
+"""
+
+from collections import deque
+from typing import Any
+
+import pytest
+
+from cfnlint.jsonschema._resolvers_cfn import ResolutionResult, Validator
+from cfnlint.jsonschema.exceptions import ValidationError
+from cfnlint.jsonschema.validators import CfnTemplateValidator
+
+
+def _resolver(validator: Validator, instance: Any) -> ResolutionResult:
+    if instance == "fail":
+        yield None, validator, ValidationError("Foo")
+        return
+
+    yield "foo", validator, None
+
+
+@pytest.fixture
+def validator():
+    validator = CfnTemplateValidator({})
+    validator.fn_resolvers = {
+        "Ref": _resolver,
+    }
+    validator.context = validator.context.evolve(functions=["Ref"])
+    return validator
+
+
+@pytest.mark.parametrize(
+    "name,instance,expected",
+    [
+        (
+            "Valid with function",
+            {"Ref": "fail"},
+            [(None, ValidationError("Foo", path=deque(["Ref"])))],
+        ),
+        ("Valid string", "foo", [("foo", None)]),
+        ("Valid with function", {"Ref": "pass"}, [("foo", None)]),
+    ],
+)
+def test_validator_resolver(name, instance, expected, validator):
+    results = list(validator.resolve_value(instance))
+
+    if len(results) > len(expected):
+        for result, expected_result in zip(results, expected):
+            assert result[0] == expected_result[0]
+            assert result[2] == expected_result[1]
+    else:
+        for expected_result, result in zip(expected, results):
+            assert result[0] == expected_result[0]
+            assert result[2] == expected_result[1]
diff --git a/test/unit/rules/functions/test_find_in_map.py b/test/unit/rules/functions/test_find_in_map.py
index fb23ba0957..3524b8b893 100644
--- a/test/unit/rules/functions/test_find_in_map.py
+++ b/test/unit/rules/functions/test_find_in_map.py
@@ -147,6 +147,20 @@ def context(cfn):
                 ),
             ],
         ),
+        (
+            "Invalid Fn::FindInMap with a bad map key",
+            {"Fn::FindInMap": ["A", "C", "B"]},
+            {"type": "string"},
+            {"transforms": Transforms(["AWS::LanguageExtensions"])},
+            [ValidationError("Foo")],
+            [
+                ValidationError(
+                    "'C' is not one of ['B']",
+                    path=deque(["Fn::FindInMap", 1]),
+                    schema_path=deque([]),
+                ),
+            ],
+        ),
         (
             "Valid Fn::FindInMap with a Ref to AWS::NoValue",
             {