Skip to content

Commit b7bc622

Browse files
tal66kddejong
andauthored
New rule for Lambda zip deployment (#2682)
* New rule for Lambda zip deployment --------- Co-authored-by: Kevin DeJong <[email protected]>
1 parent 24e6f29 commit b7bc622

File tree

5 files changed

+168
-1
lines changed

5 files changed

+168
-1
lines changed

docs/rules.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ To include these rules, use the `-e/include-experimental` argument when running
4646
## Rules
4747
(_This documentation is generated by running `cfn-lint --update-documentation`, do not alter this manually_)
4848

49-
The following **152** rules are applied by this linter:
49+
The following **153** rules are applied by this linter:
5050

5151
| Rule ID | Title | Description | Config<br />(Name:Type:Default) | Source | Tags |
5252
| -------- | ----- | ----------- | ---------- | ------ | ---- |
@@ -191,6 +191,7 @@ The following **152** rules are applied by this linter:
191191
| [W2510<a name="W2510"></a>](../src/cfnlint/rules/parameters/LambdaMemorySize.py) | Parameter Memory Size attributes should have max and min | Check if a parameter that is used for Lambda memory size should have a min and max size that matches Lambda constraints | | [Source](https://docs.aws.amazon.com/lambda/latest/dg/API_CreateFunction.html#SSS-CreateFunction-request-MemorySize) | `parameters`,`lambda` |
192192
| [W2511<a name="W2511"></a>](../src/cfnlint/rules/resources/iam/PolicyVersion.py) | Check IAM Resource Policies syntax | See if the elements inside an IAM Resource policy are configured correctly. | | [Source](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html) | `properties`,`iam` |
193193
| [W2531<a name="W2531"></a>](../src/cfnlint/rules/resources/lmbd/DeprecatedRuntimeEol.py) | Check if EOL Lambda Function Runtimes are used | Check if an EOL Lambda Runtime is specified and give a warning if used. | | [Source](https://docs.aws.amazon.com/lambda/latest/dg/runtime-support-policy.html) | `resources`,`lambda`,`runtime` |
194+
| [W2533<a name="W2533"></a>](../src/cfnlint/rules/resources/lmbd/ZipPackageRequiredProperties.py) | Check required properties for Lambda if the deployment package is a .zip file | When the package type is Zip, you must also specify the `handler` and `runtime` properties. | | [Source](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html) | `resources`,`lambda` |
194195
| [W3002<a name="W3002"></a>](../src/cfnlint/rules/resources/properties/PropertiesTemplated.py) | Warn when properties are configured to only work with the package command | Some properties can be configured to only work with the CloudFormationpackage command. Warn when this is the case so user is aware. | | [Source](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/package.html) | `resources` |
195196
| [W3005<a name="W3005"></a>](../src/cfnlint/rules/resources/DependsOnObsolete.py) | Check obsolete DependsOn configuration for Resources | Check if DependsOn is specified if not needed. A Ref or a Fn::GetAtt already is an implicit dependency. | | [Source](https://aws.amazon.com/blogs/devops/optimize-aws-cloudformation-templates/) | `resources`,`dependson`,`ref`,`getatt` |
196197
| [W3010<a name="W3010"></a>](../src/cfnlint/rules/resources/properties/AvailabilityZone.py) | Availability Zone Parameters should not be hardcoded | Check if an Availability Zone property is hardcoded. | | [Source](https://github.com/aws-cloudformation/cfn-python-lint) | `parameters`,`availabilityzone` |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"""
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: MIT-0
4+
"""
5+
from cfnlint.rules import CloudFormationLintRule, RuleMatch
6+
7+
8+
class ZipPackageRequiredProperties(CloudFormationLintRule):
9+
id = "W2533"
10+
shortdesc = (
11+
"Check required properties for Lambda if the deployment package is a .zip file"
12+
)
13+
description = (
14+
"When the package type is Zip, "
15+
"you must also specify the `handler` and `runtime` properties."
16+
)
17+
source_url = "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html"
18+
tags = ["resources", "lambda"]
19+
20+
def match(self, cfn):
21+
matches = []
22+
required_properties = [
23+
"Handler",
24+
"Runtime",
25+
] # required if package is a .zip file
26+
27+
resources = cfn.get_resources(["AWS::Lambda::Function"])
28+
29+
for resource_name, resource in resources.items():
30+
properties = resource.get("Properties")
31+
if not isinstance(properties, dict):
32+
continue
33+
34+
for scenario in cfn.get_object_without_conditions(
35+
properties, ["PackageType", "Code", "Handler", "Runtime"]
36+
):
37+
props = scenario.get("Object")
38+
path = ["Resources", resource_name, "Properties"]
39+
40+
# check is zip deployment
41+
is_zip_deployment = True
42+
code = props.get("Code")
43+
44+
if props.get("PackageType") == "Zip":
45+
path.append("PackageType")
46+
elif isinstance(code, dict) and (
47+
code.get("ZipFile") or code.get("S3Key")
48+
):
49+
path.append("Code")
50+
else:
51+
is_zip_deployment = False
52+
53+
if not is_zip_deployment:
54+
continue
55+
56+
# check required properties for zip deployment
57+
missing_properties = []
58+
for p in required_properties:
59+
if props.get(p) is None:
60+
missing_properties.append(p)
61+
62+
if len(missing_properties) > 0:
63+
message = "Properties {0} missing for zip file deployment at {1}"
64+
matches.append(
65+
RuleMatch(
66+
path,
67+
message.format(
68+
missing_properties,
69+
"/".join(
70+
map(str, ["Resources", resource_name, "Properties"])
71+
),
72+
),
73+
)
74+
)
75+
76+
return matches
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Description: Missing properties.
3+
Resources:
4+
Function1:
5+
Type: AWS::Lambda::Function
6+
Properties:
7+
# Handler: index.handler
8+
Role: arn:aws:iam::123456789012:role/lambda-role
9+
Code:
10+
S3Bucket: my-bucket
11+
S3Key: function.zip
12+
# Runtime: nodejs16.x
13+
Function2:
14+
Type: AWS::Lambda::Function
15+
Properties:
16+
# Handler: index.handler
17+
Role: arn:aws:iam::123456789012:role/lambda-role
18+
Code:
19+
S3Bucket: my-bucket
20+
S3Key: function.zip
21+
Runtime: python3.9
22+
PackageType: Zip
23+
Function3:
24+
Type: AWS::Lambda::Function
25+
Properties:
26+
Handler: index.handler
27+
Role: arn:aws:iam::123456789012:role/lambda-role
28+
Code:
29+
ZipFile: |
30+
var aws = require('aws-sdk')
31+
exports.handler = function(event, context) {}
32+
# Runtime: nodejs16.x
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Description: Required Properties.
3+
Resources:
4+
Function1: # S3 key to deployment package
5+
Type: AWS::Lambda::Function
6+
Properties:
7+
Handler: index.handler
8+
Role: arn:aws:iam::123456789012:role/lambda-role
9+
Code:
10+
S3Bucket: my-bucket
11+
S3Key: function.zip
12+
Runtime: python3.9
13+
Function2: # source inline (zipped by CloudFormation)
14+
Type: AWS::Lambda::Function
15+
Properties:
16+
Handler: index.handler
17+
Role: arn:aws:iam::123456789012:role/lambda-role
18+
Code:
19+
ZipFile: |
20+
var aws = require('aws-sdk')
21+
exports.handler = function(event, context) {}
22+
Runtime: nodejs16.x
23+
Function3: # image deployment
24+
Type: AWS::Lambda::Function
25+
Properties:
26+
Role: arn:aws:iam::123456789012:role/lambda-role
27+
Code:
28+
ImageUri : 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
29+
PackageType: Image
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: MIT-0
4+
"""
5+
from test.unit.rules import BaseRuleTestCase
6+
7+
from cfnlint.rules.resources.lmbd.ZipPackageRequiredProperties import (
8+
ZipPackageRequiredProperties,
9+
)
10+
11+
12+
class TestZipPackageRequiredProperties(BaseRuleTestCase):
13+
"""Test required properties"""
14+
15+
def setUp(self):
16+
super(TestZipPackageRequiredProperties, self).setUp()
17+
self.collection.register(ZipPackageRequiredProperties())
18+
self.success_templates = [
19+
"test/fixtures/templates/good/resources/lambda/required_properties.yaml"
20+
]
21+
22+
def test_file_positive(self):
23+
self.helper_file_positive()
24+
25+
def test_file_negative(self):
26+
self.helper_file_negative(
27+
"test/fixtures/templates/bad/resources/lambda/required_properties.yaml",
28+
err_count=3,
29+
)

0 commit comments

Comments
 (0)