aws-cloudformation / cfn-lint

CloudFormation Linter
MIT No Attribution
2.45k stars 593 forks source link

[Bug] Impossible, rules-unaware condition errors #3630

Closed alnoki closed 2 months ago

alnoki commented 2 months ago

CloudFormation Lint Version

1.11.0

What operating system are you using?

Mac pre-commit

Describe the bug

The reproduction template throws:

W1001 Ref to resource 'InternetGateway' that may not be available when condition 'ProvisionStack' is False and when condition 'ProvisionVpc' is True at Resources/InternetGatewayAttachment/Properties/InternetGatewayId

Specifically, the purported hypothetical situation

when condition 'ProvisionStack' is False and when condition 'ProvisionVpc' is True

is impossible per the ProvisionVpc rule.

Expected behavior

The lint should pass, without having to duplicate ProvisionVpc rule logic in the ProvisionVpc condition. E.g. while updating the condition to:

  ProvisionVpc: !And
  - !Condition 'ProvisionStack'
  - !Equals
    - !Ref 'ProvisionVpc'
    - 'true'

results in a successful lint, this situation requires duplicate definitions just to satisfy the linter, thus reducing maintainability.

Moreover, since cfn-lint's static analysis is based off of conditions instead of rules (presumably, based on the reproduction template), templates that pass lints might not preserve the intended behavior if a cascaded condition is added without an accompanying duplicate rule.

Reproduction template

---
Conditions:
  ProvisionStack: !Equals
  - !Ref 'ProvisionStack'
  - 'true'
  ProvisionVpc: !Equals
  - !Ref 'ProvisionVpc'
  - 'true'
Parameters:
  ProvisionStack:
    AllowedValues:
    - 'false'
    - 'true'
    Type: 'String'
  ProvisionVpc:
    AllowedValues:
    - 'false'
    - 'true'
    Type: 'String'
Resources:
  InternetGateway:
    Condition: 'ProvisionStack'
    Type: 'AWS::EC2::InternetGateway'
  InternetGatewayAttachment:
    Condition: 'ProvisionVpc'
    Properties:
      InternetGatewayId: !Ref 'InternetGateway'
      VpcId: !Ref 'Vpc'
    Type: 'AWS::EC2::VPCGatewayAttachment'
  Vpc:
    Condition: 'ProvisionVpc'
    Properties:
      CidrBlock: '0.0.0.0/16'
    Type: 'AWS::EC2::VPC'
Rules:
  ProvisionVpc:
    Assertions:
    - Assert: !Or
      - Fn::Not: !Condition 'ProvisionVpc'
      - !Condition 'ProvisionStack'
...
kddejong commented 2 months ago

Duplicate #1888. We would need to add support for Rules.

alnoki commented 1 month ago

@kddejong unfortunately with v1.14.2 the reproduction template still throws the same error described above, despite #3634's inclusion in v1.12.0. Did you verify #3634 against the reproduction template I provided above?

kddejong commented 1 month ago

Yea, but with the change of Fn::Not: !Condition 'ProvisionVpc' to Fn::Not: [!Condition 'ProvisionVpc']. I suppose it is possible the Rules version of the Fn::Not supports a none list but the docs say to use a list.

kddejong commented 1 month ago

Also as provided by the CloudFormation service Template error: Fn::Not requires a list argument with one element

alnoki commented 1 month ago

@kddejong thanks for the followup and for the docs references.

I updated a template I was actually using with the new list-based Fn::Not style and my lints passed, but then I was unable to deploy a changeset: it appears that !Condition is not a supported rule-specific intrinsic function, so I've filed #3710 accordingly

kddejong commented 1 month ago

Working on the Condition portion of this today.