vscode-yaml icon indicating copy to clipboard operation
vscode-yaml copied to clipboard

Cloudformation template: result of !Join fails validation for string

Open jrnail23 opened this issue 5 years ago • 13 comments

Given the below setup, my cloudformation template is failing validation, as it's (correctly) stating the Name property below should be a string, but I'm otherwise properly using the !Join function, which should return a string.

Here's a simplified version of my cloudformation template, to demonstrate failure mytemplate.cf.yml

AWSTemplateFormatVersion: 2010-09-09

Resources:
  MyWebAppUrl:
    Type: "AWS::Route53::RecordSet"
    Properties:
      Type: A
      Name: !Join [".", ["StringA", "StringB"]]
      HostedZoneId: "FAKE_ZONE_ID"

my settings.json

{
	"yaml.customTags": [
		"!Join sequence"
	],
	"yaml.format.enable": true
}

validation failure

        {
            "severity": 1,
            "range": {
                "start": {
                    "line": 22,
                    "character": 18
                },
                "end": {
                    "line": 22,
                    "character": 47
                }
            },
            "message": "Incorrect type. Expected \"string\"."
        }

here's what I suspect is the AST:

[
    {
        "name": "AWSTemplateFormatVersion",
        "kind": 15,
        "location": {
            "uri": "file:///Users/myname/dev/myproject/ops/.cfn/mytemplate.cf.yml",
            "range": {
                "start": {
                    "line": 0,
                    "character": 0
                },
                "end": {
                    "line": 0,
                    "character": 36
                }
            }
        }
    },
    {
        "name": "Resources",
        "kind": 2,
        "location": {
            "uri": "file:///Users/myname/dev/myproject/ops/.cfn/mytemplate.cf.yml",
            "range": {
                "start": {
                    "line": 2,
                    "character": 0
                },
                "end": {
                    "line": 8,
                    "character": 34
                }
            }
        }
    },
    {
        "name": "MyWebAppUrl",
        "kind": 2,
        "location": {
            "uri": "file:///Users/myname/dev/myproject/ops/.cfn/mytemplate.cf.yml",
            "range": {
                "start": {
                    "line": 3,
                    "character": 2
                },
                "end": {
                    "line": 8,
                    "character": 34
                }
            }
        },
        "containerName": "Resources"
    },
    {
        "name": "Type",
        "kind": 15,
        "location": {
            "uri": "file:///Users/myname/dev/myproject/ops/.cfn/mytemplate.cf.yml",
            "range": {
                "start": {
                    "line": 4,
                    "character": 4
                },
                "end": {
                    "line": 4,
                    "character": 35
                }
            }
        },
        "containerName": "Resources.MyWebAppUrl"
    },
    {
        "name": "Properties",
        "kind": 2,
        "location": {
            "uri": "file:///Users/myname/dev/myproject/ops/.cfn/mytemplate.cf.yml",
            "range": {
                "start": {
                    "line": 5,
                    "character": 4
                },
                "end": {
                    "line": 8,
                    "character": 34
                }
            }
        },
        "containerName": "Resources.MyWebAppUrl"
    },
    {
        "name": "Type",
        "kind": 15,
        "location": {
            "uri": "file:///Users/myname/dev/myproject/ops/.cfn/mytemplate.cf.yml",
            "range": {
                "start": {
                    "line": 6,
                    "character": 6
                },
                "end": {
                    "line": 6,
                    "character": 13
                }
            }
        },
        "containerName": "Resources.MyWebAppUrl.Properties"
    },
    {
        "name": "Name",
        "kind": 18,
        "location": {
            "uri": "file:///Users/myname/dev/myproject/ops/.cfn/mytemplate.cf.yml",
            "range": {
                "start": {
                    "line": 7,
                    "character": 6
                },
                "end": {
                    "line": 7,
                    "character": 47
                }
            }
        },
        "containerName": "Resources.MyWebAppUrl.Properties"
    },
    {
        "name": "HostedZoneId",
        "kind": 15,
        "location": {
            "uri": "file:///Users/myname/dev/myproject/ops/.cfn/mytemplate.cf.yml",
            "range": {
                "start": {
                    "line": 8,
                    "character": 6
                },
                "end": {
                    "line": 8,
                    "character": 34
                }
            }
        },
        "containerName": "Resources.MyWebAppUrl.Properties"
    }
]

jrnail23 avatar Apr 26 '19 01:04 jrnail23

After digging into the code a bit, it seems that the problem here is that !Join actually transforms a sequence into a scalar, but that concept doesn't appear to be supported by the custom tag parsing mechanism. As such, I'd expect that cloudformation's !Split function might be problematic for the same reasons (although in the opposite direction).

Perhaps the problem might be solved by adding another optional token to the custom tag to indicate the return type (if it differs from the input type). Something like !Join sequence -> scalar could work, and with that approach you could also have !Split -> sequence, where it would apply the convention of scalar being the default node type (thus omitted in this example), and sequence being the actual type of the transformed node.

jrnail23 avatar Apr 26 '19 02:04 jrnail23

It is crucial to fix because many other extensions have vscode-yaml as dependency e.g. Kubernetes, Atlassian for VSCode etc. So when you want to use vscode-cfn-lint you have to uninstall them and vscode-yaml.

programmer04 avatar May 14 '19 07:05 programmer04

I have the same problem with cloudformation script and !Join.

DamirAinullin avatar May 16 '19 09:05 DamirAinullin

If it helps I notice I don't get the issue on a S3 WebsiteBucketPolicy Resource, but I do get the !Join not a string issue on a CloudFront Distribution Properties Origins DomainName.

Resources:
  S3Bucket:
  WebsiteBucketPolicy:
      Type: AWS::S3::BucketPolicy
      Properties:
        Bucket: !Ref S3Bucket
        PolicyDocument:
          Statement:
          - Sid: PublicReadForGetBucketObjects
            Effect: Allow
            Principal: '*'
            Action: s3:GetObject
            Resource: !Join [ '', ['arn:aws:s3:::', !Ref S3Bucket, /*] ]

vs

CFDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Comment: Cloudfront Distribution pointing to S3 Bucket
        Origins:
        - DomainName: !Join [ '', [ !Ref S3Bucket, '.s3.amazonaws.com' ] ] # <-- Error Incorrect type, expected string

cybercussion avatar Jun 25 '19 21:06 cybercussion

I'm experiencing this same issue when working with yaml template. I had to turn off yaml validation in config.json to get rid of it. My config.json settings:

"yaml.customTags": [
        "!And scalar",
        "!And mapping",
        "!And sequence",
        "!If scalar",
        "!If mapping",
        "!If sequence",
        "!Not scalar",
        "!Not mapping",
        "!Not sequence",
        "!Equals scalar",
        "!Equals mapping",
        "!Equals sequence",
        "!Or scalar",
        "!Or mapping",
        "!Or sequence",
        "!FindInMap scalar",
        "!FindInMap mappping",
        "!FindInMap sequence",
        "!Base64 scalar",
        "!Base64 mapping",
        "!Base64 sequence",
        "!Cidr scalar",
        "!Cidr mapping",
        "!Cidr sequence",
        "!Ref scalar",
        "!Ref mapping",
        "!Ref sequence",
        "!Sub scalar",
        "!Sub mapping",
        "!Sub sequence",
        "!GetAtt scalar",
        "!GetAtt mapping",
        "!GetAtt sequence",
        "!GetAZs scalar",
        "!GetAZs mapping",
        "!GetAZs sequence",
        "!ImportValue scalar",
        "!ImportValue mapping",
        "!ImportValue sequence",
        "!Select scalar",
        "!Select mapping",
        "!Select sequence",
        "!Split scalar",
        "!Split mapping",
        "!Split sequence",
        "!Join scalar",
        "!Join mapping",
        "!Join sequence",
        "!And",
        "!If",
        "!Not",
        "!Equals",
        "!Or",
        "!FindInMap",
        "!Base64",
        "!Join",
        "!Cidr",
        "!Ref",
        "!Sub",
        "!GetAtt",
        "!GetAZs",
        "!ImportValue",
        "!Select",
        "!Split"
    ],
    "yaml.format.enable": true,
    "yaml.validate": false,

maczes avatar Feb 19 '20 10:02 maczes

@jrnail23 were you ever able to resolve this issue or find a suitable workaround? I am facing the same thing today. Thanks.

pflugs30 avatar Jun 05 '20 15:06 pflugs30

no, @pflugs30, I wasn't. We've since moved on to other ways of working with CloudFormation (building up the config using JS, rather than using YAML).

jrnail23 avatar Jun 05 '20 15:06 jrnail23

Sad that this got closed b/c this is still an issue.

samuelms1 avatar Apr 01 '21 19:04 samuelms1

@samuelms1 this is not closed. I just hasn't been touched in a while.

joshuawilson avatar Apr 01 '21 20:04 joshuawilson

@samuelms1 this is not closed. I just hasn't been touched in a while.

Any new update?

oshribr avatar Apr 26 '22 14:04 oshribr

This is still an issue: image

djodrell avatar Mar 31 '23 15:03 djodrell

This is as well: LogGroupName: !Join ["/", ["/aws/pipeline", !Ref "AWS::StackName"]]

connell-theaa avatar Apr 18 '23 12:04 connell-theaa

Mismo problema: La unica fue deshabilitar la valiacion... busque por horas y nada funciono!

AutorizerApiEntityManagements0001: Type: "AWS::ApiGateway::Authorizer" Properties: IdentitySource: method.request.header.Authorization Name: !ImportValue "Stack-AWS-Cognito-UserPool-UAT-UserPool" RestApiId: !Ref ApiEntityManagements0001 Type: "COGNITO_USER_POOLS" ProviderARNs: - !Join - "" - - !Sub "arn:aws:cognito-idp:us-east-1:${AWS::AccountId}:userpool/" - !ImportValue "Stack-AWS-Cognito-UserPool-UAT-UserPool"

diegojaguares avatar Apr 28 '23 23:04 diegojaguares