Repository: aws-cloudformation/cfn-lint

Issue:
ImportValue in Output Value check W6001 is bugged
### CloudFormation Lint Version

v1.9.5

### What operating system are you using?

RHEL, Ubuntu

### Describe the bug

Initially we received the following error on a template that passed under cfn-lint v.1.3.5, but not under v1.9.2 or v.1.9.5: `E1016 Exception 'deque index out of range' raised while validating 'fn_importvalue' complex.cfn.yaml:519:5`

This template has an output with a value containing an ImportValue statement, and that's what's at the line of code pointed to by the error. Because of this, our call to cfn-lint includes `--ignore-checks W6001`, but that must filter the output instead of blocking the checks from running, because I eventually tracked the issue to a bug [in the rules/output/ImportValue.py file for W6001](https://github.com/aws-cloudformation/cfn-lint/blob/main/src/cfnlint/rules/outputs/ImportValue.py#L28-L32):

```
   if len(validator.context.path.path) >= 2:
      if (
         validator.context.path.path[0] == "Outputs"
         and validator.context.path.path[2] == "Value"
      ):
```

The `if` statement checks whether the length of `validator.context.path.path` is greater than or equal to 2, but then proceeds to try and access `validator.context.path.path[2]`, which causes the deque index error when the length of `validator.context.path.path` is equal to 2.

The above code is the same in v1.3.5, though, and we didn't experience this issue with that version, so I did some more digging. It looks like [this change](https://github.com/aws-cloudformation/cfn-lint/commit/31ac633b18cd02528fac0038fa22ee5caa16b82f#diff-72d4623485ba2a9f8de2ec1e9586d2daddb4c2eba80c5810deab192c7ded6466R26) made the above bug possible to trigger:

```
diff --git a/src/cfnlint/rules/outputs/Value.py b/src/cfnlint/rules/outputs/Value.py
index 3125be6c6..4d86d9fb8 100644
--- a/src/cfnlint/rules/outputs/Value.py
+++ b/src/cfnlint/rules/outputs/Value.py
@@ -23,14 +23,25 @@ class Value(CfnLintJsonSchema):

     def __init__(self):
         super().__init__(
-            keywords=["Outputs/*/Value"],
+            keywords=["Outputs/*"],
             all_matches=True,
         )
```

I confirmed if I changed the above-mentioned `if` statement to check for `>= 3` or if I changed `keywords=["Outputs/*"]` back to `keywords=["Outputs/*/Value"]`, the test would properly proc W6001, or pass with `--ignore-checks W6001`.

I'm filing this as a bug report instead of a PR because I'm unsure of the reason for the change to the `keywords` variable, which might require the logic of the `if` statement to be further changed depending on whether "Value" will ever appear in `validator.context.path.path`, and I didn't want to risk mangling things further.

### Expected behavior

W6001 would be triggered, or ignored when passing `--ignore-checks W6001`

### Reproduction template

```
AWSTemplateFormatVersion: 2010-09-09

Parameters:

  ComplexName:
    Type: String
    AllowedPattern: '[a-z0-9]+'
 
  VpcStackName:
    Type: String

Resources:
  # omitted

Outputs:

  VPC:
    Value: 
      Fn::ImportValue:
        !Sub ${VpcStackName}-VPC
    Export:
      Name: !Sub ${ComplexName}-VPC
```


Discussion:
Thank you, the quick fix is appreciated. At the same time, the issue of the if statement checking for `>= 2` and then accessing index 2 is still there and could cause issues in the future.
Put into the next PR along with a little smarter logic



Patch:
diff --git a/src/cfnlint/rules/outputs/Value.py b/src/cfnlint/rules/outputs/Value.py
index 4d86d9fb87..7d6ec9739f 100644
--- a/src/cfnlint/rules/outputs/Value.py
+++ b/src/cfnlint/rules/outputs/Value.py
@@ -28,7 +28,8 @@ def __init__(self):
         )
 
     def validate(self, validator: Validator, _: Any, instance: Any, schema: Any):
-        value = instance.get("Value")
+        key = "Value"
+        value = instance.get(key)
         if not value:
             return
 
@@ -42,6 +43,10 @@ def validate(self, validator: Validator, _: Any, instance: Any, schema: Any):
                 conditions=validator.context.conditions.evolve(
                     conditions,
                 ),
+                path=validator.context.path.descend(
+                    path=key,
+                    cfn_path=key,
+                ),
             ),
             schema={
                 "type": ["array", "string"],
@@ -52,5 +57,5 @@ def validate(self, validator: Validator, _: Any, instance: Any, schema: Any):
         )
 
         for err in self._iter_errors(validator, value):
-            err.path.appendleft("Value")
+            err.path.appendleft(key)
             yield err


Test patch:
diff --git a/test/unit/rules/outputs/test_value.py b/test/unit/rules/outputs/test_value.py
index e2739cfec9..ec1b481d45 100644
--- a/test/unit/rules/outputs/test_value.py
+++ b/test/unit/rules/outputs/test_value.py
@@ -7,11 +7,14 @@
 
 import pytest
 
+from cfnlint.context import Path
 from cfnlint.jsonschema import CfnTemplateValidator, ValidationError
 from cfnlint.rules.functions.Cidr import Cidr
+from cfnlint.rules.functions.ImportValue import ImportValue
 from cfnlint.rules.functions.Join import Join
 from cfnlint.rules.functions.Ref import Ref
 from cfnlint.rules.functions.RefResolved import RefResolved
+from cfnlint.rules.outputs.ImportValue import ImportValue as OutputsImportValue
 from cfnlint.rules.outputs.Value import Value  # pylint: disable=E0401
 
 
@@ -54,19 +57,34 @@ def template():
 
 
 @pytest.fixture
-def validator(cfn):
+def path():
+    return Path(
+        path=deque(["Outputs", "Test"]),
+        value_path=deque(),
+        cfn_path=deque(["Outputs", "*"]),
+    )
+
+
+@pytest.fixture
+def validator(cfn, context):
 
     ref = Ref()
     ref.child_rules["W1030"] = RefResolved()
+
+    importvalue = ImportValue()
+    importvalue.child_rules["W6001"] = OutputsImportValue()
+
     yield CfnTemplateValidator(schema={}).extend(
         validators={
             "fn_join": Join().fn_join,
             "ref": ref.ref,
             "fn_cidr": Cidr().fn_cidr,
+            "fn_importvalue": importvalue.fn_importvalue,
         }
     )(
         schema={},
         cfn=cfn,
+        context=context,
     )
 
 
@@ -143,6 +161,23 @@ def validator(cfn):
                 )
             ],
         ),
+        (
+            {
+                "Value": {"Fn::ImportValue": "test-stack-value"},
+            },
+            [
+                ValidationError(
+                    (
+                        "The output value {'Fn::ImportValue': 'test-stack-value'} "
+                        "is an import from another output"
+                    ),
+                    validator="fn_importvalue",
+                    schema_path=deque(["fn_importvalue"]),
+                    path=deque(["Value", "Fn::ImportValue"]),
+                    rule=OutputsImportValue(),
+                )
+            ],
+        ),
         (
             {
                 "Condition": "isAdditionalVpc",