Repository: aws-cloudformation/cfn-lint

Issue:
Crash processing Rules section following upgrade from 1.12.2 to 1.12.3
### CloudFormation Lint Version

1.12.3

### What operating system are you using?

Ubuntu

### Describe the bug

Since upgrading from 1.12.2 to 1.12.3 cfn-lint is crashing on one of my templates with `sympy.core.sympify.SympifyError: SympifyError: None`.  I'll attach the stack trace.

This template happens to have a "Rules" section, which I think is the cause.

[trace.txt](https://github.com/user-attachments/files/16887728/trace.txt)


### Expected behavior

not crashing

### Reproduction template

```
{
  "AWSTemplateFormatVersion" : "2010-09-09",

  "Parameters": {
    "FooAccountId": {
      "Type" : "String",
      "MinLength" : "12",
      "MaxLength" : "12",
      "AllowedPattern" : "^[0-9]{12}$",
      "ConstraintDescription" : "AWS Account ID must be 12 digits"
    }
  },

  "Rules" : {
    "expectedAccount" : {
      "Assertions" : [ {
        "Assert" :  { "Fn::Equals": [ { "Ref": "FooAccountId" }, { "Ref" : "AWS::AccountId" } ] },
        "AssertDescription" : "The foo account should match the current logged-in account."
      }
      ]
    }
  },

  "Resources" : {
    "Dummy": {
      "Type": "Custom::NullResource",
      "Properties": { "ServiceToken": { "Ref" : "FooAccountId" } }
    }
  }
}
```


Discussion:
I can confirm I'm having the same issues. Commenting out the "rules" section doesnt throw the error.

The error thrown:

```
Traceback (most recent call last):
  File "/opt/homebrew/bin/cfn-lint", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/cfnlint/runner.py", line 452, in main
    runner.cli()
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/cfnlint/runner.py", line 443, in cli
    self._cli_output(list(self.run()))
                     ^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/cfnlint/runner.py", line 395, in run
    yield from self._validate_filenames(self.config.templates)
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/cfnlint/runner.py", line 299, in _validate_filenames
    yield from self.validate_template(filename, template)  # type: ignore[arg-type] # noqa: E501
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/cfnlint/runner.py", line 321, in validate_template
    runner = TemplateRunner(filename, template, self.config, self.rules)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/cfnlint/runner.py", line 98, in __init__
    self.cfn = Template(filename, template, self.config.regions)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/cfnlint/template/template.py", line 78, in __init__
    self.conditions = cfnlint.conditions.Conditions(self)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/cfnlint/conditions/conditions.py", line 40, in __init__
    self._cnf, self._solver_params = self._build_cnf(list(self._conditions.keys()))
                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/cfnlint/conditions/conditions.py", line 185, in _build_cnf
    cnf.add_prop(rule.build_cnf(equal_vars))
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/cfnlint/conditions/_rule.py", line 143, in build_cnf
    return self._assertions.build_cnf(params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/cfnlint/conditions/_rule.py", line 94, in build_cnf
    return And(*assertions)
           ^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/sympy/core/operations.py", line 513, in __new__
    _args = frozenset(cls._new_args_filter(args))
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/sympy/logic/boolalg.py", line 578, in _new_args_filter
    args = BooleanFunction.binary_check_and_simplify(*args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/sympy/core/operations.py", line 506, in <genexpr>
    args = (_sympify_(arg) for arg in args)
            ^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/sympy/core/sympify.py", line 514, in _sympify
    return sympify(a, strict=True)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/cfn-lint/1.12.3/libexec/lib/python3.12/site-packages/sympy/core/sympify.py", line 400, in sympify
    raise SympifyError(a)
sympy.core.sympify.SympifyError: SympifyError: None
```



Patch:
diff --git a/src/cfnlint/conditions/_equals.py b/src/cfnlint/conditions/_equals.py
index 59b596cc36..06872c4223 100644
--- a/src/cfnlint/conditions/_equals.py
+++ b/src/cfnlint/conditions/_equals.py
@@ -158,7 +158,10 @@ def build_cnf(self, params: dict[str, Symbol]) -> BooleanFunction:
                 return BooleanTrue()
             return BooleanFalse()
 
-        return params.get(self.hash)
+        if self.hash in params:
+            return params.get(self.hash)
+
+        return Symbol(self.hash)
 
     def test(self, scenarios: Mapping[str, str]) -> bool:
         """Do an equals based on the provided scenario"""
diff --git a/src/cfnlint/conditions/_rule.py b/src/cfnlint/conditions/_rule.py
index 2201f678d2..48a6320af7 100644
--- a/src/cfnlint/conditions/_rule.py
+++ b/src/cfnlint/conditions/_rule.py
@@ -91,7 +91,11 @@ def build_cnf(self, params: dict[str, Symbol]) -> BooleanFunction | Symbol | Non
         for assertion in self._assertions:
             assertions.append(assertion.build_cnf(params))
 
-        return And(*assertions)
+        try:
+            return And(*assertions)
+        except Exception as e:
+            LOGGER.debug(f"Error building conditions: {e}")
+            return BooleanTrue()
 
     @property
     def equals(self) -> list[Equal]:


Test patch:
diff --git a/test/unit/module/conditions/test_rules.py b/test/unit/module/conditions/test_rules.py
index 4a367eb44c..f9871bc44c 100644
--- a/test/unit/module/conditions/test_rules.py
+++ b/test/unit/module/conditions/test_rules.py
@@ -302,6 +302,70 @@ def test_fn_equals_assertions_one(self):
             )
         )
 
+    def test_fn_equals_assertions_ref_no_data(self):
+        template = decode_str(
+            """
+        Parameters:
+            AccountId:
+                Type: String
+        Rules:
+          Rule1:
+            Assertions:
+            - Assert: !Equals [!Ref AccountId, !Ref AWS::AccountId]
+        """
+        )[0]
+
+        cfn = Template("", template)
+        self.assertEqual(len(cfn.conditions._conditions), 0)
+        self.assertEqual(len(cfn.conditions._rules), 1)
+
+        self.assertListEqual(
+            [equal.hash for equal in cfn.conditions._rules[0].equals],
+            [
+                "f36e61f3d5bf6cdc6ea2e7f01487af728094a439",
+            ],
+        )
+
+        self.assertTrue(
+            cfn.conditions.satisfiable(
+                {},
+                {},
+            )
+        )
+
+    def test_fn_equals_assertions_ref_never_satisfiable(self):
+        template = decode_str(
+            """
+        Parameters:
+            AccountId:
+                Type: String
+        Rules:
+          Rule1:
+            Assertions:
+            - Assert: !Equals [!Ref AccountId, !Ref AWS::AccountId]
+            - Assert: !Not [!Equals [!Ref AccountId, !Ref AWS::AccountId]]
+        """
+        )[0]
+
+        cfn = Template("", template)
+        self.assertEqual(len(cfn.conditions._conditions), 0)
+        self.assertEqual(len(cfn.conditions._rules), 1)
+
+        self.assertListEqual(
+            [equal.hash for equal in cfn.conditions._rules[0].equals],
+            [
+                "f36e61f3d5bf6cdc6ea2e7f01487af728094a439",
+                "f36e61f3d5bf6cdc6ea2e7f01487af728094a439",
+            ],
+        )
+
+        self.assertFalse(
+            cfn.conditions.satisfiable(
+                {},
+                {},
+            )
+        )
+
 
 class TestAssertion(TestCase):
     def test_assertion_errors(self):