From f7ff568ebc876f3ffd985214353ebb417095160c Mon Sep 17 00:00:00 2001 From: Kevin DeJong Date: Tue, 16 Jul 2024 09:44:50 -0700 Subject: [PATCH 1/2] Add rule E3663 to validate lambda fn env vars --- .../environment_variable_keys.json | 26 +++++ .../resources/lmbd/FunctionEnvironmentKeys.py | 51 ++++++++ .../lmbd/test_function_environment_keys.py | 109 ++++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 src/cfnlint/data/schemas/extensions/aws_lambda_function/environment_variable_keys.json create mode 100644 src/cfnlint/rules/resources/lmbd/FunctionEnvironmentKeys.py create mode 100644 test/unit/rules/resources/lmbd/test_function_environment_keys.py diff --git a/src/cfnlint/data/schemas/extensions/aws_lambda_function/environment_variable_keys.json b/src/cfnlint/data/schemas/extensions/aws_lambda_function/environment_variable_keys.json new file mode 100644 index 0000000000..6c3897baea --- /dev/null +++ b/src/cfnlint/data/schemas/extensions/aws_lambda_function/environment_variable_keys.json @@ -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" + ] + } + } +} diff --git a/src/cfnlint/rules/resources/lmbd/FunctionEnvironmentKeys.py b/src/cfnlint/rules/resources/lmbd/FunctionEnvironmentKeys.py new file mode 100644 index 0000000000..756398a27f --- /dev/null +++ b/src/cfnlint/rules/resources/lmbd/FunctionEnvironmentKeys.py @@ -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 diff --git a/test/unit/rules/resources/lmbd/test_function_environment_keys.py b/test/unit/rules/resources/lmbd/test_function_environment_keys.py new file mode 100644 index 0000000000..bad7695b21 --- /dev/null +++ b/test/unit/rules/resources/lmbd/test_function_environment_keys.py @@ -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}" From 16147f49f3c5fd5109925bce5a4660be4b56cfe8 Mon Sep 17 00:00:00 2001 From: Kevin DeJong Date: Tue, 16 Jul 2024 10:28:12 -0700 Subject: [PATCH 2/2] Fix graph tests