Repository: aws-cloudformation/cfn-lint

Issue:
E0001 when LayerVersion ContentUri references local file
*cfn-lint version: 0.16.0*

Using latest version of cfn-lint and updated spec files.

*Description of issue.*

Linting a SAM template fails when including a LayerVersion with `ContentUri` referencing a local file.

Example template:

```yaml
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Resources:
    ExampleLayer:
        Type: AWS::Serverless::LayerVersion
        Properties:
            LayerName: "Example"
            ContentUri: "./layers/example.zip"
            CompatibleRuntimes:
                - python3.6
```

Error:

```
E0001 Error transforming template: Resource with id [ExampleLayere5b6fe5ccd] is invalid. 'ContentUri' is not a valid S3 Uri of the form "s3://bucket/key" with optional versionId query parameter.
example.yaml:1:1
```

However, this template validates with `sam validate` and works as expected with `sam package`. Example output template from `sam package`:

```yaml
AWSTemplateFormatVersion: 2010-09-09
Resources:
  ExampleLayer:
    Properties:
      CompatibleRuntimes:
      - python3.6
      ContentUri: s3://<redacted>/ca1212f406e4a73dbe62c2ac6b8b02f0
      LayerName: Example
    Type: AWS::Serverless::LayerVersion
Transform: AWS::Serverless-2016-10-31
```

I will note that even though this is the expected `sam package` behavior, I do not believe it is properly documented in either SAM CLI or AWS CLI (`aws cloudformation package`) docs.


Discussion:

Resolving patch:
diff --git a/src/cfnlint/transform.py b/src/cfnlint/transform.py
--- a/src/cfnlint/transform.py
+++ b/src/cfnlint/transform.py
@@ -70,7 +70,9 @@ def _replace_local_codeuri(self):
             if resource_type == 'AWS::Serverless::Function':
 
                 Transform._update_to_s3_uri('CodeUri', resource_dict)
-
+            if resource_type in ['AWS::Serverless::LayerVersion']:
+                if resource_dict.get('ContentUri'):
+                    Transform._update_to_s3_uri('ContentUri', resource_dict)
             if resource_type == 'AWS::Serverless::Api':
                 if 'DefinitionBody' not in resource_dict:
                     Transform._update_to_s3_uri('DefinitionUri', resource_dict)


Test patch:
diff --git a/test/fixtures/templates/bad/transform_serverless_template.yaml b/test/fixtures/templates/bad/transform_serverless_template.yaml
--- a/test/fixtures/templates/bad/transform_serverless_template.yaml
+++ b/test/fixtures/templates/bad/transform_serverless_template.yaml
@@ -47,6 +47,12 @@ Resources:
               detail:
                 state:
                   - terminated
+  ExampleLayer:
+    Type: AWS::Serverless::LayerVersion
+    Properties:
+        LayerName: "Example"
+        CompatibleRuntimes:
+            - python3.6
   myBucket:
     Type: AWS::S3::Bucket
     Properties: {}
diff --git a/test/fixtures/templates/good/transform.yaml b/test/fixtures/templates/good/transform.yaml
--- a/test/fixtures/templates/good/transform.yaml
+++ b/test/fixtures/templates/good/transform.yaml
@@ -8,6 +8,13 @@ Resources:
       Handler: index.handler
       Runtime: nodejs4.3
       CodeUri: 's3://testBucket/mySourceCode.zip'
+  ExampleLayer:
+    Type: AWS::Serverless::LayerVersion
+    Properties:
+        LayerName: "Example"
+        ContentUri: "./layers/example.zip"
+        CompatibleRuntimes:
+            - python3.6
 Outputs:
   myOutput:
     Value: !GetAtt [ MyServerlessFunctionLogicalID, Arn ]