Skip to content

Commit 07b6398

Browse files
committed
Added feature to ignore F828 errors in cfn-inline-lambda-linter
1 parent 27225dd commit 07b6398

4 files changed

Lines changed: 143 additions & 11 deletions

File tree

cfn_inline_lambda_linter/linter.py

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,28 @@ def extractLambdaCode(resources, parameters, dict_to_check, args=None):
104104
if "python" in val:
105105
if args is None:
106106
process = subprocess.Popen(
107-
['python', '-m', 'flake8', "-"],
107+
['python', '-m', 'flake8', "-", "--ignore=F828"],
108108
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
109109
)
110110
else:
111-
process = subprocess.Popen(
112-
['python', '-m', 'flake8', "-"] + args.split(),
113-
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
114-
)
111+
if "F828" in args:
112+
process = subprocess.Popen(
113+
['python', '-m', 'flake8', "-"] + args.split(),
114+
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
115+
)
116+
else:
117+
if "--ignore" in args:
118+
y=args.split("--ignore=")[1] + ",F828"
119+
z=args.split("--ignore")[:-1] + ["--ignore=" + y]
120+
process = subprocess.Popen(
121+
['python', '-m', 'flake8', "-"] + z,
122+
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
123+
)
124+
else:
125+
process = subprocess.Popen(
126+
['python', '-m', 'flake8', "-", "--ignore=F828"] + args.split(),
127+
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
128+
)
115129
else:
116130
print(f"❌ Found a programming language that is not supported at the moment")
117131
dict_to_check[i] = {
@@ -126,14 +140,28 @@ def extractLambdaCode(resources, parameters, dict_to_check, args=None):
126140
if "python" in programming_lang:
127141
if args is None:
128142
process = subprocess.Popen(
129-
['python', '-m', 'flake8', "-"],
143+
['python', '-m', 'flake8', "-", "--ignore=F828"],
130144
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
131145
)
132146
else:
133-
process = subprocess.Popen(
134-
['python', '-m', 'flake8', "-"] + args.split(),
135-
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
136-
)
147+
if "F828" in args:
148+
process = subprocess.Popen(
149+
['python', '-m', 'flake8', "-"] + args.split(),
150+
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
151+
)
152+
else:
153+
if "--ignore" in args:
154+
y=args.split("--ignore=")[1] + ",F828"
155+
z=args.split("--ignore")[:-1] + ["--ignore=" + y]
156+
process = subprocess.Popen(
157+
['python', '-m', 'flake8', "-"] + z,
158+
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
159+
)
160+
else:
161+
process = subprocess.Popen(
162+
['python', '-m', 'flake8', "-", "--ignore=F828"] + args.split(),
163+
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
164+
)
137165
else:
138166
print(f"❌ Found a programming language that is not supported at the moment")
139167
dict_to_check[i] = {

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "cfn-inline-lambda-linter"
3-
version = "0.1.4"
3+
version = "0.1.5"
44
description = "Prints out linting errors found in inline cloudformation lambda code"
55
authors = ["Saad Mohsin Khan <saadk687@gmail.com>"]
66
license = "MIT"

tests/integration_tests/test_linter_end_to_end.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,35 @@ def test_linter_simple_yaml_not_cloudformation(tmp_path, monkeypatch):
8484

8585
# Should exit with code 0 (success) since it's skipping the file
8686
assert exc_info.value.code == 0
87+
88+
def test_linter_lambda_with_sub_function_ignores_f828(tmp_path, monkeypatch):
89+
"""Test that F828 errors are ignored when Lambda code uses !Sub with CloudFormation parameters/resources"""
90+
file_path = tmp_path / "lambda_with_sub_template.yaml"
91+
file_path.write_text("""
92+
Parameters:
93+
BucketName:
94+
Type: String
95+
Default: "my-test-bucket"
96+
97+
Resources:
98+
MyS3Bucket:
99+
Type: "AWS::S3::Bucket"
100+
Properties:
101+
BucketName: !Ref BucketName
102+
103+
LambdaFunction:
104+
Type: "AWS::Lambda::Function"
105+
Properties:
106+
Runtime: "python3.8"
107+
Code:
108+
ZipFile: !Sub |
109+
import boto3
110+
bucket_name = "${BucketName}"
111+
s3_bucket = "${MyS3Bucket}"
112+
def lambda_handler(event, context):
113+
print(f"Bucket name: {bucket_name}")
114+
print(f"S3 bucket: {s3_bucket}")
115+
return {"statusCode": 200}
116+
""")
117+
monkeypatch.setattr("sys.exit", lambda x: x) # Prevent pytest from exiting
118+
linter(str(file_path))

tests/unit_tests/test_extractLambdaCode.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,75 @@ def test_extract_lambda_code_missing_zipfile():
4444
result = extractLambdaCode(resources, {}, dict_to_check, args=None)
4545
# Should skip and leave status unchanged (or set to a specific value if your logic does)
4646
assert result["LambdaFunction"]["status"] == "SkippingLambda"
47+
48+
def test_extract_lambda_code_ignore_f828():
49+
"""Test that F828 errors are ignored when Lambda code uses CloudFormation substitutions."""
50+
resources = {
51+
"LambdaFunction": {
52+
"Type": "AWS::Lambda::Function",
53+
"Properties": {
54+
"Runtime": "python3.8",
55+
"Code": {
56+
"ZipFile": "import boto3\nimport json\n\n# This would normally trigger F828 - undefined name\nmy_resource = ${MyResource}\nbucket_name = ${BucketName}\n\ndef handler(event, context):\n return {'statusCode': 200}"
57+
}
58+
}
59+
}
60+
}
61+
dict_to_check = {"LambdaFunction": {"status": "CodeNotFormatted"}}
62+
result = extractLambdaCode(resources, {}, dict_to_check, args=None)
63+
64+
# The linter should ignore F828 errors and not report them as failures
65+
errors = result["LambdaFunction"].get("errors", "")
66+
assert "F828" not in errors, "F828 should be ignored for CloudFormation substitutions"
67+
68+
# Since we're ignoring F828, the status should be FoundNoErrors (other errors might still exist)
69+
# But F828 specifically should not be present
70+
if result["LambdaFunction"]["status"] == "FoundErrors":
71+
# If there are errors, make sure F828 is not one of them
72+
assert "F828" not in errors
73+
74+
def test_extract_lambda_code_ignore_f828_with_custom_args():
75+
"""Test that F828 is still ignored when custom flake8 args are provided."""
76+
resources = {
77+
"LambdaFunction": {
78+
"Type": "AWS::Lambda::Function",
79+
"Properties": {
80+
"Runtime": "python3.8",
81+
"Code": {
82+
"ZipFile": "import boto3\n\n# Variables from CloudFormation substitution\nmy_var = ${MyVariable}\n\ndef handler(event, context):\n return my_var"
83+
}
84+
}
85+
}
86+
}
87+
dict_to_check = {"LambdaFunction": {"status": "CodeNotFormatted"}}
88+
89+
# Test with custom args that don't mention F828
90+
result = extractLambdaCode(resources, {}, dict_to_check, args="--max-line-length=120")
91+
92+
errors = result["LambdaFunction"].get("errors", "")
93+
assert "F828" not in errors, "F828 should be ignored even with custom args"
94+
95+
def test_extract_lambda_code_ignore_f828_with_parameter_ref():
96+
"""Test that F828 is ignored when Runtime is referenced via parameter."""
97+
resources = {
98+
"LambdaFunction": {
99+
"Type": "AWS::Lambda::Function",
100+
"Properties": {
101+
"Runtime": "!Ref PythonRuntime",
102+
"Code": {
103+
"ZipFile": "import boto3\n\n# CloudFormation variables\nbucket = ${BucketName}\n\ndef handler(event, context):\n return bucket"
104+
}
105+
}
106+
}
107+
}
108+
parameters = {
109+
"PythonRuntime": {
110+
"Default": "python3.8"
111+
}
112+
}
113+
dict_to_check = {"LambdaFunction": {"status": "CodeNotFormatted"}}
114+
115+
result = extractLambdaCode(resources, parameters, dict_to_check, args=None)
116+
117+
errors = result["LambdaFunction"].get("errors", "")
118+
assert "F828" not in errors, "F828 should be ignored for parameter referenced runtime"

0 commit comments

Comments
 (0)