From 7a9a5ad7afebd8f80e6789c99e529c673a37e555 Mon Sep 17 00:00:00 2001 From: goya813 Date: Thu, 19 Oct 2023 13:46:30 +0900 Subject: [PATCH 1/2] Added throw error when event function name is long (#1205) * implement scheduled_event_name validation * add too long function name test case * update function name pattern in README * fix black * add event function pattern in docstring * fixed pattern * add error description * add using invalid character test case * add description * fixed error mesasge * fixed event function name pattern in README --------- Co-authored-by: monkut --- README.md | 4 ++-- tests/tests.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ zappa/core.py | 17 ++++++++++++++++- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8e9878c49..6756d0b7a 100644 --- a/README.md +++ b/README.md @@ -932,11 +932,11 @@ to change Zappa's behavior. Use these at your own risk! "environment_variables": {"your_key": "your_value"}, // A dictionary of environment variables that will be available to your deployed app. See also "remote_env" and "aws_environment_variables". Default {}. "events": [ { // Recurring events - "function": "your_module.your_recurring_function", // The function to execute + "function": "your_module.your_recurring_function", // The function to execute (Pattern: [._A-Za-z0-9]+). "expression": "rate(1 minute)" // When to execute it (in cron or rate format) }, { // AWS Reactive events - "function": "your_module.your_reactive_function", // The function to execute + "function": "your_module.your_reactive_function", // The function to execute (Pattern: [._A-Za-z0-9]+). "event_source": { "arn": "arn:aws:s3:::my-bucket", // The ARN of this event source "events": [ diff --git a/tests/tests.py b/tests/tests.py index daba1ada2..b2f4f6c4a 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -2238,6 +2238,52 @@ def test_get_scheduled_event_name__truncated__has_name__has_index(self): f"{hashed_lambda_name}-{index}-{event['name']}-{function}", ) + def test_get_scheduled_event_name__using_invalid_character(self): + zappa = Zappa() + event = {} + function = "foo$" + lambda_name = "bar" + with self.assertRaises(EnvironmentError): + zappa.get_scheduled_event_name(event, function, lambda_name) + + def test_get_scheduled_event_name__using_hyphen(self): + zappa = Zappa() + event = {} + function = "foo-2" + lambda_name = "bar" + with self.assertRaises(EnvironmentError): + zappa.get_scheduled_event_name(event, function, lambda_name) + + def test_get_scheduled_event_name__max_function_name(self): + zappa = Zappa() + event = {} + function = "a" * 63 + lambda_name = "bar" + + self.assertEqual( + zappa.get_scheduled_event_name(event, function, lambda_name), + f"-{function}", + ) + + def test_get_scheduled_event_name__over_function_name(self): + zappa = Zappa() + event = {} + function = "a" * 64 + lambda_name = "bar" + + with self.assertRaises(EnvironmentError): + zappa.get_scheduled_event_name(event, function, lambda_name) + + def test_get_scheduled_event_name__over_name_with_index(self): + zappa = Zappa() + event = {} + function = "a" * 62 + index = 1 + lambda_name = "bar" + + with self.assertRaises(EnvironmentError): + zappa.get_scheduled_event_name(event, function, lambda_name, index) + def test_shameless(self): shamelessly_promote() diff --git a/zappa/core.py b/zappa/core.py index ae80b77e1..99de5646f 100644 --- a/zappa/core.py +++ b/zappa/core.py @@ -2939,7 +2939,17 @@ def get_scheduled_event_name(self, event, function, lambda_name, index=0): """ Returns an AWS-valid CloudWatch rule name using a digest of the event name, lambda name, and function. This allows support for rule names that may be longer than the 64 char limit. + + function pattern: '^[._A-Za-z0-9]{0,63}$' """ + max_event_rule_name_length = 64 + max_name_length = max_event_rule_name_length - 1 # Because it must contain the delimiter "-". + function_regex = re.compile(f"^[._A-Za-z0-9]{{0,{max_name_length}}}$") + if not re.fullmatch(function_regex, function): + # Validation Rule: https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_Rule.html + # '-' cannot be used because it is a delimiter + raise EnvironmentError("event['function']: Pattern '^[._A-Za-z0-9]{0,63}$'.") + name = event.get("name", function) if name != function: # a custom event name has been provided, make sure function name is included as postfix, @@ -2950,11 +2960,16 @@ def get_scheduled_event_name(self, event, function, lambda_name, index=0): # prefix all entries bar the first with the index # Related: https://github.com/Miserlou/Zappa/pull/1051 name = "{}-{}".format(index, name) + + # https://github.com/zappa/Zappa/issues/1036 + # Error because the name cannot be obtained if the function name is longer than 64 characters + if len(name) > max_name_length: + raise EnvironmentError(f"Generated scheduled event name is too long, shorten the function name!: '{name}'") # prefix scheduled event names with lambda name. So we can look them up later via the prefix. event_name = self.get_event_name(lambda_name, name) # if it's possible that we truncated name, generate a unique, shortened name # https://github.com/Miserlou/Zappa/issues/970 - if len(event_name) >= 64: + if len(event_name) >= max_event_rule_name_length: lambda_name = self.get_hashed_lambda_name(lambda_name) event_name = self.get_event_name(lambda_name, name) From 3cbe3423b17a447ce329e7f2a27720e57f103cac Mon Sep 17 00:00:00 2001 From: Suriya Subramanian Date: Wed, 1 Nov 2023 05:27:43 +0530 Subject: [PATCH 2/2] Skip loading credentials for save-python-settings-file (#1008) * Skip loading credentials for save-python-settings-file Loading AWS Credentials and creating AWS Client classes take a lot of time. We do not need to do that for the save-python-settings-file command. * change list to tuple (list unnecessary) --------- Co-authored-by: monkut --- zappa/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zappa/cli.py b/zappa/cli.py index a4997d9ea..c95859325 100755 --- a/zappa/cli.py +++ b/zappa/cli.py @@ -475,7 +475,7 @@ def positive_int(s): else: self.stage_env = self.vargs.get("stage_env") - if args.command == "package": + if args.command in ("package", "save-python-settings-file"): self.load_credentials = False self.command = args.command