aws-cloudformation / cfn-lint

CloudFormation Linter
MIT No Attribution
2.4k stars 576 forks source link

Conditional with a Mapping within a Transform returns: E1022 'MapName' is not one of [] #3430

Closed onikroo closed 4 days ago

onikroo commented 5 days ago

CloudFormation Lint Version

1.3.7

What operating system are you using?

Amazon Linux 2023 (Fedora)

Describe the bug

When using transform to import mapping values with a conditional check, the MapName is fails linting. The error returned is E1022 'MapName' is not one of []

In the example file provided, there are succesful FindInMap (those outside of the conditional) and the error is returned on line 40, where FindInMap is used with the conditional.

Note that this has been in place for a long time with the last successful run with version 1.3.4 of cfn-lint. There were no changes to the template itself between successful run on 1.3.4 and the aformentioned E1022 error on 1.3.7.

Expected behavior

Either resolve the conditional or if not possible, ignore linting of anything behind an unresolvable conditional.

Reproduction template

AWSTemplateFormatVersion: 2010-09-09
Description: Example template to reproduce E1022 bug
Parameters:
  Key1Param:
    Description: Datacenter
    Type: String
    Default: Key1

Mappings:
  Fn::Transform:
    Name: AWS::Include
    Parameters:
      Location: !Sub s3://BucketName/1.0.0/mappings.yaml

Conditions:
  UsePrefix: !Not
    - !Equals
      - 'false'
      - 'true'

Resources:
  SomeInstance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !FindInMap [ MapName, !Ref Key1Param, Key2 ]

  SomeRecordSet:
    Type: 'AWS::Route53::RecordSet'
    Properties:
      HostedZoneName:
        Fn::FindInMap:
          - MapName
          - Ref: Key1Param
          - Key2
      Name: !Join
        - ''
        - - !If [UsePrefix, !Sub '${Key1Param}-', '']
          - 'some-prefix.'
          - Fn::FindInMap:
            - MapName
            - Ref: Key1Param
            - Key2
      Type: CNAME
      TTL: 90
      ResourceRecords:
        - 'SomeValue'
      SetIdentifier: some-identifier
      Weight: 100
kddejong commented 5 days ago

Based on the indentation provided the only conditional is !If [UsePrefix, !Sub '${Key1Param}-', ''] the Fn::FindInMap resides outside of the conditional and is part of the Join.

Name: !Join
        - ''
        - - !If [UsePrefix, !Sub '${Key1Param}-', '']
          - 'some-prefix.'
          - Fn::FindInMap:
            - MapName
            - Ref: Key1Param
            - Key2

Our support of Fn::Transform is kind of limited. #476 We did add some logic for handing Fn::Transform in the key area of the mappings but not at the map level. I don't think this change will be too difficult to handle.

onikroo commented 5 days ago

You are very right there. Apologies, as my suggestion of the conditional being a contributing factor here is incorrect. The culprit seems to be nesting the FindInMap inside the Join with any joined value. The FindInMap referencing a map brought in via a transform seems to pass linting outside of a join.

Does that sound like a more likely culprit to you?

kddejong commented 5 days ago

this PR will fix the issue. It has some refactoring to handle transform at the root of the Mappings section.