Repository: aws-cloudformation/cfn-lint

Issue:
Fn::ForEach could not be resolved when values array references Map using AccountId key
### CloudFormation Lint Version

cfn-lint 1.16.1 / git v1.16.1-5-g07652d4a4

### What operating system are you using?

Mac

### Describe the bug

`cfn-lint` fails to resolve `Fn::ForEach` when values array comes from Map with `AccountId` key

```
$ cfn-lint mapt.yaml 
E0001 Error transforming template: Fn::ForEach could not be resolved
mapt.yaml:11:7
```

### Expected behavior

cfn-lint passes

### Reproduction template

```yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::LanguageExtensions
Mappings:
  AccountMap:
    12345678901:
      Emails:
        - test@test.com
Resources:
  'Fn::ForEach::Subscriptions':
    - Email
    - !FindInMap [AccountMap, !Ref AWS::AccountId, Emails]
    - 'SubscriptionFor&{Email}':
        Type: AWS::SNS::Subscription
        Properties:
          TopicArn: "arn:aws:sns:us-east-1:12345678901:my-sns-topic"
          Protocol: email
          Endpoint: !Ref Email
```


Discussion:

Patch:
diff --git a/src/cfnlint/template/transforms/_language_extensions.py b/src/cfnlint/template/transforms/_language_extensions.py
index 4e81a48d35..6760be1b01 100644
--- a/src/cfnlint/template/transforms/_language_extensions.py
+++ b/src/cfnlint/template/transforms/_language_extensions.py
@@ -28,6 +28,8 @@
 
 _SCALAR_TYPES = (str, int, float, bool)
 
+_ACCOUNT_ID = None
+
 
 class _ResolveError(Exception):
     def __init__(self, message: str, key: Any) -> None:
@@ -371,7 +373,12 @@ def value(
                     for k, v in mapping.items():
                         if isinstance(v, dict):
                             if t_map[2].value(cfn, params, only_params) in v:
+                                if isinstance(t_map[1], _ForEachValueRef):
+                                    if t_map[1]._ref._value == "AWS::AccountId":
+                                        global _ACCOUNT_ID
+                                        _ACCOUNT_ID = k
                                 t_map[1] = _ForEachValue.create(k)
+                                break
                 except _ResolveError:
                     pass
 
@@ -439,7 +446,9 @@ def value(
             return region
 
         if v == "AWS::AccountId":
-            return account_id
+            if _ACCOUNT_ID is None:
+                raise _ResolveError("Can't resolve Fn::Ref", self._obj)
+            return _ACCOUNT_ID
 
         if v == "AWS::NotificationARNs":
             return [f"arn:{partition}:sns:{region}:{account_id}:notification"]


Test patch:
diff --git a/test/unit/module/template/transforms/test_language_extensions.py b/test/unit/module/template/transforms/test_language_extensions.py
index da4fa1871b..7741501121 100644
--- a/test/unit/module/template/transforms/test_language_extensions.py
+++ b/test/unit/module/template/transforms/test_language_extensions.py
@@ -4,8 +4,9 @@
 """
 
 from copy import deepcopy
-from unittest import TestCase
+from unittest import TestCase, mock
 
+import cfnlint.template.transforms._language_extensions
 from cfnlint.decode import convert_dict
 from cfnlint.template import Template
 from cfnlint.template.transforms._language_extensions import (
@@ -122,7 +123,15 @@ def test_ref(self):
         self.assertEqual(fe.value(self.cfn), "us-west-2")
 
         fe = _ForEachValue.create({"Ref": "AWS::AccountId"})
-        self.assertEqual(fe.value(self.cfn), "123456789012")
+        with self.assertRaises(_ResolveError):
+            fe.value(self.cfn)
+
+        with mock.patch(
+            "cfnlint.template.transforms._language_extensions._ACCOUNT_ID",
+            "123456789012",
+        ):
+            fe = _ForEachValue.create({"Ref": "AWS::AccountId"})
+            self.assertEqual(fe.value(self.cfn), "123456789012")
 
         fe = _ForEachValue.create({"Ref": "AWS::NotificationARNs"})
         self.assertListEqual(
@@ -357,6 +366,31 @@ def test_two_mappings(self):
         with self.assertRaises(_ResolveError):
             fe.value(self.cfn)
 
+    def test_account_id(self):
+
+        cfnlint.template.transforms._language_extensions._ACCOUNT_ID = None
+
+        with mock.patch(
+            "cfnlint.template.transforms._language_extensions._ACCOUNT_ID", None
+        ):
+            self.assertIsNone(
+                cfnlint.template.transforms._language_extensions._ACCOUNT_ID
+            )
+            fe = _ForEachValueFnFindInMap(
+                "a",
+                [
+                    "Bucket",
+                    {"Ref": "AWS::AccountId"},
+                    "Names",
+                ],
+            )
+            self.assertListEqual(fe.value(self.cfn), ["foo", "bar"])
+
+            self.assertEqual(
+                cfnlint.template.transforms._language_extensions._ACCOUNT_ID,
+                "Production",
+            )
+
 
 class TestTransform(TestCase):
     def setUp(self) -> None:
@@ -832,3 +866,108 @@ def nested_set(dic, keys, value):
         if isinstance(key, int):
             dic = dic[key]
     dic[keys[-1]] = value
+
+
+class TestTransformValueAccountId(TestCase):
+    def setUp(self) -> None:
+        self.template_obj = convert_dict(
+            {
+                "Transform": ["AWS::LanguageExtensions"],
+                "Mappings": {
+                    "Accounts": {
+                        "111111111111": {"AppName": ["A", "B"]},
+                        "222222222222": {"AppName": ["C", "D"]},
+                    },
+                },
+                "Resources": {
+                    "Fn::ForEach::Regions": [
+                        "AppName",
+                        {
+                            "Fn::FindInMap": [
+                                "Accounts",
+                                {"Ref": "AWS::AccountId"},
+                                "AppName",
+                            ]
+                        },
+                        {
+                            "${AppName}Role": {
+                                "Type": "AWS::IAM::Role",
+                                "Properties": {
+                                    "RoleName": {"Ref": "AppName"},
+                                    "AssumeRolePolicyDocument": {
+                                        "Version": "2012-10-17",
+                                        "Statement": [
+                                            {
+                                                "Effect": "Allow",
+                                                "Principal": {
+                                                    "Service": ["ec2.amazonaws.com"]
+                                                },
+                                                "Action": ["sts:AssumeRole"],
+                                            }
+                                        ],
+                                    },
+                                    "Path": "/",
+                                },
+                            }
+                        },
+                    ],
+                },
+            }
+        )
+
+        self.result = {
+            "Mappings": {
+                "Accounts": {
+                    "111111111111": {"AppName": ["A", "B"]},
+                    "222222222222": {"AppName": ["C", "D"]},
+                },
+            },
+            "Resources": {
+                "ARole": {
+                    "Properties": {
+                        "AssumeRolePolicyDocument": {
+                            "Statement": [
+                                {
+                                    "Action": ["sts:AssumeRole"],
+                                    "Effect": "Allow",
+                                    "Principal": {"Service": ["ec2.amazonaws.com"]},
+                                }
+                            ],
+                            "Version": "2012-10-17",
+                        },
+                        "Path": "/",
+                        "RoleName": "A",
+                    },
+                    "Type": "AWS::IAM::Role",
+                },
+                "BRole": {
+                    "Properties": {
+                        "AssumeRolePolicyDocument": {
+                            "Statement": [
+                                {
+                                    "Action": ["sts:AssumeRole"],
+                                    "Effect": "Allow",
+                                    "Principal": {"Service": ["ec2.amazonaws.com"]},
+                                }
+                            ],
+                            "Version": "2012-10-17",
+                        },
+                        "Path": "/",
+                        "RoleName": "B",
+                    },
+                    "Type": "AWS::IAM::Role",
+                },
+            },
+            "Transform": ["AWS::LanguageExtensions"],
+        }
+
+    def test_transform(self):
+        self.maxDiff = None
+        cfn = Template(filename="", template=self.template_obj, regions=["us-east-1"])
+        matches, template = language_extension(cfn)
+        self.assertListEqual(matches, [])
+        self.assertDictEqual(
+            template,
+            self.result,
+            template,
+        )