Repository: aws-cloudformation/cfn-lint

Issue:
Setting `AutoPublishAlias` value to a Ref reports E1019 violation on a different Property
*cfn-lint version: `0.21.4` 

Setting `AutoPublishAlias` value to a Ref, causes `E1019` to be reported on a
different property that also uses that Ref as a part of Sub. This appears to be new to `0.21.4`
as it is not present on `0.21.3`; perhaps related to #582 and result of
d57c041181f761f98fe2e86fff4f709dd037db15 ?

Failing Example on `0.21.4` (note that `FunctionName` property is reported):
```sh
$ cat template.yaml
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Parameters:
  EnvironmentName:
    Description: Environment where the function resides.
    Type: String
    Default: dev

Resources:
  Function:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub func-${EnvironmentName}-${AWS::Region}
      AutoPublishAlias: !Ref EnvironmentName
      Handler: lambda_function.handler
      Runtime: python3.6
      CodeUri:
        Bucket: foo
        Key: func.zip

$ docker run -it \
    -v $(pwd):/var/tmp/ \
    python:3.7.1-alpine3.8 \
    /bin/sh \
    -c "pip install -q 'cfn-lint==0.21.4' && cfn-lint -v && cfn-lint -t /var/tmp/template.yaml"
You are using pip version 18.1, however version 19.1.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
cfn-lint 0.21.4
E1019 Parameter EnvironmentName for Fn::Sub not found at Resources/Function/Properties/FunctionName/Fn::Sub
/var/tmp/template.yaml:11:3

$
```

No issue if a string value for `AutoPublishAlias` is used instead of a Ref:
```sh
$ cat template-string-alias.yaml
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Parameters:
  EnvironmentName:
    Description: Environment where the function resides.
    Type: String
    Default: dev

Resources:
  Function:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub func-${EnvironmentName}-${AWS::Region}
      AutoPublishAlias: myalias
      Handler: lambda_function.handler
      Runtime: python3.6
      CodeUri:
        Bucket: foo
        Key: func.zip

$ docker run -it \
    -v $(pwd):/var/tmp/ \
    python:3.7.1-alpine3.8 \
    /bin/sh \
    -c "pip install -q 'cfn-lint==0.21.4' && cfn-lint -v && cfn-lint -t /var/tmp/template-string-alias.yaml"
You are using pip version 18.1, however version 19.1.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
cfn-lint 0.21.4

$
```

Using a Ref for `AutoPublishAlias` does not report the error on `0.21.3`. Our
use does include a default value for the Parameter which may be relevant to not
seeing the issue described in #582.
```sh
$ cat template.yaml
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Parameters:
  EnvironmentName:
    Description: Environment where the function resides.
    Type: String
    Default: dev

Resources:
  Function:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub func-${EnvironmentName}-${AWS::Region}
      AutoPublishAlias: !Ref EnvironmentName
      Handler: lambda_function.handler
      Runtime: python3.6
      CodeUri:
        Bucket: foo
        Key: func.zip

$ docker run -it \
    -v $(pwd):/var/tmp/ \
    python:3.7.1-alpine3.8 \
    /bin/sh \
    -c "pip install -q 'cfn-lint==0.21.3' && cfn-lint -v && cfn-lint -t /var/tmp/template.yaml"
You are using pip version 18.1, however version 19.1.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
cfn-lint 0.21.3

$
```


Discussion:
I'm seeing the same issue. Setting the `AutoPublishAlias` with a `!Ref` throws an `E1019` for every usage of `!Sub` that uses the referenced parameter. 

An `E1012` is also being thrown on the serverless function itself.

Seems to happen regardless of whether or not the referenced parameter has a default value set.
Yea, sorry about that.  I should have a fix in early next week with a release to get this fixed for you.

Resolving patch:
diff --git a/src/cfnlint/__init__.py b/src/cfnlint/__init__.py
--- a/src/cfnlint/__init__.py
+++ b/src/cfnlint/__init__.py
@@ -451,8 +451,8 @@ def __init__(self, filename, template, regions=['us-east-1']):
             'Outputs',
             'Rules'
         ]
-        self.transform_globals = {}
         self.transform_pre = {}
+        self.transform_pre['Globals'] = {}
         self.transform_pre['Ref'] = self.search_deep_keys('Ref')
         self.transform_pre['Fn::Sub'] = self.search_deep_keys('Fn::Sub')
         self.conditions = cfnlint.conditions.Conditions(self)
@@ -703,7 +703,7 @@ def search_deep_keys(self, searchText):
         results = []
         results.extend(self._search_deep_keys(searchText, self.template, []))
         # Globals are removed during a transform.  They need to be checked manually
-        results.extend(self._search_deep_keys(searchText, self.transform_globals, []))
+        results.extend(self._search_deep_keys(searchText, self.transform_pre.get('Globals'), []))
         return results
 
     def get_condition_values(self, template, path=[]):
@@ -1336,7 +1336,7 @@ def transform(self):
         # Currently locked in to SAM specific
         if transform_type == 'AWS::Serverless-2016-10-31':
             # Save the Globals section so its available for rule processing
-            self.cfn.transform_globals = self.cfn.template.get('Globals', {})
+            self.cfn.transform_pre['Globals'] = self.cfn.template.get('Globals', {})
             transform = Transform(self.filename, self.cfn.template, self.cfn.regions[0])
             matches = transform.transform_template()
             self.cfn.template = transform.template()
diff --git a/src/cfnlint/transform.py b/src/cfnlint/transform.py
--- a/src/cfnlint/transform.py
+++ b/src/cfnlint/transform.py
@@ -114,9 +114,6 @@ def transform_template(self):
             self._template = cfnlint.helpers.convert_dict(
                 sam_translator.translate(sam_template=self._template, parameter_values=self._parameters))
 
-            for p_name in self._parameters:
-                del self._template['Parameters'][p_name]
-
             LOGGER.info('Transformed template: \n%s', cfnlint.helpers.format_json_string(self._template))
         except InvalidDocumentException as e:
             message = 'Error transforming template: {0}'


Test patch:
diff --git a/test/fixtures/templates/good/transform/auto_publish_alias.yaml b/test/fixtures/templates/good/transform/auto_publish_alias.yaml
--- a/test/fixtures/templates/good/transform/auto_publish_alias.yaml
+++ b/test/fixtures/templates/good/transform/auto_publish_alias.yaml
@@ -1,22 +1,38 @@
 ---
-  AWSTemplateFormatVersion: '2010-09-09'
-  Transform: AWS::Serverless-2016-10-31
-  
-  Parameters:
-    Stage:
-      Description: Environment stage (deployment phase)
-      Type: String
-      AllowedValues:
-        - beta
-        - prod
-  
-  Resources:
-    SkillFunction:
-      Type: AWS::Serverless::Function
-      Properties:
-        CodeUri: '.'
-        Handler: main.handler
-        Runtime: python3.7
-        Timeout: 30
-        MemorySize: 128
-        AutoPublishAlias: !Ref Stage
\ No newline at end of file
+AWSTemplateFormatVersion: '2010-09-09'
+Transform: AWS::Serverless-2016-10-31
+
+Parameters:
+  Stage1:
+    Description: Environment stage (deployment phase)
+    Type: String
+    AllowedValues:
+      - beta
+      - prod
+  Stage2:
+    Description: Environment stage (deployment phase)
+    Type: String
+    AllowedValues:
+      - beta
+      - prod
+
+Resources:
+  SkillFunction:
+    Type: AWS::Serverless::Function
+    Properties:
+      CodeUri: '.'
+      Handler: main.handler
+      Runtime: python3.7
+      Timeout: 30
+      MemorySize: 128
+      AutoPublishAlias: !Ref Stage1
+  SkillFunction2:
+    Type: AWS::Serverless::Function
+    Properties:
+      CodeUri: '.'
+      Handler: main.handler
+      Runtime: python3.7
+      Timeout: 30
+      MemorySize: 128
+      FunctionName: !Sub "Stage-${Stage2}-${AWS::Region}"
+      AutoPublishAlias: !Ref Stage2
diff --git a/test/module/transform/test_transform.py b/test/module/transform/test_transform.py
--- a/test/module/transform/test_transform.py
+++ b/test/module/transform/test_transform.py
@@ -29,7 +29,7 @@ def test_parameter_for_autopublish_version(self):
         template = cfn_yaml.load(filename)
         transformed_template = Transform(filename, template, region)
         transformed_template.transform_template()
-        self.assertDictEqual(transformed_template._parameters, {'Stage': 'Alias'})
+        self.assertDictEqual(transformed_template._parameters, {'Stage1': 'Alias', 'Stage2': 'Alias'})
         self.assertDictEqual(
           transformed_template._template.get('Resources').get('SkillFunctionAliasAlias').get('Properties'),
           {