Skip to content

Commit 0dd93b2

Browse files
authored
Add rule E3663 to validate lambda fn env vars (#3505)
* Add rule E3663 to validate lambda fn env vars
1 parent 33acafd commit 0dd93b2

File tree

3 files changed

+186
-0
lines changed

3 files changed

+186
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"propertyNames": {
3+
"not": {
4+
"enum": [
5+
"_HANDLER",
6+
"_X_AMZN_TRACE_ID",
7+
"AWS_DEFAULT_REGION",
8+
"AWS_REGION",
9+
"AWS_EXECUTION_ENV",
10+
"AWS_LAMBDA_FUNCTION_NAME",
11+
"AWS_LAMBDA_FUNCTION_MEMORY_SIZE",
12+
"AWS_LAMBDA_FUNCTION_VERSION",
13+
"AWS_LAMBDA_INITIALIZATION_TYPE",
14+
"AWS_LAMBDA_LOG_GROUP_NAME",
15+
"AWS_LAMBDA_LOG_STREAM_NAME",
16+
"AWS_ACCESS_KEY",
17+
"AWS_ACCESS_KEY_ID",
18+
"AWS_SECRET_ACCESS_KEY",
19+
"AWS_SESSION_TOKEN",
20+
"AWS_LAMBDA_RUNTIME_API",
21+
"LAMBDA_TASK_ROOT",
22+
"LAMBDA_RUNTIME_DIR"
23+
]
24+
}
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: MIT-0
4+
"""
5+
6+
from __future__ import annotations
7+
8+
from typing import Any
9+
10+
import cfnlint.data.schemas.extensions.aws_lambda_function
11+
from cfnlint.jsonschema import ValidationResult
12+
from cfnlint.jsonschema.protocols import Validator
13+
from cfnlint.rules.jsonschema import CfnLintJsonSchema, SchemaDetails
14+
15+
16+
class FunctionEnvironmentKeys(CfnLintJsonSchema):
17+
18+
id = "E3663"
19+
shortdesc = "Validate Lambda environment variable names aren't reserved"
20+
description = (
21+
"Lambda reserves a set of environment variable names for its use. "
22+
"This rule validates that the provided environment variable names "
23+
"don't use the reserved variable names"
24+
)
25+
source_url = (
26+
"https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html"
27+
)
28+
tags = ["resources", "lambda", "runtime"]
29+
30+
def __init__(self):
31+
"""Init"""
32+
super().__init__(
33+
keywords=[
34+
"Resources/AWS::Lambda::Function/Properties/Environment/Variables"
35+
],
36+
schema_details=SchemaDetails(
37+
cfnlint.data.schemas.extensions.aws_lambda_function,
38+
"environment_variable_keys.json",
39+
),
40+
all_matches=True,
41+
)
42+
43+
def validate(
44+
self, validator: Validator, keywords: Any, instance: Any, schema: dict[str, Any]
45+
) -> ValidationResult:
46+
for err in super().validate(validator, keywords, instance, schema):
47+
err.message = (
48+
f"{err.instance!r} is a reserved variable name, one of "
49+
f"{self.schema.get('propertyNames').get('not').get('enum')!r}"
50+
)
51+
yield err
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"""
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: MIT-0
4+
"""
5+
6+
from collections import deque
7+
8+
import pytest
9+
10+
from cfnlint.jsonschema import ValidationError
11+
from cfnlint.rules.resources.lmbd.FunctionEnvironmentKeys import FunctionEnvironmentKeys
12+
13+
14+
@pytest.fixture(scope="module")
15+
def rule():
16+
rule = FunctionEnvironmentKeys()
17+
yield rule
18+
19+
20+
@pytest.mark.parametrize(
21+
"instance,expected",
22+
[
23+
(
24+
{"Foo": "Bar"},
25+
[],
26+
),
27+
(
28+
{"AWS_REGION": "Bar"},
29+
[
30+
ValidationError(
31+
(
32+
"'AWS_REGION' is a reserved variable name, one of "
33+
"['_HANDLER', '_X_AMZN_TRACE_ID', 'AWS_DEFAULT_REGION', "
34+
"'AWS_REGION', 'AWS_EXECUTION_ENV', "
35+
"'AWS_LAMBDA_FUNCTION_NAME', "
36+
"'AWS_LAMBDA_FUNCTION_MEMORY_SIZE', "
37+
"'AWS_LAMBDA_FUNCTION_VERSION', "
38+
"'AWS_LAMBDA_INITIALIZATION_TYPE', "
39+
"'AWS_LAMBDA_LOG_GROUP_NAME', "
40+
"'AWS_LAMBDA_LOG_STREAM_NAME', "
41+
"'AWS_ACCESS_KEY', 'AWS_ACCESS_KEY_ID', "
42+
"'AWS_SECRET_ACCESS_KEY', "
43+
"'AWS_SESSION_TOKEN', 'AWS_LAMBDA_RUNTIME_API', "
44+
"'LAMBDA_TASK_ROOT', 'LAMBDA_RUNTIME_DIR']"
45+
),
46+
schema_path=deque(["propertyNames", "not"]),
47+
path=deque(["AWS_REGION"]),
48+
rule=FunctionEnvironmentKeys(),
49+
validator="not",
50+
)
51+
],
52+
),
53+
(
54+
{
55+
"Foo": "Bar",
56+
"AWS_REGION": "Bar",
57+
"Bar": "Foo",
58+
"AWS_ACCESS_KEY": "Foo",
59+
},
60+
[
61+
ValidationError(
62+
(
63+
"'AWS_REGION' is a reserved variable name, one of "
64+
"['_HANDLER', '_X_AMZN_TRACE_ID', 'AWS_DEFAULT_REGION', "
65+
"'AWS_REGION', 'AWS_EXECUTION_ENV', "
66+
"'AWS_LAMBDA_FUNCTION_NAME', "
67+
"'AWS_LAMBDA_FUNCTION_MEMORY_SIZE', "
68+
"'AWS_LAMBDA_FUNCTION_VERSION', "
69+
"'AWS_LAMBDA_INITIALIZATION_TYPE', "
70+
"'AWS_LAMBDA_LOG_GROUP_NAME', "
71+
"'AWS_LAMBDA_LOG_STREAM_NAME', "
72+
"'AWS_ACCESS_KEY', 'AWS_ACCESS_KEY_ID', "
73+
"'AWS_SECRET_ACCESS_KEY', "
74+
"'AWS_SESSION_TOKEN', 'AWS_LAMBDA_RUNTIME_API', "
75+
"'LAMBDA_TASK_ROOT', 'LAMBDA_RUNTIME_DIR']"
76+
),
77+
schema_path=deque(["propertyNames", "not"]),
78+
path=deque(["AWS_REGION"]),
79+
rule=FunctionEnvironmentKeys(),
80+
validator="not",
81+
),
82+
ValidationError(
83+
(
84+
"'AWS_ACCESS_KEY' is a reserved variable name, one of "
85+
"['_HANDLER', '_X_AMZN_TRACE_ID', 'AWS_DEFAULT_REGION', "
86+
"'AWS_REGION', 'AWS_EXECUTION_ENV', "
87+
"'AWS_LAMBDA_FUNCTION_NAME', "
88+
"'AWS_LAMBDA_FUNCTION_MEMORY_SIZE', "
89+
"'AWS_LAMBDA_FUNCTION_VERSION', "
90+
"'AWS_LAMBDA_INITIALIZATION_TYPE', "
91+
"'AWS_LAMBDA_LOG_GROUP_NAME', "
92+
"'AWS_LAMBDA_LOG_STREAM_NAME', "
93+
"'AWS_ACCESS_KEY', 'AWS_ACCESS_KEY_ID', "
94+
"'AWS_SECRET_ACCESS_KEY', "
95+
"'AWS_SESSION_TOKEN', 'AWS_LAMBDA_RUNTIME_API', "
96+
"'LAMBDA_TASK_ROOT', 'LAMBDA_RUNTIME_DIR']"
97+
),
98+
schema_path=deque(["propertyNames", "not"]),
99+
path=deque(["AWS_ACCESS_KEY"]),
100+
rule=FunctionEnvironmentKeys(),
101+
validator="not",
102+
),
103+
],
104+
),
105+
],
106+
)
107+
def test_validate(instance, expected, rule, validator):
108+
errs = list(rule.validate(validator, "LambdaRuntime", instance, {}))
109+
assert errs == expected, f"Expected {expected} got {errs}"

0 commit comments

Comments
 (0)