Skip to content

Commit

Permalink
Add rule E3663 to validate lambda fn env vars (#3505)
Browse files Browse the repository at this point in the history
* Add rule E3663 to validate lambda fn env vars
  • Loading branch information
kddejong authored Jul 17, 2024
1 parent 33acafd commit 0dd93b2
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"propertyNames": {
"not": {
"enum": [
"_HANDLER",
"_X_AMZN_TRACE_ID",
"AWS_DEFAULT_REGION",
"AWS_REGION",
"AWS_EXECUTION_ENV",
"AWS_LAMBDA_FUNCTION_NAME",
"AWS_LAMBDA_FUNCTION_MEMORY_SIZE",
"AWS_LAMBDA_FUNCTION_VERSION",
"AWS_LAMBDA_INITIALIZATION_TYPE",
"AWS_LAMBDA_LOG_GROUP_NAME",
"AWS_LAMBDA_LOG_STREAM_NAME",
"AWS_ACCESS_KEY",
"AWS_ACCESS_KEY_ID",
"AWS_SECRET_ACCESS_KEY",
"AWS_SESSION_TOKEN",
"AWS_LAMBDA_RUNTIME_API",
"LAMBDA_TASK_ROOT",
"LAMBDA_RUNTIME_DIR"
]
}
}
}
51 changes: 51 additions & 0 deletions src/cfnlint/rules/resources/lmbd/FunctionEnvironmentKeys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: MIT-0
"""

from __future__ import annotations

from typing import Any

import cfnlint.data.schemas.extensions.aws_lambda_function
from cfnlint.jsonschema import ValidationResult
from cfnlint.jsonschema.protocols import Validator
from cfnlint.rules.jsonschema import CfnLintJsonSchema, SchemaDetails


class FunctionEnvironmentKeys(CfnLintJsonSchema):

id = "E3663"
shortdesc = "Validate Lambda environment variable names aren't reserved"
description = (
"Lambda reserves a set of environment variable names for its use. "
"This rule validates that the provided environment variable names "
"don't use the reserved variable names"
)
source_url = (
"https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html"
)
tags = ["resources", "lambda", "runtime"]

def __init__(self):
"""Init"""
super().__init__(
keywords=[
"Resources/AWS::Lambda::Function/Properties/Environment/Variables"
],
schema_details=SchemaDetails(
cfnlint.data.schemas.extensions.aws_lambda_function,
"environment_variable_keys.json",
),
all_matches=True,
)

def validate(
self, validator: Validator, keywords: Any, instance: Any, schema: dict[str, Any]
) -> ValidationResult:
for err in super().validate(validator, keywords, instance, schema):
err.message = (
f"{err.instance!r} is a reserved variable name, one of "
f"{self.schema.get('propertyNames').get('not').get('enum')!r}"
)
yield err
109 changes: 109 additions & 0 deletions test/unit/rules/resources/lmbd/test_function_environment_keys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"""
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: MIT-0
"""

from collections import deque

import pytest

from cfnlint.jsonschema import ValidationError
from cfnlint.rules.resources.lmbd.FunctionEnvironmentKeys import FunctionEnvironmentKeys


@pytest.fixture(scope="module")
def rule():
rule = FunctionEnvironmentKeys()
yield rule


@pytest.mark.parametrize(
"instance,expected",
[
(
{"Foo": "Bar"},
[],
),
(
{"AWS_REGION": "Bar"},
[
ValidationError(
(
"'AWS_REGION' is a reserved variable name, one of "
"['_HANDLER', '_X_AMZN_TRACE_ID', 'AWS_DEFAULT_REGION', "
"'AWS_REGION', 'AWS_EXECUTION_ENV', "
"'AWS_LAMBDA_FUNCTION_NAME', "
"'AWS_LAMBDA_FUNCTION_MEMORY_SIZE', "
"'AWS_LAMBDA_FUNCTION_VERSION', "
"'AWS_LAMBDA_INITIALIZATION_TYPE', "
"'AWS_LAMBDA_LOG_GROUP_NAME', "
"'AWS_LAMBDA_LOG_STREAM_NAME', "
"'AWS_ACCESS_KEY', 'AWS_ACCESS_KEY_ID', "
"'AWS_SECRET_ACCESS_KEY', "
"'AWS_SESSION_TOKEN', 'AWS_LAMBDA_RUNTIME_API', "
"'LAMBDA_TASK_ROOT', 'LAMBDA_RUNTIME_DIR']"
),
schema_path=deque(["propertyNames", "not"]),
path=deque(["AWS_REGION"]),
rule=FunctionEnvironmentKeys(),
validator="not",
)
],
),
(
{
"Foo": "Bar",
"AWS_REGION": "Bar",
"Bar": "Foo",
"AWS_ACCESS_KEY": "Foo",
},
[
ValidationError(
(
"'AWS_REGION' is a reserved variable name, one of "
"['_HANDLER', '_X_AMZN_TRACE_ID', 'AWS_DEFAULT_REGION', "
"'AWS_REGION', 'AWS_EXECUTION_ENV', "
"'AWS_LAMBDA_FUNCTION_NAME', "
"'AWS_LAMBDA_FUNCTION_MEMORY_SIZE', "
"'AWS_LAMBDA_FUNCTION_VERSION', "
"'AWS_LAMBDA_INITIALIZATION_TYPE', "
"'AWS_LAMBDA_LOG_GROUP_NAME', "
"'AWS_LAMBDA_LOG_STREAM_NAME', "
"'AWS_ACCESS_KEY', 'AWS_ACCESS_KEY_ID', "
"'AWS_SECRET_ACCESS_KEY', "
"'AWS_SESSION_TOKEN', 'AWS_LAMBDA_RUNTIME_API', "
"'LAMBDA_TASK_ROOT', 'LAMBDA_RUNTIME_DIR']"
),
schema_path=deque(["propertyNames", "not"]),
path=deque(["AWS_REGION"]),
rule=FunctionEnvironmentKeys(),
validator="not",
),
ValidationError(
(
"'AWS_ACCESS_KEY' is a reserved variable name, one of "
"['_HANDLER', '_X_AMZN_TRACE_ID', 'AWS_DEFAULT_REGION', "
"'AWS_REGION', 'AWS_EXECUTION_ENV', "
"'AWS_LAMBDA_FUNCTION_NAME', "
"'AWS_LAMBDA_FUNCTION_MEMORY_SIZE', "
"'AWS_LAMBDA_FUNCTION_VERSION', "
"'AWS_LAMBDA_INITIALIZATION_TYPE', "
"'AWS_LAMBDA_LOG_GROUP_NAME', "
"'AWS_LAMBDA_LOG_STREAM_NAME', "
"'AWS_ACCESS_KEY', 'AWS_ACCESS_KEY_ID', "
"'AWS_SECRET_ACCESS_KEY', "
"'AWS_SESSION_TOKEN', 'AWS_LAMBDA_RUNTIME_API', "
"'LAMBDA_TASK_ROOT', 'LAMBDA_RUNTIME_DIR']"
),
schema_path=deque(["propertyNames", "not"]),
path=deque(["AWS_ACCESS_KEY"]),
rule=FunctionEnvironmentKeys(),
validator="not",
),
],
),
],
)
def test_validate(instance, expected, rule, validator):
errs = list(rule.validate(validator, "LambdaRuntime", instance, {}))
assert errs == expected, f"Expected {expected} got {errs}"

0 comments on commit 0dd93b2

Please sign in to comment.