From e51e19ec7864095757d26a5dd34eec3e32ef29b9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 6 Jun 2023 11:45:04 +0200 Subject: [PATCH 01/41] chore(ci): bump version to 2.16.2 (#2390) Co-authored-by: Powertools for AWS Lambda (Python) bot --- aws_lambda_powertools/shared/version.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aws_lambda_powertools/shared/version.py b/aws_lambda_powertools/shared/version.py index 0aabf6a54ff..1c0d9617d85 100644 --- a/aws_lambda_powertools/shared/version.py +++ b/aws_lambda_powertools/shared/version.py @@ -1,3 +1,3 @@ """Exposes version constant to avoid circular dependencies.""" -VERSION = "2.16.1" +VERSION = "2.16.2" diff --git a/pyproject.toml b/pyproject.toml index 661cdc62b79..9b2ba836cf6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "aws_lambda_powertools" -version = "2.16.1" +version = "2.16.2" description = "Powertools for AWS Lambda (Python) is a developer toolkit to implement Serverless best practices and increase developer velocity." authors = ["Amazon Web Services"] include = ["aws_lambda_powertools/py.typed", "THIRD-PARTY-LICENSES"] From d681d18bd6d821c50303924113592dfc487bf8e3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 6 Jun 2023 11:45:32 +0200 Subject: [PATCH 02/41] chore(ci): layer docs update (#2391) Co-authored-by: Powertools for AWS Lambda (Python) bot --- CHANGELOG.md | 20 ++++- docs/index.md | 128 ++++++++++++++--------------- examples/logger/sam/template.yaml | 2 +- examples/metrics/sam/template.yaml | 2 +- examples/tracer/sam/template.yaml | 2 +- 5 files changed, 86 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37205af3ffe..eb107587ddc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ # Unreleased + +## [v2.16.2] - 2023-06-06 +## Bug Fixes + +* **parameters:** AppConfigProvider when retrieving multiple unique configuration names ([#2378](https://github.com/awslabs/aws-lambda-powertools-python/issues/2378)) +* **shared:** move to static version bumping to prevent issues with customers custom builds ([#2386](https://github.com/awslabs/aws-lambda-powertools-python/issues/2386)) + +## Maintenance + +* version bump +* **deps-dev:** bump mypy-boto3-cloudformation from 1.26.108 to 1.26.147 ([#2383](https://github.com/awslabs/aws-lambda-powertools-python/issues/2383)) +* **deps-dev:** bump mypy-boto3-lambda from 1.26.122 to 1.26.147 ([#2382](https://github.com/awslabs/aws-lambda-powertools-python/issues/2382)) +* **deps-dev:** bump sentry-sdk from 1.24.0 to 1.25.0 ([#2374](https://github.com/awslabs/aws-lambda-powertools-python/issues/2374)) +* **deps-dev:** bump aws-cdk from 2.81.0 to 2.82.0 ([#2373](https://github.com/awslabs/aws-lambda-powertools-python/issues/2373)) +* **typing:** add setLevel and addHandler to Logger for mypy/pyright ([#2388](https://github.com/awslabs/aws-lambda-powertools-python/issues/2388)) + + ## [v2.16.1] - 2023-06-02 ## Bug Fixes @@ -3302,7 +3319,8 @@ * Merge pull request [#5](https://github.com/awslabs/aws-lambda-powertools-python/issues/5) from jfuss/feat/python38 -[Unreleased]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v2.16.1...HEAD +[Unreleased]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v2.16.2...HEAD +[v2.16.2]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v2.16.1...v2.16.2 [v2.16.1]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v2.16.0...v2.16.1 [v2.16.0]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v2.15.0...v2.16.0 [v2.15.0]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v2.14.1...v2.15.0 diff --git a/docs/index.md b/docs/index.md index 5ef67526277..a1590aaf564 100644 --- a/docs/index.md +++ b/docs/index.md @@ -26,8 +26,8 @@ Powertools for AWS Lambda (Python) is a developer toolkit to implement Serverles You can install Powertools for AWS Lambda (Python) using one of the following options: -* **Lambda Layer (x86_64)**: [**arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:33**](#){: .copyMe}:clipboard: -* **Lambda Layer (arm64)**: [**arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33**](#){: .copyMe}:clipboard: +* **Lambda Layer (x86_64)**: [**arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:34**](#){: .copyMe}:clipboard: +* **Lambda Layer (arm64)**: [**arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34**](#){: .copyMe}:clipboard: * **Pip**: **[`pip install "aws-lambda-powertools"`](#){: .copyMe}:clipboard:** ??? question "Using Pip? You might need to install additional dependencies." @@ -78,60 +78,60 @@ You can include Powertools for AWS Lambda (Python) Lambda Layer using [AWS Lambd | Region | Layer ARN | | ---------------- | ---------------------------------------------------------------------------------------------------------- | - | `af-south-1` | [arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `ap-east-1` | [arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `ap-south-1` | [arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `ap-south-2` | [arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `ap-southeast-3` | [arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `ap-southeast-4` | [arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `ca-central-1` | [arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `eu-central-1` | [arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `eu-central-2` | [arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `eu-north-1` | [arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `eu-south-1` | [arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `eu-south-2` | [arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `eu-west-1` | [arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `eu-west-2` | [arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `eu-west-3` | [arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `me-central-1` | [arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `me-south-1` | [arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `sa-east-1` | [arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `us-east-1` | [arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `us-east-2` | [arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `us-west-1` | [arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | - | `us-west-2` | [arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:33](#){: .copyMe}:clipboard: | + | `af-south-1` | [arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `ap-east-1` | [arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `ap-south-1` | [arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `ap-south-2` | [arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `ap-southeast-3` | [arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `ap-southeast-4` | [arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `ca-central-1` | [arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `eu-central-1` | [arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `eu-central-2` | [arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `eu-north-1` | [arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `eu-south-1` | [arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `eu-south-2` | [arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `eu-west-1` | [arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `eu-west-2` | [arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `eu-west-3` | [arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `me-central-1` | [arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `me-south-1` | [arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `sa-east-1` | [arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `us-east-1` | [arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `us-east-2` | [arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `us-west-1` | [arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | + | `us-west-2` | [arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:34](#){: .copyMe}:clipboard: | === "arm64" | Region | Layer ARN | | ---------------- | ---------------------------------------------------------------------------------------------------------------- | - | `af-south-1` | [arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `ap-east-1` | [arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `ap-south-1` | [arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `ap-southeast-3` | [arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `ca-central-1` | [arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `eu-central-1` | [arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `eu-north-1` | [arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `eu-south-1` | [arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `eu-west-1` | [arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `eu-west-2` | [arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `eu-west-3` | [arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `me-south-1` | [arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `sa-east-1` | [arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `us-east-1` | [arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `us-east-2` | [arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `us-west-1` | [arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | - | `us-west-2` | [arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33](#){: .copyMe}:clipboard: | + | `af-south-1` | [arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `ap-east-1` | [arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `ap-south-1` | [arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `ap-southeast-3` | [arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `ca-central-1` | [arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `eu-central-1` | [arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `eu-north-1` | [arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `eu-south-1` | [arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `eu-west-1` | [arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `eu-west-2` | [arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `eu-west-3` | [arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `me-south-1` | [arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `sa-east-1` | [arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `us-east-1` | [arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `us-east-2` | [arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `us-west-1` | [arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | + | `us-west-2` | [arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34](#){: .copyMe}:clipboard: | ??? note "Note: Click to expand and copy code snippets for popular frameworks" @@ -144,7 +144,7 @@ You can include Powertools for AWS Lambda (Python) Lambda Layer using [AWS Lambd Type: AWS::Serverless::Function Properties: Layers: - - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:33 + - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:34 ``` === "Serverless framework" @@ -154,7 +154,7 @@ You can include Powertools for AWS Lambda (Python) Lambda Layer using [AWS Lambd hello: handler: lambda_function.lambda_handler layers: - - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:33 + - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:34 ``` === "CDK" @@ -170,7 +170,7 @@ You can include Powertools for AWS Lambda (Python) Lambda Layer using [AWS Lambd powertools_layer = aws_lambda.LayerVersion.from_layer_version_arn( self, id="lambda-powertools", - layer_version_arn=f"arn:aws:lambda:{env.region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:33" + layer_version_arn=f"arn:aws:lambda:{env.region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:34" ) aws_lambda.Function(self, 'sample-app-lambda', @@ -219,7 +219,7 @@ You can include Powertools for AWS Lambda (Python) Lambda Layer using [AWS Lambd role = aws_iam_role.iam_for_lambda.arn handler = "index.test" runtime = "python3.9" - layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:33"] + layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:34"] source_code_hash = filebase64sha256("lambda_function_payload.zip") } @@ -272,7 +272,7 @@ You can include Powertools for AWS Lambda (Python) Lambda Layer using [AWS Lambd ? Do you want to configure advanced settings? Yes ... ? Do you want to enable Lambda layers for this function? Yes - ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33 + ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34 ❯ amplify push -y @@ -283,7 +283,7 @@ You can include Powertools for AWS Lambda (Python) Lambda Layer using [AWS Lambd - Name: ? Which setting do you want to update? Lambda layers configuration ? Do you want to enable Lambda layers for this function? Yes - ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:33 + ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:34 ? Do you want to edit the local lambda function now? No ``` @@ -297,7 +297,7 @@ You can include Powertools for AWS Lambda (Python) Lambda Layer using [AWS Lambd Properties: Architectures: [arm64] Layers: - - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33 + - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34 ``` === "Serverless framework" @@ -308,7 +308,7 @@ You can include Powertools for AWS Lambda (Python) Lambda Layer using [AWS Lambd handler: lambda_function.lambda_handler architecture: arm64 layers: - - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33 + - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34 ``` === "CDK" @@ -324,7 +324,7 @@ You can include Powertools for AWS Lambda (Python) Lambda Layer using [AWS Lambd powertools_layer = aws_lambda.LayerVersion.from_layer_version_arn( self, id="lambda-powertools", - layer_version_arn=f"arn:aws:lambda:{env.region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33" + layer_version_arn=f"arn:aws:lambda:{env.region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34" ) aws_lambda.Function(self, 'sample-app-lambda', @@ -374,7 +374,7 @@ You can include Powertools for AWS Lambda (Python) Lambda Layer using [AWS Lambd role = aws_iam_role.iam_for_lambda.arn handler = "index.test" runtime = "python3.9" - layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33"] + layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34"] architectures = ["arm64"] source_code_hash = filebase64sha256("lambda_function_payload.zip") @@ -430,7 +430,7 @@ You can include Powertools for AWS Lambda (Python) Lambda Layer using [AWS Lambd ? Do you want to configure advanced settings? Yes ... ? Do you want to enable Lambda layers for this function? Yes - ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33 + ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34 ❯ amplify push -y @@ -441,7 +441,7 @@ You can include Powertools for AWS Lambda (Python) Lambda Layer using [AWS Lambd - Name: ? Which setting do you want to update? Lambda layers configuration ? Do you want to enable Lambda layers for this function? Yes - ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:33 + ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:34 ? Do you want to edit the local lambda function now? No ``` @@ -449,7 +449,7 @@ You can include Powertools for AWS Lambda (Python) Lambda Layer using [AWS Lambd Change {region} to your AWS region, e.g. `eu-west-1` ```bash title="AWS CLI" - aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:33 --region {region} + aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:34 --region {region} ``` The pre-signed URL to download this Lambda Layer will be within `Location` key. diff --git a/examples/logger/sam/template.yaml b/examples/logger/sam/template.yaml index 2950a21653e..be1284a6dce 100644 --- a/examples/logger/sam/template.yaml +++ b/examples/logger/sam/template.yaml @@ -14,7 +14,7 @@ Globals: Layers: # Find the latest Layer version in the official documentation # https://awslabs.github.io/aws-lambda-powertools-python/latest/#lambda-layer - - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:33 + - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:34 Resources: LoggerLambdaHandlerExample: diff --git a/examples/metrics/sam/template.yaml b/examples/metrics/sam/template.yaml index 3f333878143..9c3ccf3ac02 100644 --- a/examples/metrics/sam/template.yaml +++ b/examples/metrics/sam/template.yaml @@ -15,7 +15,7 @@ Globals: Layers: # Find the latest Layer version in the official documentation # https://awslabs.github.io/aws-lambda-powertools-python/latest/#lambda-layer - - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:33 + - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:34 Resources: CaptureLambdaHandlerExample: diff --git a/examples/tracer/sam/template.yaml b/examples/tracer/sam/template.yaml index 6139832c3fd..22c38f4d984 100644 --- a/examples/tracer/sam/template.yaml +++ b/examples/tracer/sam/template.yaml @@ -13,7 +13,7 @@ Globals: Layers: # Find the latest Layer version in the official documentation # https://awslabs.github.io/aws-lambda-powertools-python/latest/#lambda-layer - - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:33 + - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:34 Resources: CaptureLambdaHandlerExample: From b99f65b740217ab61f6add63255c3ff1a10407a6 Mon Sep 17 00:00:00 2001 From: Heitor Lessa Date: Wed, 7 Jun 2023 18:25:35 +0200 Subject: [PATCH 03/41] chore(ci): document all github action workflows and enforce least-privilege (#2395) --- .github/workflows/build_changelog.yml | 10 +++++ .github/workflows/codeql-analysis.yml | 13 +++++++ .github/workflows/dispatch_analytics.yml | 10 +++++ .github/workflows/label_pr_on_title.yml | 24 ++++++++++++ .github/workflows/on_closed_issues.yml | 38 ++++++++++++------- .github/workflows/on_label_added.yml | 26 +++++++++++-- .github/workflows/on_merged_pr.yml | 24 ++++++++++++ .github/workflows/on_opened_pr.yml | 26 +++++++++++++ .github/workflows/on_push_docs.yml | 19 +++++++--- .github/workflows/publish_v2_layer.yml | 32 ++++++++++++++-- .../{python_build.yml => quality_check.yml} | 21 ++++++++-- .github/workflows/rebuild_latest_docs.yml | 24 +++++++----- .github/workflows/record_pr.yml | 37 +++++++++++++++++- .github/workflows/release-drafter.yml | 14 +++++++ .../reusable_deploy_v2_layer_stack.yml | 27 +++++++++++++ .github/workflows/reusable_deploy_v2_sar.yml | 22 ++++++++++- .../workflows/reusable_export_pr_details.yml | 16 ++++++++ .../workflows/reusable_publish_changelog.yml | 6 ++- .github/workflows/reusable_publish_docs.yml | 8 ++-- .github/workflows/run-e2e-tests.yml | 18 ++++++++- .github/workflows/secure_workflows.yml | 13 +++++++ README.md | 2 +- 22 files changed, 383 insertions(+), 47 deletions(-) rename .github/workflows/{python_build.yml => quality_check.yml} (70%) diff --git a/.github/workflows/build_changelog.yml b/.github/workflows/build_changelog.yml index f15275d07a7..b2abf5aeb47 100644 --- a/.github/workflows/build_changelog.yml +++ b/.github/workflows/build_changelog.yml @@ -1,6 +1,16 @@ # Standalone workflow to update changelog if necessary name: Build changelog +# PROCESS +# +# 1. Fetch latest changes compared to the latest tag +# 2. Rebuild CHANGELOG.md using Keep A Changelog format +# 3. Create a PR with the latest changelog (close and reference any it supersedes) + +# USAGE +# +# Always triggered on PR merge or manually from GitHub UI if we must. + on: workflow_dispatch: push: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 31561d013ad..221aaa56cc9 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,5 +1,15 @@ name: "CodeQL" +# PROCESS +# +# 1. Static code analysis with CodeQL + +# USAGE +# +# NOTE: This is our slowest workflow hence it only runs on code merged. +# +# Always triggered on PR merge when source code changes. + on: push: paths: @@ -11,6 +21,9 @@ jobs: analyze: name: Analyze runs-on: ubuntu-latest + permissions: + security-events: write + actions: read strategy: fail-fast: false diff --git a/.github/workflows/dispatch_analytics.yml b/.github/workflows/dispatch_analytics.yml index 2f7c2f5c8a3..fd35f66c9fc 100644 --- a/.github/workflows/dispatch_analytics.yml +++ b/.github/workflows/dispatch_analytics.yml @@ -1,5 +1,15 @@ name: Dispatch analytics +# PROCESS +# +# 1. Trade GitHub JWT token with AWS credentials for the analytics account +# 2. Invoke a Lambda function dispatcher synchronously with the read-only scoped JWT token +# 3. The dispatcher function will call GitHub APIs to read data from the last hour and aggregate for operational analytics + +# USAGE +# +# NOTE: meant to use as a scheduled task only (or manually for debugging purposes). + on: workflow_dispatch: diff --git a/.github/workflows/label_pr_on_title.yml b/.github/workflows/label_pr_on_title.yml index 0183cb1155d..521377058ab 100644 --- a/.github/workflows/label_pr_on_title.yml +++ b/.github/workflows/label_pr_on_title.yml @@ -1,5 +1,25 @@ name: Label PR based on title +# PROCESS +# +# 1. Fetch PR details previously saved from untrusted location +# 2. Parse details for safety +# 3. Label PR based on semantic title (e.g., area, change type) + +# USAGE +# +# NOTE: meant to be used with ./.github/workflows/record_pr.yml +# +# Security Note: +# +# This workflow depends on "Record PR" workflow that runs in an untrusted location (forks) instead of `pull_request_target`. +# This enforces zero trust where "Record PR" workflow always runs on fork with zero permissions on GH_TOKEN. +# When "Record PR" completes, this workflow runs in our repository with the appropriate permissions and sanitize inputs. +# +# Coupled with "Approve GitHub Action to run on forks", we have confidence no privilege can be escalated, +# since any malicious change would need to be approved, and upon social engineering, it'll have zero permissions. + + on: workflow_run: workflows: ["Record PR details"] @@ -8,6 +28,8 @@ on: jobs: get_pr_details: + permissions: + actions: read # download PR artifact # Guardrails to only ever run if PR recording workflow was indeed # run in a PR event and ran successfully if: ${{ github.event.workflow_run.conclusion == 'success' }} @@ -20,6 +42,8 @@ jobs: label_pr: needs: get_pr_details runs-on: ubuntu-latest + permissions: + issues: write # label respective PR steps: - name: Checkout repository uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 diff --git a/.github/workflows/on_closed_issues.yml b/.github/workflows/on_closed_issues.yml index dfe854c5fbe..f97ff42e6e9 100644 --- a/.github/workflows/on_closed_issues.yml +++ b/.github/workflows/on_closed_issues.yml @@ -1,18 +1,30 @@ name: Closed Issue Message + +# PROCESS +# +# 1. Comment on recently closed issues to warn future responses may not be looked after + +# USAGE +# +# Always triggered upon issue closure +# + on: - issues: - types: [closed] + issues: + types: [closed] jobs: - auto_comment: - runs-on: ubuntu-latest - steps: - - uses: aws-actions/closed-issue-message@8b6324312193476beecf11f8e8539d73a3553bf4 - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" - message: | - ### ⚠️COMMENT VISIBILITY WARNING⚠️ - This issue is now closed. Please be mindful that future comments are hard for our team to see. + auto_comment: + runs-on: ubuntu-latest + permissions: + issues: write # comment on issues + steps: + - uses: aws-actions/closed-issue-message@8b6324312193476beecf11f8e8539d73a3553bf4 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + message: | + ### ⚠️COMMENT VISIBILITY WARNING⚠️ + This issue is now closed. Please be mindful that future comments are hard for our team to see. - If you need more assistance, please either tag a [team member](https://github.com/awslabs/aws-lambda-powertools-python/blob/develop/MAINTAINERS.md#current-maintainers) or open a new issue that references this one. + If you need more assistance, please either tag a [team member](https://github.com/awslabs/aws-lambda-powertools-python/blob/develop/MAINTAINERS.md#current-maintainers) or open a new issue that references this one. - If you wish to keep having a conversation with other community members under this issue feel free to do so. + If you wish to keep having a conversation with other community members under this issue feel free to do so. diff --git a/.github/workflows/on_label_added.yml b/.github/workflows/on_label_added.yml index 88ca45439bd..58b88f51a1a 100644 --- a/.github/workflows/on_label_added.yml +++ b/.github/workflows/on_label_added.yml @@ -1,5 +1,24 @@ name: On Label added +# PROCESS +# +# 1. Fetch PR details previously saved from untrusted location +# 2. Parse details for safety +# 3. Comment on PR labels `size/XXL` and suggest splitting into smaller PRs if possible + +# USAGE +# +# NOTE: meant to be used with ./.github/workflows/record_pr.yml +# +# Security Note: +# +# This workflow depends on "Record PR" workflow that runs in an untrusted location (forks) instead of `pull_request_target`. +# This enforces zero trust where "Record PR" workflow always runs on fork with zero permissions on GH_TOKEN. +# When "Record PR" completes, this workflow runs in our repository with the appropriate permissions and sanitize inputs. +# +# Coupled with "Approve GitHub Action to run on forks", we have confidence no privilege can be escalated, +# since any malicious change would need to be approved, and upon social engineering, it'll have zero permissions. + on: workflow_run: workflows: ["Record PR details"] @@ -8,6 +27,8 @@ on: jobs: get_pr_details: + permissions: + actions: read # download PR artifact if: ${{ github.event.workflow_run.conclusion == 'success' }} uses: ./.github/workflows/reusable_export_pr_details.yml with: @@ -16,12 +37,11 @@ jobs: secrets: token: ${{ secrets.GITHUB_TOKEN }} - split-large-pr: + split_large_pr: needs: get_pr_details runs-on: ubuntu-latest permissions: - issues: write - pull-requests: write + pull-requests: write # comment on PR steps: - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 # Maintenance: Persist state per PR as an artifact to avoid spam on label add diff --git a/.github/workflows/on_merged_pr.yml b/.github/workflows/on_merged_pr.yml index a4e8bf6d28d..589a735b5eb 100644 --- a/.github/workflows/on_merged_pr.yml +++ b/.github/workflows/on_merged_pr.yml @@ -1,5 +1,25 @@ name: On PR merge +# PROCESS +# +# 1. Fetch PR details previously saved from untrusted location +# 2. Parse details for safety +# 3. Add `pending-release` label for related issue +# 4. Make a comment in PR if related issue is invalid or can't be labeled + +# USAGE +# +# NOTE: meant to be used with ./.github/workflows/record_pr.yml +# +# Security Note: +# +# This workflow depends on "Record PR" workflow that runs in an untrusted location (forks) instead of `pull_request_target`. +# This enforces zero trust where "Record PR" workflow always runs on fork with zero permissions on GH_TOKEN. +# When "Record PR" completes, this workflow runs in our repository with the appropriate permissions and sanitize inputs. +# +# Coupled with "Approve GitHub Action to run on forks", we have confidence no privilege can be escalated, +# since any malicious change would need to be approved, and upon social engineering, it'll have zero permissions. + on: workflow_run: workflows: ["Record PR details"] @@ -8,6 +28,8 @@ on: jobs: get_pr_details: + permissions: + actions: read # download PR artifact if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' uses: ./.github/workflows/reusable_export_pr_details.yml with: @@ -18,6 +40,8 @@ jobs: release_label_on_merge: needs: get_pr_details runs-on: ubuntu-latest + permissions: + pull-requests: write # make a comment in PR if unable to find related issue if: needs.get_pr_details.outputs.prIsMerged == 'true' steps: - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 diff --git a/.github/workflows/on_opened_pr.yml b/.github/workflows/on_opened_pr.yml index 58f580e13af..a9131926081 100644 --- a/.github/workflows/on_opened_pr.yml +++ b/.github/workflows/on_opened_pr.yml @@ -1,5 +1,25 @@ name: On new PR +# PROCESS +# +# 1. Fetch PR details previously saved from untrusted location +# 2. Parse details for safety +# 3. Confirm there is a related issue for newly opened PR +# 4. Verify if PR template is used and legal acknowledgement hasn't been removed + +# USAGE +# +# NOTE: meant to be used with ./.github/workflows/record_pr.yml +# +# Security Note: +# +# This workflow depends on "Record PR" workflow that runs in an untrusted location (forks) instead of `pull_request_target`. +# This enforces zero trust where "Record PR" workflow always runs on fork with zero permissions on GH_TOKEN. +# When "Record PR" completes, this workflow runs in our repository with the appropriate permissions and sanitize inputs. +# +# Coupled with "Approve GitHub Action to run on forks", we have confidence no privilege can be escalated, +# since any malicious change would need to be approved, and upon social engineering, it'll have zero permissions. + on: workflow_run: workflows: ["Record PR details"] @@ -8,6 +28,8 @@ on: jobs: get_pr_details: + permissions: + actions: read # download PR artifact if: ${{ github.event.workflow_run.conclusion == 'success' }} uses: ./.github/workflows/reusable_export_pr_details.yml with: @@ -16,6 +38,8 @@ jobs: secrets: token: ${{ secrets.GITHUB_TOKEN }} check_related_issue: + permissions: + pull-requests: write # label and comment on PR if missing related issue (requirement) needs: get_pr_details runs-on: ubuntu-latest steps: @@ -35,6 +59,8 @@ jobs: check_acknowledge_section: needs: get_pr_details runs-on: ubuntu-latest + permissions: + pull-requests: write # label and comment on PR if missing acknowledge section (requirement) steps: - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - name: "Ensure acknowledgement section is present" diff --git a/.github/workflows/on_push_docs.yml b/.github/workflows/on_push_docs.yml index b6051f8fa94..ec6e14c4273 100644 --- a/.github/workflows/on_push_docs.yml +++ b/.github/workflows/on_push_docs.yml @@ -1,5 +1,15 @@ name: Docs +# PROCESS +# +# 1. Build User Guide and API docs +# 2. Publish to GitHub Pages +# 3. Publish to S3 (new home) + +# USAGE +# +# Always triggered on PR merge when changes in documentation changes occur. + on: push: branches: @@ -10,15 +20,12 @@ on: - "examples/**" - "CHANGELOG.md" -permissions: - id-token: write - jobs: release-docs: permissions: - contents: write - pages: write - id-token: write + contents: write # push to gh-pages + pages: write # deploy gh-pages website + id-token: write # trade JWT token for AWS credentials in AWS Docs account secrets: inherit uses: ./.github/workflows/reusable_publish_docs.yml with: diff --git a/.github/workflows/publish_v2_layer.yml b/.github/workflows/publish_v2_layer.yml index 296ea1376c7..28f767a3a3f 100644 --- a/.github/workflows/publish_v2_layer.yml +++ b/.github/workflows/publish_v2_layer.yml @@ -1,5 +1,31 @@ name: Deploy v2 layer to all regions +# PROCESS +# +# 1. Compile Layer using cdk-aws-lambda-powertools-layer CDK construct for x86 and ARM (uses custom runner as it's CPU heavy) +# 2. Kick off pipeline for beta, prod, and canary releases +# 3. Create PR to update trunk so staged docs also point to the latest Layer ARN, when merged +# 4. Builds and publishes docs with latest Layer ARN using given version (generally coming from release) + + +# USAGE +# +# NOTE: meant to be used with ./.github/workflows/release.yml +# +# publish_layer: +# needs: [seal, release, create_tag] +# secrets: inherit +# permissions: +# id-token: write +# contents: write +# pages: write +# pull-requests: write +# uses: ./.github/workflows/publish_v2_layer.yml +# with: +# latest_published_version: ${{ needs.seal.outputs.RELEASE_VERSION }} +# pre_release: ${{ inputs.pre_release }} + + on: workflow_dispatch: inputs: @@ -91,7 +117,7 @@ jobs: id-token: write contents: read pages: write # docs will be updated with latest Layer ARNs - pull-requests: write # creation-action will create a PR with Layer ARN updates + pull-requests: write # creation-action will create a PR with Layer ARN updates uses: ./.github/workflows/reusable_deploy_v2_layer_stack.yml secrets: inherit with: @@ -107,7 +133,7 @@ jobs: id-token: write contents: read pages: write # docs will be updated with latest Layer ARNs - pull-requests: write # creation-action will create a PR with Layer ARN updates + pull-requests: write # creation-action will create a PR with Layer ARN updates uses: ./.github/workflows/reusable_deploy_v2_layer_stack.yml secrets: inherit with: @@ -133,7 +159,7 @@ jobs: package-version: ${{ inputs.latest_published_version }} sar-prod: - needs: [build-layer, sar-beta] + needs: [build-layer, beta, sar-beta] permissions: # lower privilege propagated from parent workflow (release.yml) id-token: write diff --git a/.github/workflows/python_build.yml b/.github/workflows/quality_check.yml similarity index 70% rename from .github/workflows/python_build.yml rename to .github/workflows/quality_check.yml index 0648fc30d17..3ae93bd26cf 100644 --- a/.github/workflows/python_build.yml +++ b/.github/workflows/quality_check.yml @@ -1,5 +1,20 @@ name: Code quality +# PROCESS +# +# 1. Install all dependencies and spin off containers for all supported Python versions +# 2. Run code formatters and linters (various checks) for code standard +# 3. Run static typing checker for potential bugs +# 4. Run entire test suite for regressions except end-to-end (unit, functional, performance) +# 5. Run static analysis (in addition to CodeQL) for common insecure code practices +# 6. Run complexity baseline to avoid error-prone bugs and keep maintenance lower +# 7. Collect and report on test coverage + +# USAGE +# +# Always triggered on new PRs, PR changes and PR merge. + + on: pull_request: paths: @@ -10,7 +25,6 @@ on: - "mypy.ini" branches: - develop - - v2 push: paths: - "aws_lambda_powertools/**" @@ -20,10 +34,9 @@ on: - "mypy.ini" branches: - develop - - v2 jobs: - build: + quality_check: runs-on: ubuntu-latest strategy: max-parallel: 4 @@ -31,6 +44,8 @@ jobs: python-version: ["3.7", "3.8", "3.9", "3.10"] env: PYTHON: "${{ matrix.python-version }}" + permissions: + contents: read # checkout code only steps: - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - name: Install poetry diff --git a/.github/workflows/rebuild_latest_docs.yml b/.github/workflows/rebuild_latest_docs.yml index fc65bd71673..927d6f8dc91 100644 --- a/.github/workflows/rebuild_latest_docs.yml +++ b/.github/workflows/rebuild_latest_docs.yml @@ -1,7 +1,16 @@ name: Rebuild latest docs +# PROCESS # -# === Documentation hotfix === +# 1. Build User Guide and API docs +# 2. Publish to GitHub Pages +# 3. Publish to S3 (new home) + +# USAGE +# +# Only used for deploying a documentation hotfix to /latest and its associated version w/o a full release. +# +# Steps: # # 1. Trigger "Rebuild latest docs" workflow manually: https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow # 2. Use the latest version released under Releases e.g. 2.0.0 @@ -10,19 +19,16 @@ on: workflow_dispatch: inputs: latest_published_version: - description: "Latest PyPi published version to rebuild latest docs for, e.g. 2.0.0" - default: "2.0.0" + description: "Latest PyPi published version to rebuild latest docs for, e.g. 2.16.3" + default: "2.16.3" required: true -permissions: - id-token: write - jobs: release-docs: permissions: - contents: write - pages: write - id-token: write + contents: write # push to gh-pages + pages: write # deploy gh-pages website + id-token: write # trade JWT token for AWS credentials in AWS Docs account secrets: inherit uses: ./.github/workflows/reusable_publish_docs.yml with: diff --git a/.github/workflows/record_pr.yml b/.github/workflows/record_pr.yml index 20cd93b897f..6fd933222c6 100644 --- a/.github/workflows/record_pr.yml +++ b/.github/workflows/record_pr.yml @@ -1,5 +1,38 @@ name: Record PR details +# PROCESS +# +# 1. Runs in fork location upon PR creation or changes +# 2. Saves GitHub Pull Request Webhook payload +# 3. Uploads as a temporary GitHub Action Artifact with shortest retention + +# USAGE +# +# see .github/workflows/on_merged_pr.yml and related for full example. +# +# on: +# workflow_run: +# workflows: ["Record PR details"] +# types: +# - completed +# +# Security Note: +# +# For security, this is intended to be a 2-step process: (1) collect PR, (2) act on PR. +# Do not ever use `pull_request_target` to "simplify", as it sends a write-token to the fork. Our linter should catch it. +# +# The first step runs in untrusted location (fork), therefore we limit permissions to only check out code. +# +# The second step will be workflows that want to act on a given PR, this time with intended permissions, and +# it runs on its base location (this repo!). +# +# This enforces zero trust where this workflow always runs on fork with zero permissions on GH_TOKEN. +# When this workflow completes, X workflows run in our repository with the appropriate permissions and sanitize inputs. +# +# Coupled with "Approve GitHub Action to run on forks", we have confidence no privilege can be escalated, +# since any malicious change would need to be approved, and upon social engineering, it'll have zero permissions. + + on: pull_request: types: [opened, edited, closed, labeled] @@ -7,7 +40,8 @@ on: jobs: record_pr: runs-on: ubuntu-latest - + permissions: + contents: read # NOTE: treat as untrusted location steps: - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - name: "Extract PR details" @@ -20,3 +54,4 @@ jobs: with: name: pr path: pr.txt + retention-days: 1 diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 2da4bd58b79..76e75446220 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -1,5 +1,17 @@ name: Release Drafter +# PROCESS +# +# 1. Enumerate all PRs in merged state +# 2. Filter out any PR labeled `skip-changelog` +# 3. Updates or creates a new release in Draft mode + +# USAGE +# +# Always run on merged PRs or manually via GitHub UI for debugging purposes. +# +# see .github/release-drafter.yml for configuration + on: push: branches: @@ -9,6 +21,8 @@ on: jobs: update_release_draft: runs-on: ubuntu-latest + permissions: + contents: write # create release in draft mode steps: - uses: release-drafter/release-drafter@569eb7ee3a85817ab916c8f8ff03a5bd96c9c83e # v5.20.1 env: diff --git a/.github/workflows/reusable_deploy_v2_layer_stack.yml b/.github/workflows/reusable_deploy_v2_layer_stack.yml index 425b8a092f3..66142e7bb98 100644 --- a/.github/workflows/reusable_deploy_v2_layer_stack.yml +++ b/.github/workflows/reusable_deploy_v2_layer_stack.yml @@ -1,5 +1,32 @@ name: Deploy CDK Layer v2 stack +# PROCESS +# +# 1. Split what AWS regions support ARM vs regions that Lambda support ARM +# 2. Deploy previously built layer for each AWS commercial region +# 3. Export all published Layers as JSON +# 4. Deploy Canaries to every deployed region to test whether Powertools can be imported etc. + +# USAGE +# +# NOTE: meant to be used with ./.github/workflows/publish_v2_layer.yml +# +# beta: +# needs: build-layer +# # lower privilege propagated from parent workflow (release.yml) +# permissions: +# id-token: write +# contents: read +# pages: write # docs will be updated with latest Layer ARNs +# pull-requests: write # creation-action will create a PR with Layer ARN updates +# uses: ./.github/workflows/reusable_deploy_v2_layer_stack.yml +# secrets: inherit +# with: +# stage: "BETA" +# artefact-name: "cdk-layer-artefact" +# environment: "layer-beta" +# latest_published_version: ${{ inputs.latest_published_version }} + on: workflow_call: inputs: diff --git a/.github/workflows/reusable_deploy_v2_sar.yml b/.github/workflows/reusable_deploy_v2_sar.yml index d9e2f046e9a..e50a815979d 100644 --- a/.github/workflows/reusable_deploy_v2_sar.yml +++ b/.github/workflows/reusable_deploy_v2_sar.yml @@ -1,6 +1,6 @@ name: Deploy V2 SAR -# SAR deployment process +# PROCESS # # 1. This workflow starts after the layer artifact is produced on `publish_v2_layer` # 2. We use the same layer artifact to ensure the SAR app is consistent with the published Lambda Layer @@ -9,6 +9,26 @@ name: Deploy V2 SAR # 5. We remove the previous Canary stack (if present) and deploy a new one to test the SAR App. We retain the Canary in the account for debugging purposes # 6. Finally the published SAR app is made public on the PROD environment +# USAGE +# +# NOTE: meant to be used with ./.github/workflows/publish_v2_layer.yml +# +# sar-beta: +# needs: build-layer +# permissions: +# # lower privilege propagated from parent workflow (release.yml) +# id-token: write +# contents: read +# pull-requests: none +# pages: none +# uses: ./.github/workflows/reusable_deploy_v2_sar.yml +# secrets: inherit +# with: +# stage: "BETA" +# artefact-name: "cdk-layer-artefact" +# environment: "layer-beta" +# package-version: ${{ inputs.latest_published_version }} + permissions: id-token: write contents: read diff --git a/.github/workflows/reusable_export_pr_details.yml b/.github/workflows/reusable_export_pr_details.yml index 39ce20672c6..089d735278e 100644 --- a/.github/workflows/reusable_export_pr_details.yml +++ b/.github/workflows/reusable_export_pr_details.yml @@ -1,5 +1,19 @@ name: Export previously recorded PR +# PROCESS +# +# 1. Fetch PR details previously saved from untrusted location +# 2. Parse details for safety +# 3. Export only what's needed for automation, e.g., PR number, title, body, author, action, whether is merged + +# USAGE +# +# see .github/workflows/on_merged_pr.yml and related for full example. +# +# NOTE: meant to be used with workflows that react to a given PR state (labeling, new, merged, etc.) +# done separately to isolate security practices and make it reusable. + + on: workflow_call: inputs: @@ -38,6 +52,8 @@ on: jobs: export_pr_details: + permissions: + actions: read # download PR artifact # see https://github.com/awslabs/aws-lambda-powertools-python/issues/1349 if: inputs.workflow_origin == 'awslabs/aws-lambda-powertools-python' runs-on: ubuntu-latest diff --git a/.github/workflows/reusable_publish_changelog.yml b/.github/workflows/reusable_publish_changelog.yml index f08b23ca9f1..34dfc7342fe 100644 --- a/.github/workflows/reusable_publish_changelog.yml +++ b/.github/workflows/reusable_publish_changelog.yml @@ -1,5 +1,7 @@ name: Build and publish latest changelog +# see ./.github/workflows/build_changelog.yml for docs + on: workflow_call: @@ -16,8 +18,8 @@ jobs: group: changelog-build runs-on: ubuntu-latest permissions: - contents: write - pull-requests: write + contents: write # create temporary branch with changelog + pull-requests: write # create PR steps: - name: Checkout repository # reusable workflows start clean, so we need to checkout again uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 diff --git a/.github/workflows/reusable_publish_docs.yml b/.github/workflows/reusable_publish_docs.yml index c5d4fd2dfcc..74047d7ebde 100644 --- a/.github/workflows/reusable_publish_docs.yml +++ b/.github/workflows/reusable_publish_docs.yml @@ -1,5 +1,7 @@ name: Reusable publish documentation +# see .github/workflows/on_push_docs.yml for docs + env: ORIGIN: awslabs/aws-lambda-powertools-python @@ -26,9 +28,9 @@ on: default: develop permissions: - id-token: write - contents: write - pages: write + id-token: write # trade JWT token for AWS credentials in AWS Docs account + contents: write # push to gh-pages + pages: write # deploy gh-pages website jobs: publish_docs: diff --git a/.github/workflows/run-e2e-tests.yml b/.github/workflows/run-e2e-tests.yml index dbdc9b1849a..46c303ad707 100644 --- a/.github/workflows/run-e2e-tests.yml +++ b/.github/workflows/run-e2e-tests.yml @@ -1,10 +1,24 @@ name: Run end-to-end tests +# PROCESS +# +# 1. Install all dependencies and spin off containers for all supported Python versions +# 2. Install pinned CDK version +# 3. Trade JWT token for AWS credentials to Test account +# 4. Run E2E in parallel for each feature + +# USAGE +# +# see MAINTAINERS.md#internals for full details on mechanics. +# +# Always triggered on new PR merge. + on: workflow_dispatch: push: - branches: [develop, v2] + branches: + - develop paths: - "aws_lambda_powertools/**" - "tests/e2e/**" @@ -26,7 +40,7 @@ jobs: runs-on: aws-lambda-powertools_ubuntu-latest_8-core permissions: id-token: write # needed to request JWT with GitHub's OIDC Token endpoint. docs: https://bit.ly/3MNgQO9 - contents: read + contents: read # checkout code strategy: fail-fast: false # needed so if a version fails, the others will still be able to complete and cleanup matrix: diff --git a/.github/workflows/secure_workflows.yml b/.github/workflows/secure_workflows.yml index b8ad121169c..bca7eaa80d8 100644 --- a/.github/workflows/secure_workflows.yml +++ b/.github/workflows/secure_workflows.yml @@ -1,5 +1,16 @@ name: Lockdown untrusted workflows +# PROCESS +# +# 1. Scans for any external GitHub Action being used without version pinning (@ vs @v3) +# 2. Scans for insecure practices for inline bash scripts (shellcheck) +# 3. Fail CI and prevent PRs to be merged if any malpractice is found + +# USAGE +# +# Always triggered on new PR, PR changes and PR merge. + + on: push: paths: @@ -12,6 +23,8 @@ jobs: enforce_pinned_workflows: name: Harden Security runs-on: ubuntu-latest + permissions: + contents: read # checkout code and subsequently GitHub action workflows steps: - name: Checkout code uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 diff --git a/README.md b/README.md index 9aa79dc3f2c..d9cf9a5eb85 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Powertools for AWS Lambda (Python) -[![Build](https://github.com/awslabs/aws-lambda-powertools-python/actions/workflows/python_build.yml/badge.svg)](https://github.com/awslabs/aws-lambda-powertools-python/actions/workflows/python_build.yml) +[![Build](https://github.com/awslabs/aws-lambda-powertools-python/actions/workflows/quality_check.yml/badge.svg)](https://github.com/awslabs/aws-lambda-powertools-python/actions/workflows/python_build.yml) [![codecov.io](https://codecov.io/github/awslabs/aws-lambda-powertools-python/branch/develop/graphs/badge.svg)](https://app.codecov.io/gh/awslabs/aws-lambda-powertools-python) ![PythonSupport](https://img.shields.io/static/v1?label=python&message=%203.7|%203.8|%203.9|%203.10&color=blue?style=flat-square&logo=python) ![PyPI version](https://badge.fury.io/py/aws-lambda-powertools.svg) ![PyPi monthly downloads](https://img.shields.io/pypi/dm/aws-lambda-powertools) [![Join our Discord](https://dcbadge.vercel.app/api/server/B8zZKbbyET)](https://discord.gg/B8zZKbbyET) From c288a189f5c508d7ea67d2a94793abf24cbba6bc Mon Sep 17 00:00:00 2001 From: Heitor Lessa Date: Wed, 7 Jun 2023 18:51:02 +0200 Subject: [PATCH 04/41] chore(ci): fix PR labeling permission scope (#2396) --- .github/workflows/label_pr_on_title.yml | 2 +- .github/workflows/on_merged_pr.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/label_pr_on_title.yml b/.github/workflows/label_pr_on_title.yml index 521377058ab..9d36c215e4c 100644 --- a/.github/workflows/label_pr_on_title.yml +++ b/.github/workflows/label_pr_on_title.yml @@ -43,7 +43,7 @@ jobs: needs: get_pr_details runs-on: ubuntu-latest permissions: - issues: write # label respective PR + pull-requests: write # label respective PR steps: - name: Checkout repository uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 diff --git a/.github/workflows/on_merged_pr.yml b/.github/workflows/on_merged_pr.yml index 589a735b5eb..573add4473a 100644 --- a/.github/workflows/on_merged_pr.yml +++ b/.github/workflows/on_merged_pr.yml @@ -42,6 +42,7 @@ jobs: runs-on: ubuntu-latest permissions: pull-requests: write # make a comment in PR if unable to find related issue + issues: write # label issue with pending-release if: needs.get_pr_details.outputs.prIsMerged == 'true' steps: - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 From cbaa507da4c3151b20a89beb4a8671938608bb64 Mon Sep 17 00:00:00 2001 From: Heitor Lessa Date: Wed, 7 Jun 2023 20:31:00 +0200 Subject: [PATCH 05/41] docs(maintainers): visual representation of release process (#2399) --- .github/workflows/publish_v2_layer.yml | 4 +- MAINTAINERS.md | 147 ++++++++++++++++++------- 2 files changed, 108 insertions(+), 43 deletions(-) diff --git a/.github/workflows/publish_v2_layer.yml b/.github/workflows/publish_v2_layer.yml index 28f767a3a3f..db677adcee6 100644 --- a/.github/workflows/publish_v2_layer.yml +++ b/.github/workflows/publish_v2_layer.yml @@ -143,7 +143,7 @@ jobs: latest_published_version: ${{ inputs.latest_published_version }} sar-beta: - needs: build-layer + needs: beta # canaries run on Layer Beta env permissions: # lower privilege propagated from parent workflow (release.yml) id-token: write @@ -159,7 +159,7 @@ jobs: package-version: ${{ inputs.latest_published_version }} sar-prod: - needs: [build-layer, beta, sar-beta] + needs: sar-beta permissions: # lower privilege propagated from parent workflow (release.yml) id-token: write diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 114ac52bf1e..1fe8a3e4f0c 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -13,6 +13,7 @@ - [Triage Bug Reports](#triage-bug-reports) - [Triage RFCs](#triage-rfcs) - [Releasing a new version](#releasing-a-new-version) + - [Release process visualized](#release-process-visualized) - [Drafting release notes](#drafting-release-notes) - [Run end to end tests](#run-end-to-end-tests) - [Releasing a documentation hotfix](#releasing-a-documentation-hotfix) @@ -69,42 +70,42 @@ Previous active maintainers who contributed to this project. These are the most common labels used by maintainers to triage issues, pull requests (PR), and for project management: -| Label | Usage | Notes | -| ---------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------- | -| triage | New issues that require maintainers review | Issue template | -| bug | Unexpected, reproducible and unintended software behavior | PR/Release automation; Doc snippets are excluded; | -| not-a-bug | New and existing bug reports incorrectly submitted as bug | Analytics | -| documentation | Documentation improvements | PR/Release automation; Doc additions, fixes, etc.; | -| feature-request | New or enhancements to existing features | Issue template | -| typing | New or enhancements to static typing | Issue template | -| RFC | Technical design documents related to a feature request | Issue template | -| bug-upstream | Bug caused by upstream dependency | | -| help wanted | Tasks you want help from anyone to move forward | Bandwidth, complex topics, etc. | -| need-customer-feedback | Tasks that need more feedback before proceeding | 80/20% rule, uncertain, etc. | -| need-more-information | Missing information before making any calls | | -| need-documentation | PR is missing or has incomplete documentation | | -| need-issue | PR is missing a related issue for tracking change | PR automation | -| need-rfc | Feature request requires a RFC to improve discussion | | -| pending-release | Merged changes that will be available soon | Release automation auto-closes/notifies it | -| revisit-in-3-months | Blocked issues/PRs that need to be revisited | Often related to `need-customer-feedback`, prioritization, etc. | -| breaking-change | Changes that will cause customer impact and need careful triage | | -| do-not-merge | PRs that are blocked for varying reasons | Timeline is uncertain | -| size/XS | PRs between 0-9 LOC | PR automation | -| size/S | PRs between 10-29 LOC | PR automation | -| size/M | PRs between 30-99 LOC | PR automation | -| size/L | PRs between 100-499 LOC | PR automation | -| size/XL | PRs between 500-999 LOC, often PRs that grown with feedback | PR automation | -| size/XXL | PRs with 1K+ LOC, largely documentation related | PR automation | -| tests | PRs that add or change tests | PR automation | +| Label | Usage | Notes | +| ---------------------- | ---------------------------------------------------------------------------------------- | --------------------------------------------------------------- | +| triage | New issues that require maintainers review | Issue template | +| bug | Unexpected, reproducible and unintended software behavior | PR/Release automation; Doc snippets are excluded; | +| not-a-bug | New and existing bug reports incorrectly submitted as bug | Analytics | +| documentation | Documentation improvements | PR/Release automation; Doc additions, fixes, etc.; | +| feature-request | New or enhancements to existing features | Issue template | +| typing | New or enhancements to static typing | Issue template | +| RFC | Technical design documents related to a feature request | Issue template | +| bug-upstream | Bug caused by upstream dependency | | +| help wanted | Tasks you want help from anyone to move forward | Bandwidth, complex topics, etc. | +| need-customer-feedback | Tasks that need more feedback before proceeding | 80/20% rule, uncertain, etc. | +| need-more-information | Missing information before making any calls | | +| need-documentation | PR is missing or has incomplete documentation | | +| need-issue | PR is missing a related issue for tracking change | PR automation | +| need-rfc | Feature request requires a RFC to improve discussion | | +| pending-release | Merged changes that will be available soon | Release automation auto-closes/notifies it | +| revisit-in-3-months | Blocked issues/PRs that need to be revisited | Often related to `need-customer-feedback`, prioritization, etc. | +| breaking-change | Changes that will cause customer impact and need careful triage | | +| do-not-merge | PRs that are blocked for varying reasons | Timeline is uncertain | +| size/XS | PRs between 0-9 LOC | PR automation | +| size/S | PRs between 10-29 LOC | PR automation | +| size/M | PRs between 30-99 LOC | PR automation | +| size/L | PRs between 100-499 LOC | PR automation | +| size/XL | PRs between 500-999 LOC, often PRs that grown with feedback | PR automation | +| size/XXL | PRs with 1K+ LOC, largely documentation related | PR automation | +| tests | PRs that add or change tests | PR automation | | `` | PRs related to a Powertools for AWS Lambda (Python) utility, e.g. `parameters`, `tracer` | PR automation | -| feature | New features or minor changes | PR/Release automation | -| dependencies | Changes that touch dependencies, e.g. Dependabot, etc. | PR/ automation | -| github-actions | Changes in GitHub workflows | PR automation | -| github-templates | Changes in GitHub issue/PR templates | PR automation | -| internal | Changes in governance and chores (linting setup, baseline, etc.) | PR automation | -| tech-debt | Changes in tech debt | | -| customer-reference | Authorization to use company name in our documentation | Public Relations | -| community-content | Suggested content to feature in our documentation | Public Relations | +| feature | New features or minor changes | PR/Release automation | +| dependencies | Changes that touch dependencies, e.g. Dependabot, etc. | PR/ automation | +| github-actions | Changes in GitHub workflows | PR automation | +| github-templates | Changes in GitHub issue/PR templates | PR automation | +| internal | Changes in governance and chores (linting setup, baseline, etc.) | PR automation | +| tech-debt | Changes in tech debt | | +| customer-reference | Authorization to use company name in our documentation | Public Relations | +| community-content | Suggested content to feature in our documentation | Public Relations | ## Maintainer Responsibilities @@ -185,13 +186,77 @@ Some examples using our initial and new RFC templates: #92, #94, #95, #991, #122 Firstly, make sure the commit history in the `develop` branch **(1)** it's up to date, **(2)** commit messages are semantic, and **(3)** commit messages have their respective area, for example `feat(logger): `, `chore(ci): ...`). -**Found typos or unclear commit messages?** +**Looks good, what's next?** -Reword through rebase and push with `--force-with-lease` once you're confident. This will ensure [CHANGELOG](./CHANGELOG.md) is always clear for customers looking to understand what changed in between releases - was that a bug? what new features and for which utility? +Kickoff the `Release` workflow with the intended version - this might take around 25m-30m to complete. -**Looks good, what's next?** +Once complete, you can start drafting the release notes to let customers know **what changed and what's in it for them (a.k.a why they should care)**. We have guidelines in the release notes section so you know what good looks like. + +> **NOTE**: Documentation might take a few minutes to reflect the latest version due to caching and CDN invalidations. + +#### Release process visualized + +Every release makes hundreds of checks, security scans, canaries and deployments - all of these are automated. + +This is a close visual representation of the main steps (GitHub Actions UI should be the source of truth). + + + +```mermaid +gantt + +title Release process +dateFormat HH:mm +axisFormat %H:%M + +Release commit : milestone, m1, 10:00,2m + +section Seal + Bump release version : active, 8s + Prevent source tampering : active, 43s +section QA + Quality checks : active, 2.2m +section Build + Checksum : active, 8s + Build release artifact : active, 39s + Seal : active, 8s +section Release + Checksum : active, 8s + PyPi temp credentials : active, 8s + Publish PyPi : active, pypi, 10:06, 29s -Kickoff the `Release` workflow with the intended version. Once complete, update the draft release notes within the `` section summarizing why customers should care about this release. +PyPi release : milestone, m2, 10:06,1s + +section Git release + Checksum : active, after pypi, 8s + Git Tag : active, 8s + Bump package version : active, 8s + Create PR : active, 8s + +section Layer release + Build (x86+ARM) : active, layer_build, 10:08, 6m + Deploy Beta : active, layer_beta, after layer_build, 6.3m + Deploy Prod : active, layer_prod, after layer_beta, 6.3m + +Layer release : milestone, m3, 10:26,1s + +section SAR release + Deploy Beta : active, sar_beta, after layer_beta, 2.2m + Deploy Prod : active, sar_prod, after sar_beta, 2.2m + +SAR release : milestone, m4, 10:25,1s + +section Docs + Create PR (Layer ARN) : active, after layer_prod, 8s + Release versioned docs : active, 2.2m + +Documentation release : milestone, m4, 10:28,1m + +section Post-release + Close pending issues : active, 8s + +Release complete : milestone, m6, 10:31,2m +``` #### Drafting release notes @@ -205,6 +270,8 @@ You'll notice we group all changes based on their [labels](#labels) like `featur Edit the respective PR title and update their [labels](#labels). Then run the [Release Drafter workflow](https://github.com/awslabs/aws-lambda-powertools-python/actions/workflows/release-drafter.yml) to update the Draft release. +> **NOTE**: This won't change the CHANGELOG as the merge commit is immutable. Don't worry about it. We'd only rewrite git history only if this can lead to confusion and we'd pair with another maintainer. + **All looking good, what's next?** The best part comes now. Replace the placeholder `[Human readable summary of changes]` with what you'd like to communicate to customers what this release is all about. Rule of thumb: always put yourself in the customers shoes. @@ -221,8 +288,6 @@ Once you're happy, hit `Publish release` 🎉🎉🎉. This will kick off the [Publishing workflow](https://github.com/awslabs/aws-lambda-powertools-python/actions/workflows/release.yml) and within a few minutes you should see the latest version in PyPi, and all issues labeled as `pending-release` will be closed and notified. -> TODO: Include information to verify SAR and Lambda Layers deployment; we're still finalizing Lambda Layer automated deployment in GitHub Actions - ping @am29d when in doubt. - ### Run end to end tests E2E tests are run on every push to `develop` or manually via [run-e2e-tests workflow](https://github.com/awslabs/aws-lambda-powertools-python/actions/workflows/run-e2e-tests.yml). From 4f662e235206553fbb4fd6b8efe11584d5f06ed0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 22:10:47 +0100 Subject: [PATCH 06/41] chore(deps): bump docker/setup-buildx-action from 2.5.0 to 2.6.0 (#2403) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/publish_v2_layer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish_v2_layer.yml b/.github/workflows/publish_v2_layer.yml index db677adcee6..fd7ea5ef194 100644 --- a/.github/workflows/publish_v2_layer.yml +++ b/.github/workflows/publish_v2_layer.yml @@ -90,7 +90,7 @@ jobs: # NOTE: we need QEMU to build Layer against a different architecture (e.g., ARM) - name: Set up Docker Buildx id: builder - uses: docker/setup-buildx-action@4b4e9c3e2d4531116a6f8ba8e71fc6e2cb6e6c8c # v2.5.0 + uses: docker/setup-buildx-action@6a58db7e0d21ca03e6c44877909e80e45217eed2 # v2.6.0 with: install: true driver: docker From 3a49e4014b1643b961979d1e6e3065bfee760b6c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 22:17:04 +0100 Subject: [PATCH 07/41] chore(deps): bump docker/setup-qemu-action from 2.1.0 to 2.2.0 (#2404) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Leandro Damascena --- .github/workflows/publish_v2_layer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish_v2_layer.yml b/.github/workflows/publish_v2_layer.yml index fd7ea5ef194..523fed97363 100644 --- a/.github/workflows/publish_v2_layer.yml +++ b/.github/workflows/publish_v2_layer.yml @@ -84,7 +84,7 @@ jobs: poetry export --format requirements.txt --output requirements.txt pip install -r requirements.txt - name: Set up QEMU - uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.0.0 + uses: docker/setup-qemu-action@2b82ce82d56a2a04d2637cd93a637ae1b359c0a7 # v2.0.0 with: platforms: arm64 # NOTE: we need QEMU to build Layer against a different architecture (e.g., ARM) From ce2ad8523e823eb3fc6a44cb53477ecc07e1e42a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 22:53:00 +0100 Subject: [PATCH 08/41] chore(deps-dev): bump mypy-boto3-logs from 1.26.53 to 1.26.149 (#2409) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Leandro Damascena --- poetry.lock | 176 +++++++++++++++++++++++++++++++++++++++++++++---- pyproject.toml | 2 +- 2 files changed, 163 insertions(+), 15 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4bcb070b9ed..01b96db87f5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,9 +1,10 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "anyio" version = "3.6.2" description = "High level compatibility layer for multiple asynchronous event loop implementations" +category = "dev" optional = false python-versions = ">=3.6.2" files = [ @@ -25,6 +26,7 @@ trio = ["trio (>=0.16,<0.22)"] name = "attrs" version = "22.2.0" description = "Classes Without Boilerplate" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -43,6 +45,7 @@ tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy name = "aws-cdk-asset-awscli-v1" version = "2.2.145" description = "A library that contains the AWS CLI for use in Lambda Layers" +category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -59,6 +62,7 @@ typeguard = ">=2.13.3,<2.14.0" name = "aws-cdk-asset-kubectl-v20" version = "2.1.1" description = "A library that contains kubectl for use in Lambda Layers" +category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -75,6 +79,7 @@ typeguard = ">=2.13.3,<2.14.0" name = "aws-cdk-asset-node-proxy-agent-v5" version = "2.0.120" description = "@aws-cdk/asset-node-proxy-agent-v5" +category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -91,6 +96,7 @@ typeguard = ">=2.13.3,<2.14.0" name = "aws-cdk-aws-apigatewayv2-alpha" version = "2.75.1a0" description = "The CDK Construct Library for AWS::APIGatewayv2" +category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -109,6 +115,7 @@ typeguard = ">=2.13.3,<2.14.0" name = "aws-cdk-aws-apigatewayv2-authorizers-alpha" version = "2.75.1a0" description = "Authorizers for AWS APIGateway V2" +category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -128,6 +135,7 @@ typeguard = ">=2.13.3,<2.14.0" name = "aws-cdk-aws-apigatewayv2-integrations-alpha" version = "2.75.1a0" description = "Integrations for AWS APIGateway V2" +category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -147,6 +155,7 @@ typeguard = ">=2.13.3,<2.14.0" name = "aws-cdk-lib" version = "2.75.1" description = "Version 2 of the AWS Cloud Development Kit library" +category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -167,6 +176,7 @@ typeguard = ">=2.13.3,<2.14.0" name = "aws-requests-auth" version = "0.4.3" description = "AWS signature version 4 signing process for the python requests module" +category = "dev" optional = false python-versions = "*" files = [ @@ -181,6 +191,7 @@ requests = ">=0.14.0" name = "aws-sam-translator" version = "1.68.0" description = "AWS SAM Translator is a library that transform SAM templates into AWS CloudFormation templates" +category = "dev" optional = false python-versions = ">=3.7, <=4.0, !=4.0" files = [ @@ -189,18 +200,19 @@ files = [ ] [package.dependencies] -boto3 = ">=1.19.5,<2.dev0" +boto3 = ">=1.19.5,<2.0.0" jsonschema = ">=3.2,<5" pydantic = ">=1.8,<2.0" typing-extensions = ">=4.4,<5" [package.extras] -dev = ["black (==23.1.0)", "boto3 (>=1.23,<2)", "boto3-stubs[appconfig,serverlessrepo] (>=1.19.5,<2.dev0)", "coverage (>=5.3,<8)", "dateparser (>=1.1,<2.0)", "importlib-metadata", "mypy (>=1.1.0,<1.2.0)", "parameterized (>=0.7,<1.0)", "pytest (>=6.2,<8)", "pytest-cov (>=2.10,<5)", "pytest-env (>=0.6,<1)", "pytest-rerunfailures (>=9.1,<12)", "pytest-xdist (>=2.5,<4)", "pyyaml (>=6.0,<7.0)", "requests (>=2.28,<3.0)", "ruamel.yaml (==0.17.21)", "ruff (==0.0.263)", "tenacity (>=8.0,<9.0)", "types-PyYAML (>=6.0,<7.0)", "types-jsonschema (>=3.2,<4.0)"] +dev = ["black (==23.1.0)", "boto3 (>=1.23,<2)", "boto3-stubs[appconfig,serverlessrepo] (>=1.19.5,<2.0.0)", "coverage (>=5.3,<8)", "dateparser (>=1.1,<2.0)", "importlib-metadata", "mypy (>=1.1.0,<1.2.0)", "parameterized (>=0.7,<1.0)", "pytest (>=6.2,<8)", "pytest-cov (>=2.10,<5)", "pytest-env (>=0.6,<1)", "pytest-rerunfailures (>=9.1,<12)", "pytest-xdist (>=2.5,<4)", "pyyaml (>=6.0,<7.0)", "requests (>=2.28,<3.0)", "ruamel.yaml (==0.17.21)", "ruff (==0.0.263)", "tenacity (>=8.0,<9.0)", "types-PyYAML (>=6.0,<7.0)", "types-jsonschema (>=3.2,<4.0)"] [[package]] name = "aws-xray-sdk" version = "2.12.0" description = "The AWS X-Ray SDK for Python (the SDK) enables Python developers to record and emit information from within their applications to the AWS X-Ray service." +category = "main" optional = true python-versions = "*" files = [ @@ -216,6 +228,7 @@ wrapt = "*" name = "bandit" version = "1.7.5" description = "Security oriented static analyser for python code." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -239,6 +252,7 @@ yaml = ["PyYAML"] name = "black" version = "23.3.0" description = "The uncompromising code formatter." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -289,6 +303,7 @@ uvloop = ["uvloop (>=0.15.2)"] name = "boto3" version = "1.26.115" description = "The AWS SDK for Python" +category = "main" optional = false python-versions = ">= 3.7" files = [ @@ -308,6 +323,7 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] name = "botocore" version = "1.29.115" description = "Low-level, data-driven core of boto 3." +category = "main" optional = false python-versions = ">= 3.7" files = [ @@ -327,6 +343,7 @@ crt = ["awscrt (==0.16.9)"] name = "cattrs" version = "22.2.0" description = "Composable complex class support for attrs and dataclasses." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -343,6 +360,7 @@ typing_extensions = {version = "*", markers = "python_version < \"3.8\""} name = "certifi" version = "2022.12.7" description = "Python package for providing Mozilla's CA Bundle." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -354,6 +372,7 @@ files = [ name = "cfn-lint" version = "0.77.6" description = "Checks CloudFormation templates for practices and behaviour that could potentially be improved" +category = "dev" optional = false python-versions = ">=3.7, <=4.0, !=4.0" files = [ @@ -377,6 +396,7 @@ sympy = ">=1.0.0" name = "charset-normalizer" version = "3.1.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -461,6 +481,7 @@ files = [ name = "checksumdir" version = "1.2.0" description = "Compute a single hash of the file contents of a directory." +category = "dev" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -472,6 +493,7 @@ files = [ name = "click" version = "8.1.3" description = "Composable command line interface toolkit" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -487,6 +509,7 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." +category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -498,6 +521,7 @@ files = [ name = "constructs" version = "10.2.1" description = "A programming model for software-defined state" +category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -514,6 +538,7 @@ typeguard = ">=2.13.3,<2.14.0" name = "coverage" version = "7.2.7" description = "Code coverage measurement for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -589,6 +614,7 @@ toml = ["tomli"] name = "decorator" version = "5.1.1" description = "Decorators for Humans" +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -600,6 +626,7 @@ files = [ name = "eradicate" version = "2.2.0" description = "Removes commented-out code." +category = "dev" optional = false python-versions = "*" files = [ @@ -611,6 +638,7 @@ files = [ name = "exceptiongroup" version = "1.1.1" description = "Backport of PEP 654 (exception groups)" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -625,6 +653,7 @@ test = ["pytest (>=6)"] name = "execnet" version = "1.9.0" description = "execnet: rapid multi-Python deployment" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -639,6 +668,7 @@ testing = ["pre-commit"] name = "fastjsonschema" version = "2.17.1" description = "Fastest Python implementation of JSON schema" +category = "main" optional = true python-versions = "*" files = [ @@ -653,6 +683,7 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc name = "filelock" version = "3.12.0" description = "A platform independent file lock." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -668,6 +699,7 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "p name = "flake8" version = "3.9.2" description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -685,6 +717,7 @@ pyflakes = ">=2.3.0,<2.4.0" name = "flake8" version = "5.0.4" description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -701,6 +734,7 @@ pyflakes = ">=2.5.0,<2.6.0" name = "flake8-black" version = "0.3.6" description = "flake8 plugin to call black as a code style validator" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -720,6 +754,7 @@ develop = ["build", "twine"] name = "flake8-bugbear" version = "23.3.12" description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -738,6 +773,7 @@ dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "pytest", name = "flake8-builtins" version = "2.1.0" description = "Check for python builtins being used as variables or parameters." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -755,6 +791,7 @@ test = ["pytest"] name = "flake8-comprehensions" version = "3.12.0" description = "A flake8 plugin to help you write better list/set/dict comprehensions." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -770,6 +807,7 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} name = "flake8-debugger" version = "4.1.2" description = "ipdb/pdb statement checker plugin for flake8" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -785,6 +823,7 @@ pycodestyle = "*" name = "flake8-eradicate" version = "1.4.0" description = "Flake8 plugin to find commented out code" +category = "dev" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -802,6 +841,7 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} name = "flake8-fixme" version = "1.1.1" description = "Check for FIXME, TODO and other temporary developer notes. Plugin for flake8." +category = "dev" optional = false python-versions = "*" files = [ @@ -813,6 +853,7 @@ files = [ name = "flake8-variables-names" version = "0.0.5" description = "A flake8 extension that helps to make more readable variables names" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -824,6 +865,7 @@ files = [ name = "future" version = "0.18.3" description = "Clean single-source support for Python 3 and 2" +category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -834,6 +876,7 @@ files = [ name = "ghp-import" version = "2.1.0" description = "Copy your docs directly to the gh-pages branch." +category = "dev" optional = false python-versions = "*" files = [ @@ -851,6 +894,7 @@ dev = ["flake8", "markdown", "twine", "wheel"] name = "gitdb" version = "4.0.10" description = "Git Object Database" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -865,6 +909,7 @@ smmap = ">=3.0.1,<6" name = "gitpython" version = "3.1.31" description = "GitPython is a Python library used to interact with Git repositories" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -880,6 +925,7 @@ typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\"" name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -894,6 +940,7 @@ typing-extensions = {version = "*", markers = "python_version < \"3.8\""} name = "httpcore" version = "0.17.0" description = "A minimal low-level HTTP client." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -905,16 +952,17 @@ files = [ anyio = ">=3.0,<5.0" certifi = "*" h11 = ">=0.13,<0.15" -sniffio = "==1.*" +sniffio = ">=1.0.0,<2.0.0" [package.extras] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "httpx" version = "0.24.1" description = "The next generation HTTP client." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -930,14 +978,15 @@ sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "hvac" version = "1.1.0" description = "HashiCorp Vault API client" +category = "dev" optional = false python-versions = ">=3.6.2,<4.0.0" files = [ @@ -953,6 +1002,7 @@ requests = ">=2.27.1,<3.0.0" name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -964,6 +1014,7 @@ files = [ name = "ijson" version = "3.2.0.post0" description = "Iterative JSON parser with standard Python iterator interfaces" +category = "dev" optional = false python-versions = "*" files = [ @@ -1051,6 +1102,7 @@ files = [ name = "importlib-metadata" version = "6.6.0" description = "Read metadata from Python packages" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1071,6 +1123,7 @@ testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packag name = "importlib-resources" version = "5.12.0" description = "Read resources from Python packages" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1089,6 +1142,7 @@ testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-chec name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1100,6 +1154,7 @@ files = [ name = "isort" version = "5.11.5" description = "A Python utility / library to sort Python imports." +category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -1117,6 +1172,7 @@ requirements-deprecated-finder = ["pip-api", "pipreqs"] name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1134,6 +1190,7 @@ i18n = ["Babel (>=2.7)"] name = "jmespath" version = "1.0.1" description = "JSON Matching Expressions" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1145,6 +1202,7 @@ files = [ name = "jschema-to-python" version = "1.2.3" description = "Generate source code for Python classes from a JSON schema." +category = "dev" optional = false python-versions = ">= 2.7" files = [ @@ -1161,6 +1219,7 @@ pbr = "*" name = "jsii" version = "1.80.0" description = "Python client for jsii runtime" +category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -1181,6 +1240,7 @@ typing-extensions = ">=3.7,<5.0" name = "jsonpatch" version = "1.32" description = "Apply JSON-Patches (RFC 6902)" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1195,6 +1255,7 @@ jsonpointer = ">=1.9" name = "jsonpickle" version = "3.0.1" description = "Python library for serializing any arbitrary object graph into JSON" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1214,6 +1275,7 @@ testing-libs = ["simplejson", "ujson"] name = "jsonpointer" version = "2.3" description = "Identify specific nodes in a JSON document (RFC 6901)" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1225,6 +1287,7 @@ files = [ name = "jsonschema" version = "4.17.3" description = "An implementation of JSON Schema validation for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1248,6 +1311,7 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- name = "junit-xml" version = "1.9" description = "Creates JUnit XML test result documents that can be read by tools such as Jenkins" +category = "dev" optional = false python-versions = "*" files = [ @@ -1262,6 +1326,7 @@ six = "*" name = "mako" version = "1.2.4" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1282,6 +1347,7 @@ testing = ["pytest"] name = "mando" version = "0.6.4" description = "Create Python CLI apps with little to no effort at all!" +category = "dev" optional = false python-versions = "*" files = [ @@ -1299,6 +1365,7 @@ restructuredtext = ["rst2ansi"] name = "markdown" version = "3.3.7" description = "Python implementation of Markdown." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1316,6 +1383,7 @@ testing = ["coverage", "pyyaml"] name = "markdown-it-py" version = "2.2.0" description = "Python port of markdown-it. Markdown parsing, done right!" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1341,6 +1409,7 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] name = "markupsafe" version = "2.1.2" description = "Safely add untrusted strings to HTML/XML markup." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1400,6 +1469,7 @@ files = [ name = "mccabe" version = "0.6.1" description = "McCabe checker, plugin for flake8" +category = "dev" optional = false python-versions = "*" files = [ @@ -1411,6 +1481,7 @@ files = [ name = "mccabe" version = "0.7.0" description = "McCabe checker, plugin for flake8" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1422,6 +1493,7 @@ files = [ name = "mdurl" version = "0.1.2" description = "Markdown URL utilities" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1433,6 +1505,7 @@ files = [ name = "mergedeep" version = "1.3.4" description = "A deep merge function for 🐍." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1444,6 +1517,7 @@ files = [ name = "mike" version = "1.1.2" description = "Manage multiple versions of your MkDocs-powered documentation" +category = "dev" optional = false python-versions = "*" files = [ @@ -1465,6 +1539,7 @@ test = ["coverage", "flake8 (>=3.0)", "shtab"] name = "mkdocs" version = "1.4.2" description = "Project documentation with Markdown." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1494,6 +1569,7 @@ min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-imp name = "mkdocs-git-revision-date-plugin" version = "0.3.2" description = "MkDocs plugin for setting revision date from git per markdown file." +category = "dev" optional = false python-versions = ">=3.4" files = [ @@ -1509,6 +1585,7 @@ mkdocs = ">=0.17" name = "mkdocs-material" version = "9.1.15" description = "Documentation that simply works" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1531,6 +1608,7 @@ requests = ">=2.26" name = "mkdocs-material-extensions" version = "1.1.1" description = "Extension pack for Python Markdown and MkDocs Material." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1542,6 +1620,7 @@ files = [ name = "mpmath" version = "1.3.0" description = "Python library for arbitrary-precision floating-point arithmetic" +category = "dev" optional = false python-versions = "*" files = [ @@ -1559,6 +1638,7 @@ tests = ["pytest (>=4.6)"] name = "mypy" version = "1.3.0" description = "Optional static typing for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1606,6 +1686,7 @@ reports = ["lxml"] name = "mypy-boto3-appconfig" version = "1.26.71" description = "Type annotations for boto3.AppConfig 1.26.71 service generated with mypy-boto3-builder 7.12.3" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1620,6 +1701,7 @@ typing-extensions = ">=4.1.0" name = "mypy-boto3-appconfigdata" version = "1.26.70" description = "Type annotations for boto3.AppConfigData 1.26.70 service generated with mypy-boto3-builder 7.12.3" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1634,6 +1716,7 @@ typing-extensions = ">=4.1.0" name = "mypy-boto3-cloudformation" version = "1.26.147" description = "Type annotations for boto3.CloudFormation 1.26.147 service generated with mypy-boto3-builder 7.14.5" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1648,6 +1731,7 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} name = "mypy-boto3-cloudwatch" version = "1.26.127" description = "Type annotations for boto3.CloudWatch 1.26.127 service generated with mypy-boto3-builder 7.14.5" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1662,6 +1746,7 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} name = "mypy-boto3-dynamodb" version = "1.26.115" description = "Type annotations for boto3.DynamoDB 1.26.115 service generated with mypy-boto3-builder 7.14.5" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1676,6 +1761,7 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} name = "mypy-boto3-lambda" version = "1.26.147" description = "Type annotations for boto3.Lambda 1.26.147 service generated with mypy-boto3-builder 7.14.5" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1688,22 +1774,24 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} [[package]] name = "mypy-boto3-logs" -version = "1.26.53" -description = "Type annotations for boto3.CloudWatchLogs 1.26.53 service generated with mypy-boto3-builder 7.12.3" +version = "1.26.149" +description = "Type annotations for boto3.CloudWatchLogs 1.26.149 service generated with mypy-boto3-builder 7.14.5" +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "mypy-boto3-logs-1.26.53.tar.gz", hash = "sha256:9b2d70e9a8f33e5f141ebf4abd3a78c50e80b60152eb400e69a23b5085f50ce0"}, - {file = "mypy_boto3_logs-1.26.53-py3-none-any.whl", hash = "sha256:d40de12136ef71b1effe2e00f5d608c3cd7c89796d830867617ae9e9f3668fc4"}, + {file = "mypy-boto3-logs-1.26.149.tar.gz", hash = "sha256:4a592d7d8180d45197197af4dc959f61b5c4d989a0ba615ecde6e21661c4013f"}, + {file = "mypy_boto3_logs-1.26.149-py3-none-any.whl", hash = "sha256:6d913c9be74c9eff71910b5af18f8beeeae524dae273fea7b47ead0ee1a09134"}, ] [package.dependencies] -typing-extensions = ">=4.1.0" +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} [[package]] name = "mypy-boto3-s3" version = "1.26.127" description = "Type annotations for boto3.S3 1.26.127 service generated with mypy-boto3-builder 7.14.5" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1718,6 +1806,7 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} name = "mypy-boto3-secretsmanager" version = "1.26.135" description = "Type annotations for boto3.SecretsManager 1.26.135 service generated with mypy-boto3-builder 7.14.5" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1732,6 +1821,7 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} name = "mypy-boto3-ssm" version = "1.26.97" description = "Type annotations for boto3.SSM 1.26.97 service generated with mypy-boto3-builder 7.13.0" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1746,6 +1836,7 @@ typing-extensions = ">=4.1.0" name = "mypy-boto3-xray" version = "1.26.122" description = "Type annotations for boto3.XRay 1.26.122 service generated with mypy-boto3-builder 7.14.5" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1760,6 +1851,7 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1771,6 +1863,7 @@ files = [ name = "networkx" version = "2.6.3" description = "Python package for creating and manipulating graphs and networks" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1789,6 +1882,7 @@ test = ["codecov (>=2.1)", "pytest (>=6.2)", "pytest-cov (>=2.12)"] name = "packaging" version = "23.1" description = "Core utilities for Python packages" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1800,6 +1894,7 @@ files = [ name = "pathspec" version = "0.11.1" description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1811,6 +1906,7 @@ files = [ name = "pbr" version = "5.11.1" description = "Python Build Reasonableness" +category = "dev" optional = false python-versions = ">=2.6" files = [ @@ -1822,6 +1918,7 @@ files = [ name = "pdoc3" version = "0.10.0" description = "Auto-generate API documentation for Python projects." +category = "dev" optional = false python-versions = ">= 3.6" files = [ @@ -1837,6 +1934,7 @@ markdown = ">=3.0" name = "pkgutil-resolve-name" version = "1.3.10" description = "Resolve a name to an object." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1848,6 +1946,7 @@ files = [ name = "platformdirs" version = "3.2.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1866,6 +1965,7 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.2.2)", "pytest- name = "pluggy" version = "1.0.0" description = "plugin and hook calling mechanisms for python" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1884,6 +1984,7 @@ testing = ["pytest", "pytest-benchmark"] name = "publication" version = "0.0.3" description = "Publication helps you maintain public-api-friendly modules by preventing unintentional access to private implementation details via introspection." +category = "dev" optional = false python-versions = "*" files = [ @@ -1895,6 +1996,7 @@ files = [ name = "py" version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1906,6 +2008,7 @@ files = [ name = "py-cpuinfo" version = "9.0.0" description = "Get CPU info with pure Python" +category = "dev" optional = false python-versions = "*" files = [ @@ -1917,6 +2020,7 @@ files = [ name = "pycodestyle" version = "2.7.0" description = "Python style guide checker" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1928,6 +2032,7 @@ files = [ name = "pycodestyle" version = "2.9.1" description = "Python style guide checker" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1939,6 +2044,7 @@ files = [ name = "pydantic" version = "1.10.8" description = "Data validation and settings management using python type hints" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1991,6 +2097,7 @@ email = ["email-validator (>=1.0.3)"] name = "pyflakes" version = "2.3.1" description = "passive checker of Python programs" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2002,6 +2109,7 @@ files = [ name = "pyflakes" version = "2.5.0" description = "passive checker of Python programs" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2013,6 +2121,7 @@ files = [ name = "pygments" version = "2.15.1" description = "Pygments is a syntax highlighting package written in Python." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2027,6 +2136,7 @@ plugins = ["importlib-metadata"] name = "pyhcl" version = "0.4.4" description = "HCL configuration parser for python" +category = "dev" optional = false python-versions = "*" files = [ @@ -2037,6 +2147,7 @@ files = [ name = "pymdown-extensions" version = "10.0" description = "Extension pack for Python Markdown." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2052,6 +2163,7 @@ pyyaml = "*" name = "pyrsistent" version = "0.19.3" description = "Persistent/Functional/Immutable data structures" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2088,6 +2200,7 @@ files = [ name = "pytest" version = "7.3.1" description = "pytest: simple powerful testing with Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2111,6 +2224,7 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no name = "pytest-asyncio" version = "0.21.0" description = "Pytest support for asyncio" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2130,6 +2244,7 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy name = "pytest-benchmark" version = "4.0.0" description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2150,6 +2265,7 @@ histogram = ["pygal", "pygaljs"] name = "pytest-cov" version = "4.1.0" description = "Pytest plugin for measuring coverage." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2168,6 +2284,7 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "pytest-mock" version = "3.10.0" description = "Thin-wrapper around the mock package for easier use with pytest" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2185,6 +2302,7 @@ dev = ["pre-commit", "pytest-asyncio", "tox"] name = "pytest-xdist" version = "3.3.1" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2205,6 +2323,7 @@ testing = ["filelock"] name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -2219,6 +2338,7 @@ six = ">=1.5" name = "python-snappy" version = "0.6.1" description = "Python library for the snappy compression library from Google" +category = "dev" optional = false python-versions = "*" files = [ @@ -2276,6 +2396,7 @@ files = [ name = "pyyaml" version = "6.0" description = "YAML parser and emitter for Python" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2325,6 +2446,7 @@ files = [ name = "pyyaml-env-tag" version = "0.1" description = "A custom YAML tag for referencing environment variables in YAML files. " +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2339,6 +2461,7 @@ pyyaml = "*" name = "radon" version = "5.1.0" description = "Code Metrics in Python" +category = "dev" optional = false python-versions = "*" files = [ @@ -2355,6 +2478,7 @@ mando = ">=0.6,<0.7" name = "regex" version = "2022.10.31" description = "Alternative regular expression module, to replace re." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2452,6 +2576,7 @@ files = [ name = "requests" version = "2.31.0" description = "Python HTTP for Humans." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2473,6 +2598,7 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "retry" version = "0.9.2" description = "Easy to use retry decorator." +category = "dev" optional = false python-versions = "*" files = [ @@ -2488,6 +2614,7 @@ py = ">=1.4.26,<2.0.0" name = "rich" version = "13.3.4" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -2507,6 +2634,7 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] name = "s3transfer" version = "0.6.0" description = "An Amazon S3 Transfer Manager" +category = "main" optional = false python-versions = ">= 3.7" files = [ @@ -2524,6 +2652,7 @@ crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"] name = "sarif-om" version = "1.0.4" description = "Classes implementing the SARIF 2.1.0 object model." +category = "dev" optional = false python-versions = ">= 2.7" files = [ @@ -2539,6 +2668,7 @@ pbr = "*" name = "sentry-sdk" version = "1.25.0" description = "Python client for Sentry (https://sentry.io)" +category = "dev" optional = false python-versions = "*" files = [ @@ -2581,6 +2711,7 @@ tornado = ["tornado (>=5)"] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -2592,6 +2723,7 @@ files = [ name = "smmap" version = "5.0.0" description = "A pure Python implementation of a sliding window memory map manager" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2603,6 +2735,7 @@ files = [ name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2614,6 +2747,7 @@ files = [ name = "stevedore" version = "3.5.2" description = "Manage dynamic plugins for Python applications" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2629,6 +2763,7 @@ pbr = ">=2.0.0,<2.1.0 || >2.1.0" name = "sympy" version = "1.10.1" description = "Computer algebra system (CAS) in Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2643,6 +2778,7 @@ mpmath = ">=0.19" name = "tomli" version = "2.0.1" description = "A lil' TOML parser" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2654,6 +2790,7 @@ files = [ name = "typed-ast" version = "1.5.4" description = "a fork of Python 2 and 3 ast modules with type comment support" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2687,6 +2824,7 @@ files = [ name = "typeguard" version = "2.13.3" description = "Run-time type checker for Python" +category = "dev" optional = false python-versions = ">=3.5.3" files = [ @@ -2702,6 +2840,7 @@ test = ["mypy", "pytest", "typing-extensions"] name = "types-python-dateutil" version = "2.8.19.13" description = "Typing stubs for python-dateutil" +category = "dev" optional = false python-versions = "*" files = [ @@ -2713,6 +2852,7 @@ files = [ name = "types-requests" version = "2.31.0.1" description = "Typing stubs for requests" +category = "dev" optional = false python-versions = "*" files = [ @@ -2727,6 +2867,7 @@ types-urllib3 = "*" name = "types-urllib3" version = "1.26.25.10" description = "Typing stubs for urllib3" +category = "dev" optional = false python-versions = "*" files = [ @@ -2738,6 +2879,7 @@ files = [ name = "typing-extensions" version = "4.6.2" description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2749,6 +2891,7 @@ files = [ name = "urllib3" version = "1.26.15" description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -2765,6 +2908,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] name = "verspec" version = "0.1.0" description = "Flexible version handling" +category = "dev" optional = false python-versions = "*" files = [ @@ -2779,6 +2923,7 @@ test = ["coverage", "flake8 (>=3.7)", "mypy", "pretend", "pytest"] name = "watchdog" version = "3.0.0" description = "Filesystem events monitoring" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2818,6 +2963,7 @@ watchmedo = ["PyYAML (>=3.10)"] name = "wrapt" version = "1.15.0" description = "Module for decorators, wrappers and monkey patching." +category = "main" optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -2902,6 +3048,7 @@ files = [ name = "xenon" version = "0.9.0" description = "Monitor code metrics for Python on your CI server" +category = "dev" optional = false python-versions = "*" files = [ @@ -2918,6 +3065,7 @@ requests = ">=2.0,<3.0" name = "zipp" version = "3.15.0" description = "Backport of pathlib-compatible object wrapper for zip files" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2930,7 +3078,7 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [extras] -all = ["aws-xray-sdk", "fastjsonschema", "pydantic"] +all = ["pydantic", "aws-xray-sdk", "fastjsonschema"] aws-sdk = ["boto3"] parser = ["pydantic"] tracer = ["aws-xray-sdk"] @@ -2939,4 +3087,4 @@ validation = ["fastjsonschema"] [metadata] lock-version = "2.0" python-versions = "^3.7.4" -content-hash = "23fcc55cee4680f4e082103b5fbc74fb182da8e25cc7a8498677d1efc20f6a3d" +content-hash = "e16af10078db49fe9650b5c13ca94d5e151c6886d4a8ba12bb5860860f028a9e" diff --git a/pyproject.toml b/pyproject.toml index 9b2ba836cf6..200b1461f80 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,7 +75,7 @@ mypy-boto3-cloudformation = "^1.26.147" mypy-boto3-cloudwatch = "^1.26.127" mypy-boto3-dynamodb = "^1.26.115" mypy-boto3-lambda = "^1.26.147" -mypy-boto3-logs = "^1.26.53" +mypy-boto3-logs = "^1.26.149" mypy-boto3-secretsmanager = "^1.26.135" mypy-boto3-ssm = "^1.26.97" mypy-boto3-s3 = "^1.26.127" From e57b164be76e6585c4e52866c8f587e81e965a19 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 22:56:30 +0100 Subject: [PATCH 09/41] chore(deps-dev): bump aws-cdk from 2.82.0 to 2.83.0 (#2406) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Leandro Damascena --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 68dc129148c..352ee6c2e73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,13 +8,13 @@ "name": "aws-lambda-powertools-python-e2e", "version": "1.0.0", "devDependencies": { - "aws-cdk": "^2.82.0" + "aws-cdk": "^2.83.0" } }, "node_modules/aws-cdk": { - "version": "2.82.0", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.82.0.tgz", - "integrity": "sha512-4uAhKN8HMdxxM10Th8aMQJLSINO6evYV9UKTPL0hbVQ6dh6+i5LbSejcvDRw0HfBoP6qV1LNV8P8XGLYIC3tyQ==", + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.83.0.tgz", + "integrity": "sha512-UB9foPqsQkUeFHP5ZOjxqg0N+g53MPJnpxyKeMhDQDIiS9kG1LqVyHUwHNzq0PSk4kdwH9g50keu6zslb1iA1w==", "dev": true, "bin": { "cdk": "bin/cdk" @@ -43,9 +43,9 @@ }, "dependencies": { "aws-cdk": { - "version": "2.82.0", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.82.0.tgz", - "integrity": "sha512-4uAhKN8HMdxxM10Th8aMQJLSINO6evYV9UKTPL0hbVQ6dh6+i5LbSejcvDRw0HfBoP6qV1LNV8P8XGLYIC3tyQ==", + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.83.0.tgz", + "integrity": "sha512-UB9foPqsQkUeFHP5ZOjxqg0N+g53MPJnpxyKeMhDQDIiS9kG1LqVyHUwHNzq0PSk4kdwH9g50keu6zslb1iA1w==", "dev": true, "requires": { "fsevents": "2.3.2" diff --git a/package.json b/package.json index 17211debe46..7aa708b8533 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,6 @@ "name": "aws-lambda-powertools-python-e2e", "version": "1.0.0", "devDependencies": { - "aws-cdk": "^2.82.0" + "aws-cdk": "^2.83.0" } } From c7f9a460aafa0f58e50f212424da872ce77bf6f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 23:02:14 +0100 Subject: [PATCH 10/41] chore(deps-dev): bump mypy-boto3-cloudformation from 1.26.147 to 1.26.149 (#2410) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Leandro Damascena --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index 01b96db87f5..ed7fb305146 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1714,14 +1714,14 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cloudformation" -version = "1.26.147" -description = "Type annotations for boto3.CloudFormation 1.26.147 service generated with mypy-boto3-builder 7.14.5" +version = "1.26.149" +description = "Type annotations for boto3.CloudFormation 1.26.149 service generated with mypy-boto3-builder 7.14.5" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "mypy-boto3-cloudformation-1.26.147.tar.gz", hash = "sha256:4e68713b617d7c007cd2314ebb781439cce9b8144a6077845df054fd27f537da"}, - {file = "mypy_boto3_cloudformation-1.26.147-py3-none-any.whl", hash = "sha256:d72c47f6f731226b443d4c7bc59cdd84bdbfdab671f45efbd2fee6ed4692a26d"}, + {file = "mypy-boto3-cloudformation-1.26.149.tar.gz", hash = "sha256:cdc1a41aa63acca0d732f61179c5049be94d9b3640f3807da0d595ed6dd44a15"}, + {file = "mypy_boto3_cloudformation-1.26.149-py3-none-any.whl", hash = "sha256:7a9d0b4670699e2e96efe567668bd0dd12bd6e2264aa54686cdd8b70c2d69a94"}, ] [package.dependencies] @@ -3087,4 +3087,4 @@ validation = ["fastjsonschema"] [metadata] lock-version = "2.0" python-versions = "^3.7.4" -content-hash = "e16af10078db49fe9650b5c13ca94d5e151c6886d4a8ba12bb5860860f028a9e" +content-hash = "b61c899b6159bef98d9af1c61fe63a9385b51b69c82908f49b8b79bc44cfb654" diff --git a/pyproject.toml b/pyproject.toml index 200b1461f80..f870c6238f2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,7 +71,7 @@ aws-cdk-lib = "^2.75.0" pytest-benchmark = "^4.0.0" python-snappy = "^0.6.1" mypy-boto3-appconfig = "^1.26.71" -mypy-boto3-cloudformation = "^1.26.147" +mypy-boto3-cloudformation = "^1.26.149" mypy-boto3-cloudwatch = "^1.26.127" mypy-boto3-dynamodb = "^1.26.115" mypy-boto3-lambda = "^1.26.147" From a4cbdcf8b16c5f6ed60eade8665e320dd53bde32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 23:06:08 +0100 Subject: [PATCH 11/41] chore(deps-dev): bump sentry-sdk from 1.25.0 to 1.25.1 (#2408) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Leandro Damascena --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index ed7fb305146..22d09023461 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2666,14 +2666,14 @@ pbr = "*" [[package]] name = "sentry-sdk" -version = "1.25.0" +version = "1.25.1" description = "Python client for Sentry (https://sentry.io)" category = "dev" optional = false python-versions = "*" files = [ - {file = "sentry-sdk-1.25.0.tar.gz", hash = "sha256:5be3296fc574fa8a4d9b213b4dcf8c8d0246c08f8bd78315c6286f386c37555a"}, - {file = "sentry_sdk-1.25.0-py2.py3-none-any.whl", hash = "sha256:fe85cf5d0b3d0aa3480df689f9f6dc487de783defb0a95043368375dc893645e"}, + {file = "sentry-sdk-1.25.1.tar.gz", hash = "sha256:aa796423eb6a2f4a8cd7a5b02ba6558cb10aab4ccdc0537f63a47b038c520c38"}, + {file = "sentry_sdk-1.25.1-py2.py3-none-any.whl", hash = "sha256:79afb7c896014038e358401ad1d36889f97a129dfa8031c49b3f238cd1aa3935"}, ] [package.dependencies] From f37d6e632e81d7f043245dad584a3c393385f261 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 23:10:46 +0100 Subject: [PATCH 12/41] chore(deps): bump pydantic from 1.10.8 to 1.10.9 (#2405) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Leandro Damascena --- poetry.lock | 74 ++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/poetry.lock b/poetry.lock index 22d09023461..9f4db6ffb29 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2042,48 +2042,48 @@ files = [ [[package]] name = "pydantic" -version = "1.10.8" +version = "1.10.9" description = "Data validation and settings management using python type hints" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1243d28e9b05003a89d72e7915fdb26ffd1d39bdd39b00b7dbe4afae4b557f9d"}, - {file = "pydantic-1.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0ab53b609c11dfc0c060d94335993cc2b95b2150e25583bec37a49b2d6c6c3f"}, - {file = "pydantic-1.10.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9613fadad06b4f3bc5db2653ce2f22e0de84a7c6c293909b48f6ed37b83c61f"}, - {file = "pydantic-1.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df7800cb1984d8f6e249351139667a8c50a379009271ee6236138a22a0c0f319"}, - {file = "pydantic-1.10.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0c6fafa0965b539d7aab0a673a046466d23b86e4b0e8019d25fd53f4df62c277"}, - {file = "pydantic-1.10.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e82d4566fcd527eae8b244fa952d99f2ca3172b7e97add0b43e2d97ee77f81ab"}, - {file = "pydantic-1.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:ab523c31e22943713d80d8d342d23b6f6ac4b792a1e54064a8d0cf78fd64e800"}, - {file = "pydantic-1.10.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:666bdf6066bf6dbc107b30d034615d2627e2121506c555f73f90b54a463d1f33"}, - {file = "pydantic-1.10.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:35db5301b82e8661fa9c505c800d0990bc14e9f36f98932bb1d248c0ac5cada5"}, - {file = "pydantic-1.10.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f90c1e29f447557e9e26afb1c4dbf8768a10cc676e3781b6a577841ade126b85"}, - {file = "pydantic-1.10.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93e766b4a8226e0708ef243e843105bf124e21331694367f95f4e3b4a92bbb3f"}, - {file = "pydantic-1.10.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:88f195f582851e8db960b4a94c3e3ad25692c1c1539e2552f3df7a9e972ef60e"}, - {file = "pydantic-1.10.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:34d327c81e68a1ecb52fe9c8d50c8a9b3e90d3c8ad991bfc8f953fb477d42fb4"}, - {file = "pydantic-1.10.8-cp311-cp311-win_amd64.whl", hash = "sha256:d532bf00f381bd6bc62cabc7d1372096b75a33bc197a312b03f5838b4fb84edd"}, - {file = "pydantic-1.10.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7d5b8641c24886d764a74ec541d2fc2c7fb19f6da2a4001e6d580ba4a38f7878"}, - {file = "pydantic-1.10.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b1f6cb446470b7ddf86c2e57cd119a24959af2b01e552f60705910663af09a4"}, - {file = "pydantic-1.10.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c33b60054b2136aef8cf190cd4c52a3daa20b2263917c49adad20eaf381e823b"}, - {file = "pydantic-1.10.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1952526ba40b220b912cdc43c1c32bcf4a58e3f192fa313ee665916b26befb68"}, - {file = "pydantic-1.10.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bb14388ec45a7a0dc429e87def6396f9e73c8c77818c927b6a60706603d5f2ea"}, - {file = "pydantic-1.10.8-cp37-cp37m-win_amd64.whl", hash = "sha256:16f8c3e33af1e9bb16c7a91fc7d5fa9fe27298e9f299cff6cb744d89d573d62c"}, - {file = "pydantic-1.10.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ced8375969673929809d7f36ad322934c35de4af3b5e5b09ec967c21f9f7887"}, - {file = "pydantic-1.10.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93e6bcfccbd831894a6a434b0aeb1947f9e70b7468f274154d03d71fabb1d7c6"}, - {file = "pydantic-1.10.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:191ba419b605f897ede9892f6c56fb182f40a15d309ef0142212200a10af4c18"}, - {file = "pydantic-1.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:052d8654cb65174d6f9490cc9b9a200083a82cf5c3c5d3985db765757eb3b375"}, - {file = "pydantic-1.10.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ceb6a23bf1ba4b837d0cfe378329ad3f351b5897c8d4914ce95b85fba96da5a1"}, - {file = "pydantic-1.10.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f2e754d5566f050954727c77f094e01793bcb5725b663bf628fa6743a5a9108"}, - {file = "pydantic-1.10.8-cp38-cp38-win_amd64.whl", hash = "sha256:6a82d6cda82258efca32b40040228ecf43a548671cb174a1e81477195ed3ed56"}, - {file = "pydantic-1.10.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e59417ba8a17265e632af99cc5f35ec309de5980c440c255ab1ca3ae96a3e0e"}, - {file = "pydantic-1.10.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:84d80219c3f8d4cad44575e18404099c76851bc924ce5ab1c4c8bb5e2a2227d0"}, - {file = "pydantic-1.10.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e4148e635994d57d834be1182a44bdb07dd867fa3c2d1b37002000646cc5459"}, - {file = "pydantic-1.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12f7b0bf8553e310e530e9f3a2f5734c68699f42218bf3568ef49cd9b0e44df4"}, - {file = "pydantic-1.10.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42aa0c4b5c3025483240a25b09f3c09a189481ddda2ea3a831a9d25f444e03c1"}, - {file = "pydantic-1.10.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:17aef11cc1b997f9d574b91909fed40761e13fac438d72b81f902226a69dac01"}, - {file = "pydantic-1.10.8-cp39-cp39-win_amd64.whl", hash = "sha256:66a703d1983c675a6e0fed8953b0971c44dba48a929a2000a493c3772eb61a5a"}, - {file = "pydantic-1.10.8-py3-none-any.whl", hash = "sha256:7456eb22ed9aaa24ff3e7b4757da20d9e5ce2a81018c1b3ebd81a0b88a18f3b2"}, - {file = "pydantic-1.10.8.tar.gz", hash = "sha256:1410275520dfa70effadf4c21811d755e7ef9bb1f1d077a21958153a92c8d9ca"}, + {file = "pydantic-1.10.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e692dec4a40bfb40ca530e07805b1208c1de071a18d26af4a2a0d79015b352ca"}, + {file = "pydantic-1.10.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c52eb595db83e189419bf337b59154bdcca642ee4b2a09e5d7797e41ace783f"}, + {file = "pydantic-1.10.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:939328fd539b8d0edf244327398a667b6b140afd3bf7e347cf9813c736211896"}, + {file = "pydantic-1.10.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b48d3d634bca23b172f47f2335c617d3fcb4b3ba18481c96b7943a4c634f5c8d"}, + {file = "pydantic-1.10.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f0b7628fb8efe60fe66fd4adadd7ad2304014770cdc1f4934db41fe46cc8825f"}, + {file = "pydantic-1.10.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e1aa5c2410769ca28aa9a7841b80d9d9a1c5f223928ca8bec7e7c9a34d26b1d4"}, + {file = "pydantic-1.10.9-cp310-cp310-win_amd64.whl", hash = "sha256:eec39224b2b2e861259d6f3c8b6290d4e0fbdce147adb797484a42278a1a486f"}, + {file = "pydantic-1.10.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d111a21bbbfd85c17248130deac02bbd9b5e20b303338e0dbe0faa78330e37e0"}, + {file = "pydantic-1.10.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e9aec8627a1a6823fc62fb96480abe3eb10168fd0d859ee3d3b395105ae19a7"}, + {file = "pydantic-1.10.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07293ab08e7b4d3c9d7de4949a0ea571f11e4557d19ea24dd3ae0c524c0c334d"}, + {file = "pydantic-1.10.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ee829b86ce984261d99ff2fd6e88f2230068d96c2a582f29583ed602ef3fc2c"}, + {file = "pydantic-1.10.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4b466a23009ff5cdd7076eb56aca537c745ca491293cc38e72bf1e0e00de5b91"}, + {file = "pydantic-1.10.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7847ca62e581e6088d9000f3c497267868ca2fa89432714e21a4fb33a04d52e8"}, + {file = "pydantic-1.10.9-cp311-cp311-win_amd64.whl", hash = "sha256:7845b31959468bc5b78d7b95ec52fe5be32b55d0d09983a877cca6aedc51068f"}, + {file = "pydantic-1.10.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:517a681919bf880ce1dac7e5bc0c3af1e58ba118fd774da2ffcd93c5f96eaece"}, + {file = "pydantic-1.10.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67195274fd27780f15c4c372f4ba9a5c02dad6d50647b917b6a92bf00b3d301a"}, + {file = "pydantic-1.10.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2196c06484da2b3fded1ab6dbe182bdabeb09f6318b7fdc412609ee2b564c49a"}, + {file = "pydantic-1.10.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6257bb45ad78abacda13f15bde5886efd6bf549dd71085e64b8dcf9919c38b60"}, + {file = "pydantic-1.10.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3283b574b01e8dbc982080d8287c968489d25329a463b29a90d4157de4f2baaf"}, + {file = "pydantic-1.10.9-cp37-cp37m-win_amd64.whl", hash = "sha256:5f8bbaf4013b9a50e8100333cc4e3fa2f81214033e05ac5aa44fa24a98670a29"}, + {file = "pydantic-1.10.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9cd67fb763248cbe38f0593cd8611bfe4b8ad82acb3bdf2b0898c23415a1f82"}, + {file = "pydantic-1.10.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f50e1764ce9353be67267e7fd0da08349397c7db17a562ad036aa7c8f4adfdb6"}, + {file = "pydantic-1.10.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73ef93e5e1d3c8e83f1ff2e7fdd026d9e063c7e089394869a6e2985696693766"}, + {file = "pydantic-1.10.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:128d9453d92e6e81e881dd7e2484e08d8b164da5507f62d06ceecf84bf2e21d3"}, + {file = "pydantic-1.10.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ad428e92ab68798d9326bb3e5515bc927444a3d71a93b4a2ca02a8a5d795c572"}, + {file = "pydantic-1.10.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fab81a92f42d6d525dd47ced310b0c3e10c416bbfae5d59523e63ea22f82b31e"}, + {file = "pydantic-1.10.9-cp38-cp38-win_amd64.whl", hash = "sha256:963671eda0b6ba6926d8fc759e3e10335e1dc1b71ff2a43ed2efd6996634dafb"}, + {file = "pydantic-1.10.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:970b1bdc6243ef663ba5c7e36ac9ab1f2bfecb8ad297c9824b542d41a750b298"}, + {file = "pydantic-1.10.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7e1d5290044f620f80cf1c969c542a5468f3656de47b41aa78100c5baa2b8276"}, + {file = "pydantic-1.10.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83fcff3c7df7adff880622a98022626f4f6dbce6639a88a15a3ce0f96466cb60"}, + {file = "pydantic-1.10.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0da48717dc9495d3a8f215e0d012599db6b8092db02acac5e0d58a65248ec5bc"}, + {file = "pydantic-1.10.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0a2aabdc73c2a5960e87c3ffebca6ccde88665616d1fd6d3db3178ef427b267a"}, + {file = "pydantic-1.10.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9863b9420d99dfa9c064042304868e8ba08e89081428a1c471858aa2af6f57c4"}, + {file = "pydantic-1.10.9-cp39-cp39-win_amd64.whl", hash = "sha256:e7c9900b43ac14110efa977be3da28931ffc74c27e96ee89fbcaaf0b0fe338e1"}, + {file = "pydantic-1.10.9-py3-none-any.whl", hash = "sha256:6cafde02f6699ce4ff643417d1a9223716ec25e228ddc3b436fe7e2d25a1f305"}, + {file = "pydantic-1.10.9.tar.gz", hash = "sha256:95c70da2cd3b6ddf3b9645ecaa8d98f3d80c606624b6d245558d202cd23ea3be"}, ] [package.dependencies] From 824912b109f615617a4188ec83cee50b4411ec63 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 23:23:17 +0100 Subject: [PATCH 13/41] chore(deps-dev): bump cfn-lint from 0.77.6 to 0.77.7 (#2414) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Leandro Damascena --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9f4db6ffb29..5b423b983da 100644 --- a/poetry.lock +++ b/poetry.lock @@ -370,14 +370,14 @@ files = [ [[package]] name = "cfn-lint" -version = "0.77.6" +version = "0.77.7" description = "Checks CloudFormation templates for practices and behaviour that could potentially be improved" category = "dev" optional = false python-versions = ">=3.7, <=4.0, !=4.0" files = [ - {file = "cfn-lint-0.77.6.tar.gz", hash = "sha256:84a07ae2f9af9577ab09a0f79684272976ba155687093d94c4b8ca9e253e07c7"}, - {file = "cfn_lint-0.77.6-py3-none-any.whl", hash = "sha256:22d891e1ac21fc1aa7ea6c02dd8739224a8b2ed27b602a84611f3837002ae239"}, + {file = "cfn-lint-0.77.7.tar.gz", hash = "sha256:152073ae6e7010de358903aa48cf8cc8eadc8c497f61ba04d46d551175a667ee"}, + {file = "cfn_lint-0.77.7-py3-none-any.whl", hash = "sha256:7948cf81152d8b46775da0ac1ffee67767ac53a5869226eee5c309000f6ebd40"}, ] [package.dependencies] @@ -3087,4 +3087,4 @@ validation = ["fastjsonschema"] [metadata] lock-version = "2.0" python-versions = "^3.7.4" -content-hash = "b61c899b6159bef98d9af1c61fe63a9385b51b69c82908f49b8b79bc44cfb654" +content-hash = "e19d37cdb2bff43a2a3a193503b12e9d7816a7875a1ac8302d04736a2f9a5052" diff --git a/pyproject.toml b/pyproject.toml index f870c6238f2..e9f90829c7f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -100,7 +100,7 @@ all = ["pydantic", "aws-xray-sdk", "fastjsonschema"] aws-sdk = ["boto3"] [tool.poetry.group.dev.dependencies] -cfn-lint = "0.77.6" +cfn-lint = "0.77.7" mypy = "^1.1.1" types-python-dateutil = "^2.8.19.6" httpx = ">=0.23.3,<0.25.0" From f0dcb8fbd05b94bb2916f44166abaede1e1e036d Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Thu, 8 Jun 2023 13:44:16 +0100 Subject: [PATCH 14/41] docs(navigation): standardize link targets to enhance customer experience (#2420) Co-authored-by: erikayao93 --- docs/core/event_handler/api_gateway.md | 8 ++-- docs/core/logger.md | 10 ++-- docs/core/metrics.md | 20 ++++---- docs/core/tracer.md | 14 +++--- docs/index.md | 64 +++++++++++++------------- docs/roadmap.md | 12 ++--- docs/tutorial/index.md | 20 ++++---- docs/upgrade.md | 2 +- docs/utilities/data_classes.md | 4 +- docs/utilities/feature_flags.md | 6 +-- docs/utilities/idempotency.md | 40 ++++++++-------- docs/utilities/jmespath_functions.md | 4 +- docs/utilities/middleware_factory.md | 11 +++-- docs/utilities/parameters.md | 28 +++++------ docs/utilities/parser.md | 16 +++---- docs/utilities/streaming.md | 22 ++++----- docs/utilities/validation.md | 6 +-- poetry.lock | 4 +- 18 files changed, 146 insertions(+), 145 deletions(-) diff --git a/docs/core/event_handler/api_gateway.md b/docs/core/event_handler/api_gateway.md index 4f984ecea6f..cfc6f4125d2 100644 --- a/docs/core/event_handler/api_gateway.md +++ b/docs/core/event_handler/api_gateway.md @@ -102,7 +102,7 @@ When using Amazon Application Load Balancer (ALB) to front your Lambda functions #### Lambda Function URL -When using [AWS Lambda Function URL](https://docs.aws.amazon.com/lambda/latest/dg/urls-configuration.html), you can use `LambdaFunctionUrlResolver`. +When using [AWS Lambda Function URL](https://docs.aws.amazon.com/lambda/latest/dg/urls-configuration.html){target="_blank"}, you can use `LambdaFunctionUrlResolver`. === "getting_started_lambda_function_url_resolver.py" @@ -253,7 +253,7 @@ When using [Custom Domain API Mappings feature](https://docs.aws.amazon.com/apig **Scenario**: You have a custom domain `api.mydomain.dev`. Then you set `/payment` API Mapping to forward any payment requests to your Payments API. -**Challenge**: This means your `path` value for any API requests will always contain `/payment/`, leading to HTTP 404 as Event Handler is trying to match what's after `payment/`. This gets further complicated with an [arbitrary level of nesting](https://github.com/awslabs/aws-lambda-powertools-roadmap/issues/34). +**Challenge**: This means your `path` value for any API requests will always contain `/payment/`, leading to HTTP 404 as Event Handler is trying to match what's after `payment/`. This gets further complicated with an [arbitrary level of nesting](https://github.com/awslabs/aws-lambda-powertools-roadmap/issues/34){target="_blank"}. To address this API Gateway behavior, we use `strip_prefixes` parameter to account for these prefixes that are now injected into the path regardless of which type of API Gateway you're using. @@ -344,7 +344,7 @@ You can use the `Response` class to have full control over the response. For exa Some event sources require headers and cookies to be encoded as `multiValueHeaders`. ???+ warning "Using multiple values for HTTP headers in ALB?" - Make sure you [enable the multi value headers feature](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#multi-value-headers) to serialize response headers correctly. + Make sure you [enable the multi value headers feature](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#multi-value-headers){target="_blank"} to serialize response headers correctly. === "fine_grained_responses.py" @@ -420,7 +420,7 @@ Like `compress` feature, the client must send the `Accept` header with the corre ### Debug mode -You can enable debug mode via `debug` param, or via `POWERTOOLS_DEV` [environment variable](../../index.md#environment-variables). +You can enable debug mode via `debug` param, or via `POWERTOOLS_DEV` [environment variable](../../index.md#environment-variables){target="_blank"}. This will enable full tracebacks errors in the response, print request and responses, and set CORS in development mode. diff --git a/docs/core/logger.md b/docs/core/logger.md index 305a7cef0f3..16f81e8b2ba 100644 --- a/docs/core/logger.md +++ b/docs/core/logger.md @@ -108,7 +108,7 @@ You can set a Correlation ID using `correlation_id_path` param by passing a [JME #### set_correlation_id method -You can also use `set_correlation_id` method to inject it anywhere else in your code. Example below uses [Event Source Data Classes utility](../utilities/data_classes.md) to easily access events properties. +You can also use `set_correlation_id` method to inject it anywhere else in your code. Example below uses [Event Source Data Classes utility](../utilities/data_classes.md){target="_blank"} to easily access events properties. === "set_correlation_id_method.py" @@ -242,7 +242,7 @@ You can remove any additional key from Logger state using `remove_keys`. #### Clearing all state -Logger is commonly initialized in the global scope. Due to [Lambda Execution Context reuse](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html), this means that custom keys can be persisted across invocations. If you want all custom keys to be deleted, you can use `clear_state=True` param in `inject_lambda_context` decorator. +Logger is commonly initialized in the global scope. Due to [Lambda Execution Context reuse](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html){target="_blank"}, this means that custom keys can be persisted across invocations. If you want all custom keys to be deleted, you can use `clear_state=True` param in `inject_lambda_context` decorator. ???+ tip "Tip: When is this useful?" It is useful when you add multiple custom keys conditionally, instead of setting a default `None` value if not present. Any key with `None` value is automatically removed by Logger. @@ -360,7 +360,7 @@ You can use any of the following built-in JMESPath expressions as part of [injec ### Reusing Logger across your code -Similar to [Tracer](./tracer.md#reusing-tracer-across-your-code), a new instance that uses the same `service` name - env var or explicit parameter - will reuse a previous Logger instance. Just like `logging.getLogger("logger_name")` would in the standard library if called with the same logger name. +Similar to [Tracer](./tracer.md#reusing-tracer-across-your-code){target="_blank"}, a new instance that uses the same `service` name - env var or explicit parameter - will reuse a previous Logger instance. Just like `logging.getLogger("logger_name")` would in the standard library if called with the same logger name. Notice in the CloudWatch Logs output how `payment_id` appeared as expected when logging in `collect.py`. @@ -407,7 +407,7 @@ You can use values ranging from `0.0` to `1` (100%) when setting `POWERTOOLS_LOG Sampling decision happens at the Logger initialization. This means sampling may happen significantly more or less than depending on your traffic patterns, for example a steady low number of invocations and thus few cold starts. ???+ note - Open a [feature request](https://github.com/awslabs/aws-lambda-powertools-python/issues/new?assignees=&labels=feature-request%2C+triage&template=feature_request.md&title=) if you want Logger to calculate sampling for every invocation + Open a [feature request](https://github.com/awslabs/aws-lambda-powertools-python/issues/new?assignees=&labels=feature-request%2C+triage&template=feature_request.md&title=){target="_blank"} if you want Logger to calculate sampling for every invocation === "sampling_debug_logs.py" @@ -744,4 +744,4 @@ Here's an example where we persist `payment_id` not `request_id`. Note that `pay ### How do I aggregate and search Powertools for AWS Lambda (Python) logs across accounts? -As of now, ElasticSearch (ELK) or 3rd party solutions are best suited to this task. Please refer to this [discussion for more details](https://github.com/awslabs/aws-lambda-powertools-python/issues/460) +As of now, ElasticSearch (ELK) or 3rd party solutions are best suited to this task. Please refer to this [discussion for more details](https://github.com/awslabs/aws-lambda-powertools-python/issues/460){target="_blank"} diff --git a/docs/core/metrics.md b/docs/core/metrics.md index ba9f746e867..6948a3d4c8d 100644 --- a/docs/core/metrics.md +++ b/docs/core/metrics.md @@ -3,9 +3,9 @@ title: Metrics description: Core utility --- -Metrics creates custom metrics asynchronously by logging metrics to standard output following [Amazon CloudWatch Embedded Metric Format (EMF)](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format.html). +Metrics creates custom metrics asynchronously by logging metrics to standard output following [Amazon CloudWatch Embedded Metric Format (EMF)](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format.html){target="_blank"}. -These metrics can be visualized through [Amazon CloudWatch Console](https://console.aws.amazon.com/cloudwatch/). +These metrics can be visualized through [Amazon CloudWatch Console](https://console.aws.amazon.com/cloudwatch/){target="_blank"}. ## Key features @@ -22,7 +22,7 @@ If you're new to Amazon CloudWatch, there are two terminologies you must be awar * **Dimensions**. Metrics metadata in key-value format. They help you slice and dice metrics visualization, for example `ColdStart` metric by Payment `service`. * **Metric**. It's the name of the metric, for example: `SuccessfulBooking` or `UpdatedBooking`. * **Unit**. It's a value representing the unit of measure for the corresponding metric, for example: `Count` or `Seconds`. -* **Resolution**. It's a value representing the storage resolution for the corresponding metric. Metrics can be either Standard or High resolution. Read more [here](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/publishingMetrics.html#high-resolution-metrics). +* **Resolution**. It's a value representing the storage resolution for the corresponding metric. Metrics can be either Standard or High resolution. Read more [here](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/publishingMetrics.html#high-resolution-metrics){target="_blank"}.
@@ -83,7 +83,7 @@ You can create metrics using `add_metric`, and you can create dimensions for all ### Adding high-resolution metrics -You can create [high-resolution metrics](https://aws.amazon.com/about-aws/whats-new/2023/02/amazon-cloudwatch-high-resolution-metric-extraction-structured-logs/) passing `resolution` parameter to `add_metric`. +You can create [high-resolution metrics](https://aws.amazon.com/about-aws/whats-new/2023/02/amazon-cloudwatch-high-resolution-metric-extraction-structured-logs/){target="_blank"} passing `resolution` parameter to `add_metric`. ???+ tip "When is it useful?" High-resolution metrics are data with a granularity of one second and are very useful in several situations such as telemetry, time series, real-time incident management, and others. @@ -154,7 +154,7 @@ This decorator also **validates**, **serializes**, and **flushes** all your metr * Maximum of 29 user-defined dimensions * Namespace is set, and no more than one - * Metric units must be [supported by CloudWatch](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html) + * Metric units must be [supported by CloudWatch](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html){target="_blank"} #### Raising SchemaValidationError on empty metrics @@ -191,7 +191,7 @@ If it's a cold start invocation, this feature will: This has the advantage of keeping cold start metric separate from your application metrics, where you might have unrelated dimensions. ???+ info - We do not emit 0 as a value for ColdStart metric for cost reasons. [Let us know](https://github.com/awslabs/aws-lambda-powertools-python/issues/new?assignees=&labels=feature-request%2C+triage&template=feature_request.md&title=) if you'd prefer a flag to override it. + We do not emit 0 as a value for ColdStart metric for cost reasons. [Let us know](https://github.com/awslabs/aws-lambda-powertools-python/issues/new?assignees=&labels=feature-request%2C+triage&template=feature_request.md&title=){target="_blank"} if you'd prefer a flag to override it. ## Advanced @@ -219,7 +219,7 @@ You can add high-cardinality data as part of your Metrics log with `add_metadata CloudWatch EMF uses the same dimensions across all your metrics. Use `single_metric` if you have a metric that should have different dimensions. ???+ info - Generally, this would be an edge case since you [pay for unique metric](https://aws.amazon.com/cloudwatch/pricing). Keep the following formula in mind: + Generally, this would be an edge case since you [pay for unique metric](https://aws.amazon.com/cloudwatch/pricing){target="_blank"}. Keep the following formula in mind: **unique metric = (metric_name + dimension_name + dimension_value)** @@ -292,7 +292,7 @@ The former creates metrics asynchronously via CloudWatch Logs, and the latter us !!! important "Key concept" CloudWatch [considers a metric unique](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html#Metric){target="_blank"} by a combination of metric **name**, metric **namespace**, and zero or more metric **dimensions**. -With EMF, metric dimensions are shared with any metrics you define. With `PutMetricData` API, you can set a [list](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html) defining one or more metrics with distinct dimensions. +With EMF, metric dimensions are shared with any metrics you define. With `PutMetricData` API, you can set a [list](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html){target="_blank"} defining one or more metrics with distinct dimensions. This is a subtle yet important distinction. Imagine you had the following metrics to emit: @@ -329,7 +329,7 @@ That is why `Metrics` shares data across instances by default, as that covers 80 For example, `Metrics(namespace="ServerlessAirline", service="booking")` -Make sure to set `POWERTOOLS_METRICS_NAMESPACE` and `POWERTOOLS_SERVICE_NAME` before running your tests to prevent failing on `SchemaValidation` exception. You can set it before you run tests or via pytest plugins like [dotenv](https://pypi.org/project/pytest-dotenv/). +Make sure to set `POWERTOOLS_METRICS_NAMESPACE` and `POWERTOOLS_SERVICE_NAME` before running your tests to prevent failing on `SchemaValidation` exception. You can set it before you run tests or via pytest plugins like [dotenv](https://pypi.org/project/pytest-dotenv/){target="_blank"}. ```bash title="Injecting dummy Metric Namespace before running tests" --8<-- "examples/metrics/src/run_tests_env_var.sh" @@ -374,4 +374,4 @@ You can read standard output and assert whether metrics have been flushed. Here' ``` ???+ tip - For more elaborate assertions and comparisons, check out [our functional testing for Metrics utility.](https://github.com/awslabs/aws-lambda-powertools-python/blob/develop/tests/functional/test_metrics.py) + For more elaborate assertions and comparisons, check out [our functional testing for Metrics utility.](https://github.com/awslabs/aws-lambda-powertools-python/blob/develop/tests/functional/test_metrics.py){target="_blank"} diff --git a/docs/core/tracer.md b/docs/core/tracer.md index 0b701928d10..b65a7c0107f 100644 --- a/docs/core/tracer.md +++ b/docs/core/tracer.md @@ -3,7 +3,7 @@ title: Tracer description: Core utility --- -Tracer is an opinionated thin wrapper for [AWS X-Ray Python SDK](https://github.com/aws/aws-xray-sdk-python/). +Tracer is an opinionated thin wrapper for [AWS X-Ray Python SDK](https://github.com/aws/aws-xray-sdk-python/){target="_blank"}. ![Tracer showcase](../media/tracer_utility_showcase.png) @@ -29,7 +29,7 @@ Add `aws-lambda-powertools[tracer]` as a dependency in your preferred tool: _e.g ### Permissions -Before your use this utility, your AWS Lambda function [must have permissions](https://docs.aws.amazon.com/lambda/latest/dg/services-xray.html#services-xray-permissions) to send traces to AWS X-Ray. +Before your use this utility, your AWS Lambda function [must have permissions](https://docs.aws.amazon.com/lambda/latest/dg/services-xray.html#services-xray-permissions){target="_blank"} to send traces to AWS X-Ray. ```yaml hl_lines="9 12" title="AWS Serverless Application Model (SAM) example" --8<-- "examples/tracer/sam/template.yaml" @@ -51,7 +51,7 @@ You can quickly start by initializing `Tracer` and use `capture_lambda_handler` ### Annotations & Metadata -**Annotations** are key-values associated with traces and indexed by AWS X-Ray. You can use them to filter traces and to create [Trace Groups](https://aws.amazon.com/about-aws/whats-new/2018/11/aws-xray-adds-the-ability-to-group-traces/) to slice and dice your transactions. +**Annotations** are key-values associated with traces and indexed by AWS X-Ray. You can use them to filter traces and to create [Trace Groups](https://aws.amazon.com/about-aws/whats-new/2018/11/aws-xray-adds-the-ability-to-group-traces/){target="_blank"} to slice and dice your transactions. ```python hl_lines="8" title="Adding annotations with put_annotation method" --8<-- "examples/tracer/src/put_trace_annotations.py" @@ -107,7 +107,7 @@ You can trace asynchronous functions and generator functions (including context ### Patching modules -Tracer automatically patches all [supported libraries by X-Ray](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-python-patching.html) during initialization, by default. Underneath, AWS X-Ray SDK checks whether a supported library has been imported before patching. +Tracer automatically patches all [supported libraries by X-Ray](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-python-patching.html){target="_blank"} during initialization, by default. Underneath, AWS X-Ray SDK checks whether a supported library has been imported before patching. If you're looking to shave a few microseconds, or milliseconds depending on your function memory configuration, you can patch specific modules using `patch_modules` param: @@ -172,7 +172,7 @@ You can use `aiohttp_trace_config` function to create a valid [aiohttp trace_con You can use `tracer.provider` attribute to access all methods provided by AWS X-Ray `xray_recorder` object. -This is useful when you need a feature available in X-Ray that is not available in the Tracer utility, for example [thread-safe](https://github.com/aws/aws-xray-sdk-python/#user-content-trace-threadpoolexecutor), or [context managers](https://github.com/aws/aws-xray-sdk-python/#user-content-start-a-custom-segmentsubsegment). +This is useful when you need a feature available in X-Ray that is not available in the Tracer utility, for example [thread-safe](https://github.com/aws/aws-xray-sdk-python/#user-content-trace-threadpoolexecutor){target="_blank"}, or [context managers](https://github.com/aws/aws-xray-sdk-python/#user-content-start-a-custom-segmentsubsegment){target="_blank"}. ```python hl_lines="14" title="Tracing a code block with in_subsegment escape hatch" --8<-- "examples/tracer/src/sdk_escape_hatch.py" @@ -181,7 +181,7 @@ This is useful when you need a feature available in X-Ray that is not available ### Concurrent asynchronous functions ???+ warning - [X-Ray SDK will raise an exception](https://github.com/aws/aws-xray-sdk-python/issues/164) when async functions are run and traced concurrently + [X-Ray SDK will raise an exception](https://github.com/aws/aws-xray-sdk-python/issues/164){target="_blank"} when async functions are run and traced concurrently A safe workaround mechanism is to use `in_subsegment_async` available via Tracer escape hatch (`tracer.provider`). @@ -221,4 +221,4 @@ Tracer is disabled by default when not running in the AWS Lambda environment - T * Use annotations on key operations to slice and dice traces, create unique views, and create metrics from it via Trace Groups * Use a namespace when adding metadata to group data more easily -* Annotations and metadata are added to the current subsegment opened. If you want them in a specific subsegment, use a [context manager](https://github.com/aws/aws-xray-sdk-python/#start-a-custom-segmentsubsegment) via the escape hatch mechanism +* Annotations and metadata are added to the current subsegment opened. If you want them in a specific subsegment, use a [context manager](https://github.com/aws/aws-xray-sdk-python/#start-a-custom-segmentsubsegment){target="_blank"} via the escape hatch mechanism diff --git a/docs/index.md b/docs/index.md index a1590aaf564..aa7c1323a94 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,9 +14,9 @@ Powertools for AWS Lambda (Python) is a developer toolkit to implement Serverles You can choose to support us in three ways: - 1) [**Become a reference customer**](https://github.com/awslabs/aws-lambda-powertools-python/issues/new?assignees=&labels=customer-reference&template=support_powertools.yml&title=%5BSupport+Lambda+Powertools%5D%3A+%3Cyour+organization+name%3E). This gives us permission to list your company in our documentation. + 1) [**Become a reference customer**](https://github.com/awslabs/aws-lambda-powertools-python/issues/new?assignees=&labels=customer-reference&template=support_powertools.yml&title=%5BSupport+Lambda+Powertools%5D%3A+%3Cyour+organization+name%3E){target="_blank"}. This gives us permission to list your company in our documentation. - 2) [**Share your work**](https://github.com/awslabs/aws-lambda-powertools-python/issues/new?assignees=&labels=community-content&template=share_your_work.yml&title=%5BI+Made+This%5D%3A+%3CTITLE%3E). Blog posts, video, sample projects you used Powertools! + 2) [**Share your work**](https://github.com/awslabs/aws-lambda-powertools-python/issues/new?assignees=&labels=community-content&template=share_your_work.yml&title=%5BI+Made+This%5D%3A+%3CTITLE%3E){target="_blank"}. Blog posts, video, sample projects you used Powertools! 3) Use [**Lambda Layers**](#lambda-layer) or [**SAR**](#sar), if possible. This helps us understand who uses Powertools for AWS Lambda (Python) in a non-intrusive way, and helps us gain future investments for other Powertools for AWS Lambda languages. @@ -462,8 +462,8 @@ Compared with the [public Layer ARN](#lambda-layer) option, SAR allows you to ch | App | ARN | Description | | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------- | -| [aws-lambda-powertools-python-layer](https://serverlessrepo.aws.amazon.com/applications/eu-west-1/057560766410/aws-lambda-powertools-python-layer) | [arn:aws:serverlessrepo:eu-west-1:057560766410:applications/aws-lambda-powertools-python-layer](#){: .copyMe}:clipboard: | Contains all extra dependencies (e.g: pydantic). | -| [aws-lambda-powertools-python-layer-arm64](https://serverlessrepo.aws.amazon.com/applications/eu-west-1/057560766410/aws-lambda-powertools-python-layer-arm64) | [arn:aws:serverlessrepo:eu-west-1:057560766410:applications/aws-lambda-powertools-python-layer-arm64](#){: .copyMe}:clipboard: | Contains all extra dependencies (e.g: pydantic). For arm64 functions. | +| [aws-lambda-powertools-python-layer](https://serverlessrepo.aws.amazon.com/applications/eu-west-1/057560766410/aws-lambda-powertools-python-layer){target="_blank"} | [arn:aws:serverlessrepo:eu-west-1:057560766410:applications/aws-lambda-powertools-python-layer](#){: .copyMe}:clipboard: | Contains all extra dependencies (e.g: pydantic). | +| [aws-lambda-powertools-python-layer-arm64](https://serverlessrepo.aws.amazon.com/applications/eu-west-1/057560766410/aws-lambda-powertools-python-layer-arm64){target="_blank"} | [arn:aws:serverlessrepo:eu-west-1:057560766410:applications/aws-lambda-powertools-python-layer-arm64](#){: .copyMe}:clipboard: | Contains all extra dependencies (e.g: pydantic). For arm64 functions. | ??? note "Click to expand and copy SAR code snippets for popular frameworks" @@ -547,7 +547,7 @@ Compared with the [public Layer ARN](#lambda-layer) option, SAR allows you to ch === "Terraform" - > Credits to [Dani Comnea](https://github.com/DanyC97) for providing the Terraform equivalent. + > Credits to [Dani Comnea](https://github.com/DanyC97){target="_blank"} for providing the Terraform equivalent. ```terraform hl_lines="12-13 15-20 23-25 40" terraform { @@ -595,7 +595,7 @@ Compared with the [public Layer ARN](#lambda-layer) option, SAR allows you to ch ??? example "Example: Least-privileged IAM permissions to deploy Layer" - > Credits to [mwarkentin](https://github.com/mwarkentin) for providing the scoped down IAM permissions. + > Credits to [mwarkentin](https://github.com/mwarkentin){target="_blank"} for providing the scoped down IAM permissions. The region and the account id for `CloudFormationTransform` and `GetCfnTemplate` are fixed. @@ -679,21 +679,21 @@ Core utilities such as Tracing, Logging, Metrics, and Event Handler will be avai | Utility | Description | | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [**Tracing**](./core/tracer.md) | Decorators and utilities to trace Lambda function handlers, and both synchronous and asynchronous functions | -| [**Logger**](./core/logger.md) | Structured logging made easier, and decorator to enrich structured logging with key Lambda context details | -| [**Metrics**](./core/metrics.md) | Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) | -| [**Event handler: AppSync**](./core/event_handler/appsync.md) | AppSync event handler for Lambda Direct Resolver and Amplify GraphQL Transformer function | +| [**Tracing**](./core/tracer.md){target="_blank"} | Decorators and utilities to trace Lambda function handlers, and both synchronous and asynchronous functions | +| [**Logger**](./core/logger.md){target="_blank"} | Structured logging made easier, and decorator to enrich structured logging with key Lambda context details | +| [**Metrics**](./core/metrics.md){target="_blank"} | Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) | +| [**Event handler: AppSync**](./core/event_handler/appsync.md){target="_blank"} | AppSync event handler for Lambda Direct Resolver and Amplify GraphQL Transformer function | | [**Event handler: API Gateway, ALB and Lambda Function URL**](https://awslabs.github.io/aws-lambda-powertools-python/latest/core/event_handler/api_gateway/) | Amazon API Gateway REST/HTTP API and ALB event handler for Lambda functions invoked using Proxy integration, and Lambda Function URL | -| [**Middleware factory**](./utilities/middleware_factory.md) | Decorator factory to create your own middleware to run logic before, and after each Lambda invocation | -| [**Parameters**](./utilities/parameters.md) | Retrieve parameter values from AWS Systems Manager Parameter Store, AWS Secrets Manager, or Amazon DynamoDB, and cache them for a specific amount of time | -| [**Batch processing**](./utilities/batch.md) | Handle partial failures for AWS SQS batch processing | -| [**Typing**](./utilities/typing.md) | Static typing classes to speedup development in your IDE | -| [**Validation**](./utilities/validation.md) | JSON Schema validator for inbound events and responses | -| [**Event source data classes**](./utilities/data_classes.md) | Data classes describing the schema of common Lambda event triggers | -| [**Parser**](./utilities/parser.md) | Data parsing and deep validation using Pydantic | -| [**Idempotency**](./utilities/idempotency.md) | Idempotent Lambda handler | -| [**Feature Flags**](./utilities/feature_flags.md) | A simple rule engine to evaluate when one or multiple features should be enabled depending on the input | -| [**Streaming**](./utilities/streaming.md) | Streams datasets larger than the available memory as streaming data. | +| [**Middleware factory**](./utilities/middleware_factory.md){target="_blank"} | Decorator factory to create your own middleware to run logic before, and after each Lambda invocation | +| [**Parameters**](./utilities/parameters.md){target="_blank"} | Retrieve parameter values from AWS Systems Manager Parameter Store, AWS Secrets Manager, or Amazon DynamoDB, and cache them for a specific amount of time | +| [**Batch processing**](./utilities/batch.md){target="_blank"} | Handle partial failures for AWS SQS batch processing | +| [**Typing**](./utilities/typing.md){target="_blank"} | Static typing classes to speedup development in your IDE | +| [**Validation**](./utilities/validation.md){target="_blank"} | JSON Schema validator for inbound events and responses | +| [**Event source data classes**](./utilities/data_classes.md){target="_blank"} | Data classes describing the schema of common Lambda event triggers | +| [**Parser**](./utilities/parser.md){target="_blank"} | Data parsing and deep validation using Pydantic | +| [**Idempotency**](./utilities/idempotency.md){target="_blank"} | Idempotent Lambda handler | +| [**Feature Flags**](./utilities/feature_flags.md){target="_blank"} | A simple rule engine to evaluate when one or multiple features should be enabled depending on the input | +| [**Streaming**](./utilities/streaming.md){target="_blank"} | Streams datasets larger than the available memory as streaming data. | ## Environment variables @@ -703,18 +703,18 @@ Core utilities such as Tracing, Logging, Metrics, and Event Handler will be avai | Environment variable | Description | Utility | Default | | ----------------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | --------------------- | | **POWERTOOLS_SERVICE_NAME** | Sets service name used for tracing namespace, metrics dimension and structured logging | All | `"service_undefined"` | -| **POWERTOOLS_METRICS_NAMESPACE** | Sets namespace used for metrics | [Metrics](./core/metrics) | `None` | -| **POWERTOOLS_TRACE_DISABLED** | Explicitly disables tracing | [Tracing](./core/tracer) | `false` | -| **POWERTOOLS_TRACER_CAPTURE_RESPONSE** | Captures Lambda or method return as metadata. | [Tracing](./core/tracer) | `true` | -| **POWERTOOLS_TRACER_CAPTURE_ERROR** | Captures Lambda or method exception as metadata. | [Tracing](./core/tracer) | `true` | -| **POWERTOOLS_TRACE_MIDDLEWARES** | Creates sub-segment for each custom middleware | [Middleware factory](./utilities/middleware_factory) | `false` | -| **POWERTOOLS_LOGGER_LOG_EVENT** | Logs incoming event | [Logging](./core/logger) | `false` | -| **POWERTOOLS_LOGGER_SAMPLE_RATE** | Debug log sampling | [Logging](./core/logger) | `0` | -| **POWERTOOLS_LOG_DEDUPLICATION_DISABLED** | Disables log deduplication filter protection to use Pytest Live Log feature | [Logging](./core/logger) | `false` | -| **POWERTOOLS_PARAMETERS_MAX_AGE** | Adjust how long values are kept in cache (in seconds) | [Parameters](./utilities/parameters/#adjusting-cache-ttl) | `5` | -| **POWERTOOLS_PARAMETERS_SSM_DECRYPT** | Sets whether to decrypt or not values retrieved from AWS SSM Parameters Store | [Parameters](./utilities/parameters/#ssmprovider) | `false` | +| **POWERTOOLS_METRICS_NAMESPACE** | Sets namespace used for metrics | [Metrics](./core/metrics){target="_blank"} | `None` | +| **POWERTOOLS_TRACE_DISABLED** | Explicitly disables tracing | [Tracing](./core/tracer){target="_blank"} | `false` | +| **POWERTOOLS_TRACER_CAPTURE_RESPONSE** | Captures Lambda or method return as metadata. | [Tracing](./core/tracer){target="_blank"} | `true` | +| **POWERTOOLS_TRACER_CAPTURE_ERROR** | Captures Lambda or method exception as metadata. | [Tracing](./core/tracer){target="_blank"} | `true` | +| **POWERTOOLS_TRACE_MIDDLEWARES** | Creates sub-segment for each custom middleware | [Middleware factory](./utilities/middleware_factory){target="_blank"} | `false` | +| **POWERTOOLS_LOGGER_LOG_EVENT** | Logs incoming event | [Logging](./core/logger){target="_blank"} | `false` | +| **POWERTOOLS_LOGGER_SAMPLE_RATE** | Debug log sampling | [Logging](./core/logger){target="_blank"} | `0` | +| **POWERTOOLS_LOG_DEDUPLICATION_DISABLED** | Disables log deduplication filter protection to use Pytest Live Log feature | [Logging](./core/logger){target="_blank"} | `false` | +| **POWERTOOLS_PARAMETERS_MAX_AGE** | Adjust how long values are kept in cache (in seconds) | [Parameters](./utilities/parameters/#adjusting-cache-ttl){target="_blank"} | `5` | +| **POWERTOOLS_PARAMETERS_SSM_DECRYPT** | Sets whether to decrypt or not values retrieved from AWS SSM Parameters Store | [Parameters](./utilities/parameters/#ssmprovider){target="_blank"} | `false` | | **POWERTOOLS_DEV** | Increases verbosity across utilities | Multiple; see [POWERTOOLS_DEV effect below](#increasing-verbosity-across-utilities) | `false` | -| **LOG_LEVEL** | Sets logging level | [Logging](./core/logger) | `INFO` | +| **LOG_LEVEL** | Sets logging level | [Logging](./core/logger){target="_blank"} | `INFO` | ### Optimizing for non-production environments @@ -757,7 +757,7 @@ The following companies, among others, use Powertools: ### Sharing your work -Share what you did with Powertools for AWS Lambda (Python) 💞💞. Blog post, workshops, presentation, sample apps and others. Check out what the community has already shared about Powertools for AWS Lambda (Python) [here](https://awslabs.github.io/aws-lambda-powertools-python/latest/we_made_this/). +Share what you did with Powertools for AWS Lambda (Python) 💞💞. Blog post, workshops, presentation, sample apps and others. Check out what the community has already shared about Powertools for AWS Lambda (Python) [here](https://awslabs.github.io/aws-lambda-powertools-python/latest/we_made_this/){target="_blank"}. ### Using Lambda Layer or SAR diff --git a/docs/roadmap.md b/docs/roadmap.md index bd082bc8ef7..960003e198e 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -20,7 +20,7 @@ Some Lambda Event Sources require clusters (e.g., MSK) leading to additional del ### Observability providers -We want to extend Tracer, Metrics, and Logger to support any [observability provider](https://github.com/awslabs/aws-lambda-powertools-python/issues/1433). We need a RFC to define a contract and to identify two most requested observability providers that we can work with as an initial step. +We want to extend Tracer, Metrics, and Logger to support any [observability provider](https://github.com/awslabs/aws-lambda-powertools-python/issues/1433){target="_blank"}. We need a RFC to define a contract and to identify two most requested observability providers that we can work with as an initial step. ### Lambda Layer in release notes @@ -34,15 +34,15 @@ This means we have room to include a JSON map for Lambda Layers and facilitate a We want to enable MyPy strict mode against the code base. We need a RFC to identify most critical areas to start, and do so gradually as to not impact new features and enhancements in parallel. -This also means bringing `typing-extensions` as a runtime dependency to ensure complete coverage across all Python versions. Future wise, we might be able to experiment with [MyPyC](https://github.com/mypyc/mypyc) to compile less performing parts of the code base as a C-Extension. +This also means bringing `typing-extensions` as a runtime dependency to ensure complete coverage across all Python versions. Future wise, we might be able to experiment with [MyPyC](https://github.com/mypyc/mypyc){target="_blank"} to compile less performing parts of the code base as a C-Extension. ### New utilities - -With V2 launched, we want to resume working on new utilities, specifically but not limited to the most commonly asked: **(1)** [Sensitive Data Masking](https://github.com/awslabs/aws-lambda-powertools-python/issues/1173), **(2)** [Integration/End-to-end Testing](https://github.com/awslabs/aws-lambda-powertools-python/issues/1169), and **(3)** [Event Bridge](https://github.com/awslabs/aws-lambda-powertools-python/issues/1168). + +With V2 launched, we want to resume working on new utilities, specifically but not limited to the most commonly asked: **(1)** [Sensitive Data Masking](https://github.com/awslabs/aws-lambda-powertools-python/issues/1173){target="_blank"}, **(2)** [Integration/End-to-end Testing](https://github.com/awslabs/aws-lambda-powertools-python/issues/1169){target="_blank"}, and **(3)** [Event Bridge](https://github.com/awslabs/aws-lambda-powertools-python/issues/1168){target="_blank"}. ### Open iteration planning -We want to experiment running a bi-weekly audio channel on [Discord](https://discord.gg/B8zZKbbyET) to help us prioritize backlog in real-time. Depending on attendance, we might switch to run an office hours instead. +We want to experiment running a bi-weekly audio channel on [Discord](https://discord.gg/B8zZKbbyET){target="_blank"} to help us prioritize backlog in real-time. Depending on attendance, we might switch to run an office hours instead. ## Roadmap status definition @@ -89,7 +89,7 @@ Our end-to-end mechanism follows four major steps: * **Decision**. After carefully reviewing and discussing them, maintainers make a final decision on whether to start implementation, defer or reject it, and update everyone with the next steps. * **Implementation**. For approved features, maintainers give priority to the original authors for implementation unless it is a sensitive task that is best handled by maintainers. -???+ info "See [Maintainers](https://github.com/awslabs/aws-lambda-powertools-python/blob/develop/MAINTAINERS.md) document to understand how we triage issues and pull requests, labels and governance." +???+ info "See [Maintainers](https://github.com/awslabs/aws-lambda-powertools-python/blob/develop/MAINTAINERS.md){target="_blank"} document to understand how we triage issues and pull requests, labels and governance." ## Disclaimer diff --git a/docs/tutorial/index.md b/docs/tutorial/index.md index 29ec6ebadd2..c02f9cd93e9 100644 --- a/docs/tutorial/index.md +++ b/docs/tutorial/index.md @@ -111,7 +111,7 @@ As a result, a local API endpoint will be exposed and you can invoke it using yo ``` ???+ info - To learn more about local testing, please visit the [AWS SAM CLI local testing](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-local-start-api.html) documentation. + To learn more about local testing, please visit the [AWS SAM CLI local testing](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-local-start-api.html){target="_blank"} documentation. #### Live test @@ -147,7 +147,7 @@ At the end of the deployment, you will find the API endpoint URL within `Outputs ``` ???+ Info - For more details on AWS SAM deployment mechanism, see [SAM Deploy reference docs](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-deploy.html). + For more details on AWS SAM deployment mechanism, see [SAM Deploy reference docs](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-deploy.html){target="_blank"}. ## Routing @@ -364,13 +364,13 @@ Lastly, we used `return app.resolve(event, context)` so Event Handler can resolv From here, we could handle [404 routes](../core/event_handler/api_gateway.md#handling-not-found-routes){target="_blank"}, [error handling](../core/event_handler/api_gateway.md#exception-handling){target="_blank"}, [access query strings, payload](../core/event_handler/api_gateway.md#accessing-request-details){target="_blank"}, etc. ???+ tip - If you'd like to learn how python decorators work under the hood, you can follow [Real Python](https://realpython.com/primer-on-python-decorators/)'s article. + If you'd like to learn how python decorators work under the hood, you can follow [Real Python](https://realpython.com/primer-on-python-decorators/){target="_blank"}'s article. ## Structured Logging Over time, you realize that searching logs as text results in poor observability, it's hard to create metrics from, enumerate common exceptions, etc. -Then, you decided to propose production quality logging capabilities to your Lambda code. You found out that by having logs as `JSON` you can [structure them](https://docs.aws.amazon.com/lambda/latest/operatorguide/parse-logs.html), so that you can use any Log Analytics tool out there to quickly analyze them. +Then, you decided to propose production quality logging capabilities to your Lambda code. You found out that by having logs as `JSON` you can [structure them](https://docs.aws.amazon.com/lambda/latest/operatorguide/parse-logs.html){target="_blank"}, so that you can use any Log Analytics tool out there to quickly analyze them. This helps not only in searching, but produces consistent logs containing enough context and data to ask arbitrary questions on the status of your system. We can take advantage of CloudWatch Logs and Cloudwatch Insight for this purpose. @@ -487,7 +487,7 @@ Let's break this down: * **L5**: We add Powertools for AWS Lambda (Python) Logger; the boilerplate is now done for you. By default, we set `INFO` as the logging level if `LOG_LEVEL` env var isn't set. * **L22**: We use `logger.inject_lambda_context` decorator to inject key information from Lambda context into every log. -* **L22**: We also instruct Logger to use the incoming API Gateway Request ID as a [correlation id](../core/logger.md##set_correlation_id-method) automatically. +* **L22**: We also instruct Logger to use the incoming API Gateway Request ID as a [correlation id](../core/logger.md##set_correlation_id-method){target="_blank"} automatically. * **L22**: Since we're in dev, we also use `log_event=True` to automatically log each incoming request for debugging. This can be also set via [environment variables](./index.md#environment-variables){target="_blank"}. This is how the logs would look like now: @@ -709,7 +709,7 @@ Let's break it down: * **L45**: We include the final response under `response` key as part of the `handler` subsegment. ???+ info - If you want to understand how the Lambda execution environment (sandbox) works and why cold starts can occur, see this [blog series on Lambda performance](https://aws.amazon.com/blogs/compute/operating-lambda-performance-optimization-part-1/). + If you want to understand how the Lambda execution environment (sandbox) works and why cold starts can occur, see this [blog series on Lambda performance](https://aws.amazon.com/blogs/compute/operating-lambda-performance-optimization-part-1/){target="_blank"}. Repeat the process of building, deploying, and invoking your application via the API endpoint. @@ -788,7 +788,7 @@ From here, you can browse to specific logs in CloudWatch Logs Insight, Metrics D ![CloudWatch ServiceLens View](../media/tracer_utility_showcase_3.png) ???+ info - For more information on Amazon CloudWatch ServiceLens, please visit [link](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/ServiceLens.html). + For more information on Amazon CloudWatch ServiceLens, please visit [link](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/ServiceLens.html){target="_blank"}. ## Custom Metrics @@ -796,7 +796,7 @@ From here, you can browse to specific logs in CloudWatch Logs Insight, Metrics D Let's add custom metrics to better understand our application and business behavior (e.g. number of reservations, etc.). -By default, AWS Lambda adds [invocation and performance metrics](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-metrics.html#monitoring-metrics-types){target="_blank"}, and Amazon API Gateway adds [latency and some HTTP metrics](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-metrics-and-dimensions.html#api-gateway-metrics). +By default, AWS Lambda adds [invocation and performance metrics](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-metrics.html#monitoring-metrics-types){target="_blank"}, and Amazon API Gateway adds [latency and some HTTP metrics](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-metrics-and-dimensions.html#api-gateway-metrics){target="_blank"}. ???+ tip You can [optionally enable detailed metrics](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-metrics-and-dimensions.html#api-gateway-metricdimensions){target="_blank"} per each API route, stage, and method in API Gateway. @@ -936,7 +936,7 @@ Within `template.yaml`, we add [CloudWatchPutMetricPolicy](https://docs.aws.amaz ### Simplifying with Metrics -[Powertools for AWS Lambda (Python) Metrics](../core/metrics.md){target="_blank} uses [Amazon CloudWatch Embedded Metric Format (EMF)](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format.html) to create custom metrics **asynchronously** via a native integration with Lambda. +[Powertools for AWS Lambda (Python) Metrics](../core/metrics.md){target="_blank} uses [Amazon CloudWatch Embedded Metric Format (EMF)](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format.html){target="_blank"} to create custom metrics **asynchronously** via a native integration with Lambda. In general terms, EMF is a specification that expects metrics in a JSON payload within CloudWatch Logs. Lambda ingests all logs emitted by a given function into CloudWatch Logs. CloudWatch automatically looks up for log entries that follow the EMF format and transforms them into a CloudWatch metric. @@ -1041,7 +1041,7 @@ When it comes to the observability features ([Tracer](../core/tracer.md){target= This requires a change in mindset to ensure operational excellence is part of the software development lifecycle. ???+ tip - You can find more details on other leading practices described in the [Well-Architected Serverless Lens](https://aws.amazon.com/blogs/aws/new-serverless-lens-in-aws-well-architected-tool/). + You can find more details on other leading practices described in the [Well-Architected Serverless Lens](https://aws.amazon.com/blogs/aws/new-serverless-lens-in-aws-well-architected-tool/){target="_blank"}. Powertools for AWS Lambda (Python) is largely designed to make some of these practices easier to adopt from day 1. diff --git a/docs/upgrade.md b/docs/upgrade.md index 097c2d35b2a..fb7aef94712 100644 --- a/docs/upgrade.md +++ b/docs/upgrade.md @@ -9,7 +9,7 @@ description: Guide to update between major Powertools for AWS Lambda (Python) ve !!! warning "On March 31st, 2023, Powertools for AWS Lambda (Python) v1 reached end of support and will no longer receive updates or releases. If you are still using v1, we strongly recommend you to read our upgrade guide and update to the latest version." -Given our commitment to all of our customers using Powertools for AWS Lambda (Python), we will keep [Pypi](https://pypi.org/project/aws-lambda-powertools/) v1 releases and documentation 1.x versions to prevent any disruption. +Given our commitment to all of our customers using Powertools for AWS Lambda (Python), we will keep [Pypi](https://pypi.org/project/aws-lambda-powertools/){target="_blank"} v1 releases and documentation 1.x versions to prevent any disruption. ## Migrate to v2 from v1 diff --git a/docs/utilities/data_classes.md b/docs/utilities/data_classes.md index 04779ccf0f5..cbf8a5e9a6f 100644 --- a/docs/utilities/data_classes.md +++ b/docs/utilities/data_classes.md @@ -538,7 +538,7 @@ decompress and parse json data from the event. return "nothing to be processed" ``` -Alternatively, you can use `extract_cloudwatch_logs_from_record` to seamless integrate with the [Batch utility](./batch.md) for more robust log processing. +Alternatively, you can use `extract_cloudwatch_logs_from_record` to seamless integrate with the [Batch utility](./batch.md){target="_blank"} for more robust log processing. === "app.py" @@ -614,7 +614,7 @@ Data classes and utility functions to help create continuous delivery pipelines ### Cognito User Pool -Cognito User Pools have several [different Lambda trigger sources](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html#cognito-user-identity-pools-working-with-aws-lambda-trigger-sources), all of which map to a different data class, which +Cognito User Pools have several [different Lambda trigger sources](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html#cognito-user-identity-pools-working-with-aws-lambda-trigger-sources){target="_blank"}, all of which map to a different data class, which can be imported from `aws_lambda_powertools.data_classes.cognito_user_pool_event`: | Trigger/Event Source | Data Class | diff --git a/docs/utilities/feature_flags.md b/docs/utilities/feature_flags.md index 79657c436f6..c8a1faf4ab4 100644 --- a/docs/utilities/feature_flags.md +++ b/docs/utilities/feature_flags.md @@ -17,7 +17,7 @@ Feature flags are used to modify behaviour without changing the application's co **Dynamic flags**. Indicates something can have varying states, for example enable a list of premium features for customer X not Y. ???+ tip - You can use [Parameters utility](parameters.md) for static flags while this utility can do both static and dynamic feature flags. + You can use [Parameters utility](parameters.md){target="_blank"} for static flags while this utility can do both static and dynamic feature flags. ???+ warning Be mindful that feature flags can increase the complexity of your application over time; use them sparingly. @@ -453,7 +453,7 @@ These are the available options for further customization. | **max_age** | `5` | Number of seconds to cache feature flags configuration fetched from AWS AppConfig | | **sdk_config** | `None` | [Botocore Config object](https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html){target="_blank"} | | **jmespath_options** | `None` | For advanced use cases when you want to bring your own [JMESPath functions](https://github.com/jmespath/jmespath.py#custom-functions){target="_blank"} | -| **logger** | `logging.Logger` | Logger to use for debug. You can optionally supply an instance of Powertools for AWS Lambda (Python) Logger. | +| **logger** | `logging.Logger` | Logger to use for debug. You can optionally supply an instance of Powertools for AWS Lambda (Python) Logger. | === "appconfig_provider_options.py" @@ -529,5 +529,5 @@ You can unit test your feature flags locally and independently without setting u | Method | When to use | Requires new deployment on changes | Supported services | | --------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ----------------------------------------------------- | | **[Environment variables](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html){target="_blank"}** | Simple configuration that will rarely if ever change, because changing it requires a Lambda function deployment. | Yes | Lambda | -| **[Parameters utility](parameters.md)** | Access to secrets, or fetch parameters in different formats from AWS System Manager Parameter Store or Amazon DynamoDB. | No | Parameter Store, DynamoDB, Secrets Manager, AppConfig | +| **[Parameters utility](parameters.md){target="_blank"}** | Access to secrets, or fetch parameters in different formats from AWS System Manager Parameter Store or Amazon DynamoDB. | No | Parameter Store, DynamoDB, Secrets Manager, AppConfig | | **Feature flags utility** | Rule engine to define when one or multiple features should be enabled depending on the input. | No | AppConfig | diff --git a/docs/utilities/idempotency.md b/docs/utilities/idempotency.md index f43dc68487f..37b34bf9750 100644 --- a/docs/utilities/idempotency.md +++ b/docs/utilities/idempotency.md @@ -75,7 +75,7 @@ If you're not [changing the default configuration for the DynamoDB persistence l | TTL attribute name | `expiration` | This can only be configured after your table is created if you're using AWS Console | ???+ tip "Tip: You can share a single state table for all functions" - You can reuse the same DynamoDB table to store idempotency state. We add `module_name` and [qualified name for classes and functions](https://peps.python.org/pep-3155/) in addition to the idempotency key as a hash key. + You can reuse the same DynamoDB table to store idempotency state. We add `module_name` and [qualified name for classes and functions](https://peps.python.org/pep-3155/){target="_blank"} in addition to the idempotency key as a hash key. ```yaml hl_lines="5-13 21-23" title="AWS Serverless Application Model (SAM) example" Resources: @@ -104,14 +104,14 @@ Resources: ``` ???+ warning "Warning: Large responses with DynamoDB persistence layer" - When using this utility with DynamoDB, your function's responses must be [smaller than 400KB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html#limits-items). + When using this utility with DynamoDB, your function's responses must be [smaller than 400KB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html#limits-items){target="_blank"}. Larger items cannot be written to DynamoDB and will cause exceptions. ???+ info "Info: DynamoDB" Each function invocation will generally make 2 requests to DynamoDB. If the result returned by your Lambda is less than 1kb, you can expect 2 WCUs per invocation. For retried invocations, you will - see 1WCU and 1RCU. Review the [DynamoDB pricing documentation](https://aws.amazon.com/dynamodb/pricing/) to + see 1WCU and 1RCU. Review the [DynamoDB pricing documentation](https://aws.amazon.com/dynamodb/pricing/){target="_blank"} to estimate the cost. ### Idempotent decorator @@ -247,7 +247,7 @@ When using `idempotent_function`, you must tell us which keyword parameter in yo #### Batch integration -You can can easily integrate with [Batch utility](batch.md) via context manager. This ensures that you process each record in an idempotent manner, and guard against a [Lambda timeout](#lambda-timeouts) idempotent situation. +You can can easily integrate with [Batch utility](batch.md){target="_blank"} via context manager. This ensures that you process each record in an idempotent manner, and guard against a [Lambda timeout](#lambda-timeouts) idempotent situation. ???+ "Choosing an unique batch record attribute" In this example, we choose `messageId` as our idempotency key since we know it'll be unique. @@ -339,7 +339,7 @@ Imagine the function executes successfully, but the client never receives the re ???+ tip "Deserializing JSON strings in payloads for increased accuracy." The payload extracted by the `event_key_jmespath` is treated as a string by default. This means there could be differences in whitespace even when the JSON payload itself is identical. - To alter this behaviour, we can use the [JMESPath built-in function](jmespath_functions.md#powertools_json-function) `powertools_json()` to treat the payload as a JSON object (dict) rather than a string. + To alter this behaviour, we can use the [JMESPath built-in function](jmespath_functions.md#powertools_json-function){target="_blank"} `powertools_json()` to treat the payload as a JSON object (dict) rather than a string. === "payment.py" @@ -410,7 +410,7 @@ Imagine the function executes successfully, but the client never receives the re ???+ note This is automatically done when you decorate your Lambda handler with [@idempotent decorator](#idempotent-decorator). -To prevent against extended failed retries when a [Lambda function times out](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-verify-invocation-timeouts/), Powertools for AWS Lambda (Python) calculates and includes the remaining invocation available time as part of the idempotency record. +To prevent against extended failed retries when a [Lambda function times out](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-verify-invocation-timeouts/){target="_blank"}, Powertools for AWS Lambda (Python) calculates and includes the remaining invocation available time as part of the idempotency record. ???+ example If a second invocation happens **after** this timestamp, and the record is marked as `INPROGRESS`, we will execute the invocation again as if it was in the `EXPIRED` state (e.g, `expire_seconds` field elapsed). @@ -698,15 +698,15 @@ When using DynamoDB as a persistence layer, you can alter the attribute names by Idempotent decorator can be further configured with **`IdempotencyConfig`** as seen in the previous example. These are the available options for further configuration -| Parameter | Default | Description | -| ------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| **event_key_jmespath** | `""` | JMESPath expression to extract the idempotency key from the event record using [built-in functions](/utilities/jmespath_functions) | -| **payload_validation_jmespath** | `""` | JMESPath expression to validate whether certain parameters have changed in the event while the event payload | -| **raise_on_no_idempotency_key** | `False` | Raise exception if no idempotency key was found in the request | -| **expires_after_seconds** | 3600 | The number of seconds to wait before a record is expired | -| **use_local_cache** | `False` | Whether to locally cache idempotency results | -| **local_cache_max_items** | 256 | Max number of items to store in local cache | -| **hash_function** | `md5` | Function to use for calculating hashes, as provided by [hashlib](https://docs.python.org/3/library/hashlib.html) in the standard library. | +| Parameter | Default | Description | +| ------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| **event_key_jmespath** | `""` | JMESPath expression to extract the idempotency key from the event record using [built-in functions](/utilities/jmespath_functions){target="_blank"} | +| **payload_validation_jmespath** | `""` | JMESPath expression to validate whether certain parameters have changed in the event while the event payload | +| **raise_on_no_idempotency_key** | `False` | Raise exception if no idempotency key was found in the request | +| **expires_after_seconds** | 3600 | The number of seconds to wait before a record is expired | +| **use_local_cache** | `False` | Whether to locally cache idempotency results | +| **local_cache_max_items** | 256 | Max number of items to store in local cache | +| **hash_function** | `md5` | Function to use for calculating hashes, as provided by [hashlib](https://docs.python.org/3/library/hashlib.html){target="_blank"} in the standard library. | ### Handling concurrent executions with the same payload @@ -912,7 +912,7 @@ This means that we will raise **`IdempotencyKeyError`** if the evaluation of **` ### Customizing boto configuration -The **`boto_config`** and **`boto3_session`** parameters enable you to pass in a custom [botocore config object](https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html) or a custom [boto3 session](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html) when constructing the persistence store. +The **`boto_config`** and **`boto3_session`** parameters enable you to pass in a custom [botocore config object](https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html){target="_blank"} or a custom [boto3 session](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html){target="_blank"} when constructing the persistence store. === "Custom session" @@ -1166,7 +1166,7 @@ The idempotency utility provides several routes to test your code. ### Disabling the idempotency utility When testing your code, you may wish to disable the idempotency logic altogether and focus on testing your business logic. To do this, you can set the environment variable `POWERTOOLS_IDEMPOTENCY_DISABLED` -with a truthy value. If you prefer setting this for specific tests, and are using Pytest, you can use [monkeypatch](https://docs.pytest.org/en/latest/monkeypatch.html) fixture: +with a truthy value. If you prefer setting this for specific tests, and are using Pytest, you can use [monkeypatch](https://docs.pytest.org/en/latest/monkeypatch.html){target="_blank"} fixture: === "tests.py" @@ -1221,7 +1221,7 @@ with a truthy value. If you prefer setting this for specific tests, and are usin ### Testing with DynamoDB Local -To test with [DynamoDB Local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html), you can replace the `DynamoDB client` used by the persistence layer with one you create inside your tests. This allows you to set the endpoint_url. +To test with [DynamoDB Local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html){target="_blank"}, you can replace the `DynamoDB client` used by the persistence layer with one you create inside your tests. This allows you to set the endpoint_url. === "tests.py" @@ -1281,7 +1281,7 @@ To test with [DynamoDB Local](https://docs.aws.amazon.com/amazondynamodb/latest/ ### How do I mock all DynamoDB I/O operations -The idempotency utility lazily creates the dynamodb [Table](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table) which it uses to access DynamoDB. +The idempotency utility lazily creates the dynamodb [Table](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table){target="_blank"} which it uses to access DynamoDB. This means it is possible to pass a mocked Table resource, or stub various methods. === "tests.py" @@ -1341,4 +1341,4 @@ This means it is possible to pass a mocked Table resource, or stub various metho ## Extra resources If you're interested in a deep dive on how Amazon uses idempotency when building our APIs, check out -[this article](https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/). +[this article](https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/){target="_blank"}. diff --git a/docs/utilities/jmespath_functions.md b/docs/utilities/jmespath_functions.md index 5550cdc507e..9313c702d6f 100644 --- a/docs/utilities/jmespath_functions.md +++ b/docs/utilities/jmespath_functions.md @@ -23,7 +23,7 @@ Built-in [JMESPath](https://jmespath.org/){target="_blank"} Functions to easily You might have events that contains encoded JSON payloads as string, base64, or even in compressed format. It is a common use case to decode and extract them partially or fully as part of your Lambda function invocation. -Powertools for AWS Lambda (Python) also have utilities like [validation](validation.md), [idempotency](idempotency.md), or [feature flags](feature_flags.md) where you might need to extract a portion of your data before using them. +Powertools for AWS Lambda (Python) also have utilities like [validation](validation.md){target="_blank"}, [idempotency](idempotency.md){target="_blank"}, or [feature flags](feature_flags.md){target="_blank"} where you might need to extract a portion of your data before using them. ???+ info "Terminology" **Envelope** is the terminology we use for the **JMESPath expression** to extract your JSON object from your data input. We might use those two terms interchangeably. @@ -81,7 +81,7 @@ These are all built-in envelopes you can use along with their expression as a re | **`SQS`** | `Records[*].powertools_json(body)` | ???+ tip "Using SNS?" - If you don't require SNS metadata, enable [raw message delivery](https://docs.aws.amazon.com/sns/latest/dg/sns-large-payload-raw-message-delivery.html){target="_blank"}. It will reduce multiple payload layers and size, when using SNS in combination with other services (_e.g., SQS, S3, etc_). + If you don't require SNS metadata, enable [raw message delivery](https://docs.aws.amazon.com/sns/latest/dg/sns-large-payload-raw-message-delivery.html). It will reduce multiple payload layers and size, when using SNS in combination with other services (_e.g., SQS, S3, etc_). ## Advanced diff --git a/docs/utilities/middleware_factory.md b/docs/utilities/middleware_factory.md index 1552311ea17..e855a3f451c 100644 --- a/docs/utilities/middleware_factory.md +++ b/docs/utilities/middleware_factory.md @@ -70,7 +70,7 @@ You can also have your own keyword arguments after the mandatory arguments. ## Advanced -For advanced use cases, you can instantiate [Tracer](../core/tracer.md) inside your middleware, and add annotations as well as metadata for additional operational insights. +For advanced use cases, you can instantiate [Tracer](../core/tracer.md){target="_blank"} inside your middleware, and add annotations as well as metadata for additional operational insights. === "advanced_middleware_tracer_function.py" ```python hl_lines="7 9 12 16 17 19 25 42" @@ -87,12 +87,12 @@ For advanced use cases, you can instantiate [Tracer](../core/tracer.md) inside y ### Tracing middleware **execution** -If you are making use of [Tracer](../core/tracer.md), you can trace the execution of your middleware to ease operations. +If you are making use of [Tracer](../core/tracer.md){target="_blank"}, you can trace the execution of your middleware to ease operations. This makes use of an existing Tracer instance that you may have initialized anywhere in your code. ???+ warning - You must [enable Active Tracing](../core/tracer/#permissions) in your Lambda function when using this feature, otherwise Lambda cannot send traces to XRay. + You must [enable Active Tracing](../core/tracer/#permissions){target="_blank"} in your Lambda function when using this feature, otherwise Lambda cannot send traces to XRay. === "getting_started_middleware_tracer_function.py" ```python hl_lines="8 14 15 36" @@ -105,13 +105,14 @@ This makes use of an existing Tracer instance that you may have initialized anyw --8<-- "examples/middleware_factory/src/getting_started_middleware_tracer_payload.json" ``` -When executed, your middleware name will [appear in AWS X-Ray Trace details as](../core/tracer.md) `## middleware_name`, in this example the middleware name is `## middleware_with_tracing`. +When executed, your middleware name will [appear in AWS X-Ray Trace details as](../core/tracer.md){target="_blank"} `## middleware_name`, in this example the middleware name is `## middleware_with_tracing`. ![Middleware simple Tracer](../media/middleware_factory_tracer_1.png) ### Combining Powertools for AWS Lambda (Python) utilities -You can create your own middleware and combine many features of Powertools for AWS Lambda (Python) such as [trace](../core/logger.md), [logs](../core/logger.md), [feature flags](feature_flags.md), [validation](validation.md), [jmespath_functions](jmespath_functions.md) and others to abstract non-functional code. + +You can create your own middleware and combine many features of Powertools for AWS Lambda (Python) such as [trace](../core/logger.md){target="_blank"}, [logs](../core/logger.md){target="_blank"}, [feature flags](feature_flags.md){target="_blank"}, [validation](validation.md){target="_blank"}, [jmespath_functions](jmespath_functions.md){target="_blank"} and others to abstract non-functional code. In the example below, we create a Middleware with the following features: diff --git a/docs/utilities/parameters.md b/docs/utilities/parameters.md index 7c77a976983..a7fe0278511 100644 --- a/docs/utilities/parameters.md +++ b/docs/utilities/parameters.md @@ -296,7 +296,7 @@ You can create your own custom parameter store provider by inheriting the `BaseP All transformation and caching logic is handled by the `get()` and `get_multiple()` methods from the base provider class. -Here are two examples of implementing a custom parameter store. One using an external service like [Hashicorp Vault](https://www.vaultproject.io/), a widely popular key-value and secret storage and the other one using [Amazon S3](https://aws.amazon.com/s3/?nc1=h_ls), a popular object storage. +Here are two examples of implementing a custom parameter store. One using an external service like [Hashicorp Vault](https://www.vaultproject.io/){target="_blank"}, a widely popular key-value and secret storage and the other one using [Amazon S3](https://aws.amazon.com/s3/?nc1=h_ls){target="_blank"}, a popular object storage. === "working_with_own_provider_vault.py" ```python hl_lines="5 13 20 24" @@ -391,15 +391,15 @@ Here is the mapping between this utility's functions and methods and the underly | Provider | Function/Method | Client name | Function name | | ------------------- | ------------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| SSM Parameter Store | `get_parameter` | `ssm` | [get_parameter](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameter) | -| SSM Parameter Store | `get_parameters` | `ssm` | [get_parameters_by_path](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameters_by_path) | -| SSM Parameter Store | `SSMProvider.get` | `ssm` | [get_parameter](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameter) | -| SSM Parameter Store | `SSMProvider.get_multiple` | `ssm` | [get_parameters_by_path](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameters_by_path) | -| Secrets Manager | `get_secret` | `secretsmanager` | [get_secret_value](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.get_secret_value) | -| Secrets Manager | `SecretsProvider.get` | `secretsmanager` | [get_secret_value](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.get_secret_value) | -| DynamoDB | `DynamoDBProvider.get` | `dynamodb` | ([Table resource](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table)) | [get_item](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.get_item) | -| DynamoDB | `DynamoDBProvider.get_multiple` | `dynamodb` | ([Table resource](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table)) | [query](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.query) | -| App Config | `get_app_config` | `appconfigdata` | [start_configuration_session](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/appconfigdata.html#AppConfigData.Client.start_configuration_session) and [get_latest_configuration](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/appconfigdata.html#AppConfigData.Client.get_latest_configuration) | +| SSM Parameter Store | `get_parameter` | `ssm` | [get_parameter](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameter){target="_blank"} | +| SSM Parameter Store | `get_parameters` | `ssm` | [get_parameters_by_path](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameters_by_path){target="_blank"} | +| SSM Parameter Store | `SSMProvider.get` | `ssm` | [get_parameter](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameter){target="_blank"} | +| SSM Parameter Store | `SSMProvider.get_multiple` | `ssm` | [get_parameters_by_path](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameters_by_path){target="_blank"} | +| Secrets Manager | `get_secret` | `secretsmanager` | [get_secret_value](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.get_secret_value){target="_blank"} | +| Secrets Manager | `SecretsProvider.get` | `secretsmanager` | [get_secret_value](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.get_secret_value){target="_blank"} | +| DynamoDB | `DynamoDBProvider.get` | `dynamodb` | ([Table resource](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table){target="_blank"}) | [get_item](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.get_item) | +| DynamoDB | `DynamoDBProvider.get_multiple` | `dynamodb` | ([Table resource](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table){target="_blank"}) | [query](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.query) | +| App Config | `get_app_config` | `appconfigdata` | [start_configuration_session](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/appconfigdata.html#AppConfigData.Client.start_configuration_session){target="_blank"} and [get_latest_configuration](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/appconfigdata.html#AppConfigData.Client.get_latest_configuration){target="_blank"} | ### Bring your own boto client @@ -424,7 +424,7 @@ Bringing them together in a single code snippet would look like this: ### Customizing boto configuration -The **`config`** , **`boto3_session`**, and **`boto3_client`** parameters enable you to pass in a custom [botocore config object](https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html) , [boto3 session](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html), or a [boto3 client](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/boto3.html) when constructing any of the built-in provider classes. +The **`config`** , **`boto3_session`**, and **`boto3_client`** parameters enable you to pass in a custom [botocore config object](https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html){target="_blank"}, [boto3 session](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html){target="_blank"}, or a [boto3 client](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/boto3.html){target="_blank"} when constructing any of the built-in provider classes. ???+ tip You can use a custom session for retrieving parameters cross-account/region and for snapshot testing. @@ -450,7 +450,7 @@ The **`config`** , **`boto3_session`**, and **`boto3_client`** parameters enabl ### Mocking parameter values -For unit testing your applications, you can mock the calls to the parameters utility to avoid calling AWS APIs. This can be achieved in a number of ways - in this example, we use the [pytest monkeypatch fixture](https://docs.pytest.org/en/latest/how-to/monkeypatch.html) to patch the `parameters.get_parameter` method: +For unit testing your applications, you can mock the calls to the parameters utility to avoid calling AWS APIs. This can be achieved in a number of ways - in this example, we use the [pytest monkeypatch fixture](https://docs.pytest.org/en/latest/how-to/monkeypatch.html){target="_blank"} to patch the `parameters.get_parameter` method: === "test_single_mock.py" ```python hl_lines="4 8" @@ -470,8 +470,8 @@ If we need to use this pattern across multiple tests, we can avoid repetition by ``` Alternatively, if we need more fully featured mocking (for example checking the arguments passed to `get_parameter`), we -can use [unittest.mock](https://docs.python.org/3/library/unittest.mock.html) from the python stdlib instead of pytest's `monkeypatch` fixture. In this example, we use the -[patch](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch) decorator to replace the `aws_lambda_powertools.utilities.parameters.get_parameter` function with a [MagicMock](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock) +can use [unittest.mock](https://docs.python.org/3/library/unittest.mock.html){target="_blank"} from the python stdlib instead of pytest's `monkeypatch` fixture. In this example, we use the +[patch](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch){target="_blank"} decorator to replace the `aws_lambda_powertools.utilities.parameters.get_parameter` function with a [MagicMock](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock){target="_blank"} object named `get_parameter_mock`. === "test_with_monkeypatch.py" diff --git a/docs/utilities/parser.md b/docs/utilities/parser.md index 5ff419f8777..b0852a0129f 100644 --- a/docs/utilities/parser.md +++ b/docs/utilities/parser.md @@ -4,7 +4,7 @@ description: Utility --- -This utility provides data parsing and deep validation using [Pydantic](https://pydantic-docs.helpmanual.io/). +This utility provides data parsing and deep validation using [Pydantic](https://pydantic-docs.helpmanual.io/){target="_blank"}. ## Key features @@ -24,7 +24,7 @@ Add `aws-lambda-powertools[parser]` as a dependency in your preferred tool: _e.g This will increase the compressed package size by >10MB due to the Pydantic dependency. To reduce the impact on the package size at the expense of 30%-50% of its performance [Pydantic can also be - installed without binary files](https://pydantic-docs.helpmanual.io/install/#performance-vs-package-size-trade-off): + installed without binary files](https://pydantic-docs.helpmanual.io/install/#performance-vs-package-size-trade-off){target="_blank"}: Pip example: `SKIP_CYTHON=1 pip install --no-binary pydantic aws-lambda-powertools[parser]` @@ -245,13 +245,13 @@ for order_item in ret.detail.items: ???+ tip When extending a `string` field containing JSON, you need to wrap the field - with [Pydantic's Json Type](https://pydantic-docs.helpmanual.io/usage/types/#json-type): + with [Pydantic's Json Type](https://pydantic-docs.helpmanual.io/usage/types/#json-type){target="_blank"}: ```python hl_lines="14 18-19" --8<-- "examples/parser/src/extending_built_in_models_with_json_mypy.py" ``` - Alternatively, you could use a [Pydantic validator](https://pydantic-docs.helpmanual.io/usage/validators/) to transform the JSON string into a dict before the mapping: + Alternatively, you could use a [Pydantic validator](https://pydantic-docs.helpmanual.io/usage/validators/){target="_blank"} to transform the JSON string into a dict before the mapping: ```python hl_lines="18-20 24-25" --8<-- "examples/parser/src/extending_built_in_models_with_json_validator.py" @@ -495,14 +495,14 @@ parse(model=UserModel, event=payload) ### Advanced use cases ???+ tip "Tip: Looking to auto-generate models from JSON, YAML, JSON Schemas, OpenApi, etc?" - Use Koudai Aono's [data model code generation tool for Pydantic](https://github.com/koxudaxi/datamodel-code-generator) + Use Koudai Aono's [data model code generation tool for Pydantic](https://github.com/koxudaxi/datamodel-code-generator){target="_blank"} -There are number of advanced use cases well documented in Pydantic's doc such as creating [immutable models](https://pydantic-docs.helpmanual.io/usage/models/#faux-immutability), [declaring fields with dynamic values](https://pydantic-docs.helpmanual.io/usage/models/#field-with-dynamic-default-value). +There are number of advanced use cases well documented in Pydantic's doc such as creating [immutable models](https://pydantic-docs.helpmanual.io/usage/models/#faux-immutability){target="_blank"}, [declaring fields with dynamic values](https://pydantic-docs.helpmanual.io/usage/models/#field-with-dynamic-default-value){target="_blank"}. ???+ tip "Pydantic helper functions" - Pydantic also offers [functions](https://pydantic-docs.helpmanual.io/usage/models/#helper-functions) to parse models from files, dicts, string, etc. + Pydantic also offers [functions](https://pydantic-docs.helpmanual.io/usage/models/#helper-functions){target="_blank"} to parse models from files, dicts, string, etc. -Two possible unknown use cases are Models and exception' serialization. Models have methods to [export them](https://pydantic-docs.helpmanual.io/usage/exporting_models/) as `dict`, `JSON`, `JSON Schema`, and Validation exceptions can be exported as JSON. +Two possible unknown use cases are Models and exception' serialization. Models have methods to [export them](https://pydantic-docs.helpmanual.io/usage/exporting_models/){target="_blank"} as `dict`, `JSON`, `JSON Schema`, and Validation exceptions can be exported as JSON. ```python hl_lines="21 28-31" title="Converting data models in various formats" from aws_lambda_powertools.utilities import Logger diff --git a/docs/utilities/streaming.md b/docs/utilities/streaming.md index ed10d436550..fe4d59f9f94 100644 --- a/docs/utilities/streaming.md +++ b/docs/utilities/streaming.md @@ -85,11 +85,11 @@ That said, you can still open a specific file as a stream, reading only the nece We provide popular built-in transformations that you can apply against your streaming data. -| Name | Description | Class name | -| -------- | ------------------------------------------------------------------------------------------------ | ------------- | -| **Gzip** | Gunzips the stream of data using the [gzip library](https://docs.python.org/3/library/gzip.html) | GzipTransform | -| **Zip** | Exposes the stream as a [ZipFile object](https://docs.python.org/3/library/zipfile.html) | ZipTransform | -| **CSV** | Parses each CSV line as a CSV object, returning dictionary objects | CsvTransform | +| Name | Description | Class name | +| -------- | ----------------------------------------------------------------------------------------------------------------- | ------------- | +| **Gzip** | Gunzips the stream of data using the [gzip library](https://docs.python.org/3/library/gzip.html){target="_blank"} | GzipTransform | +| **Zip** | Exposes the stream as a [ZipFile object](https://docs.python.org/3/library/zipfile.html){target="_blank"} | ZipTransform | +| **CSV** | Parses each CSV line as a CSV object, returning dictionary objects | CsvTransform | ## Advanced @@ -131,11 +131,11 @@ You found out that each row has 8 bytes, the header line has 21 bytes, and every We will propagate additional options to the underlying implementation for each transform class. -| Name | Available options | -| ----------------- | ------------------------------------------------------------------------------------- | -| **GzipTransform** | [GzipFile constructor](https://docs.python.org/3/library/gzip.html#gzip.GzipFile) | -| **ZipTransform** | [ZipFile constructor](https://docs.python.org/3/library/zipfile.html#zipfile.ZipFile) | -| **CsvTransform** | [DictReader constructor](https://docs.python.org/3/library/csv.html#csv.DictReader) | +| Name | Available options | +| ----------------- | ------------------------------------------------------------------------------------------------------ | +| **GzipTransform** | [GzipFile constructor](https://docs.python.org/3/library/gzip.html#gzip.GzipFile){target="_blank"} | +| **ZipTransform** | [ZipFile constructor](https://docs.python.org/3/library/zipfile.html#zipfile.ZipFile){target="_blank"} | +| **CsvTransform** | [DictReader constructor](https://docs.python.org/3/library/csv.html#csv.DictReader){target="_blank"} | For instance, take `ZipTransform`. You can use the `compression` parameter if you want to unzip an S3 object compressed with `LZMA`. @@ -185,6 +185,6 @@ Create an input payload using `io.BytesIO` and assert the response of the transf ### AWS X-Ray segment size limit -We make multiple API calls to S3 as you read chunks from your S3 object. If your function is decorated with [Tracer](./../core/tracer.md), you can easily hit [AWS X-Ray 64K segment size](https://docs.aws.amazon.com/general/latest/gr/xray.html#limits_xray) when processing large files. +We make multiple API calls to S3 as you read chunks from your S3 object. If your function is decorated with [Tracer](./../core/tracer.md){target="_blank"}, you can easily hit [AWS X-Ray 64K segment size](https://docs.aws.amazon.com/general/latest/gr/xray.html#limits_xray){target="_blank"} when processing large files. !!! tip "Use tracer decorators in parts where you don't read your `S3Object` instead." diff --git a/docs/utilities/validation.md b/docs/utilities/validation.md index cef3b1e3134..c9fd08e31cc 100644 --- a/docs/utilities/validation.md +++ b/docs/utilities/validation.md @@ -91,7 +91,7 @@ You can also gracefully handle schema validation errors by catching `SchemaValid You might want to validate only a portion of your event - This is what the `envelope` parameter is for. -Envelopes are [JMESPath expressions](https://jmespath.org/tutorial.html) to extract a portion of JSON you want before applying JSON Schema validation. +Envelopes are [JMESPath expressions](https://jmespath.org/tutorial.html){target="_blank"} to extract a portion of JSON you want before applying JSON Schema validation. Here is a sample custom EventBridge event, where we only validate what's inside the `detail` key: @@ -113,7 +113,7 @@ Here is a sample custom EventBridge event, where we only validate what's inside --8<-- "examples/validation/src/getting_started_validator_unwrapping_payload.json" ``` -This is quite powerful because you can use JMESPath Query language to extract records from [arrays](https://jmespath.org/tutorial.html#list-and-slice-projections), combine [pipe](https://jmespath.org/tutorial.html#pipe-expressions) and [function expressions](https://jmespath.org/tutorial.html#functions). +This is quite powerful because you can use JMESPath Query language to extract records from [arrays](https://jmespath.org/tutorial.html#list-and-slice-projections){target="_blank"}, combine [pipe](https://jmespath.org/tutorial.html#pipe-expressions){target="_blank"} and [function expressions](https://jmespath.org/tutorial.html#functions){target="_blank"}. When combined, these features allow you to extract what you need before validating the actual payload. @@ -194,7 +194,7 @@ For each format defined in a dictionary key, you must use a regex, or a function You might have events or responses that contain non-encoded JSON, where you need to decode before validating them. -You can use our built-in [JMESPath functions](./jmespath_functions.md) within your expressions to do exactly that to [deserialize JSON Strings](./jmespath_functions.md#powertools_json-function), [decode base64](./jmespath_functions.md#powertools_base64-function), and [decompress gzip data](./jmespath_functions.md#powertools_base64_gzip-function). +You can use our built-in [JMESPath functions](./jmespath_functions.md){target="_blank"} within your expressions to do exactly that to [deserialize JSON Strings](./jmespath_functions.md#powertools_json-function){target="_blank"}, [decode base64](./jmespath_functions.md#powertools_base64-function){target="_blank"}, and [decompress gzip data](./jmespath_functions.md#powertools_base64_gzip-function){target="_blank"}. ???+ info We use these for [built-in envelopes](#built-in-envelopes) to easily to decode and unwrap events from sources like Kinesis, CloudWatch Logs, etc. diff --git a/poetry.lock b/poetry.lock index 5b423b983da..8a4cc9242c0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. [[package]] name = "anyio" @@ -3078,7 +3078,7 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [extras] -all = ["pydantic", "aws-xray-sdk", "fastjsonschema"] +all = ["aws-xray-sdk", "fastjsonschema", "pydantic"] aws-sdk = ["boto3"] parser = ["pydantic"] tracer = ["aws-xray-sdk"] From ad6a85b918744d3537bd6a8222f3513a6a24f10f Mon Sep 17 00:00:00 2001 From: Stephen Bawks <5246651+stephenbawks@users.noreply.github.com> Date: Thu, 8 Jun 2023 08:50:16 -0400 Subject: [PATCH 15/41] feat(event_sources): add support for VPC Lattice events (#2358) Co-authored-by: Leandro Damascena Co-authored-by: Heitor Lessa --- .../utilities/data_classes/__init__.py | 2 + .../utilities/data_classes/vpc_lattice.py | 91 +++++++++++++++++++ docs/utilities/data_classes.md | 19 ++++ examples/event_sources/src/vpc_lattice.py | 19 ++++ .../src/vpc_lattice_payload.json | 15 +++ tests/events/vpcLatticeEvent.json | 15 +++ tests/functional/test_data_classes.py | 16 ++++ 7 files changed, 177 insertions(+) create mode 100644 aws_lambda_powertools/utilities/data_classes/vpc_lattice.py create mode 100644 examples/event_sources/src/vpc_lattice.py create mode 100644 examples/event_sources/src/vpc_lattice_payload.json create mode 100644 tests/events/vpcLatticeEvent.json diff --git a/aws_lambda_powertools/utilities/data_classes/__init__.py b/aws_lambda_powertools/utilities/data_classes/__init__.py index 1d268fef7cb..076616b95d2 100644 --- a/aws_lambda_powertools/utilities/data_classes/__init__.py +++ b/aws_lambda_powertools/utilities/data_classes/__init__.py @@ -20,6 +20,7 @@ from .ses_event import SESEvent from .sns_event import SNSEvent from .sqs_event import SQSEvent +from .vpc_lattice import VPCLatticeEvent __all__ = [ "APIGatewayProxyEvent", @@ -42,4 +43,5 @@ "SNSEvent", "SQSEvent", "event_source", + "VPCLatticeEvent", ] diff --git a/aws_lambda_powertools/utilities/data_classes/vpc_lattice.py b/aws_lambda_powertools/utilities/data_classes/vpc_lattice.py new file mode 100644 index 00000000000..4e503daf4ab --- /dev/null +++ b/aws_lambda_powertools/utilities/data_classes/vpc_lattice.py @@ -0,0 +1,91 @@ +import base64 +from typing import Any, Dict, Optional + +from aws_lambda_powertools.utilities.data_classes.common import ( + DictWrapper, + get_header_value, +) + + +class VPCLatticeEvent(DictWrapper): + @property + def body(self) -> str: + """The VPC Lattice body.""" + return self["body"] + + @property + def json_body(self) -> Any: + """Parses the submitted body as json""" + if self._json_data is None: + self._json_data = self._json_deserializer(self.decoded_body) + return self._json_data + + @property + def headers(self) -> Dict[str, str]: + """The VPC Lattice event headers.""" + return self["headers"] + + @property + def is_base64_encoded(self) -> bool: + """A boolean flag to indicate if the applicable request payload is Base64-encode""" + return self["is_base64_encoded"] + + @property + def decoded_body(self) -> str: + """Dynamically base64 decode body as a str""" + body: str = self["body"] + if self.is_base64_encoded: + return base64.b64decode(body.encode()).decode() + return body + + @property + def method(self) -> str: + """The VPC Lattice method used. Valid values include: DELETE, GET, HEAD, OPTIONS, PATCH, POST, and PUT.""" + return self["method"] + + @property + def query_string_parameters(self) -> Dict[str, str]: + """The request query string parameters.""" + return self["query_string_parameters"] + + @property + def raw_path(self) -> str: + """The raw VPC Lattice request path.""" + return self["raw_path"] + + def get_query_string_value(self, name: str, default_value: Optional[str] = None) -> Optional[str]: + """Get query string value by name + + Parameters + ---------- + name: str + Query string parameter name + default_value: str, optional + Default value if no value was found by name + Returns + ------- + str, optional + Query string parameter value + """ + params = self.query_string_parameters + return default_value if params is None else params.get(name, default_value) + + def get_header_value( + self, name: str, default_value: Optional[str] = None, case_sensitive: Optional[bool] = False + ) -> Optional[str]: + """Get header value by name + + Parameters + ---------- + name: str + Header name + default_value: str, optional + Default value if no value was found by name + case_sensitive: bool + Whether to use a case-sensitive look up + Returns + ------- + str, optional + Header value + """ + return get_header_value(self.headers, name, default_value, case_sensitive) diff --git a/docs/utilities/data_classes.md b/docs/utilities/data_classes.md index cbf8a5e9a6f..64557db6063 100644 --- a/docs/utilities/data_classes.md +++ b/docs/utilities/data_classes.md @@ -102,6 +102,7 @@ Log Data Event for Troubleshooting | [SES](#ses) | `SESEvent` | | [SNS](#sns) | `SNSEvent` | | [SQS](#sqs) | `SQSEvent` | +| [VPC Lattice](#vpc-lattice) | `VPCLatticeEvent` | ???+ info The examples provided below are far from exhaustive - the data classes themselves are designed to provide a form of @@ -1121,6 +1122,24 @@ This example is based on the AWS Blog post [Introducing Amazon S3 Object Lambda do_something_with(record.body) ``` +### VPC Lattice + +You can register your Lambda functions as targets within an Amazon VPC Lattice service network. By doing this, your Lambda function becomes a service within the network, and clients that have access to the VPC Lattice service network can call your service. + +[Click here](https://docs.aws.amazon.com/lambda/latest/dg/services-vpc-lattice.html){target="_blank"} for more information about using AWS Lambda with Amazon VPC Lattice. + +=== "app.py" + + ```python hl_lines="2 8" + --8<-- "examples/event_sources/src/vpc_lattice.py" + ``` + +=== "Lattice Example Event" + + ```json + --8<-- "examples/event_sources/src/vpc_lattice_payload.json" + ``` + ## Advanced ### Debugging diff --git a/examples/event_sources/src/vpc_lattice.py b/examples/event_sources/src/vpc_lattice.py new file mode 100644 index 00000000000..93291b5eb76 --- /dev/null +++ b/examples/event_sources/src/vpc_lattice.py @@ -0,0 +1,19 @@ +from aws_lambda_powertools import Logger +from aws_lambda_powertools.utilities.data_classes import VPCLatticeEvent, event_source +from aws_lambda_powertools.utilities.typing import LambdaContext + +logger = Logger() + + +@event_source(data_class=VPCLatticeEvent) +def lambda_handler(event: VPCLatticeEvent, context: LambdaContext): + logger.info(event.body) + + response = { + "isBase64Encoded": False, + "statusCode": 200, + "headers": {"Content-Type": "application/text"}, + "body": "Event Response to VPC Lattice 🔥🚀🔥", + } + + return response diff --git a/examples/event_sources/src/vpc_lattice_payload.json b/examples/event_sources/src/vpc_lattice_payload.json new file mode 100644 index 00000000000..0038592227a --- /dev/null +++ b/examples/event_sources/src/vpc_lattice_payload.json @@ -0,0 +1,15 @@ +{ + "raw_path": "/testpath", + "method": "GET", + "headers": { + "user_agent": "curl/7.64.1", + "x-forwarded-for": "10.213.229.10", + "host": "test-lambda-service-3908sdf9u3u.dkfjd93.vpc-lattice-svcs.us-east-2.on.aws", + "accept": "*/*" + }, + "query_string_parameters": { + "order-id": "1" + }, + "body": "eyJ0ZXN0IjogImV2ZW50In0=", + "is_base64_encoded": true + } diff --git a/tests/events/vpcLatticeEvent.json b/tests/events/vpcLatticeEvent.json new file mode 100644 index 00000000000..936bfb22d1b --- /dev/null +++ b/tests/events/vpcLatticeEvent.json @@ -0,0 +1,15 @@ +{ + "raw_path": "/testpath", + "method": "GET", + "headers": { + "user_agent": "curl/7.64.1", + "x-forwarded-for": "10.213.229.10", + "host": "test-lambda-service-3908sdf9u3u.dkfjd93.vpc-lattice-svcs.us-east-2.on.aws", + "accept": "*/*" + }, + "query_string_parameters": { + "order-id": "1" + }, + "body": "eyJ0ZXN0IjogImV2ZW50In0=", + "is_base64_encoded": true +} diff --git a/tests/functional/test_data_classes.py b/tests/functional/test_data_classes.py index b3a24b0865a..23f4b18e53d 100644 --- a/tests/functional/test_data_classes.py +++ b/tests/functional/test_data_classes.py @@ -25,6 +25,7 @@ SESEvent, SNSEvent, SQSEvent, + VPCLatticeEvent, ) from aws_lambda_powertools.utilities.data_classes.api_gateway_authorizer_event import ( APIGatewayAuthorizerEventV2, @@ -2041,3 +2042,18 @@ def test_api_gateway_route_arn_parser(): details = parse_api_gateway_arn(arn) assert details.resource == "" assert details.arn == arn + "/" + + +def test_vpc_lattice_event(): + event = VPCLatticeEvent(load_event("vpcLatticeEvent.json")) + + assert event.raw_path == event["raw_path"] + assert event.get_query_string_value("order-id") == "1" + assert event.get_header_value("user_agent") == "curl/7.64.1" + assert event.decoded_body == '{"test": "event"}' + assert event.json_body == {"test": "event"} + assert event.method == event["method"] + assert event.headers == event["headers"] + assert event.query_string_parameters == event["query_string_parameters"] + assert event.body == event["body"] + assert event.is_base64_encoded == event["is_base64_encoded"] From a9c965a0214c995ec28879970234ce848204d709 Mon Sep 17 00:00:00 2001 From: Heitor Lessa Date: Fri, 9 Jun 2023 10:48:29 +0200 Subject: [PATCH 16/41] docs(we-made-this): new article about idempotency design (#2425) --- docs/we_made_this.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/we_made_this.md b/docs/we_made_this.md index f160b30e39c..13dff74a7c7 100644 --- a/docs/we_made_this.md +++ b/docs/we_made_this.md @@ -76,6 +76,14 @@ This article walks through how CyberArk uses Powertools to implement Feature Fla * [aws.amazon.com/blogs/mt/how-cyberark-implements-feature-flags-with-aws-appconfig](https://aws.amazon.com/blogs/mt/how-cyberark-implements-feature-flags-with-aws-appconfig){target="_blank"} +### Designing for Idempotency + +> **Author: [Valentin Dreismann](linkedin.com/in/valentin-dreismann-69694b16a){target="_blank"}** :material-linkedin: + +This article outlines the importance of idempotency, key considerations and trade-offs when implementing in your systems. + +* [Idempotency the right way](https://engineering.cloudflight.io/idempotency-the-right-way){target="_blank"} + ## Videos #### Building a resilient input handling with Parser From 9a45a01fd9f0d9e317a93de81a03600ee62a53e0 Mon Sep 17 00:00:00 2001 From: Heitor Lessa Date: Fri, 9 Jun 2023 11:48:29 +0200 Subject: [PATCH 17/41] docs(event_handler): improve compress example using Response class (#2426) --- docs/core/event_handler/api_gateway.md | 6 +++--- .../src/compressing_responses.py | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/docs/core/event_handler/api_gateway.md b/docs/core/event_handler/api_gateway.md index cfc6f4125d2..956b7cab6bd 100644 --- a/docs/core/event_handler/api_gateway.md +++ b/docs/core/event_handler/api_gateway.md @@ -327,7 +327,7 @@ For convenience, these are the default values when using `CORSConfig` to enable If you need to allow multiple origins, pass the additional origins using the `extra_origins` key. | Key | Value | Note | -|----------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **[allow_origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin){target="_blank"}**: `str` | `*` | Only use the default value for development. **Never use `*` for production** unless your use case requires it | | **[extra_origins](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin){target="_blank"}**: `List[str]` | `[]` | Additional origins to be allowed, in addition to the one specified in `allow_origin` | | **[allow_headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers){target="_blank"}**: `List[str]` | `[Authorization, Content-Type, X-Amz-Date, X-Api-Key, X-Amz-Security-Token]` | Additional headers will be appended to the default list for your convenience | @@ -367,7 +367,7 @@ You can compress with gzip and base64 encode your responses via `compress` param === "compressing_responses.py" - ```python hl_lines="14" + ```python hl_lines="17 27" --8<-- "examples/event_handler_rest/src/compressing_responses.py" ``` @@ -486,7 +486,7 @@ When necessary, you can set a prefix when including a router object. This means You can use specialized router classes according to the type of event that you are resolving. This way you'll get type hints from your IDE as you access the `current_event` property. | Router | Resolver | `current_event` type | -|-------------------------|---------------------------|------------------------| +| ----------------------- | ------------------------- | ---------------------- | | APIGatewayRouter | APIGatewayRestResolver | APIGatewayProxyEvent | | APIGatewayHttpRouter | APIGatewayHttpResolver | APIGatewayProxyEventV2 | | ALBRouter | ALBResolver | ALBEvent | diff --git a/examples/event_handler_rest/src/compressing_responses.py b/examples/event_handler_rest/src/compressing_responses.py index 1af4b9a58b2..52369c59cca 100644 --- a/examples/event_handler_rest/src/compressing_responses.py +++ b/examples/event_handler_rest/src/compressing_responses.py @@ -1,8 +1,11 @@ import requests -from requests import Response from aws_lambda_powertools import Logger, Tracer -from aws_lambda_powertools.event_handler import APIGatewayRestResolver +from aws_lambda_powertools.event_handler import ( + APIGatewayRestResolver, + Response, + content_types, +) from aws_lambda_powertools.logging import correlation_paths from aws_lambda_powertools.utilities.typing import LambdaContext @@ -14,13 +17,22 @@ @app.get("/todos", compress=True) @tracer.capture_method def get_todos(): - todos: Response = requests.get("https://jsonplaceholder.typicode.com/todos") + todos: requests.Response = requests.get("https://jsonplaceholder.typicode.com/todos") todos.raise_for_status() # for brevity, we'll limit to the first 10 only return {"todos": todos.json()[:10]} +@app.get("/todos/", compress=True) +@tracer.capture_method +def get_todo_by_id(todo_id: str): # same example using Response class + todos: requests.Response = requests.get(f"https://jsonplaceholder.typicode.com/todos/{todo_id}") + todos.raise_for_status() + + return Response(status_code=200, content_type=content_types.APPLICATION_JSON, body=todos.json()) + + # You can continue to use other utilities just as before @logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST) @tracer.capture_lambda_handler From 29d6b94ee7c8aa7d1ab0cd9bcb6c04b225dca19b Mon Sep 17 00:00:00 2001 From: Ran Isenberg <60175085+ran-isenberg@users.noreply.github.com> Date: Fri, 9 Jun 2023 18:57:49 +0300 Subject: [PATCH 18/41] feat(parser): support for CloudFormation Custom Resources (#2335) Co-authored-by: Leandro Damascena Co-authored-by: Ran Isenberg Co-authored-by: heitorlessa --- .../utilities/parser/models/__init__.py | 10 +++ .../models/cloudformation_custom_resource.py | 29 ++++++ docs/utilities/parser.md | 45 +++++----- .../cloudformationCustomResourceCreate.json | 13 +++ .../cloudformationCustomResourceDelete.json | 13 +++ .../cloudformationCustomResourceUpdate.json | 17 ++++ .../test_cloudformation_custom_resource.py | 89 +++++++++++++++++++ 7 files changed, 195 insertions(+), 21 deletions(-) create mode 100644 aws_lambda_powertools/utilities/parser/models/cloudformation_custom_resource.py create mode 100644 tests/events/cloudformationCustomResourceCreate.json create mode 100644 tests/events/cloudformationCustomResourceDelete.json create mode 100644 tests/events/cloudformationCustomResourceUpdate.json create mode 100644 tests/unit/parser/test_cloudformation_custom_resource.py diff --git a/aws_lambda_powertools/utilities/parser/models/__init__.py b/aws_lambda_powertools/utilities/parser/models/__init__.py index c2385b7bf14..952280a519c 100644 --- a/aws_lambda_powertools/utilities/parser/models/__init__.py +++ b/aws_lambda_powertools/utilities/parser/models/__init__.py @@ -14,6 +14,12 @@ RequestContextV2AuthorizerJwt, RequestContextV2Http, ) +from .cloudformation_custom_resource import ( + CloudFormationCustomResourceBaseModel, + CloudFormationCustomResourceCreateModel, + CloudFormationCustomResourceDeleteModel, + CloudFormationCustomResourceUpdateModel, +) from .cloudwatch import ( CloudWatchLogsData, CloudWatchLogsDecode, @@ -147,4 +153,8 @@ "KafkaBaseEventModel", "KinesisFirehoseSqsModel", "KinesisFirehoseSqsRecord", + "CloudFormationCustomResourceUpdateModel", + "CloudFormationCustomResourceDeleteModel", + "CloudFormationCustomResourceCreateModel", + "CloudFormationCustomResourceBaseModel", ] diff --git a/aws_lambda_powertools/utilities/parser/models/cloudformation_custom_resource.py b/aws_lambda_powertools/utilities/parser/models/cloudformation_custom_resource.py new file mode 100644 index 00000000000..479ff53fb45 --- /dev/null +++ b/aws_lambda_powertools/utilities/parser/models/cloudformation_custom_resource.py @@ -0,0 +1,29 @@ +from typing import Any, Dict, Union + +from pydantic import BaseModel, Field, HttpUrl + +from aws_lambda_powertools.utilities.parser.types import Literal + + +class CloudFormationCustomResourceBaseModel(BaseModel): + request_type: str = Field(..., alias="RequestType") + service_token: str = Field(..., alias="ServiceToken") + response_url: HttpUrl = Field(..., alias="ResponseURL") + stack_id: str = Field(..., alias="StackId") + request_id: str = Field(..., alias="RequestId") + logical_resource_id: str = Field(..., alias="LogicalResourceId") + resource_type: str = Field(..., alias="ResourceType") + resource_properties: Union[Dict[str, Any], BaseModel, None] = Field(None, alias="ResourceProperties") + + +class CloudFormationCustomResourceCreateModel(CloudFormationCustomResourceBaseModel): + request_type: Literal["Create"] = Field(..., alias="RequestType") + + +class CloudFormationCustomResourceDeleteModel(CloudFormationCustomResourceBaseModel): + request_type: Literal["Delete"] = Field(..., alias="RequestType") + + +class CloudFormationCustomResourceUpdateModel(CloudFormationCustomResourceBaseModel): + request_type: Literal["Update"] = Field(..., alias="RequestType") + old_resource_properties: Union[Dict[str, Any], BaseModel, None] = Field(None, alias="OldResourceProperties") diff --git a/docs/utilities/parser.md b/docs/utilities/parser.md index b0852a0129f..0e25f9441a4 100644 --- a/docs/utilities/parser.md +++ b/docs/utilities/parser.md @@ -156,27 +156,30 @@ def my_function(): Parser comes with the following built-in models: -| Model name | Description | -| --------------------------------------- | ------------------------------------------------------------------------------------- | -| **AlbModel** | Lambda Event Source payload for Amazon Application Load Balancer | -| **APIGatewayProxyEventModel** | Lambda Event Source payload for Amazon API Gateway | -| **APIGatewayProxyEventV2Model** | Lambda Event Source payload for Amazon API Gateway v2 payload | -| **CloudwatchLogsModel** | Lambda Event Source payload for Amazon CloudWatch Logs | -| **DynamoDBStreamModel** | Lambda Event Source payload for Amazon DynamoDB Streams | -| **EventBridgeModel** | Lambda Event Source payload for Amazon EventBridge | -| **KafkaMskEventModel** | Lambda Event Source payload for AWS MSK payload | -| **KafkaSelfManagedEventModel** | Lambda Event Source payload for self managed Kafka payload | -| **KinesisDataStreamModel** | Lambda Event Source payload for Amazon Kinesis Data Streams | -| **KinesisFirehoseModel** | Lambda Event Source payload for Amazon Kinesis Firehose | -| **KinesisFirehoseSqsModel** | Lambda Event Source payload for SQS messages wrapped in Kinesis Firehose records | -| **LambdaFunctionUrlModel** | Lambda Event Source payload for Lambda Function URL payload | -| **S3EventNotificationEventBridgeModel** | Lambda Event Source payload for Amazon S3 Event Notification to EventBridge. | -| **S3Model** | Lambda Event Source payload for Amazon S3 | -| **S3ObjectLambdaEvent** | Lambda Event Source payload for Amazon S3 Object Lambda | -| **S3SqsEventNotificationModel** | Lambda Event Source payload for S3 event notifications wrapped in SQS event (S3->SQS) | -| **SesModel** | Lambda Event Source payload for Amazon Simple Email Service | -| **SnsModel** | Lambda Event Source payload for Amazon Simple Notification Service | -| **SqsModel** | Lambda Event Source payload for Amazon SQS | +| Model name | Description | +| ------------------------------------------- | ------------------------------------------------------------------------------------- | +| **AlbModel** | Lambda Event Source payload for Amazon Application Load Balancer | +| **APIGatewayProxyEventModel** | Lambda Event Source payload for Amazon API Gateway | +| **APIGatewayProxyEventV2Model** | Lambda Event Source payload for Amazon API Gateway v2 payload | +| **CloudFormationCustomResourceCreateModel** | Lambda Event Source payload for AWS CloudFormation `CREATE` operation | +| **CloudFormationCustomResourceUpdateModel** | Lambda Event Source payload for AWS CloudFormation `UPDATE` operation | +| **CloudFormationCustomResourceDeleteModel** | Lambda Event Source payload for AWS CloudFormation `DELETE` operation | +| **CloudwatchLogsModel** | Lambda Event Source payload for Amazon CloudWatch Logs | +| **DynamoDBStreamModel** | Lambda Event Source payload for Amazon DynamoDB Streams | +| **EventBridgeModel** | Lambda Event Source payload for Amazon EventBridge | +| **KafkaMskEventModel** | Lambda Event Source payload for AWS MSK payload | +| **KafkaSelfManagedEventModel** | Lambda Event Source payload for self managed Kafka payload | +| **KinesisDataStreamModel** | Lambda Event Source payload for Amazon Kinesis Data Streams | +| **KinesisFirehoseModel** | Lambda Event Source payload for Amazon Kinesis Firehose | +| **KinesisFirehoseSqsModel** | Lambda Event Source payload for SQS messages wrapped in Kinesis Firehose records | +| **LambdaFunctionUrlModel** | Lambda Event Source payload for Lambda Function URL payload | +| **S3EventNotificationEventBridgeModel** | Lambda Event Source payload for Amazon S3 Event Notification to EventBridge. | +| **S3Model** | Lambda Event Source payload for Amazon S3 | +| **S3ObjectLambdaEvent** | Lambda Event Source payload for Amazon S3 Object Lambda | +| **S3SqsEventNotificationModel** | Lambda Event Source payload for S3 event notifications wrapped in SQS event (S3->SQS) | +| **SesModel** | Lambda Event Source payload for Amazon Simple Email Service | +| **SnsModel** | Lambda Event Source payload for Amazon Simple Notification Service | +| **SqsModel** | Lambda Event Source payload for Amazon SQS | #### Extending built-in models diff --git a/tests/events/cloudformationCustomResourceCreate.json b/tests/events/cloudformationCustomResourceCreate.json new file mode 100644 index 00000000000..5c32d8c7aa1 --- /dev/null +++ b/tests/events/cloudformationCustomResourceCreate.json @@ -0,0 +1,13 @@ +{ + "RequestType": "Create", + "ServiceToken": "arn:aws:lambda:us-east-1:xxx:function:xxxx-CrbuiltinfunctionidProvi-2vKAalSppmKe", + "ResponseURL": "https://cloudformation-custom-resource-response-useast1.s3.amazonaws.com/7F%7Cb1f50fdfc25f3b", + "StackId": "arn:aws:cloudformation:us-east-1:xxxx:stack/xxxx/271845b0-f2e8-11ed-90ac-0eeb25b8ae21", + "RequestId": "xxxxx-d2a0-4dfb-ab1f-xxxxxx", + "LogicalResourceId": "xxxxxxxxx", + "ResourceType": "Custom::MyType", + "ResourceProperties": { + "ServiceToken": "arn:aws:lambda:us-east-1:xxxxx:function:xxxxx", + "MyProps": "ss" + } +} \ No newline at end of file diff --git a/tests/events/cloudformationCustomResourceDelete.json b/tests/events/cloudformationCustomResourceDelete.json new file mode 100644 index 00000000000..f26738133db --- /dev/null +++ b/tests/events/cloudformationCustomResourceDelete.json @@ -0,0 +1,13 @@ +{ + "RequestType": "Delete", + "ServiceToken": "arn:aws:lambda:us-east-1:xxx:function:xxxx-CrbuiltinfunctionidProvi-2vKAalSppmKe", + "ResponseURL": "https://cloudformation-custom-resource-response-useast1.s3.amazonaws.com/7F%7Cb1f50fdfc25f3b", + "StackId": "arn:aws:cloudformation:us-east-1:xxxx:stack/xxxx/271845b0-f2e8-11ed-90ac-0eeb25b8ae21", + "RequestId": "xxxxx-d2a0-4dfb-ab1f-xxxxxx", + "LogicalResourceId": "xxxxxxxxx", + "ResourceType": "Custom::MyType", + "ResourceProperties": { + "ServiceToken": "arn:aws:lambda:us-east-1:xxxxx:function:xxxxx", + "MyProps": "ss" + } +} \ No newline at end of file diff --git a/tests/events/cloudformationCustomResourceUpdate.json b/tests/events/cloudformationCustomResourceUpdate.json new file mode 100644 index 00000000000..52257463455 --- /dev/null +++ b/tests/events/cloudformationCustomResourceUpdate.json @@ -0,0 +1,17 @@ +{ + "RequestType": "Update", + "ServiceToken": "arn:aws:lambda:us-east-1:xxx:function:xxxx-CrbuiltinfunctionidProvi-2vKAalSppmKe", + "ResponseURL": "https://cloudformation-custom-resource-response-useast1.s3.amazonaws.com/7F%7Cb1f50fdfc25f3b", + "StackId": "arn:aws:cloudformation:us-east-1:xxxx:stack/xxxx/271845b0-f2e8-11ed-90ac-0eeb25b8ae21", + "RequestId": "xxxxx-d2a0-4dfb-ab1f-xxxxxx", + "LogicalResourceId": "xxxxxxxxx", + "ResourceType": "Custom::MyType", + "ResourceProperties": { + "ServiceToken": "arn:aws:lambda:us-east-1:xxxxx:function:xxxxx", + "MyProps": "new" + }, + "OldResourceProperties": { + "ServiceToken": "arn:aws:lambda:us-east-1:xxxxx:function:xxxxx-xxxx-xxx", + "MyProps": "old" + } +} \ No newline at end of file diff --git a/tests/unit/parser/test_cloudformation_custom_resource.py b/tests/unit/parser/test_cloudformation_custom_resource.py new file mode 100644 index 00000000000..b5646c3f36a --- /dev/null +++ b/tests/unit/parser/test_cloudformation_custom_resource.py @@ -0,0 +1,89 @@ +import pytest +from pydantic import BaseModel, Field + +from aws_lambda_powertools.utilities.parser import ValidationError +from aws_lambda_powertools.utilities.parser.models import ( + CloudFormationCustomResourceCreateModel, + CloudFormationCustomResourceDeleteModel, + CloudFormationCustomResourceUpdateModel, +) +from tests.functional.utils import load_event + + +def test_cloudformation_custom_resource_create_event(): + raw_event = load_event("cloudformationCustomResourceCreate.json") + model = CloudFormationCustomResourceCreateModel(**raw_event) + + assert model.request_type == raw_event["RequestType"] + assert model.request_id == raw_event["RequestId"] + assert model.service_token == raw_event["ServiceToken"] + assert str(model.response_url) == raw_event["ResponseURL"] + assert model.stack_id == raw_event["StackId"] + assert model.logical_resource_id == raw_event["LogicalResourceId"] + assert model.resource_type == raw_event["ResourceType"] + assert model.resource_properties == raw_event["ResourceProperties"] + + +def test_cloudformation_custom_resource_create_event_custom_model(): + class MyModel(BaseModel): + MyProps: str + + class MyCustomResource(CloudFormationCustomResourceCreateModel): + resource_properties: MyModel = Field(..., alias="ResourceProperties") + + raw_event = load_event("cloudformationCustomResourceCreate.json") + model = MyCustomResource(**raw_event) + + assert model.resource_properties.MyProps == raw_event["ResourceProperties"].get("MyProps") + + +def test_cloudformation_custom_resource_create_event_invalid(): + raw_event = load_event("cloudformationCustomResourceCreate.json") + raw_event["ResourceProperties"] = ["some_data"] + + with pytest.raises(ValidationError): + CloudFormationCustomResourceCreateModel(**raw_event) + + +def test_cloudformation_custom_resource_update_event(): + raw_event = load_event("cloudformationCustomResourceUpdate.json") + model = CloudFormationCustomResourceUpdateModel(**raw_event) + + assert model.request_type == raw_event["RequestType"] + assert model.request_id == raw_event["RequestId"] + assert model.service_token == raw_event["ServiceToken"] + assert str(model.response_url) == raw_event["ResponseURL"] + assert model.stack_id == raw_event["StackId"] + assert model.logical_resource_id == raw_event["LogicalResourceId"] + assert model.resource_type == raw_event["ResourceType"] + assert model.resource_properties == raw_event["ResourceProperties"] + assert model.old_resource_properties == raw_event["OldResourceProperties"] + + +def test_cloudformation_custom_resource_update_event_invalid(): + raw_event = load_event("cloudformationCustomResourceUpdate.json") + raw_event["OldResourceProperties"] = ["some_data"] + + with pytest.raises(ValidationError): + CloudFormationCustomResourceUpdateModel(**raw_event) + + +def test_cloudformation_custom_resource_delete_event(): + raw_event = load_event("cloudformationCustomResourceDelete.json") + model = CloudFormationCustomResourceDeleteModel(**raw_event) + + assert model.request_type == raw_event["RequestType"] + assert model.request_id == raw_event["RequestId"] + assert model.service_token == raw_event["ServiceToken"] + assert str(model.response_url) == raw_event["ResponseURL"] + assert model.stack_id == raw_event["StackId"] + assert model.logical_resource_id == raw_event["LogicalResourceId"] + assert model.resource_type == raw_event["ResourceType"] + assert model.resource_properties == raw_event["ResourceProperties"] + + +def test_cloudformation_custom_resource_delete_event_invalid(): + raw_event = load_event("cloudformationCustomResourceDelete.json") + raw_event["ResourceProperties"] = ["some_data"] + with pytest.raises(ValidationError): + CloudFormationCustomResourceDeleteModel(**raw_event) From 9ddeb55411996d7e6ed3405f848b46849be51bb5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jun 2023 17:37:34 +0200 Subject: [PATCH 19/41] chore(deps-dev): bump aws-cdk from 2.83.0 to 2.83.1 (#2432) Bumps [aws-cdk](https://github.com/aws/aws-cdk/tree/HEAD/packages/aws-cdk) from 2.83.0 to 2.83.1. - [Release notes](https://github.com/aws/aws-cdk/releases) - [Changelog](https://github.com/aws/aws-cdk/blob/v2.83.1/CHANGELOG.v2.md) - [Commits](https://github.com/aws/aws-cdk/commits/v2.83.1/packages/aws-cdk) --- updated-dependencies: - dependency-name: aws-cdk dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 352ee6c2e73..e5990842d28 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,13 +8,13 @@ "name": "aws-lambda-powertools-python-e2e", "version": "1.0.0", "devDependencies": { - "aws-cdk": "^2.83.0" + "aws-cdk": "^2.83.1" } }, "node_modules/aws-cdk": { - "version": "2.83.0", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.83.0.tgz", - "integrity": "sha512-UB9foPqsQkUeFHP5ZOjxqg0N+g53MPJnpxyKeMhDQDIiS9kG1LqVyHUwHNzq0PSk4kdwH9g50keu6zslb1iA1w==", + "version": "2.83.1", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.83.1.tgz", + "integrity": "sha512-hM2fsHl2TXk3B0MTq7zRU/KqJiVrnTQ3SXbAfleQCfCf/Jpy6yD6nGqrEADFAYNLSPoA9iC3SLnO73SPqqjjRQ==", "dev": true, "bin": { "cdk": "bin/cdk" @@ -43,9 +43,9 @@ }, "dependencies": { "aws-cdk": { - "version": "2.83.0", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.83.0.tgz", - "integrity": "sha512-UB9foPqsQkUeFHP5ZOjxqg0N+g53MPJnpxyKeMhDQDIiS9kG1LqVyHUwHNzq0PSk4kdwH9g50keu6zslb1iA1w==", + "version": "2.83.1", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.83.1.tgz", + "integrity": "sha512-hM2fsHl2TXk3B0MTq7zRU/KqJiVrnTQ3SXbAfleQCfCf/Jpy6yD6nGqrEADFAYNLSPoA9iC3SLnO73SPqqjjRQ==", "dev": true, "requires": { "fsevents": "2.3.2" diff --git a/package.json b/package.json index 7aa708b8533..93b51ac296d 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,6 @@ "name": "aws-lambda-powertools-python-e2e", "version": "1.0.0", "devDependencies": { - "aws-cdk": "^2.83.0" + "aws-cdk": "^2.83.1" } } From 944464b7b46e88a9419ebfd7858a2d50a5ff2416 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jun 2023 17:39:40 +0200 Subject: [PATCH 20/41] chore(deps): bump actions/checkout from 3.5.2 to 3.5.3 (#2431) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.2 to 3.5.3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/8e5e7e5ab8b370d6c329ec480221332ada57f0ab...c85c95e3d7251135ab7dc9ce3241c5835cc595a9) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Leandro Damascena --- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/label_pr_on_title.yml | 2 +- .github/workflows/on_label_added.yml | 2 +- .github/workflows/on_merged_pr.yml | 2 +- .github/workflows/on_opened_pr.yml | 4 ++-- .github/workflows/publish_v2_layer.yml | 4 ++-- .github/workflows/quality_check.yml | 2 +- .github/workflows/record_pr.yml | 2 +- .github/workflows/release.yml | 14 +++++++------- .../workflows/reusable_deploy_v2_layer_stack.yml | 2 +- .github/workflows/reusable_deploy_v2_sar.yml | 2 +- .github/workflows/reusable_export_pr_details.yml | 2 +- .github/workflows/reusable_publish_changelog.yml | 2 +- .github/workflows/reusable_publish_docs.yml | 2 +- .github/workflows/run-e2e-tests.yml | 2 +- .github/workflows/secure_workflows.yml | 2 +- 16 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 221aaa56cc9..ac4e4812eee 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -36,7 +36,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/label_pr_on_title.yml b/.github/workflows/label_pr_on_title.yml index 9d36c215e4c..41bdeed0ec9 100644 --- a/.github/workflows/label_pr_on_title.yml +++ b/.github/workflows/label_pr_on_title.yml @@ -46,7 +46,7 @@ jobs: pull-requests: write # label respective PR steps: - name: Checkout repository - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: "Label PR based on title" uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 env: diff --git a/.github/workflows/on_label_added.yml b/.github/workflows/on_label_added.yml index 58b88f51a1a..17ee840a7ea 100644 --- a/.github/workflows/on_label_added.yml +++ b/.github/workflows/on_label_added.yml @@ -43,7 +43,7 @@ jobs: permissions: pull-requests: write # comment on PR steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 # Maintenance: Persist state per PR as an artifact to avoid spam on label add - name: "Suggest split large Pull Request" uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 diff --git a/.github/workflows/on_merged_pr.yml b/.github/workflows/on_merged_pr.yml index 573add4473a..e9ac01f1c17 100644 --- a/.github/workflows/on_merged_pr.yml +++ b/.github/workflows/on_merged_pr.yml @@ -45,7 +45,7 @@ jobs: issues: write # label issue with pending-release if: needs.get_pr_details.outputs.prIsMerged == 'true' steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: "Label PR related issue for release" uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 env: diff --git a/.github/workflows/on_opened_pr.yml b/.github/workflows/on_opened_pr.yml index a9131926081..5e7914b09a3 100644 --- a/.github/workflows/on_opened_pr.yml +++ b/.github/workflows/on_opened_pr.yml @@ -43,7 +43,7 @@ jobs: needs: get_pr_details runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: "Ensure related issue is present" uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 env: @@ -62,7 +62,7 @@ jobs: permissions: pull-requests: write # label and comment on PR if missing acknowledge section (requirement) steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: "Ensure acknowledgement section is present" uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 env: diff --git a/.github/workflows/publish_v2_layer.yml b/.github/workflows/publish_v2_layer.yml index 523fed97363..cb169596520 100644 --- a/.github/workflows/publish_v2_layer.yml +++ b/.github/workflows/publish_v2_layer.yml @@ -63,7 +63,7 @@ jobs: working-directory: ./layer steps: - name: checkout - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 with: fetch-depth: 0 - name: Install poetry @@ -196,7 +196,7 @@ jobs: pages: none steps: - name: Checkout repository # reusable workflows start clean, so we need to checkout again - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 with: fetch-depth: 0 - name: Download CDK layer artifact diff --git a/.github/workflows/quality_check.yml b/.github/workflows/quality_check.yml index 3ae93bd26cf..51eebc668ff 100644 --- a/.github/workflows/quality_check.yml +++ b/.github/workflows/quality_check.yml @@ -47,7 +47,7 @@ jobs: permissions: contents: read # checkout code only steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: Install poetry run: pipx install poetry - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/record_pr.yml b/.github/workflows/record_pr.yml index 6fd933222c6..55377f06981 100644 --- a/.github/workflows/record_pr.yml +++ b/.github/workflows/record_pr.yml @@ -43,7 +43,7 @@ jobs: permissions: contents: read # NOTE: treat as untrusted location steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: "Extract PR details" uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8d021fed5cb..2d18917fe57 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -72,7 +72,7 @@ jobs: RELEASE_VERSION="${RELEASE_TAG_VERSION:1}" echo "RELEASE_VERSION=${RELEASE_VERSION}" >> "$GITHUB_OUTPUT" - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 with: ref: ${{ env.RELEASE_COMMIT }} @@ -125,7 +125,7 @@ jobs: SOURCE_INTEGRITY_HASH: ${{ needs.seal.outputs.SOURCE_CODE_HASH }} steps: # NOTE: we need actions/checkout to configure git first (pre-commit hooks in make dev) - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 with: ref: ${{ env.RELEASE_COMMIT }} @@ -166,7 +166,7 @@ jobs: SOURCE_INTEGRITY_HASH: ${{ needs.seal.outputs.SOURCE_CODE_HASH }} steps: # NOTE: we need actions/checkout to configure git first (pre-commit hooks in make dev) - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 with: ref: ${{ env.RELEASE_COMMIT }} @@ -225,7 +225,7 @@ jobs: BUILD_INTEGRITY_HASH: ${{ needs.build.outputs.BUILD_INTEGRITY_HASH }} steps: # NOTE: we need actions/checkout in order to use our local actions (e.g., ./.github/actions) - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 with: ref: ${{ env.RELEASE_COMMIT }} @@ -266,7 +266,7 @@ jobs: SOURCE_INTEGRITY_HASH: ${{ needs.seal.outputs.SOURCE_CODE_HASH }} steps: # NOTE: we need actions/checkout to authenticate and configure git first - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 with: ref: ${{ env.RELEASE_COMMIT }} @@ -312,7 +312,7 @@ jobs: SOURCE_INTEGRITY_HASH: ${{ needs.seal.outputs.SOURCE_CODE_HASH }} steps: # NOTE: we need actions/checkout to authenticate and configure git first - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 with: ref: ${{ env.RELEASE_COMMIT }} @@ -372,7 +372,7 @@ jobs: env: RELEASE_VERSION: ${{ needs.seal.outputs.RELEASE_VERSION }} steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 with: ref: ${{ env.RELEASE_COMMIT }} - name: Close issues related to this release diff --git a/.github/workflows/reusable_deploy_v2_layer_stack.yml b/.github/workflows/reusable_deploy_v2_layer_stack.yml index 66142e7bb98..47eb1680ccd 100644 --- a/.github/workflows/reusable_deploy_v2_layer_stack.yml +++ b/.github/workflows/reusable_deploy_v2_layer_stack.yml @@ -122,7 +122,7 @@ jobs: has_arm64_support: "true" steps: - name: checkout - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: Install poetry run: pipx install poetry - name: aws credentials diff --git a/.github/workflows/reusable_deploy_v2_sar.yml b/.github/workflows/reusable_deploy_v2_sar.yml index e50a815979d..3a54ae97579 100644 --- a/.github/workflows/reusable_deploy_v2_sar.yml +++ b/.github/workflows/reusable_deploy_v2_sar.yml @@ -68,7 +68,7 @@ jobs: architecture: ["x86_64", "arm64"] steps: - name: Checkout - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: AWS credentials uses: aws-actions/configure-aws-credentials@5727f247b64f324ec403ac56ae05e220fd02b65f # v2.1.0 with: diff --git a/.github/workflows/reusable_export_pr_details.yml b/.github/workflows/reusable_export_pr_details.yml index 089d735278e..eb98e7e156d 100644 --- a/.github/workflows/reusable_export_pr_details.yml +++ b/.github/workflows/reusable_export_pr_details.yml @@ -69,7 +69,7 @@ jobs: prIsMerged: ${{ steps.prIsMerged.outputs.prIsMerged }} steps: - name: Checkout repository # in case caller workflow doesn't checkout thus failing with file not found - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: "Download previously saved PR" uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 env: diff --git a/.github/workflows/reusable_publish_changelog.yml b/.github/workflows/reusable_publish_changelog.yml index 34dfc7342fe..23139b77729 100644 --- a/.github/workflows/reusable_publish_changelog.yml +++ b/.github/workflows/reusable_publish_changelog.yml @@ -22,7 +22,7 @@ jobs: pull-requests: write # create PR steps: - name: Checkout repository # reusable workflows start clean, so we need to checkout again - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 with: fetch-depth: 0 - name: "Generate latest changelog" diff --git a/.github/workflows/reusable_publish_docs.yml b/.github/workflows/reusable_publish_docs.yml index 74047d7ebde..5e0027154c4 100644 --- a/.github/workflows/reusable_publish_docs.yml +++ b/.github/workflows/reusable_publish_docs.yml @@ -41,7 +41,7 @@ jobs: runs-on: ubuntu-latest environment: "Docs" steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 with: fetch-depth: 0 ref: ${{ inputs.git_ref }} diff --git a/.github/workflows/run-e2e-tests.yml b/.github/workflows/run-e2e-tests.yml index 46c303ad707..4a93bb88b14 100644 --- a/.github/workflows/run-e2e-tests.yml +++ b/.github/workflows/run-e2e-tests.yml @@ -48,7 +48,7 @@ jobs: if: ${{ github.actor != 'dependabot[bot]' }} steps: - name: "Checkout" - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: Install poetry run: pipx install poetry - name: "Use Python" diff --git a/.github/workflows/secure_workflows.yml b/.github/workflows/secure_workflows.yml index bca7eaa80d8..1430e91d6f2 100644 --- a/.github/workflows/secure_workflows.yml +++ b/.github/workflows/secure_workflows.yml @@ -27,6 +27,6 @@ jobs: contents: read # checkout code and subsequently GitHub action workflows steps: - name: Checkout code - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: Ensure 3rd party workflows have SHA pinned uses: zgosalvez/github-actions-ensure-sha-pinned-actions@555a30da2656b4a7cf47b107800bef097723363e # v2.1.3 From 7b67f15dcfcc70a9405f5ef89247356c7615784b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 09:24:11 +0200 Subject: [PATCH 21/41] chore(deps-dev): bump mypy-boto3-dynamodb from 1.26.115 to 1.26.152 (#2444) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 172 ++++--------------------------------------------- pyproject.toml | 2 +- 2 files changed, 13 insertions(+), 161 deletions(-) diff --git a/poetry.lock b/poetry.lock index 8a4cc9242c0..a2d671ac4d4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "anyio" version = "3.6.2" description = "High level compatibility layer for multiple asynchronous event loop implementations" -category = "dev" optional = false python-versions = ">=3.6.2" files = [ @@ -26,7 +25,6 @@ trio = ["trio (>=0.16,<0.22)"] name = "attrs" version = "22.2.0" description = "Classes Without Boilerplate" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -45,7 +43,6 @@ tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy name = "aws-cdk-asset-awscli-v1" version = "2.2.145" description = "A library that contains the AWS CLI for use in Lambda Layers" -category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -62,7 +59,6 @@ typeguard = ">=2.13.3,<2.14.0" name = "aws-cdk-asset-kubectl-v20" version = "2.1.1" description = "A library that contains kubectl for use in Lambda Layers" -category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -79,7 +75,6 @@ typeguard = ">=2.13.3,<2.14.0" name = "aws-cdk-asset-node-proxy-agent-v5" version = "2.0.120" description = "@aws-cdk/asset-node-proxy-agent-v5" -category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -96,7 +91,6 @@ typeguard = ">=2.13.3,<2.14.0" name = "aws-cdk-aws-apigatewayv2-alpha" version = "2.75.1a0" description = "The CDK Construct Library for AWS::APIGatewayv2" -category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -115,7 +109,6 @@ typeguard = ">=2.13.3,<2.14.0" name = "aws-cdk-aws-apigatewayv2-authorizers-alpha" version = "2.75.1a0" description = "Authorizers for AWS APIGateway V2" -category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -135,7 +128,6 @@ typeguard = ">=2.13.3,<2.14.0" name = "aws-cdk-aws-apigatewayv2-integrations-alpha" version = "2.75.1a0" description = "Integrations for AWS APIGateway V2" -category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -155,7 +147,6 @@ typeguard = ">=2.13.3,<2.14.0" name = "aws-cdk-lib" version = "2.75.1" description = "Version 2 of the AWS Cloud Development Kit library" -category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -176,7 +167,6 @@ typeguard = ">=2.13.3,<2.14.0" name = "aws-requests-auth" version = "0.4.3" description = "AWS signature version 4 signing process for the python requests module" -category = "dev" optional = false python-versions = "*" files = [ @@ -191,7 +181,6 @@ requests = ">=0.14.0" name = "aws-sam-translator" version = "1.68.0" description = "AWS SAM Translator is a library that transform SAM templates into AWS CloudFormation templates" -category = "dev" optional = false python-versions = ">=3.7, <=4.0, !=4.0" files = [ @@ -200,19 +189,18 @@ files = [ ] [package.dependencies] -boto3 = ">=1.19.5,<2.0.0" +boto3 = ">=1.19.5,<2.dev0" jsonschema = ">=3.2,<5" pydantic = ">=1.8,<2.0" typing-extensions = ">=4.4,<5" [package.extras] -dev = ["black (==23.1.0)", "boto3 (>=1.23,<2)", "boto3-stubs[appconfig,serverlessrepo] (>=1.19.5,<2.0.0)", "coverage (>=5.3,<8)", "dateparser (>=1.1,<2.0)", "importlib-metadata", "mypy (>=1.1.0,<1.2.0)", "parameterized (>=0.7,<1.0)", "pytest (>=6.2,<8)", "pytest-cov (>=2.10,<5)", "pytest-env (>=0.6,<1)", "pytest-rerunfailures (>=9.1,<12)", "pytest-xdist (>=2.5,<4)", "pyyaml (>=6.0,<7.0)", "requests (>=2.28,<3.0)", "ruamel.yaml (==0.17.21)", "ruff (==0.0.263)", "tenacity (>=8.0,<9.0)", "types-PyYAML (>=6.0,<7.0)", "types-jsonschema (>=3.2,<4.0)"] +dev = ["black (==23.1.0)", "boto3 (>=1.23,<2)", "boto3-stubs[appconfig,serverlessrepo] (>=1.19.5,<2.dev0)", "coverage (>=5.3,<8)", "dateparser (>=1.1,<2.0)", "importlib-metadata", "mypy (>=1.1.0,<1.2.0)", "parameterized (>=0.7,<1.0)", "pytest (>=6.2,<8)", "pytest-cov (>=2.10,<5)", "pytest-env (>=0.6,<1)", "pytest-rerunfailures (>=9.1,<12)", "pytest-xdist (>=2.5,<4)", "pyyaml (>=6.0,<7.0)", "requests (>=2.28,<3.0)", "ruamel.yaml (==0.17.21)", "ruff (==0.0.263)", "tenacity (>=8.0,<9.0)", "types-PyYAML (>=6.0,<7.0)", "types-jsonschema (>=3.2,<4.0)"] [[package]] name = "aws-xray-sdk" version = "2.12.0" description = "The AWS X-Ray SDK for Python (the SDK) enables Python developers to record and emit information from within their applications to the AWS X-Ray service." -category = "main" optional = true python-versions = "*" files = [ @@ -228,7 +216,6 @@ wrapt = "*" name = "bandit" version = "1.7.5" description = "Security oriented static analyser for python code." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -252,7 +239,6 @@ yaml = ["PyYAML"] name = "black" version = "23.3.0" description = "The uncompromising code formatter." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -303,7 +289,6 @@ uvloop = ["uvloop (>=0.15.2)"] name = "boto3" version = "1.26.115" description = "The AWS SDK for Python" -category = "main" optional = false python-versions = ">= 3.7" files = [ @@ -323,7 +308,6 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] name = "botocore" version = "1.29.115" description = "Low-level, data-driven core of boto 3." -category = "main" optional = false python-versions = ">= 3.7" files = [ @@ -343,7 +327,6 @@ crt = ["awscrt (==0.16.9)"] name = "cattrs" version = "22.2.0" description = "Composable complex class support for attrs and dataclasses." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -360,7 +343,6 @@ typing_extensions = {version = "*", markers = "python_version < \"3.8\""} name = "certifi" version = "2022.12.7" description = "Python package for providing Mozilla's CA Bundle." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -372,7 +354,6 @@ files = [ name = "cfn-lint" version = "0.77.7" description = "Checks CloudFormation templates for practices and behaviour that could potentially be improved" -category = "dev" optional = false python-versions = ">=3.7, <=4.0, !=4.0" files = [ @@ -396,7 +377,6 @@ sympy = ">=1.0.0" name = "charset-normalizer" version = "3.1.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -481,7 +461,6 @@ files = [ name = "checksumdir" version = "1.2.0" description = "Compute a single hash of the file contents of a directory." -category = "dev" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -493,7 +472,6 @@ files = [ name = "click" version = "8.1.3" description = "Composable command line interface toolkit" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -509,7 +487,6 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -521,7 +498,6 @@ files = [ name = "constructs" version = "10.2.1" description = "A programming model for software-defined state" -category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -538,7 +514,6 @@ typeguard = ">=2.13.3,<2.14.0" name = "coverage" version = "7.2.7" description = "Code coverage measurement for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -614,7 +589,6 @@ toml = ["tomli"] name = "decorator" version = "5.1.1" description = "Decorators for Humans" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -626,7 +600,6 @@ files = [ name = "eradicate" version = "2.2.0" description = "Removes commented-out code." -category = "dev" optional = false python-versions = "*" files = [ @@ -638,7 +611,6 @@ files = [ name = "exceptiongroup" version = "1.1.1" description = "Backport of PEP 654 (exception groups)" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -653,7 +625,6 @@ test = ["pytest (>=6)"] name = "execnet" version = "1.9.0" description = "execnet: rapid multi-Python deployment" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -668,7 +639,6 @@ testing = ["pre-commit"] name = "fastjsonschema" version = "2.17.1" description = "Fastest Python implementation of JSON schema" -category = "main" optional = true python-versions = "*" files = [ @@ -683,7 +653,6 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc name = "filelock" version = "3.12.0" description = "A platform independent file lock." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -699,7 +668,6 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "p name = "flake8" version = "3.9.2" description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -717,7 +685,6 @@ pyflakes = ">=2.3.0,<2.4.0" name = "flake8" version = "5.0.4" description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -734,7 +701,6 @@ pyflakes = ">=2.5.0,<2.6.0" name = "flake8-black" version = "0.3.6" description = "flake8 plugin to call black as a code style validator" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -754,7 +720,6 @@ develop = ["build", "twine"] name = "flake8-bugbear" version = "23.3.12" description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -773,7 +738,6 @@ dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "pytest", name = "flake8-builtins" version = "2.1.0" description = "Check for python builtins being used as variables or parameters." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -791,7 +755,6 @@ test = ["pytest"] name = "flake8-comprehensions" version = "3.12.0" description = "A flake8 plugin to help you write better list/set/dict comprehensions." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -807,7 +770,6 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} name = "flake8-debugger" version = "4.1.2" description = "ipdb/pdb statement checker plugin for flake8" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -823,7 +785,6 @@ pycodestyle = "*" name = "flake8-eradicate" version = "1.4.0" description = "Flake8 plugin to find commented out code" -category = "dev" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -841,7 +802,6 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} name = "flake8-fixme" version = "1.1.1" description = "Check for FIXME, TODO and other temporary developer notes. Plugin for flake8." -category = "dev" optional = false python-versions = "*" files = [ @@ -853,7 +813,6 @@ files = [ name = "flake8-variables-names" version = "0.0.5" description = "A flake8 extension that helps to make more readable variables names" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -865,7 +824,6 @@ files = [ name = "future" version = "0.18.3" description = "Clean single-source support for Python 3 and 2" -category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -876,7 +834,6 @@ files = [ name = "ghp-import" version = "2.1.0" description = "Copy your docs directly to the gh-pages branch." -category = "dev" optional = false python-versions = "*" files = [ @@ -894,7 +851,6 @@ dev = ["flake8", "markdown", "twine", "wheel"] name = "gitdb" version = "4.0.10" description = "Git Object Database" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -909,7 +865,6 @@ smmap = ">=3.0.1,<6" name = "gitpython" version = "3.1.31" description = "GitPython is a Python library used to interact with Git repositories" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -925,7 +880,6 @@ typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\"" name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -940,7 +894,6 @@ typing-extensions = {version = "*", markers = "python_version < \"3.8\""} name = "httpcore" version = "0.17.0" description = "A minimal low-level HTTP client." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -952,17 +905,16 @@ files = [ anyio = ">=3.0,<5.0" certifi = "*" h11 = ">=0.13,<0.15" -sniffio = ">=1.0.0,<2.0.0" +sniffio = "==1.*" [package.extras] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (>=1.0.0,<2.0.0)"] +socks = ["socksio (==1.*)"] [[package]] name = "httpx" version = "0.24.1" description = "The next generation HTTP client." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -978,15 +930,14 @@ sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (>=1.0.0,<2.0.0)"] +socks = ["socksio (==1.*)"] [[package]] name = "hvac" version = "1.1.0" description = "HashiCorp Vault API client" -category = "dev" optional = false python-versions = ">=3.6.2,<4.0.0" files = [ @@ -1002,7 +953,6 @@ requests = ">=2.27.1,<3.0.0" name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1014,7 +964,6 @@ files = [ name = "ijson" version = "3.2.0.post0" description = "Iterative JSON parser with standard Python iterator interfaces" -category = "dev" optional = false python-versions = "*" files = [ @@ -1102,7 +1051,6 @@ files = [ name = "importlib-metadata" version = "6.6.0" description = "Read metadata from Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1123,7 +1071,6 @@ testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packag name = "importlib-resources" version = "5.12.0" description = "Read resources from Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1142,7 +1089,6 @@ testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-chec name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1154,7 +1100,6 @@ files = [ name = "isort" version = "5.11.5" description = "A Python utility / library to sort Python imports." -category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -1172,7 +1117,6 @@ requirements-deprecated-finder = ["pip-api", "pipreqs"] name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1190,7 +1134,6 @@ i18n = ["Babel (>=2.7)"] name = "jmespath" version = "1.0.1" description = "JSON Matching Expressions" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1202,7 +1145,6 @@ files = [ name = "jschema-to-python" version = "1.2.3" description = "Generate source code for Python classes from a JSON schema." -category = "dev" optional = false python-versions = ">= 2.7" files = [ @@ -1219,7 +1161,6 @@ pbr = "*" name = "jsii" version = "1.80.0" description = "Python client for jsii runtime" -category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -1240,7 +1181,6 @@ typing-extensions = ">=3.7,<5.0" name = "jsonpatch" version = "1.32" description = "Apply JSON-Patches (RFC 6902)" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1255,7 +1195,6 @@ jsonpointer = ">=1.9" name = "jsonpickle" version = "3.0.1" description = "Python library for serializing any arbitrary object graph into JSON" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1275,7 +1214,6 @@ testing-libs = ["simplejson", "ujson"] name = "jsonpointer" version = "2.3" description = "Identify specific nodes in a JSON document (RFC 6901)" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1287,7 +1225,6 @@ files = [ name = "jsonschema" version = "4.17.3" description = "An implementation of JSON Schema validation for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1311,7 +1248,6 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- name = "junit-xml" version = "1.9" description = "Creates JUnit XML test result documents that can be read by tools such as Jenkins" -category = "dev" optional = false python-versions = "*" files = [ @@ -1326,7 +1262,6 @@ six = "*" name = "mako" version = "1.2.4" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1347,7 +1282,6 @@ testing = ["pytest"] name = "mando" version = "0.6.4" description = "Create Python CLI apps with little to no effort at all!" -category = "dev" optional = false python-versions = "*" files = [ @@ -1365,7 +1299,6 @@ restructuredtext = ["rst2ansi"] name = "markdown" version = "3.3.7" description = "Python implementation of Markdown." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1383,7 +1316,6 @@ testing = ["coverage", "pyyaml"] name = "markdown-it-py" version = "2.2.0" description = "Python port of markdown-it. Markdown parsing, done right!" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1409,7 +1341,6 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] name = "markupsafe" version = "2.1.2" description = "Safely add untrusted strings to HTML/XML markup." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1469,7 +1400,6 @@ files = [ name = "mccabe" version = "0.6.1" description = "McCabe checker, plugin for flake8" -category = "dev" optional = false python-versions = "*" files = [ @@ -1481,7 +1411,6 @@ files = [ name = "mccabe" version = "0.7.0" description = "McCabe checker, plugin for flake8" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1493,7 +1422,6 @@ files = [ name = "mdurl" version = "0.1.2" description = "Markdown URL utilities" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1505,7 +1433,6 @@ files = [ name = "mergedeep" version = "1.3.4" description = "A deep merge function for 🐍." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1517,7 +1444,6 @@ files = [ name = "mike" version = "1.1.2" description = "Manage multiple versions of your MkDocs-powered documentation" -category = "dev" optional = false python-versions = "*" files = [ @@ -1539,7 +1465,6 @@ test = ["coverage", "flake8 (>=3.0)", "shtab"] name = "mkdocs" version = "1.4.2" description = "Project documentation with Markdown." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1569,7 +1494,6 @@ min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-imp name = "mkdocs-git-revision-date-plugin" version = "0.3.2" description = "MkDocs plugin for setting revision date from git per markdown file." -category = "dev" optional = false python-versions = ">=3.4" files = [ @@ -1585,7 +1509,6 @@ mkdocs = ">=0.17" name = "mkdocs-material" version = "9.1.15" description = "Documentation that simply works" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1608,7 +1531,6 @@ requests = ">=2.26" name = "mkdocs-material-extensions" version = "1.1.1" description = "Extension pack for Python Markdown and MkDocs Material." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1620,7 +1542,6 @@ files = [ name = "mpmath" version = "1.3.0" description = "Python library for arbitrary-precision floating-point arithmetic" -category = "dev" optional = false python-versions = "*" files = [ @@ -1638,7 +1559,6 @@ tests = ["pytest (>=4.6)"] name = "mypy" version = "1.3.0" description = "Optional static typing for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1686,7 +1606,6 @@ reports = ["lxml"] name = "mypy-boto3-appconfig" version = "1.26.71" description = "Type annotations for boto3.AppConfig 1.26.71 service generated with mypy-boto3-builder 7.12.3" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1701,7 +1620,6 @@ typing-extensions = ">=4.1.0" name = "mypy-boto3-appconfigdata" version = "1.26.70" description = "Type annotations for boto3.AppConfigData 1.26.70 service generated with mypy-boto3-builder 7.12.3" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1716,7 +1634,6 @@ typing-extensions = ">=4.1.0" name = "mypy-boto3-cloudformation" version = "1.26.149" description = "Type annotations for boto3.CloudFormation 1.26.149 service generated with mypy-boto3-builder 7.14.5" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1731,7 +1648,6 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} name = "mypy-boto3-cloudwatch" version = "1.26.127" description = "Type annotations for boto3.CloudWatch 1.26.127 service generated with mypy-boto3-builder 7.14.5" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1744,14 +1660,13 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} [[package]] name = "mypy-boto3-dynamodb" -version = "1.26.115" -description = "Type annotations for boto3.DynamoDB 1.26.115 service generated with mypy-boto3-builder 7.14.5" -category = "dev" +version = "1.26.152" +description = "Type annotations for boto3.DynamoDB 1.26.152 service generated with mypy-boto3-builder 7.14.5" optional = false python-versions = ">=3.7" files = [ - {file = "mypy-boto3-dynamodb-1.26.115.tar.gz", hash = "sha256:b94d69617d118421d625120d38b81772ef3aa2ba2d98e771008f9c72388f60f1"}, - {file = "mypy_boto3_dynamodb-1.26.115-py3-none-any.whl", hash = "sha256:280d4b71b716e221887cfbd8aeb27699efb2ed5f5ac98621878dbe99492dcd8c"}, + {file = "mypy-boto3-dynamodb-1.26.152.tar.gz", hash = "sha256:b31dfd107fed0a030bc32b4cf2b498aa38560920e33d6ec00c6e283d14d2421e"}, + {file = "mypy_boto3_dynamodb-1.26.152-py3-none-any.whl", hash = "sha256:4c5d95f1e10088cbaf3715c4127dde84e011368d26a92994d514f5a2f981813f"}, ] [package.dependencies] @@ -1761,7 +1676,6 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} name = "mypy-boto3-lambda" version = "1.26.147" description = "Type annotations for boto3.Lambda 1.26.147 service generated with mypy-boto3-builder 7.14.5" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1776,7 +1690,6 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} name = "mypy-boto3-logs" version = "1.26.149" description = "Type annotations for boto3.CloudWatchLogs 1.26.149 service generated with mypy-boto3-builder 7.14.5" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1791,7 +1704,6 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} name = "mypy-boto3-s3" version = "1.26.127" description = "Type annotations for boto3.S3 1.26.127 service generated with mypy-boto3-builder 7.14.5" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1806,7 +1718,6 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} name = "mypy-boto3-secretsmanager" version = "1.26.135" description = "Type annotations for boto3.SecretsManager 1.26.135 service generated with mypy-boto3-builder 7.14.5" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1821,7 +1732,6 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} name = "mypy-boto3-ssm" version = "1.26.97" description = "Type annotations for boto3.SSM 1.26.97 service generated with mypy-boto3-builder 7.13.0" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1836,7 +1746,6 @@ typing-extensions = ">=4.1.0" name = "mypy-boto3-xray" version = "1.26.122" description = "Type annotations for boto3.XRay 1.26.122 service generated with mypy-boto3-builder 7.14.5" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1851,7 +1760,6 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1863,7 +1771,6 @@ files = [ name = "networkx" version = "2.6.3" description = "Python package for creating and manipulating graphs and networks" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1882,7 +1789,6 @@ test = ["codecov (>=2.1)", "pytest (>=6.2)", "pytest-cov (>=2.12)"] name = "packaging" version = "23.1" description = "Core utilities for Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1894,7 +1800,6 @@ files = [ name = "pathspec" version = "0.11.1" description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1906,7 +1811,6 @@ files = [ name = "pbr" version = "5.11.1" description = "Python Build Reasonableness" -category = "dev" optional = false python-versions = ">=2.6" files = [ @@ -1918,7 +1822,6 @@ files = [ name = "pdoc3" version = "0.10.0" description = "Auto-generate API documentation for Python projects." -category = "dev" optional = false python-versions = ">= 3.6" files = [ @@ -1934,7 +1837,6 @@ markdown = ">=3.0" name = "pkgutil-resolve-name" version = "1.3.10" description = "Resolve a name to an object." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1946,7 +1848,6 @@ files = [ name = "platformdirs" version = "3.2.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1965,7 +1866,6 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.2.2)", "pytest- name = "pluggy" version = "1.0.0" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1984,7 +1884,6 @@ testing = ["pytest", "pytest-benchmark"] name = "publication" version = "0.0.3" description = "Publication helps you maintain public-api-friendly modules by preventing unintentional access to private implementation details via introspection." -category = "dev" optional = false python-versions = "*" files = [ @@ -1996,7 +1895,6 @@ files = [ name = "py" version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -2008,7 +1906,6 @@ files = [ name = "py-cpuinfo" version = "9.0.0" description = "Get CPU info with pure Python" -category = "dev" optional = false python-versions = "*" files = [ @@ -2020,7 +1917,6 @@ files = [ name = "pycodestyle" version = "2.7.0" description = "Python style guide checker" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2032,7 +1928,6 @@ files = [ name = "pycodestyle" version = "2.9.1" description = "Python style guide checker" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2044,7 +1939,6 @@ files = [ name = "pydantic" version = "1.10.9" description = "Data validation and settings management using python type hints" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2097,7 +1991,6 @@ email = ["email-validator (>=1.0.3)"] name = "pyflakes" version = "2.3.1" description = "passive checker of Python programs" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2109,7 +2002,6 @@ files = [ name = "pyflakes" version = "2.5.0" description = "passive checker of Python programs" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2121,7 +2013,6 @@ files = [ name = "pygments" version = "2.15.1" description = "Pygments is a syntax highlighting package written in Python." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2136,7 +2027,6 @@ plugins = ["importlib-metadata"] name = "pyhcl" version = "0.4.4" description = "HCL configuration parser for python" -category = "dev" optional = false python-versions = "*" files = [ @@ -2147,7 +2037,6 @@ files = [ name = "pymdown-extensions" version = "10.0" description = "Extension pack for Python Markdown." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2163,7 +2052,6 @@ pyyaml = "*" name = "pyrsistent" version = "0.19.3" description = "Persistent/Functional/Immutable data structures" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2200,7 +2088,6 @@ files = [ name = "pytest" version = "7.3.1" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2224,7 +2111,6 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no name = "pytest-asyncio" version = "0.21.0" description = "Pytest support for asyncio" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2244,7 +2130,6 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy name = "pytest-benchmark" version = "4.0.0" description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2265,7 +2150,6 @@ histogram = ["pygal", "pygaljs"] name = "pytest-cov" version = "4.1.0" description = "Pytest plugin for measuring coverage." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2284,7 +2168,6 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "pytest-mock" version = "3.10.0" description = "Thin-wrapper around the mock package for easier use with pytest" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2302,7 +2185,6 @@ dev = ["pre-commit", "pytest-asyncio", "tox"] name = "pytest-xdist" version = "3.3.1" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2323,7 +2205,6 @@ testing = ["filelock"] name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -2338,7 +2219,6 @@ six = ">=1.5" name = "python-snappy" version = "0.6.1" description = "Python library for the snappy compression library from Google" -category = "dev" optional = false python-versions = "*" files = [ @@ -2396,7 +2276,6 @@ files = [ name = "pyyaml" version = "6.0" description = "YAML parser and emitter for Python" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2446,7 +2325,6 @@ files = [ name = "pyyaml-env-tag" version = "0.1" description = "A custom YAML tag for referencing environment variables in YAML files. " -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2461,7 +2339,6 @@ pyyaml = "*" name = "radon" version = "5.1.0" description = "Code Metrics in Python" -category = "dev" optional = false python-versions = "*" files = [ @@ -2478,7 +2355,6 @@ mando = ">=0.6,<0.7" name = "regex" version = "2022.10.31" description = "Alternative regular expression module, to replace re." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2576,7 +2452,6 @@ files = [ name = "requests" version = "2.31.0" description = "Python HTTP for Humans." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2598,7 +2473,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "retry" version = "0.9.2" description = "Easy to use retry decorator." -category = "dev" optional = false python-versions = "*" files = [ @@ -2614,7 +2488,6 @@ py = ">=1.4.26,<2.0.0" name = "rich" version = "13.3.4" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -2634,7 +2507,6 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] name = "s3transfer" version = "0.6.0" description = "An Amazon S3 Transfer Manager" -category = "main" optional = false python-versions = ">= 3.7" files = [ @@ -2652,7 +2524,6 @@ crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"] name = "sarif-om" version = "1.0.4" description = "Classes implementing the SARIF 2.1.0 object model." -category = "dev" optional = false python-versions = ">= 2.7" files = [ @@ -2668,7 +2539,6 @@ pbr = "*" name = "sentry-sdk" version = "1.25.1" description = "Python client for Sentry (https://sentry.io)" -category = "dev" optional = false python-versions = "*" files = [ @@ -2711,7 +2581,6 @@ tornado = ["tornado (>=5)"] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -2723,7 +2592,6 @@ files = [ name = "smmap" version = "5.0.0" description = "A pure Python implementation of a sliding window memory map manager" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2735,7 +2603,6 @@ files = [ name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2747,7 +2614,6 @@ files = [ name = "stevedore" version = "3.5.2" description = "Manage dynamic plugins for Python applications" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2763,7 +2629,6 @@ pbr = ">=2.0.0,<2.1.0 || >2.1.0" name = "sympy" version = "1.10.1" description = "Computer algebra system (CAS) in Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2778,7 +2643,6 @@ mpmath = ">=0.19" name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2790,7 +2654,6 @@ files = [ name = "typed-ast" version = "1.5.4" description = "a fork of Python 2 and 3 ast modules with type comment support" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2824,7 +2687,6 @@ files = [ name = "typeguard" version = "2.13.3" description = "Run-time type checker for Python" -category = "dev" optional = false python-versions = ">=3.5.3" files = [ @@ -2840,7 +2702,6 @@ test = ["mypy", "pytest", "typing-extensions"] name = "types-python-dateutil" version = "2.8.19.13" description = "Typing stubs for python-dateutil" -category = "dev" optional = false python-versions = "*" files = [ @@ -2852,7 +2713,6 @@ files = [ name = "types-requests" version = "2.31.0.1" description = "Typing stubs for requests" -category = "dev" optional = false python-versions = "*" files = [ @@ -2867,7 +2727,6 @@ types-urllib3 = "*" name = "types-urllib3" version = "1.26.25.10" description = "Typing stubs for urllib3" -category = "dev" optional = false python-versions = "*" files = [ @@ -2879,7 +2738,6 @@ files = [ name = "typing-extensions" version = "4.6.2" description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2891,7 +2749,6 @@ files = [ name = "urllib3" version = "1.26.15" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -2908,7 +2765,6 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] name = "verspec" version = "0.1.0" description = "Flexible version handling" -category = "dev" optional = false python-versions = "*" files = [ @@ -2923,7 +2779,6 @@ test = ["coverage", "flake8 (>=3.7)", "mypy", "pretend", "pytest"] name = "watchdog" version = "3.0.0" description = "Filesystem events monitoring" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2963,7 +2818,6 @@ watchmedo = ["PyYAML (>=3.10)"] name = "wrapt" version = "1.15.0" description = "Module for decorators, wrappers and monkey patching." -category = "main" optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -3048,7 +2902,6 @@ files = [ name = "xenon" version = "0.9.0" description = "Monitor code metrics for Python on your CI server" -category = "dev" optional = false python-versions = "*" files = [ @@ -3065,7 +2918,6 @@ requests = ">=2.0,<3.0" name = "zipp" version = "3.15.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3087,4 +2939,4 @@ validation = ["fastjsonschema"] [metadata] lock-version = "2.0" python-versions = "^3.7.4" -content-hash = "e19d37cdb2bff43a2a3a193503b12e9d7816a7875a1ac8302d04736a2f9a5052" +content-hash = "98e5bf36bbaef77382c788d839c31c7ae4934aa1226e69df648ce6aae7bdb878" diff --git a/pyproject.toml b/pyproject.toml index e9f90829c7f..1f8499f3e5a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,7 +73,7 @@ python-snappy = "^0.6.1" mypy-boto3-appconfig = "^1.26.71" mypy-boto3-cloudformation = "^1.26.149" mypy-boto3-cloudwatch = "^1.26.127" -mypy-boto3-dynamodb = "^1.26.115" +mypy-boto3-dynamodb = "^1.26.152" mypy-boto3-lambda = "^1.26.147" mypy-boto3-logs = "^1.26.149" mypy-boto3-secretsmanager = "^1.26.135" From 10b5a1a9a5ec68f9eb4044b4306ea99558e34701 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 10:05:04 +0200 Subject: [PATCH 22/41] chore(deps-dev): bump ijson from 3.2.0.post0 to 3.2.1 (#2441) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 160 ++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 81 insertions(+), 81 deletions(-) diff --git a/poetry.lock b/poetry.lock index a2d671ac4d4..39d3e35ad08 100644 --- a/poetry.lock +++ b/poetry.lock @@ -962,89 +962,89 @@ files = [ [[package]] name = "ijson" -version = "3.2.0.post0" +version = "3.2.1" description = "Iterative JSON parser with standard Python iterator interfaces" optional = false python-versions = "*" files = [ - {file = "ijson-3.2.0.post0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5809752045ef74c26adf159ed03df7fb7e7a8d656992fd7562663ed47d6d39d9"}, - {file = "ijson-3.2.0.post0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ce4be2beece2629bd24bcab147741d1532bd5ed40fb52f2b4fcde5c5bf606df0"}, - {file = "ijson-3.2.0.post0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5d365df54d18076f1d5f2ffb1eef2ac7f0d067789838f13d393b5586fbb77b02"}, - {file = "ijson-3.2.0.post0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c93ae4d49d8cf8accfedc8a8e7815851f56ceb6e399b0c186754a68fed22844"}, - {file = "ijson-3.2.0.post0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47a56e3628c227081a2aa58569cbf2af378bad8af648aa904080e87cd6644cfb"}, - {file = "ijson-3.2.0.post0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8af68fe579f6f0b9a8b3f033d10caacfed6a4b89b8c7a1d9478a8f5d8aba4a1"}, - {file = "ijson-3.2.0.post0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6eed1ddd3147de49226db4f213851cf7860493a7b6c7bd5e62516941c007094c"}, - {file = "ijson-3.2.0.post0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9ecbf85a6d73fc72f6534c38f7d92ed15d212e29e0dbe9810a465d61c8a66d23"}, - {file = "ijson-3.2.0.post0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd218b338ac68213c997d4c88437c0e726f16d301616bf837e1468901934042c"}, - {file = "ijson-3.2.0.post0-cp310-cp310-win32.whl", hash = "sha256:4e7c4fdc7d24747c8cc7d528c145afda4de23210bf4054bd98cd63bf07e4882d"}, - {file = "ijson-3.2.0.post0-cp310-cp310-win_amd64.whl", hash = "sha256:4d4e143908f47307042c9678803d27706e0e2099d0a6c1988c6cae1da07760bf"}, - {file = "ijson-3.2.0.post0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:56500dac8f52989ef7c0075257a8b471cbea8ef77f1044822742b3cbf2246e8b"}, - {file = "ijson-3.2.0.post0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:535665a77408b6bea56eb828806fae125846dff2e2e0ed4cb2e0a8e36244d753"}, - {file = "ijson-3.2.0.post0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a4465c90b25ca7903410fabe4145e7b45493295cc3b84ec1216653fbe9021276"}, - {file = "ijson-3.2.0.post0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efee1e9b4f691e1086730f3010e31c55625bc2e0f7db292a38a2cdf2774c2e13"}, - {file = "ijson-3.2.0.post0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fd55f7a46429de95383fc0d0158c1bfb798e976d59d52830337343c2d9bda5c"}, - {file = "ijson-3.2.0.post0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25919b444426f58dcc62f763d1c6be6297f309da85ecab55f51da6ca86fc9fdf"}, - {file = "ijson-3.2.0.post0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c85892d68895ba7a0b16a0e6b7d9f9a0e30e86f2b1e0f6986243473ba8735432"}, - {file = "ijson-3.2.0.post0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:27409ba44cfd006901971063d37699f72e092b5efaa1586288b5067d80c6b5bd"}, - {file = "ijson-3.2.0.post0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:11dfd64633fe1382c4237477ac3836f682ca17e25e0d0799e84737795b0611df"}, - {file = "ijson-3.2.0.post0-cp311-cp311-win32.whl", hash = "sha256:41e955e173f77f54337fecaaa58a35c464b75e232b1f939b282497134a4d4f0e"}, - {file = "ijson-3.2.0.post0-cp311-cp311-win_amd64.whl", hash = "sha256:b3bdd2e12d9b9a18713dd6f3c5ef3734fdab25b79b177054ba9e35ecc746cb6e"}, - {file = "ijson-3.2.0.post0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:26b57838e712b8852c40ec6d74c6de8bb226446440e1af1354c077a6f81b9142"}, - {file = "ijson-3.2.0.post0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6464242f7895268d3086d7829ef031b05c77870dad1e13e51ef79d0a9cfe029"}, - {file = "ijson-3.2.0.post0-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3c6cf18b61b94db9590f86af0dd60edbccb36e151643152b8688066f677fbc9"}, - {file = "ijson-3.2.0.post0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:992e9e68003df32e2aa0f31eb82c0a94f21286203ab2f2b2c666410e17b59d2f"}, - {file = "ijson-3.2.0.post0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:d3e255ef05b434f20fc9d4b18ea15733d1038bec3e4960d772b06216fa79e82d"}, - {file = "ijson-3.2.0.post0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:424232c2bf3e8181f1b572db92c179c2376b57eba9fc8931453fba975f48cb80"}, - {file = "ijson-3.2.0.post0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bced6cd5b09d4d002dda9f37292dd58d26eb1c4d0d179b820d3708d776300bb4"}, - {file = "ijson-3.2.0.post0-cp36-cp36m-win32.whl", hash = "sha256:a8c84dff2d60ae06d5280ec87cd63050bbd74a90c02bfc7c390c803cfc8ac8fc"}, - {file = "ijson-3.2.0.post0-cp36-cp36m-win_amd64.whl", hash = "sha256:a340413a9bf307fafd99254a4dd4ac6c567b91a205bf896dde18888315fd7fcd"}, - {file = "ijson-3.2.0.post0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b3456cd5b16ec9db3ef23dd27f37bf5a14f765e8272e9af3e3de9ee9a4cba867"}, - {file = "ijson-3.2.0.post0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0eb838b4e4360e65c00aa13c78b35afc2477759d423b602b60335af5bed3de5b"}, - {file = "ijson-3.2.0.post0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe7f414edd69dd9199b0dfffa0ada22f23d8009e10fe2a719e0993b7dcc2e6e2"}, - {file = "ijson-3.2.0.post0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:183841b8d033ca95457f61fb0719185dc7f51a616070bdf1dcaf03473bed05b2"}, - {file = "ijson-3.2.0.post0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1302dc6490da7d44c3a76a5f0b87d8bec9f918454c6d6e6bf4ed922e47da58bb"}, - {file = "ijson-3.2.0.post0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3b21b1ecd20ed2f918f6f99cdfa68284a416c0f015ffa64b68fa933df1b24d40"}, - {file = "ijson-3.2.0.post0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e97e6e07851cefe7baa41f1ebf5c0899d2d00d94bfef59825752e4c784bebbe8"}, - {file = "ijson-3.2.0.post0-cp37-cp37m-win32.whl", hash = "sha256:cd0450e76b9c629b7f86e7d5b91b7cc9c281dd719630160a992b19a856f7bdbd"}, - {file = "ijson-3.2.0.post0-cp37-cp37m-win_amd64.whl", hash = "sha256:bed8dcb7dbfdb98e647ad47676045e0891f610d38095dcfdae468e1e1efb2766"}, - {file = "ijson-3.2.0.post0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a7698bc480df76073067017f73ba4139dbaae20f7a6c9a0c7855b9c5e9a62124"}, - {file = "ijson-3.2.0.post0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2f204f6d4cedeb28326c230a0b046968b5263c234c65a5b18cee22865800fff7"}, - {file = "ijson-3.2.0.post0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9829a17f6f78d7f4d0aeff28c126926a1e5f86828ebb60d6a0acfa0d08457f9f"}, - {file = "ijson-3.2.0.post0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f470f3d750e00df86e03254fdcb422d2f726f4fb3a0d8eeee35e81343985e58a"}, - {file = "ijson-3.2.0.post0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb167ee21d9c413d6b0ab65ec12f3e7ea0122879da8b3569fa1063526f9f03a8"}, - {file = "ijson-3.2.0.post0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84eed88177f6c243c52b280cb094f751de600d98d2221e0dec331920894889ec"}, - {file = "ijson-3.2.0.post0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:53f1a13eb99ab514c562869513172135d4b55a914b344e6518ba09ad3ef1e503"}, - {file = "ijson-3.2.0.post0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f6785ba0f65eb64b1ce3b7fcfec101085faf98f4e77b234f14287fd4138ffb25"}, - {file = "ijson-3.2.0.post0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:79b94662c2e9d366ab362c2c5858097eae0da100dea0dfd340db09ab28c8d5e8"}, - {file = "ijson-3.2.0.post0-cp38-cp38-win32.whl", hash = "sha256:5242cb2313ba3ece307b426efa56424ac13cc291c36f292b501d412a98ad0703"}, - {file = "ijson-3.2.0.post0-cp38-cp38-win_amd64.whl", hash = "sha256:775444a3b647350158d0b3c6c39c88b4a0995643a076cb104bf25042c9aedcf8"}, - {file = "ijson-3.2.0.post0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1d64ffaab1d006a4fa9584a4c723e95cc9609bf6c3365478e250cd0bffaaadf3"}, - {file = "ijson-3.2.0.post0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:434e57e7ec5c334ccb0e67bb4d9e60c264dcb2a3843713dbeb12cb19fe42a668"}, - {file = "ijson-3.2.0.post0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:158494bfe89ccb32618d0e53b471364080ceb975462ec464d9f9f37d9832b653"}, - {file = "ijson-3.2.0.post0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f20072376e338af0e51ccecb02335b4e242d55a9218a640f545be7fc64cca99"}, - {file = "ijson-3.2.0.post0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3e8d46c1004afcf2bf513a8fb575ee2ec3d8009a2668566b5926a2dcf7f1a45"}, - {file = "ijson-3.2.0.post0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:986a0347fe19e5117a5241276b72add570839e5bcdc7a6dac4b538c5928eeff5"}, - {file = "ijson-3.2.0.post0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:535a59d61b9aef6fc2a3d01564c1151e38e5a44b92cd6583cb4e8ccf0f58043f"}, - {file = "ijson-3.2.0.post0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:830de03f391f7e72b8587bb178c22d534da31153e9ee4234d54ef82cde5ace5e"}, - {file = "ijson-3.2.0.post0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6def9ac8d73b76cb02e9e9837763f27f71e5e67ec0afae5f1f4cf8f61c39b1ac"}, - {file = "ijson-3.2.0.post0-cp39-cp39-win32.whl", hash = "sha256:11bb84a53c37e227e733c6dffad2037391cf0b3474bff78596dc4373b02008a0"}, - {file = "ijson-3.2.0.post0-cp39-cp39-win_amd64.whl", hash = "sha256:f349bee14d0a4a72ba41e1b1cce52af324ebf704f5066c09e3dd04cfa6f545f0"}, - {file = "ijson-3.2.0.post0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5418066666b25b05f2b8ae2698408daa0afa68f07b0b217f2ab24465b7e9cbd9"}, - {file = "ijson-3.2.0.post0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ccc4d4b947549f9c431651c02b95ef571412c78f88ded198612a41d5c5701a0"}, - {file = "ijson-3.2.0.post0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dcec67fc15e5978ad286e8cc2a3f9347076e28e0e01673b5ace18c73da64e3ff"}, - {file = "ijson-3.2.0.post0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ee9537e8a8aa15dd2d0912737aeb6265e781e74f7f7cad8165048fcb5f39230"}, - {file = "ijson-3.2.0.post0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:03dfd4c8ed19e704d04b0ad4f34f598dc569fd3f73089f80eed698e7f6069233"}, - {file = "ijson-3.2.0.post0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2d50b2ad9c6c51ca160aa60de7f4dacd1357c38d0e503f51aed95c1c1945ff53"}, - {file = "ijson-3.2.0.post0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51c1db80d7791fb761ad9a6c70f521acd2c4b0e5afa2fe0d813beb2140d16c37"}, - {file = "ijson-3.2.0.post0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13f2939db983327dd0492f6c1c0e77be3f2cbf9b620c92c7547d1d2cd6ef0486"}, - {file = "ijson-3.2.0.post0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f9d449f86f8971c24609e319811f7f3b6b734f0218c4a0e799debe19300d15b"}, - {file = "ijson-3.2.0.post0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7e0d1713a9074a7677eb8e43f424b731589d1c689d4676e2f57a5ce59d089e89"}, - {file = "ijson-3.2.0.post0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c8646eb81eec559d7d8b1e51a5087299d06ecab3bc7da54c01f7df94350df135"}, - {file = "ijson-3.2.0.post0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fe3a53e00c59de33b825ba8d6d39f544a7d7180983cd3d6bd2c3794ae35442"}, - {file = "ijson-3.2.0.post0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93aaec00cbde65c192f15c21f3ee44d2ab0c11eb1a35020b5c4c2676f7fe01d0"}, - {file = "ijson-3.2.0.post0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00594ed3ef2218fee8c652d9e7f862fb39f8251b67c6379ef12f7e044bf6bbf3"}, - {file = "ijson-3.2.0.post0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1a75cfb34217b41136b714985be645f12269e4345da35d7b48aabd317c82fd10"}, - {file = "ijson-3.2.0.post0.tar.gz", hash = "sha256:80a5bd7e9923cab200701f67ad2372104328b99ddf249dbbe8834102c852d316"}, + {file = "ijson-3.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6f827f6961f093e1055a2be0c3137f0e7d667979da455ac9648f72d4a2bb8970"}, + {file = "ijson-3.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b6e51f4497065cd0d09f5e906cd538a8d22609eab716e3c883769acf147ab1b6"}, + {file = "ijson-3.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f022686c40bff3e340627a5a0c9212718d529e787ada3b76ba546d47a9ecdbbd"}, + {file = "ijson-3.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4105c15a13fa1dc24ebd3bf2e679fa14dcbfcc48bc39138a0fa3f4ddf6cc09b"}, + {file = "ijson-3.2.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:404423e666f185dfb753ddc92705c84dffdc4cc872aaf825bbe0607893cb5b02"}, + {file = "ijson-3.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39e71f32830827cf21d0233a814092e5a23668e18f52eca5cac4f670d9df1240"}, + {file = "ijson-3.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43af7ed5292caa1452747e2b62485b6c0ece4bcbc5bf6f2758abd547e4124a14"}, + {file = "ijson-3.2.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e805aa6897a11b0f73f1f6bca078981df8960aeeccf527a214f240409c742bab"}, + {file = "ijson-3.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5b2df0bd84889e9017a670328fe3e82ec509fd6744c7ac2c99c7ee2300d76afa"}, + {file = "ijson-3.2.1-cp310-cp310-win32.whl", hash = "sha256:675259c7ea7f51ffaf8cb9e79bf875e28bb09622892943f4f415588fd7ab7bec"}, + {file = "ijson-3.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:90d4b2eb771a3585c8186820fe50e3282ef62477b865e765a50a8295674abeac"}, + {file = "ijson-3.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fc581a61e210bf6013c1fa6536566e51127be1cfbd69539b63d8b813206d2fe0"}, + {file = "ijson-3.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75cdf7ad4c00a8f5ac94ff27e3b7c1bf5ac463f125bca2be1744c5bc9600db5c"}, + {file = "ijson-3.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:85a2bf4636ace4d92e7c5d857a1c5694f42407c868953cf2927f18127bcd0d58"}, + {file = "ijson-3.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fe0cb66e7dd4aa11da5fff60bdf5ee04819a5e6a57acf7ca12c65f7fc009afc"}, + {file = "ijson-3.2.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6f7957ad38cb714378944032f2c2ee9c6531b5b0b38c5ccd08cedbb0ceddd02"}, + {file = "ijson-3.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13283d264cca8a63e5bad91e82eec39711e95893e7e8d4a419799a8c5f85203a"}, + {file = "ijson-3.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:12c24cde850fe79bc806be0e9fc38b47dd5ac0a223070ccb12e9b695425e2936"}, + {file = "ijson-3.2.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2ce8eed838e5a0791cb5948117b5453f2b3b3c28d93d06ee2bbf2c198c47881c"}, + {file = "ijson-3.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b81c2589f191b0dc741f532be00b4bea617297dd9698431c8053e2d28272d4db"}, + {file = "ijson-3.2.1-cp311-cp311-win32.whl", hash = "sha256:ba2beac56ac96f728d0f2430e4c667c66819a423d321bb9db9ebdebd803e1b5b"}, + {file = "ijson-3.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:c71614ed4bbc6a32ff1e42d7ce92a176fb67d658913343792d2c4567aa130817"}, + {file = "ijson-3.2.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:683fc8b0ea085e75ea34044fdc70649b37367d494f132a2bd1e59d7135054d89"}, + {file = "ijson-3.2.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deeaecec2f4e20e8bec20b0a5cdc34daebe7903f2e700f7dcaef68b5925d35ea"}, + {file = "ijson-3.2.1-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11923ac3188877f19dbb7051f7345202701cc39bf8e5ac44f8ae536c9eca8c82"}, + {file = "ijson-3.2.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:400deefcdae21e90fc39c1dcfc6ba2df24537e8c65bd57b763ed5256b73ba64d"}, + {file = "ijson-3.2.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:56bc4bad53770710a3a91944fe640fdeb269987a14352b74ebbad2aa55801c00"}, + {file = "ijson-3.2.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:f5a179523e085126844c6161aabcd193dbb5747bd01fadb68e92abf048f32ec9"}, + {file = "ijson-3.2.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:ee24655986e4415fbb7a0cf51445fff3072ceac0e219f4bbbd5c53535a3c5680"}, + {file = "ijson-3.2.1-cp36-cp36m-win32.whl", hash = "sha256:4a5c672b0540005c1bb0bba97aa559a87a2e4ee409fc68e2f5ba5b30f009ac99"}, + {file = "ijson-3.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:cfaf1d89b0e122e69c87a15db6d6f44feb9db96d2af7fe88cdc464177a257b5d"}, + {file = "ijson-3.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1cbd052eb67c1b3611f25974ba967886e89391faaf55afec93808c19f06ca612"}, + {file = "ijson-3.2.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f13ffc491886e5d7bde7d68712d168bce0141b2a918db1164bc8599c0123e293"}, + {file = "ijson-3.2.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc4c4fc6bafc777f8422fe36edb1cbd72a13cb29695893a064c9c95776a4bdf9"}, + {file = "ijson-3.2.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a42fcb2bf9748c26f004690b2feb6e13e4875bb7c9d83535f887c21e0a982a7c"}, + {file = "ijson-3.2.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0c92f7bc2f3a947c2ba7f7aa48382c36079f8259c930e81d9164341f9b853c45"}, + {file = "ijson-3.2.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fd497042db562379339660e787bc8679ed3abaa740768d39bc3746e769e7c7a5"}, + {file = "ijson-3.2.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7d61c7cd8ddd75dcef818ff5a111a31b902a6a0e410ee0c2b2ecaa6dac92658a"}, + {file = "ijson-3.2.1-cp37-cp37m-win32.whl", hash = "sha256:36caf624d263fc40e7e805d759d09ea368d8cf497aecb3241ac2f0a286ad8eca"}, + {file = "ijson-3.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:32f9ed25ff80942e433119600bca13b86a8f9b8b0966edbc1d91a48ccbdd4d54"}, + {file = "ijson-3.2.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e89bbd747140eac3a3c9e7e5835b90d85c4a02763fc5134861bfc1ea03b66ae7"}, + {file = "ijson-3.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d69b4b1d509de36ec42a0e4af30ede39fb754e4039b2928ef7282ebc2125ffdd"}, + {file = "ijson-3.2.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e7feb0771f50deabe6ce85b210fa9e005843d3d3c60fb3315d69e1f9d0d75e0c"}, + {file = "ijson-3.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fd8148a363888054ff06eaaa1103f2f98720ab39666084a214e4fedfc13cf64"}, + {file = "ijson-3.2.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:598638dcc5141e9ae269903901877103f5362e0db4443e34721df8f8d34577b4"}, + {file = "ijson-3.2.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e979190b7d0fabca20d6b7224ab1c1aa461ad1ab72ba94f1bb1e5894cd59f342"}, + {file = "ijson-3.2.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bc810eb80b4f486c7957201ba2a53f53ddc9b3233af67e4359e29371bf04883b"}, + {file = "ijson-3.2.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:26e758584611dfe826dd18ffd94dc0d8a062ce56e41674ad3bfa371c7b78c4b5"}, + {file = "ijson-3.2.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:24e9ae5b35b85ea094b6c36495bc856089254aed6a48bada8d7eec5a04f74439"}, + {file = "ijson-3.2.1-cp38-cp38-win32.whl", hash = "sha256:4b5dc7b5b4b8cb3087d188f37911cd67e26672d33d3571e73440de3f0a86f7e6"}, + {file = "ijson-3.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:1af94ff40609270bbb3eac47e072582bb578f5023fac8408cccd80fe5892d221"}, + {file = "ijson-3.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2dda67affceebc52c8bc5fe72c3a4a1e338e4d4b0497dbac5089c2d3862df214"}, + {file = "ijson-3.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bd780303ddfedc8d57cdb9f2d53a8cea2f2f4a6fb857bf8fe5a0c3ab1d4ca901"}, + {file = "ijson-3.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4fbab6af1bab88a8e46beda08cf44610eed0adb8d157a1a60b4bb6c3a121c6de"}, + {file = "ijson-3.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97a07988a1e0ce2bc8e8a62eb5f25195a3bd58a939ac353cbc6018a548cc08d"}, + {file = "ijson-3.2.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a65671a6826ae723837143914c823ad7bcc0d1a3e38d87c71df897a2556fb48f"}, + {file = "ijson-3.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1806372008bbed9ee92db5747e38c047fa1c4ee89cb2dd5daaa57feb46ce50a"}, + {file = "ijson-3.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:91e5a8e96f78a59e2520078c227a4fec5bf91c13adeded9e33fb13981cb823c3"}, + {file = "ijson-3.2.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1f820fce8ef093718f2319ff6f1322390664659b783775919dadccb1b470153d"}, + {file = "ijson-3.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bca3e8c91a1076a20620dbaa6a2848772b0e8a4055e86d42d3fa39221b53ed1a"}, + {file = "ijson-3.2.1-cp39-cp39-win32.whl", hash = "sha256:de87f137b7438d43840f4339a37d4e6a58c987f4bb2a70609969f854f8ae20f3"}, + {file = "ijson-3.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:0caebb8350b47266a58b766ec08e1de441d6d160702c428b5cf7504d93c832c4"}, + {file = "ijson-3.2.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:37389785c1abd27fcc24800fcfa9a6b1022743413e4056507fd32356b623ff33"}, + {file = "ijson-3.2.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b364b82231d51cbeae52468c3b27e8a042e544ab764c8f3975e912cf010603f"}, + {file = "ijson-3.2.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a5999d0ec28a8ec47cf20c736fd4f895dc077bf6441bf237b00b074315a295d"}, + {file = "ijson-3.2.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd481857a39305517fb6f1313d558c2dc4e78c9e9384cc5bc1c3e28f1afbedf"}, + {file = "ijson-3.2.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:545f62f12f89350d4d73f2a779cb269198ae578fac080085a1927148b803e602"}, + {file = "ijson-3.2.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4d5622505d01c2f3d7b9638c1eb8c747eb550936b505225893704289ff28576f"}, + {file = "ijson-3.2.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20293bb36423b129fad3753858ccf7b2ccb5b2c0d3759efe810d0b9d79633a7e"}, + {file = "ijson-3.2.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cd8a4921b852fd2cb5b0c985540c97ff6893139a57fe7121d510ec5d1c0ca44"}, + {file = "ijson-3.2.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc902ff1ae1efed7d526294d7a9dd3df66d29b2cdc05fb5479838fef1327a534"}, + {file = "ijson-3.2.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2925a7978d8170146a9cb49a15a982b71fbbf21980bf2e16cd90c528545b7c02"}, + {file = "ijson-3.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c21c6509f6944939399f3630c5dc424d30d71d375f6cd58f9af56158fdf7251c"}, + {file = "ijson-3.2.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5729fc7648bc972d70922d7dad15459cca3a9e5ed0328eb9ae3ffa004066194"}, + {file = "ijson-3.2.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:805a2d5ed5a15d60327bc9347f2d4125ab621fb18071db98b1c598f1ee99e8f1"}, + {file = "ijson-3.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d0220a4b6c63f44589e429157174e3f4b8d1e534d5fb82bdb43a7f8dd77ae4b"}, + {file = "ijson-3.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:271d9b7c083f65c58ff0afd9dbb5d2f3d445f734632aebfef4a261b0a337abdb"}, + {file = "ijson-3.2.1.tar.gz", hash = "sha256:8574bf19f31fab870488769ad919a80f130825236ac8bde9a733f69c2961d7a7"}, ] [[package]] @@ -2939,4 +2939,4 @@ validation = ["fastjsonschema"] [metadata] lock-version = "2.0" python-versions = "^3.7.4" -content-hash = "98e5bf36bbaef77382c788d839c31c7ae4934aa1226e69df648ce6aae7bdb878" +content-hash = "2a9cf8422e1643934adcfb7e04c7790e474a715f382b70b6b241b47c959fe2d4" diff --git a/pyproject.toml b/pyproject.toml index 1f8499f3e5a..33cb28e768c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,7 +86,7 @@ mkdocs-material = "^9.1.15" filelock = "^3.12.0" checksumdir = "^1.2.0" mypy-boto3-appconfigdata = "^1.26.70" -ijson = "^3.2.0" +ijson = "^3.2.1" typed-ast = { version = "^1.5.4", python = "< 3.8"} hvac = "^1.1.0" aws-requests-auth = "^0.4.3" From 84ea0d50041100e8f39579d96b46b09f912b8218 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 10:13:24 +0200 Subject: [PATCH 23/41] chore(deps-dev): bump filelock from 3.12.0 to 3.12.2 (#2446) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 12 ++++++------ pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index 39d3e35ad08..3f42f5ea634 100644 --- a/poetry.lock +++ b/poetry.lock @@ -651,18 +651,18 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc [[package]] name = "filelock" -version = "3.12.0" +version = "3.12.2" description = "A platform independent file lock." optional = false python-versions = ">=3.7" files = [ - {file = "filelock-3.12.0-py3-none-any.whl", hash = "sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"}, - {file = "filelock-3.12.0.tar.gz", hash = "sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718"}, + {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, + {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, ] [package.extras] -docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] [[package]] name = "flake8" @@ -2939,4 +2939,4 @@ validation = ["fastjsonschema"] [metadata] lock-version = "2.0" python-versions = "^3.7.4" -content-hash = "2a9cf8422e1643934adcfb7e04c7790e474a715f382b70b6b241b47c959fe2d4" +content-hash = "105e5216c694fa50bb949e26f4bba2cac37cc77d36e85603655fdddfc9f7a33f" diff --git a/pyproject.toml b/pyproject.toml index 33cb28e768c..07ea22cee54 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -83,7 +83,7 @@ mypy-boto3-xray = "^1.26.122" types-requests = "^2.31.0" typing-extensions = "^4.6.2" mkdocs-material = "^9.1.15" -filelock = "^3.12.0" +filelock = "^3.12.2" checksumdir = "^1.2.0" mypy-boto3-appconfigdata = "^1.26.70" ijson = "^3.2.1" From decee5949eff01b57bfbbcfe95a0a80ef8dc3f88 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 13:12:18 +0200 Subject: [PATCH 24/41] chore(deps-dev): bump pytest from 7.3.1 to 7.3.2 (#2443) Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.3.1 to 7.3.2. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.3.1...7.3.2) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3f42f5ea634..d257a1690d9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2086,13 +2086,13 @@ files = [ [[package]] name = "pytest" -version = "7.3.1" +version = "7.3.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, - {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, + {file = "pytest-7.3.2-py3-none-any.whl", hash = "sha256:cdcbd012c9312258922f8cd3f1b62a6580fdced17db6014896053d47cddf9295"}, + {file = "pytest-7.3.2.tar.gz", hash = "sha256:ee990a3cc55ba808b80795a79944756f315c67c12b56abd3ac993a7b8c17030b"}, ] [package.dependencies] @@ -2105,7 +2105,7 @@ pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" @@ -2939,4 +2939,4 @@ validation = ["fastjsonschema"] [metadata] lock-version = "2.0" python-versions = "^3.7.4" -content-hash = "105e5216c694fa50bb949e26f4bba2cac37cc77d36e85603655fdddfc9f7a33f" +content-hash = "66fc803d39e8cd22fadbedfda721019b4b94eb81990ba144f9b39f23aef801c4" diff --git a/pyproject.toml b/pyproject.toml index 07ea22cee54..1d3cf74bec3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ typing-extensions = "^4.6.2" [tool.poetry.dev-dependencies] coverage = {extras = ["toml"], version = "^7.2"} -pytest = "^7.3.1" +pytest = "^7.3.2" black = "^23.3" boto3 = "^1.18" flake8 = [ From 928e43a057ebbcff0c412ea21ed5ecbe26a8f86a Mon Sep 17 00:00:00 2001 From: Erika Yao <71943596+erikayao93@users.noreply.github.com> Date: Wed, 14 Jun 2023 07:06:52 -0500 Subject: [PATCH 25/41] feat(logger): type log record in LambdaPowertoolsFormatter with TypedDict (#2419) Co-authored-by: erikayao93 Co-authored-by: Heitor Lessa Co-authored-by: Leandro Damascena --- .pre-commit-config.yaml | 8 +-- aws_lambda_powertools/logging/formatter.py | 19 ++++--- .../logging/formatters/datadog.py | 7 +-- aws_lambda_powertools/logging/types.py | 50 +++++++++++++++++++ docs/core/logger.md | 2 +- .../logger/src/bring_your_own_formatter.py | 9 ++-- 6 files changed, 76 insertions(+), 19 deletions(-) create mode 100644 aws_lambda_powertools/logging/types.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 73684a22221..88a29906a98 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.4.0 + rev: "f71fa2c1f9cf5cb705f73dffe4b21f7c61470ba9" # v4.4.0 hooks: - id: check-merge-conflict - id: trailing-whitespace @@ -30,9 +30,9 @@ repos: language: system types: [python] - repo: https://github.com/igorshubovych/markdownlint-cli - rev: "11c08644ce6df850480d98f628596446a526cbc6" # frozen: v0.31.1 + rev: "ce0d77ac47dc921b62429804fe763d4d35f66a76" # v0.34.0 hooks: - - id: markdownlint + - id: markdownlint-docker args: ["--fix"] - repo: local hooks: @@ -43,7 +43,7 @@ repos: types: [yaml] files: examples/.* - repo: https://github.com/rhysd/actionlint - rev: v1.6.23 + rev: "fd7ba3c382e13dcc0248e425b4cbc3f1185fa3ee" # v1.6.24 hooks: - id: actionlint-docker args: [-pyflakes=] diff --git a/aws_lambda_powertools/logging/formatter.py b/aws_lambda_powertools/logging/formatter.py index 600a1e726c4..03bb4211f49 100644 --- a/aws_lambda_powertools/logging/formatter.py +++ b/aws_lambda_powertools/logging/formatter.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import inspect import json import logging @@ -8,8 +10,9 @@ from functools import partial from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union -from ..shared import constants -from ..shared.functions import powertools_dev_is_set +from aws_lambda_powertools.logging.types import LogRecord +from aws_lambda_powertools.shared import constants +from aws_lambda_powertools.shared.functions import powertools_dev_is_set RESERVED_LOG_ATTRS = ( "name", @@ -66,12 +69,12 @@ class LambdaPowertoolsFormatter(BasePowertoolsFormatter): def __init__( self, - json_serializer: Optional[Callable[[Dict], str]] = None, - json_deserializer: Optional[Callable[[Union[Dict, str, bool, int, float]], str]] = None, - json_default: Optional[Callable[[Any], Any]] = None, - datefmt: Optional[str] = None, + json_serializer: Callable[[LogRecord], str] | None = None, + json_deserializer: Callable[[Dict | str | bool | int | float], str] | None = None, + json_default: Callable[[Any], Any] | None = None, + datefmt: str | None = None, use_datetime_directive: bool = False, - log_record_order: Optional[List[str]] = None, + log_record_order: List[str] | None = None, utc: bool = False, use_rfc3339: bool = False, **kwargs, @@ -144,7 +147,7 @@ def __init__( super().__init__(datefmt=self.datefmt) - def serialize(self, log: Dict) -> str: + def serialize(self, log: LogRecord) -> str: """Serialize structured log dict to JSON str""" return self.json_serializer(log) diff --git a/aws_lambda_powertools/logging/formatters/datadog.py b/aws_lambda_powertools/logging/formatters/datadog.py index fa92bf74598..15218302250 100644 --- a/aws_lambda_powertools/logging/formatters/datadog.py +++ b/aws_lambda_powertools/logging/formatters/datadog.py @@ -1,15 +1,16 @@ from __future__ import annotations -from typing import Any, Callable +from typing import Any, Callable, Dict from aws_lambda_powertools.logging.formatter import LambdaPowertoolsFormatter +from aws_lambda_powertools.logging.types import LogRecord class DatadogLogFormatter(LambdaPowertoolsFormatter): def __init__( self, - json_serializer: Callable[[dict], str] | None = None, - json_deserializer: Callable[[dict | str | bool | int | float], str] | None = None, + json_serializer: Callable[[LogRecord], str] | None = None, + json_deserializer: Callable[[Dict | str | bool | int | float], str] | None = None, json_default: Callable[[Any], Any] | None = None, datefmt: str | None = None, use_datetime_directive: bool = False, diff --git a/aws_lambda_powertools/logging/types.py b/aws_lambda_powertools/logging/types.py new file mode 100644 index 00000000000..ede369491f1 --- /dev/null +++ b/aws_lambda_powertools/logging/types.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +import sys + +if sys.version_info >= (3, 11): + from typing import NotRequired +else: + from typing_extensions import NotRequired + +if sys.version_info >= (3, 8): + from typing import TypedDict +else: + from typing_extensions import TypedDict + +if sys.version_info >= (3, 10): + from typing import TypeAlias +else: + from typing_extensions import TypeAlias + +from typing import Any, Dict, List, Union + +LogRecord: TypeAlias = Union[Dict[str, Any], "PowertoolsLogRecord"] + + +class PowertoolsLogRecord(TypedDict): + # Base fields (required) + level: str + location: str + message: Dict[str, Any] | str | bool | List[Any] + timestamp: str | int + service: str + + # Fields from logger.inject_lambda_context + cold_start: NotRequired[bool] + function_name: NotRequired[str] + function_memory_size: NotRequired[int] + function_arn: NotRequired[str] + function_request_id: NotRequired[str] + # From logger.inject_lambda_context if AWS X-Ray is enabled + xray_trace_id: NotRequired[str] + + # If sample_rate is defined + sampling_rate: NotRequired[float] + + # From logger.set_correlation_id + correlation_id: NotRequired[str] + + # Fields from logger.exception + exception_name: NotRequired[str] + exception: NotRequired[str] diff --git a/docs/core/logger.md b/docs/core/logger.md index 16f81e8b2ba..08bf663bb0a 100644 --- a/docs/core/logger.md +++ b/docs/core/logger.md @@ -604,7 +604,7 @@ For these, you can override the `serialize` method from [LambdaPowertoolsFormatt === "bring_your_own_formatter.py" - ```python hl_lines="2 5-6 12" + ```python hl_lines="2-3 6 11-12 15" --8<-- "examples/logger/src/bring_your_own_formatter.py" ``` diff --git a/examples/logger/src/bring_your_own_formatter.py b/examples/logger/src/bring_your_own_formatter.py index 1b85105f930..a4b303558bb 100644 --- a/examples/logger/src/bring_your_own_formatter.py +++ b/examples/logger/src/bring_your_own_formatter.py @@ -1,12 +1,15 @@ from aws_lambda_powertools import Logger from aws_lambda_powertools.logging.formatter import LambdaPowertoolsFormatter +from aws_lambda_powertools.logging.types import LogRecord class CustomFormatter(LambdaPowertoolsFormatter): - def serialize(self, log: dict) -> str: + def serialize(self, log: LogRecord) -> str: """Serialize final structured log dict to JSON str""" - log["event"] = log.pop("message") # rename message key to event - return self.json_serializer(log) # use configured json serializer + # in this example, log["message"] is a required field + # but we want to remap to "event" and delete "message", hence mypy ignore checks + log["event"] = log.pop("message") # type: ignore[typeddict-unknown-key,misc] + return self.json_serializer(log) logger = Logger(service="payment", logger_formatter=CustomFormatter()) From b4a68782e102396fa9118308c5f55926f5a126d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Jun 2023 15:26:12 +0200 Subject: [PATCH 26/41] chore(deps): bump docker/setup-buildx-action from 2.6.0 to 2.7.0 (#2450) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/publish_v2_layer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish_v2_layer.yml b/.github/workflows/publish_v2_layer.yml index cb169596520..90e8a010ab0 100644 --- a/.github/workflows/publish_v2_layer.yml +++ b/.github/workflows/publish_v2_layer.yml @@ -90,7 +90,7 @@ jobs: # NOTE: we need QEMU to build Layer against a different architecture (e.g., ARM) - name: Set up Docker Buildx id: builder - uses: docker/setup-buildx-action@6a58db7e0d21ca03e6c44877909e80e45217eed2 # v2.6.0 + uses: docker/setup-buildx-action@ecf95283f03858871ff00b787d79c419715afc34 # v2.7.0 with: install: true driver: docker From 5a84149f7b6b4cf6364fbe4ef0694130e6f4dc26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Jun 2023 15:26:43 +0200 Subject: [PATCH 27/41] chore(deps-dev): bump cfn-lint from 0.77.7 to 0.77.8 (#2451) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index d257a1690d9..cadb4dac256 100644 --- a/poetry.lock +++ b/poetry.lock @@ -352,13 +352,13 @@ files = [ [[package]] name = "cfn-lint" -version = "0.77.7" +version = "0.77.8" description = "Checks CloudFormation templates for practices and behaviour that could potentially be improved" optional = false python-versions = ">=3.7, <=4.0, !=4.0" files = [ - {file = "cfn-lint-0.77.7.tar.gz", hash = "sha256:152073ae6e7010de358903aa48cf8cc8eadc8c497f61ba04d46d551175a667ee"}, - {file = "cfn_lint-0.77.7-py3-none-any.whl", hash = "sha256:7948cf81152d8b46775da0ac1ffee67767ac53a5869226eee5c309000f6ebd40"}, + {file = "cfn-lint-0.77.8.tar.gz", hash = "sha256:34364e687670f8c7e8d77155baddd18c26dadc5e188fd6bdd2af260dbe14404d"}, + {file = "cfn_lint-0.77.8-py3-none-any.whl", hash = "sha256:f20bd659837c7352f605b34bc520c7a38ebb079fd6996b645fe87e14b2c79718"}, ] [package.dependencies] @@ -2939,4 +2939,4 @@ validation = ["fastjsonschema"] [metadata] lock-version = "2.0" python-versions = "^3.7.4" -content-hash = "66fc803d39e8cd22fadbedfda721019b4b94eb81990ba144f9b39f23aef801c4" +content-hash = "2784e820c3c01a1ed3b1d16aad2e903ce550c82b09a918281dc46f728c284398" diff --git a/pyproject.toml b/pyproject.toml index 1d3cf74bec3..ca140efe8a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -100,7 +100,7 @@ all = ["pydantic", "aws-xray-sdk", "fastjsonschema"] aws-sdk = ["boto3"] [tool.poetry.group.dev.dependencies] -cfn-lint = "0.77.7" +cfn-lint = "0.77.8" mypy = "^1.1.1" types-python-dateutil = "^2.8.19.6" httpx = ">=0.23.3,<0.25.0" From 3a3f342c064b8b832abfd370af5495658baaae25 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Jun 2023 13:28:26 +0000 Subject: [PATCH 28/41] chore(deps-dev): bump mypy-boto3-s3 from 1.26.127 to 1.26.153 (#2452) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index cadb4dac256..d6b3a2d1bca 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1702,13 +1702,13 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} [[package]] name = "mypy-boto3-s3" -version = "1.26.127" -description = "Type annotations for boto3.S3 1.26.127 service generated with mypy-boto3-builder 7.14.5" +version = "1.26.153" +description = "Type annotations for boto3.S3 1.26.153 service generated with mypy-boto3-builder 7.14.5" optional = false python-versions = ">=3.7" files = [ - {file = "mypy-boto3-s3-1.26.127.tar.gz", hash = "sha256:0e548b97c6a2589f7bff5d26a1ca101622749771379226e3ad0822629d0613c5"}, - {file = "mypy_boto3_s3-1.26.127-py3-none-any.whl", hash = "sha256:21e647caa18d98dbbc706597c9b27d41674f18850f42b2cfdb9a39b39820e470"}, + {file = "mypy-boto3-s3-1.26.153.tar.gz", hash = "sha256:2d50350394aea8f934e5bc67f6ad0f7f51544bb07640275a2db9fd3a040816b1"}, + {file = "mypy_boto3_s3-1.26.153-py3-none-any.whl", hash = "sha256:dcf903bdcdbc955f4d5ba62cb8a58069808f357a67b02a4fb6b888596c2ee455"}, ] [package.dependencies] @@ -2939,4 +2939,4 @@ validation = ["fastjsonschema"] [metadata] lock-version = "2.0" python-versions = "^3.7.4" -content-hash = "2784e820c3c01a1ed3b1d16aad2e903ce550c82b09a918281dc46f728c284398" +content-hash = "5317bebeb3cd902772ccbbb9e302988b98a0c19923958efee657a90799c86c23" diff --git a/pyproject.toml b/pyproject.toml index ca140efe8a6..a0465e458f1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,7 +78,7 @@ mypy-boto3-lambda = "^1.26.147" mypy-boto3-logs = "^1.26.149" mypy-boto3-secretsmanager = "^1.26.135" mypy-boto3-ssm = "^1.26.97" -mypy-boto3-s3 = "^1.26.127" +mypy-boto3-s3 = "^1.26.153" mypy-boto3-xray = "^1.26.122" types-requests = "^2.31.0" typing-extensions = "^4.6.2" From 2c4a52ec63fed36ddf1c4ed3e92bd3d9f8da7299 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 14 Jun 2023 15:38:57 +0200 Subject: [PATCH 29/41] chore(ci): changelog rebuild (#2456) Co-authored-by: Powertools for AWS Lambda (Python) bot --- CHANGELOG.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb107587ddc..c721a4288e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,41 @@ # Unreleased +## Documentation + +* **event_handler:** improve compress example using Response class ([#2426](https://github.com/awslabs/aws-lambda-powertools-python/issues/2426)) +* **maintainers:** visual representation of release process ([#2399](https://github.com/awslabs/aws-lambda-powertools-python/issues/2399)) +* **navigation:** standardize link targets to enhance customer experience ([#2420](https://github.com/awslabs/aws-lambda-powertools-python/issues/2420)) +* **we-made-this:** new article about idempotency design ([#2425](https://github.com/awslabs/aws-lambda-powertools-python/issues/2425)) + +## Features + +* **event_sources:** add support for VPC Lattice events ([#2358](https://github.com/awslabs/aws-lambda-powertools-python/issues/2358)) +* **logger:** type log record in LambdaPowertoolsFormatter with TypedDict ([#2419](https://github.com/awslabs/aws-lambda-powertools-python/issues/2419)) +* **parser:** support for CloudFormation Custom Resources ([#2335](https://github.com/awslabs/aws-lambda-powertools-python/issues/2335)) + +## Maintenance + +* **ci:** document all github action workflows and enforce least-privilege ([#2395](https://github.com/awslabs/aws-lambda-powertools-python/issues/2395)) +* **ci:** fix PR labeling permission scope ([#2396](https://github.com/awslabs/aws-lambda-powertools-python/issues/2396)) +* **deps:** bump docker/setup-buildx-action from 2.6.0 to 2.7.0 ([#2450](https://github.com/awslabs/aws-lambda-powertools-python/issues/2450)) +* **deps:** bump docker/setup-buildx-action from 2.5.0 to 2.6.0 ([#2403](https://github.com/awslabs/aws-lambda-powertools-python/issues/2403)) +* **deps:** bump docker/setup-qemu-action from 2.1.0 to 2.2.0 ([#2404](https://github.com/awslabs/aws-lambda-powertools-python/issues/2404)) +* **deps:** bump actions/checkout from 3.5.2 to 3.5.3 ([#2431](https://github.com/awslabs/aws-lambda-powertools-python/issues/2431)) +* **deps:** bump pydantic from 1.10.8 to 1.10.9 ([#2405](https://github.com/awslabs/aws-lambda-powertools-python/issues/2405)) +* **deps-dev:** bump cfn-lint from 0.77.6 to 0.77.7 ([#2414](https://github.com/awslabs/aws-lambda-powertools-python/issues/2414)) +* **deps-dev:** bump aws-cdk from 2.83.0 to 2.83.1 ([#2432](https://github.com/awslabs/aws-lambda-powertools-python/issues/2432)) +* **deps-dev:** bump sentry-sdk from 1.25.0 to 1.25.1 ([#2408](https://github.com/awslabs/aws-lambda-powertools-python/issues/2408)) +* **deps-dev:** bump mypy-boto3-cloudformation from 1.26.147 to 1.26.149 ([#2410](https://github.com/awslabs/aws-lambda-powertools-python/issues/2410)) +* **deps-dev:** bump aws-cdk from 2.82.0 to 2.83.0 ([#2406](https://github.com/awslabs/aws-lambda-powertools-python/issues/2406)) +* **deps-dev:** bump mypy-boto3-logs from 1.26.53 to 1.26.149 ([#2409](https://github.com/awslabs/aws-lambda-powertools-python/issues/2409)) +* **deps-dev:** bump mypy-boto3-dynamodb from 1.26.115 to 1.26.152 ([#2444](https://github.com/awslabs/aws-lambda-powertools-python/issues/2444)) +* **deps-dev:** bump ijson from 3.2.0.post0 to 3.2.1 ([#2441](https://github.com/awslabs/aws-lambda-powertools-python/issues/2441)) +* **deps-dev:** bump filelock from 3.12.0 to 3.12.2 ([#2446](https://github.com/awslabs/aws-lambda-powertools-python/issues/2446)) +* **deps-dev:** bump pytest from 7.3.1 to 7.3.2 ([#2443](https://github.com/awslabs/aws-lambda-powertools-python/issues/2443)) +* **deps-dev:** bump cfn-lint from 0.77.7 to 0.77.8 ([#2451](https://github.com/awslabs/aws-lambda-powertools-python/issues/2451)) +* **deps-dev:** bump mypy-boto3-s3 from 1.26.127 to 1.26.153 ([#2452](https://github.com/awslabs/aws-lambda-powertools-python/issues/2452)) + ## [v2.16.2] - 2023-06-06 From 62a123cf3eda2e539d418dade54614e9e67c5126 Mon Sep 17 00:00:00 2001 From: Ruben Fonseca Date: Wed, 14 Jun 2023 19:04:48 +0200 Subject: [PATCH 30/41] fix(event_handler): prioritize static over dynamic route to prevent order of route registration mismatch (#2458) Co-authored-by: heitorlessa --- .../event_handler/api_gateway.py | 17 +++++++++--- .../event_handler/test_api_gateway.py | 27 +++++++++++++++++-- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/aws_lambda_powertools/event_handler/api_gateway.py b/aws_lambda_powertools/event_handler/api_gateway.py index 05fbc1c06c1..962fd51ccf4 100644 --- a/aws_lambda_powertools/event_handler/api_gateway.py +++ b/aws_lambda_powertools/event_handler/api_gateway.py @@ -483,7 +483,8 @@ def __init__( with api gateways with multiple custom mappings. """ self._proxy_type = proxy_type - self._routes: List[Route] = [] + self._dynamic_routes: List[Route] = [] + self._static_routes: List[Route] = [] self._route_keys: List[str] = [] self._exception_handlers: Dict[Type, Callable] = {} self._cors = cors @@ -515,7 +516,17 @@ def register_resolver(func: Callable): cors_enabled = cors for item in methods: - self._routes.append(Route(item, self._compile_regex(rule), func, cors_enabled, compress, cache_control)) + _route = Route(item, self._compile_regex(rule), func, cors_enabled, compress, cache_control) + + # The more specific route wins. + # We store dynamic (/studies/{studyid}) and static routes (/studies/fetch) separately. + # Then attempt a match for static routes before dynamic routes. + # This ensures that the most specific route is prioritized and processed first (studies/fetch). + if _route.rule.groups > 0: + self._dynamic_routes.append(_route) + else: + self._static_routes.append(_route) + route_key = item + rule if route_key in self._route_keys: warnings.warn( @@ -624,7 +635,7 @@ def _resolve(self) -> ResponseBuilder: """Resolves the response or return the not found response""" method = self.current_event.http_method.upper() path = self._remove_prefix(self.current_event.path) - for route in self._routes: + for route in self._static_routes + self._dynamic_routes: if method != route.method: continue match_results: Optional[Match] = route.rule.match(path) diff --git a/tests/functional/event_handler/test_api_gateway.py b/tests/functional/event_handler/test_api_gateway.py index 6faad88d7f1..c17422f8d94 100644 --- a/tests/functional/event_handler/test_api_gateway.py +++ b/tests/functional/event_handler/test_api_gateway.py @@ -298,7 +298,7 @@ def handler(event, context): return app.resolve(event, context) # Also check the route configurations - routes = app._routes + routes = app._static_routes assert len(routes) == 5 for route in routes: if route.func == get_func: @@ -1205,7 +1205,7 @@ def patch_func(): app.include_router(router) # Also check check the route configurations - routes = app._routes + routes = app._static_routes assert len(routes) == 5 for route in routes: if route.func == get_func: @@ -1647,3 +1647,26 @@ def get_message(): assert response["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] response_body = json.loads(response["body"]) assert response_body["message"] == "success" + + +def test_route_match_prioritize_full_match(): + # GIVEN a Http API V1, with a function registered with two routes + app = APIGatewayRestResolver() + router = Router() + + @router.get("/my/{path}") + def dynamic_handler() -> Response: + return Response(200, content_types.APPLICATION_JSON, json.dumps({"hello": "dynamic"})) + + @router.get("/my/path") + def static_handler() -> Response: + return Response(200, content_types.APPLICATION_JSON, json.dumps({"hello": "static"})) + + app.include_router(router) + + # WHEN calling the event handler with /foo/dynamic + response = app(LOAD_GW_EVENT, {}) + + # THEN the static_handler should have been called, because it fully matches the path directly + response_body = json.loads(response["body"]) + assert response_body["hello"] == "static" From 480dea4ddab119f12285a7f6818f7e9dc6f1a74e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Jun 2023 22:37:17 +0100 Subject: [PATCH 31/41] chore(deps-dev): bump aws-cdk from 2.83.1 to 2.84.0 (#2460) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index e5990842d28..023cdde90f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,13 +8,13 @@ "name": "aws-lambda-powertools-python-e2e", "version": "1.0.0", "devDependencies": { - "aws-cdk": "^2.83.1" + "aws-cdk": "^2.84.0" } }, "node_modules/aws-cdk": { - "version": "2.83.1", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.83.1.tgz", - "integrity": "sha512-hM2fsHl2TXk3B0MTq7zRU/KqJiVrnTQ3SXbAfleQCfCf/Jpy6yD6nGqrEADFAYNLSPoA9iC3SLnO73SPqqjjRQ==", + "version": "2.84.0", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.84.0.tgz", + "integrity": "sha512-XypGsMW+H6DLLIPt4zG5KWv1FuUlpS6jqEROxg5maJFFsRaQnMkfgXP/ZT1IELyIWCYAZl6xD1rz7WRS3yMueA==", "dev": true, "bin": { "cdk": "bin/cdk" @@ -43,9 +43,9 @@ }, "dependencies": { "aws-cdk": { - "version": "2.83.1", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.83.1.tgz", - "integrity": "sha512-hM2fsHl2TXk3B0MTq7zRU/KqJiVrnTQ3SXbAfleQCfCf/Jpy6yD6nGqrEADFAYNLSPoA9iC3SLnO73SPqqjjRQ==", + "version": "2.84.0", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.84.0.tgz", + "integrity": "sha512-XypGsMW+H6DLLIPt4zG5KWv1FuUlpS6jqEROxg5maJFFsRaQnMkfgXP/ZT1IELyIWCYAZl6xD1rz7WRS3yMueA==", "dev": true, "requires": { "fsevents": "2.3.2" diff --git a/package.json b/package.json index 93b51ac296d..cde5c93b3b8 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,6 @@ "name": "aws-lambda-powertools-python-e2e", "version": "1.0.0", "devDependencies": { - "aws-cdk": "^2.83.1" + "aws-cdk": "^2.84.0" } } From 7cd1812a0f841e591e960e38ad54bb996832fa16 Mon Sep 17 00:00:00 2001 From: Ran Isenberg <60175085+ran-isenberg@users.noreply.github.com> Date: Thu, 15 Jun 2023 16:51:52 +0300 Subject: [PATCH 32/41] docs(idempotency): add CDK example (#2434) Co-authored-by: Ran Isenberg Co-authored-by: Ruben Fonseca --- docs/utilities/idempotency.md | 65 +++++++++++++++-------------------- examples/idempotency/cdk.py | 21 +++++++++++ examples/idempotency/sam.yaml | 31 +++++++++++++++++ 3 files changed, 79 insertions(+), 38 deletions(-) create mode 100644 examples/idempotency/cdk.py create mode 100644 examples/idempotency/sam.yaml diff --git a/docs/utilities/idempotency.md b/docs/utilities/idempotency.md index 37b34bf9750..a0f42b4f304 100644 --- a/docs/utilities/idempotency.md +++ b/docs/utilities/idempotency.md @@ -77,31 +77,16 @@ If you're not [changing the default configuration for the DynamoDB persistence l ???+ tip "Tip: You can share a single state table for all functions" You can reuse the same DynamoDB table to store idempotency state. We add `module_name` and [qualified name for classes and functions](https://peps.python.org/pep-3155/){target="_blank"} in addition to the idempotency key as a hash key. -```yaml hl_lines="5-13 21-23" title="AWS Serverless Application Model (SAM) example" -Resources: - IdempotencyTable: - Type: AWS::DynamoDB::Table - Properties: - AttributeDefinitions: - - AttributeName: id - AttributeType: S - KeySchema: - - AttributeName: id - KeyType: HASH - TimeToLiveSpecification: - AttributeName: expiration - Enabled: true - BillingMode: PAY_PER_REQUEST - - HelloWorldFunction: - Type: AWS::Serverless::Function - Properties: - Runtime: python3.9 - ... - Policies: - - DynamoDBCrudPolicy: - TableName: !Ref IdempotencyTable -``` +=== "sam.yaml" + + ```yaml hl_lines="6-14 24-31" title="AWS Serverless Application Model (SAM) example" + --8<-- "examples/idempotency/sam.yaml" + ``` +=== "cdk.py" + + ```python hl_lines="10 13 16 19-21" title="AWS Cloud Development Kit (CDK) Construct example" + --8<-- "examples/idempotency/cdk.py" + ``` ???+ warning "Warning: Large responses with DynamoDB persistence layer" When using this utility with DynamoDB, your function's responses must be [smaller than 400KB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html#limits-items){target="_blank"}. @@ -148,7 +133,7 @@ You can quickly start by initializing the `DynamoDBPersistenceLayer` class and u === "Example event" - ```json + ```json { "username": "xyz", "product_id": "123456789" @@ -334,10 +319,12 @@ In this example, we have a Lambda handler that creates a payment for a user subs Imagine the function executes successfully, but the client never receives the response due to a connection issue. It is safe to retry in this instance, as the idempotent decorator will return a previously saved response. -**What we want here** is to instruct Idempotency to use `user` and `product_id` fields from our incoming payload as our idempotency key. If we were to treat the entire request as our idempotency key, a simple HTTP header change would cause our customer to be charged twice. +**What we want here** is to instruct Idempotency to use `user` and `product_id` fields from our incoming payload as our idempotency key. +If we were to treat the entire request as our idempotency key, a simple HTTP header change would cause our customer to be charged twice. ???+ tip "Deserializing JSON strings in payloads for increased accuracy." - The payload extracted by the `event_key_jmespath` is treated as a string by default. This means there could be differences in whitespace even when the JSON payload itself is identical. + The payload extracted by the `event_key_jmespath` is treated as a string by default. + This means there could be differences in whitespace even when the JSON payload itself is identical. To alter this behaviour, we can use the [JMESPath built-in function](jmespath_functions.md#powertools_json-function){target="_blank"} `powertools_json()` to treat the payload as a JSON object (dict) rather than a string. @@ -410,7 +397,8 @@ Imagine the function executes successfully, but the client never receives the re ???+ note This is automatically done when you decorate your Lambda handler with [@idempotent decorator](#idempotent-decorator). -To prevent against extended failed retries when a [Lambda function times out](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-verify-invocation-timeouts/){target="_blank"}, Powertools for AWS Lambda (Python) calculates and includes the remaining invocation available time as part of the idempotency record. +To prevent against extended failed retries when a [Lambda function times out](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-verify-invocation-timeouts/){target="_blank"}, +Powertools for AWS Lambda (Python) calculates and includes the remaining invocation available time as part of the idempotency record. ???+ example If a second invocation happens **after** this timestamp, and the record is marked as `INPROGRESS`, we will execute the invocation again as if it was in the `EXPIRED` state (e.g, `expire_seconds` field elapsed). @@ -418,7 +406,8 @@ To prevent against extended failed retries when a [Lambda function times out](ht This means that if an invocation expired during execution, it will be quickly executed again on the next retry. ???+ important - If you are only using the [@idempotent_function decorator](#idempotent_function-decorator) to guard isolated parts of your code, you must use `register_lambda_context` available in the [idempotency config object](#customizing-the-default-behavior) to benefit from this protection. + If you are only using the [@idempotent_function decorator](#idempotent_function-decorator) to guard isolated parts of your code, + you must use `register_lambda_context` available in the [idempotency config object](#customizing-the-default-behavior) to benefit from this protection. Here is an example on how you register the Lambda context in your handler: @@ -698,14 +687,14 @@ When using DynamoDB as a persistence layer, you can alter the attribute names by Idempotent decorator can be further configured with **`IdempotencyConfig`** as seen in the previous example. These are the available options for further configuration -| Parameter | Default | Description | -| ------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| **event_key_jmespath** | `""` | JMESPath expression to extract the idempotency key from the event record using [built-in functions](/utilities/jmespath_functions){target="_blank"} | -| **payload_validation_jmespath** | `""` | JMESPath expression to validate whether certain parameters have changed in the event while the event payload | -| **raise_on_no_idempotency_key** | `False` | Raise exception if no idempotency key was found in the request | -| **expires_after_seconds** | 3600 | The number of seconds to wait before a record is expired | -| **use_local_cache** | `False` | Whether to locally cache idempotency results | -| **local_cache_max_items** | 256 | Max number of items to store in local cache | +| Parameter | Default | Description | +| ------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **event_key_jmespath** | `""` | JMESPath expression to extract the idempotency key from the event record using [built-in functions](/utilities/jmespath_functions){target="_blank"} | +| **payload_validation_jmespath** | `""` | JMESPath expression to validate whether certain parameters have changed in the event while the event payload | +| **raise_on_no_idempotency_key** | `False` | Raise exception if no idempotency key was found in the request | +| **expires_after_seconds** | 3600 | The number of seconds to wait before a record is expired | +| **use_local_cache** | `False` | Whether to locally cache idempotency results | +| **local_cache_max_items** | 256 | Max number of items to store in local cache | | **hash_function** | `md5` | Function to use for calculating hashes, as provided by [hashlib](https://docs.python.org/3/library/hashlib.html){target="_blank"} in the standard library. | ### Handling concurrent executions with the same payload diff --git a/examples/idempotency/cdk.py b/examples/idempotency/cdk.py new file mode 100644 index 00000000000..4b22656defe --- /dev/null +++ b/examples/idempotency/cdk.py @@ -0,0 +1,21 @@ +from aws_cdk import RemovalPolicy +from aws_cdk import aws_dynamodb as dynamodb +from aws_cdk import aws_iam as iam +from constructs import Construct + + +class IdempotencyConstruct(Construct): + def __init__(self, scope: Construct, name: str, lambda_role: iam.Role) -> None: + super().__init__(scope, name) + self.idempotency_table = dynamodb.Table( + self, + "IdempotencyTable", + partition_key=dynamodb.Attribute(name="id", type=dynamodb.AttributeType.STRING), + billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST, + removal_policy=RemovalPolicy.DESTROY, + time_to_live_attribute="expiration", + point_in_time_recovery=True, + ) + self.idempotency_table.grant( + lambda_role, "dynamodb:PutItem", "dynamodb:GetItem", "dynamodb:UpdateItem", "dynamodb:DeleteItem" + ) diff --git a/examples/idempotency/sam.yaml b/examples/idempotency/sam.yaml new file mode 100644 index 00000000000..ee9b7540de9 --- /dev/null +++ b/examples/idempotency/sam.yaml @@ -0,0 +1,31 @@ +Transform: AWS::Serverless-2016-10-31 +Resources: + IdempotencyTable: + Type: AWS::DynamoDB::Table + Properties: + AttributeDefinitions: + - AttributeName: id + AttributeType: S + KeySchema: + - AttributeName: id + KeyType: HASH + TimeToLiveSpecification: + AttributeName: expiration + Enabled: true + BillingMode: PAY_PER_REQUEST + + HelloWorldFunction: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.9 + Handler: app.py + Policies: + - Statement: + - Sid: AllowDynamodbReadWrite + Effect: Allow + Action: + - dynamodb:PutItem + - dynamodb:GetItem + - dynamodb:UpdateItem + - dynamodb:DeleteItem + Resource: !GetAtt IdempotencyTable.Arn From ec207b14b7ad1265caa8466e4468a95a4d5fe4e7 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Thu, 15 Jun 2023 16:32:55 +0200 Subject: [PATCH 33/41] feat(event_sources): add AWS Config Rule event data class (#2175) --- .../utilities/data_classes/__init__.py | 2 + .../data_classes/aws_config_rule_event.py | 361 ++++++++++++++++++ docs/utilities/data_classes.md | 21 + examples/event_sources/src/aws_config_rule.py | 17 + .../src/aws_config_rule_item_changed.json | 13 + .../src/aws_config_rule_oversized.json | 12 + .../src/aws_config_rule_scheduled.json | 13 + .../awsConfigRuleConfigurationChanged.json | 13 + .../awsConfigRuleOversizedConfiguration.json | 12 + tests/events/awsConfigRuleScheduled.json | 13 + tests/functional/test_data_classes.py | 171 +++++++++ 11 files changed, 648 insertions(+) create mode 100644 aws_lambda_powertools/utilities/data_classes/aws_config_rule_event.py create mode 100644 examples/event_sources/src/aws_config_rule.py create mode 100644 examples/event_sources/src/aws_config_rule_item_changed.json create mode 100644 examples/event_sources/src/aws_config_rule_oversized.json create mode 100644 examples/event_sources/src/aws_config_rule_scheduled.json create mode 100644 tests/events/awsConfigRuleConfigurationChanged.json create mode 100644 tests/events/awsConfigRuleOversizedConfiguration.json create mode 100644 tests/events/awsConfigRuleScheduled.json diff --git a/aws_lambda_powertools/utilities/data_classes/__init__.py b/aws_lambda_powertools/utilities/data_classes/__init__.py index 076616b95d2..c619104fda8 100644 --- a/aws_lambda_powertools/utilities/data_classes/__init__.py +++ b/aws_lambda_powertools/utilities/data_classes/__init__.py @@ -5,6 +5,7 @@ from .alb_event import ALBEvent from .api_gateway_proxy_event import APIGatewayProxyEvent, APIGatewayProxyEventV2 from .appsync_resolver_event import AppSyncResolverEvent +from .aws_config_rule_event import AWSConfigRuleEvent from .cloud_watch_custom_widget_event import CloudWatchDashboardCustomWidgetEvent from .cloud_watch_logs_event import CloudWatchLogsEvent from .code_pipeline_job_event import CodePipelineJobEvent @@ -43,5 +44,6 @@ "SNSEvent", "SQSEvent", "event_source", + "AWSConfigRuleEvent", "VPCLatticeEvent", ] diff --git a/aws_lambda_powertools/utilities/data_classes/aws_config_rule_event.py b/aws_lambda_powertools/utilities/data_classes/aws_config_rule_event.py new file mode 100644 index 00000000000..2bfa2df61c5 --- /dev/null +++ b/aws_lambda_powertools/utilities/data_classes/aws_config_rule_event.py @@ -0,0 +1,361 @@ +from __future__ import annotations + +import json +from typing import Any, Dict, List, Optional + +from aws_lambda_powertools.utilities.data_classes.common import DictWrapper + + +def get_invoke_event( + invoking_event: dict, +) -> AWSConfigConfigurationChanged | AWSConfigScheduledNotification | AWSConfigOversizedConfiguration: + """ + Returns the corresponding event object based on the messageType in the invoking event. + + Parameters + ---------- + invoking_event: dict + The invoking event received. + + Returns + ------- + AWSConfigConfigurationChanged | AWSConfigScheduledNotification | AWSConfigOversizedConfiguration: + The event object based on the messageType in the invoking event. + """ + + message_type = invoking_event.get("messageType") + + if message_type == "ScheduledNotification": + return AWSConfigScheduledNotification(invoking_event) + + if message_type == "OversizedConfigurationItemChangeNotification": + return AWSConfigOversizedConfiguration(invoking_event) + + # Default return is AWSConfigConfigurationChanged event + return AWSConfigConfigurationChanged(invoking_event) + + +class AWSConfigConfigurationChanged(DictWrapper): + @property + def configuration_item_diff(self) -> Dict: + """The configuration item diff of the ConfigurationItemChangeNotification event.""" + return self["configurationItemDiff"] + + @property + def configuration_item(self) -> AWSConfigConfigurationItemChanged: + """The configuration item of the ConfigurationItemChangeNotification event.""" + return AWSConfigConfigurationItemChanged(self["configurationItem"]) + + @property + def raw_configuration_item(self) -> Dict: + """The raw configuration item of the ConfigurationItemChangeNotification event.""" + return self["configurationItem"] + + @property + def record_version(self) -> str: + """The record version of the ConfigurationItemChangeNotification event.""" + return self["recordVersion"] + + @property + def message_type(self) -> str: + """The message type of the ConfigurationItemChangeNotification event.""" + return self["messageType"] + + @property + def notification_creation_time(self) -> str: + """The notification creation time of the ConfigurationItemChangeNotification event.""" + return self["notificationCreationTime"] + + +class AWSConfigConfigurationItemChanged(DictWrapper): + @property + def related_events(self) -> List: + """The related events of the ConfigurationItemChangeNotification event.""" + return self["relatedEvents"] + + @property + def relationships(self) -> List: + """The relationships of the ConfigurationItemChangeNotification event.""" + return self["relationships"] + + @property + def configuration(self) -> Dict: + """The configuration of the ConfigurationItemChangeNotification event.""" + return self["configuration"] + + @property + def supplementary_configuration(self) -> Dict: + """The supplementary configuration of the ConfigurationItemChangeNotification event.""" + return self["supplementaryConfiguration"] + + @property + def tags(self) -> Dict: + """The tags of the ConfigurationItemChangeNotification event.""" + return self["tags"] + + @property + def configuration_item_version(self) -> str: + """The configuration item version of the ConfigurationItemChangeNotification event.""" + return self["configurationItemVersion"] + + @property + def configuration_item_capture_time(self) -> str: + """The configuration item capture time of the ConfigurationItemChangeNotification event.""" + return self["configurationItemCaptureTime"] + + @property + def configuration_state_id(self) -> str: + """The configuration state id of the ConfigurationItemChangeNotification event.""" + return self["configurationStateId"] + + @property + def accountid(self) -> str: + """The accountid of the ConfigurationItemChangeNotification event.""" + return self["awsAccountId"] + + @property + def configuration_item_status(self) -> str: + """The configuration item status of the ConfigurationItemChangeNotification event.""" + return self["configurationItemStatus"] + + @property + def resource_type(self) -> str: + """The resource type of the ConfigurationItemChangeNotification event.""" + return self["resourceType"] + + @property + def resource_id(self) -> str: + """The resource id of the ConfigurationItemChangeNotification event.""" + return self["resourceId"] + + @property + def resource_name(self) -> str: + """The resource name of the ConfigurationItemChangeNotification event.""" + return self["resourceName"] + + @property + def resource_arn(self) -> str: + """The resource arn of the ConfigurationItemChangeNotification event.""" + return self["ARN"] + + @property + def region(self) -> str: + """The region of the ConfigurationItemChangeNotification event.""" + return self["awsRegion"] + + @property + def availability_zone(self) -> str: + """The availability zone of the ConfigurationItemChangeNotification event.""" + return self["availabilityZone"] + + @property + def configuration_state_md5_hash(self) -> str: + """The md5 hash of the state of the ConfigurationItemChangeNotification event.""" + return self["configurationStateMd5Hash"] + + @property + def resource_creation_time(self) -> str: + """The resource creation time of the ConfigurationItemChangeNotification event.""" + return self["resourceCreationTime"] + + +class AWSConfigScheduledNotification(DictWrapper): + @property + def accountid(self) -> str: + """The accountid of the ScheduledNotification event.""" + return self["awsAccountId"] + + @property + def notification_creation_time(self) -> str: + """The notification creation time of the ScheduledNotification event.""" + return self["notificationCreationTime"] + + @property + def record_version(self) -> str: + """The record version of the ScheduledNotification event.""" + return self["recordVersion"] + + @property + def message_type(self) -> str: + """The message type of the ScheduledNotification event.""" + return self["messageType"] + + +class AWSConfigOversizedConfiguration(DictWrapper): + @property + def configuration_item_summary(self) -> AWSConfigOversizedConfigurationItemSummary: + """The configuration item summary of the OversizedConfiguration event.""" + return AWSConfigOversizedConfigurationItemSummary(self["configurationItemSummary"]) + + @property + def raw_configuration_item_summary(self) -> str: + """The raw configuration item summary of the OversizedConfiguration event.""" + return self["configurationItemSummary"] + + @property + def message_type(self) -> str: + """The message type of the OversizedConfiguration event.""" + return self["messageType"] + + @property + def notification_creation_time(self) -> str: + """The notification creation time of the OversizedConfiguration event.""" + return self["notificationCreationTime"] + + @property + def record_version(self) -> str: + """The record version of the OversizedConfiguration event.""" + return self["recordVersion"] + + +class AWSConfigOversizedConfigurationItemSummary(DictWrapper): + @property + def change_type(self) -> str: + """The change type of the OversizedConfiguration event.""" + return self["changeType"] + + @property + def configuration_item_version(self) -> str: + """The configuration item version of the OversizedConfiguration event.""" + return self["configurationItemVersion"] + + @property + def configuration_item_capture_time(self) -> str: + """The configuration item capture time of the OversizedConfiguration event.""" + return self["configurationItemCaptureTime"] + + @property + def configuration_state_id(self) -> str: + """The configuration state id of the OversizedConfiguration event.""" + return self["configurationStateId"] + + @property + def accountid(self) -> str: + """The accountid of the OversizedConfiguration event.""" + return self["awsAccountId"] + + @property + def configuration_item_status(self) -> str: + """The configuration item status of the OversizedConfiguration event.""" + return self["configurationItemStatus"] + + @property + def resource_type(self) -> str: + """The resource type of the OversizedConfiguration event.""" + return self["resourceType"] + + @property + def resource_id(self) -> str: + """The resource id of the OversizedConfiguration event.""" + return self["resourceId"] + + @property + def resource_name(self) -> str: + """The resource name of the OversizedConfiguration event.""" + return self["resourceName"] + + @property + def resource_arn(self) -> str: + """The resource arn of the OversizedConfiguration event.""" + return self["ARN"] + + @property + def region(self) -> str: + """The region of the OversizedConfiguration event.""" + return self["awsRegion"] + + @property + def availability_zone(self) -> str: + """The availability zone of the OversizedConfiguration event.""" + return self["availabilityZone"] + + @property + def configuration_state_md5_hash(self) -> str: + """The state md5 hash of the OversizedConfiguration event.""" + return self["configurationStateMd5Hash"] + + @property + def resource_creation_time(self) -> str: + """The resource creation time of the OversizedConfiguration event.""" + return self["resourceCreationTime"] + + +class AWSConfigRuleEvent(DictWrapper): + """Events for AWS Config Rules + Documentation: + -------------- + - https://docs.aws.amazon.com/config/latest/developerguide/evaluate-config_develop-rules_lambda-functions.html + """ + + def __init__(self, data: Dict[str, Any]): + super().__init__(data) + self._invoking_event: Optional[Any] = None + self._rule_parameters: Optional[Any] = None + + @property + def version(self) -> str: + """The version of the event.""" + return self["version"] + + @property + def invoking_event( + self, + ) -> AWSConfigConfigurationChanged | AWSConfigScheduledNotification | AWSConfigOversizedConfiguration: + """The invoking payload of the event.""" + if self._invoking_event is None: + self._invoking_event = self["invokingEvent"] + + return get_invoke_event(json.loads(self._invoking_event)) + + @property + def raw_invoking_event(self) -> str: + """The raw invoking payload of the event.""" + return self["invokingEvent"] + + @property + def rule_parameters(self) -> Dict: + """The parameters of the event.""" + if self._rule_parameters is None: + self._rule_parameters = self["ruleParameters"] + + return json.loads(self._rule_parameters) + + @property + def result_token(self) -> str: + """The result token of the event.""" + return self["resultToken"] + + @property + def event_left_scope(self) -> bool: + """The left scope of the event.""" + return self["eventLeftScope"] + + @property + def execution_role_arn(self) -> str: + """The execution role arn of the event.""" + return self["executionRoleArn"] + + @property + def config_rule_arn(self) -> str: + """The arn of the rule of the event.""" + return self["configRuleArn"] + + @property + def config_rule_name(self) -> str: + """The name of the rule of the event.""" + return self["configRuleName"] + + @property + def config_rule_id(self) -> str: + """The id of the rule of the event.""" + return self["configRuleId"] + + @property + def accountid(self) -> str: + """The accountid of the event.""" + return self["accountId"] + + @property + def evalution_mode(self) -> Optional[str]: + """The evalution mode of the event.""" + return self.get("evaluationMode") diff --git a/docs/utilities/data_classes.md b/docs/utilities/data_classes.md index 64557db6063..dcdca921ef6 100644 --- a/docs/utilities/data_classes.md +++ b/docs/utilities/data_classes.md @@ -84,6 +84,7 @@ Log Data Event for Troubleshooting | [Application Load Balancer](#application-load-balancer) | `ALBEvent` | | [AppSync Authorizer](#appsync-authorizer) | `AppSyncAuthorizerEvent` | | [AppSync Resolver](#appsync-resolver) | `AppSyncResolverEvent` | +| [AWS Config Rule](#aws-config-rule) | `AWSConfigRuleEvent` | | [CloudWatch Dashboard Custom Widget](#cloudwatch-dashboard-custom-widget) | `CloudWatchDashboardCustomWidgetEvent` | | [CloudWatch Logs](#cloudwatch-logs) | `CloudWatchLogsEvent` | | [CodePipeline Job Event](#codepipeline-job) | `CodePipelineJobEvent` | @@ -462,6 +463,26 @@ In this example, we also use the new Logger `correlation_id` and built-in `corre } ``` +### AWS Config Rule + +=== "aws_config_rule.py" + ```python hl_lines="3 11" + --8<-- "examples/event_sources/src/aws_config_rule.py" + ``` + +=== "Event - ItemChanged" + ```json + --8<-- "examples/event_sources/src/aws_config_rule_item_changed.json" + ``` +=== "Event - Oversized" + ```json + --8<-- "examples/event_sources/src/aws_config_rule_oversized.json" + ``` +=== "Event - ScheduledNotification" + ```json + --8<-- "examples/event_sources/src/aws_config_rule_scheduled.json" + ``` + ### CloudWatch Dashboard Custom Widget === "app.py" diff --git a/examples/event_sources/src/aws_config_rule.py b/examples/event_sources/src/aws_config_rule.py new file mode 100644 index 00000000000..b81ae39bd25 --- /dev/null +++ b/examples/event_sources/src/aws_config_rule.py @@ -0,0 +1,17 @@ +from aws_lambda_powertools import Logger +from aws_lambda_powertools.utilities.data_classes import ( + AWSConfigRuleEvent, + event_source, +) +from aws_lambda_powertools.utilities.typing import LambdaContext + +logger = Logger() + + +@event_source(data_class=AWSConfigRuleEvent) +def lambda_handler(event: AWSConfigRuleEvent, context: LambdaContext): + message_type = event.invoking_event.message_type + + logger.info(f"Logging {message_type} event rule", invoke_event=event.raw_invoking_event) + + return {"Success": "OK"} diff --git a/examples/event_sources/src/aws_config_rule_item_changed.json b/examples/event_sources/src/aws_config_rule_item_changed.json new file mode 100644 index 00000000000..cbf7abf67aa --- /dev/null +++ b/examples/event_sources/src/aws_config_rule_item_changed.json @@ -0,0 +1,13 @@ +{ + "version":"1.0", + "invokingEvent":"{\"configurationItemDiff\":{\"changedProperties\":{\"Configuration.InstanceType\":{\"previousValue\":\"t2.micro\",\"updatedValue\":\"t2.medium\",\"changeType\":\"UPDATE\"},\"Configuration.State.Name\":{\"previousValue\":\"running\",\"updatedValue\":\"stopped\",\"changeType\":\"UPDATE\"},\"Configuration.StateTransitionReason\":{\"previousValue\":\"\",\"updatedValue\":\"User initiated (2023-04-27 15:01:07 GMT)\",\"changeType\":\"UPDATE\"},\"Configuration.StateReason\":{\"previousValue\":null,\"updatedValue\":{\"code\":\"Client.UserInitiatedShutdown\",\"message\":\"Client.UserInitiatedShutdown: User initiated shutdown\"},\"changeType\":\"CREATE\"},\"Configuration.CpuOptions.CoreCount\":{\"previousValue\":1,\"updatedValue\":2,\"changeType\":\"UPDATE\"}},\"changeType\":\"UPDATE\"},\"configurationItem\":{\"relatedEvents\":[],\"relationships\":[{\"resourceId\":\"eipalloc-0ebb4367662263cc1\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::EIP\",\"name\":\"Is attached to ElasticIp\"},{\"resourceId\":\"eni-034dd31c4b17ada8c\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::NetworkInterface\",\"name\":\"Contains NetworkInterface\"},{\"resourceId\":\"eni-09a604c0ec356b06f\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::NetworkInterface\",\"name\":\"Contains NetworkInterface\"},{\"resourceId\":\"sg-0fb295a327d9b4835\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::SecurityGroup\",\"name\":\"Is associated with SecurityGroup\"},{\"resourceId\":\"subnet-cad1f2f4\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::Subnet\",\"name\":\"Is contained in Subnet\"},{\"resourceId\":\"vol-0a288b5eb9fea4b30\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::Volume\",\"name\":\"Is attached to Volume\"},{\"resourceId\":\"vpc-2d96be57\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::VPC\",\"name\":\"Is contained in Vpc\"}],\"configuration\":{\"amiLaunchIndex\":0,\"imageId\":\"ami-09d95fab7fff3776c\",\"instanceId\":\"i-042dd005362091826\",\"instanceType\":\"t2.medium\",\"kernelId\":null,\"keyName\":\"mihaec2\",\"launchTime\":\"2023-04-27T14:57:16.000Z\",\"monitoring\":{\"state\":\"disabled\"},\"placement\":{\"availabilityZone\":\"us-east-1e\",\"affinity\":null,\"groupName\":\"\",\"partitionNumber\":null,\"hostId\":null,\"tenancy\":\"default\",\"spreadDomain\":null,\"hostResourceGroupArn\":null},\"platform\":null,\"privateDnsName\":\"ip-172-31-78-41.ec2.internal\",\"privateIpAddress\":\"172.31.78.41\",\"productCodes\":[],\"publicDnsName\":\"ec2-3-232-229-57.compute-1.amazonaws.com\",\"publicIpAddress\":\"3.232.229.57\",\"ramdiskId\":null,\"state\":{\"code\":80,\"name\":\"stopped\"},\"stateTransitionReason\":\"User initiated (2023-04-27 15:01:07 GMT)\",\"subnetId\":\"subnet-cad1f2f4\",\"vpcId\":\"vpc-2d96be57\",\"architecture\":\"x86_64\",\"blockDeviceMappings\":[{\"deviceName\":\"/dev/xvda\",\"ebs\":{\"attachTime\":\"2020-05-30T15:21:58.000Z\",\"deleteOnTermination\":true,\"status\":\"attached\",\"volumeId\":\"vol-0a288b5eb9fea4b30\"}}],\"clientToken\":\"\",\"ebsOptimized\":false,\"enaSupport\":true,\"hypervisor\":\"xen\",\"iamInstanceProfile\":{\"arn\":\"arn:aws:iam::0123456789012:instance-profile/AmazonSSMRoleForInstancesQuickSetup\",\"id\":\"AIPAS5S4WFUBL72S3QXW5\"},\"instanceLifecycle\":null,\"elasticGpuAssociations\":[],\"elasticInferenceAcceleratorAssociations\":[],\"networkInterfaces\":[{\"association\":{\"carrierIp\":null,\"ipOwnerId\":\"0123456789012\",\"publicDnsName\":\"ec2-3-232-229-57.compute-1.amazonaws.com\",\"publicIp\":\"3.232.229.57\"},\"attachment\":{\"attachTime\":\"2020-05-30T15:21:57.000Z\",\"attachmentId\":\"eni-attach-0a7e75dc9c1c291a0\",\"deleteOnTermination\":true,\"deviceIndex\":0,\"status\":\"attached\",\"networkCardIndex\":0},\"description\":\"\",\"groups\":[{\"groupName\":\"minhaec2\",\"groupId\":\"sg-0fb295a327d9b4835\"}],\"ipv6Addresses\":[],\"macAddress\":\"06:cf:00:c2:17:db\",\"networkInterfaceId\":\"eni-034dd31c4b17ada8c\",\"ownerId\":\"0123456789012\",\"privateDnsName\":\"ip-172-31-78-41.ec2.internal\",\"privateIpAddress\":\"172.31.78.41\",\"privateIpAddresses\":[{\"association\":{\"carrierIp\":null,\"ipOwnerId\":\"0123456789012\",\"publicDnsName\":\"ec2-3-232-229-57.compute-1.amazonaws.com\",\"publicIp\":\"3.232.229.57\"},\"primary\":true,\"privateDnsName\":\"ip-172-31-78-41.ec2.internal\",\"privateIpAddress\":\"172.31.78.41\"}],\"sourceDestCheck\":true,\"status\":\"in-use\",\"subnetId\":\"subnet-cad1f2f4\",\"vpcId\":\"vpc-2d96be57\",\"interfaceType\":\"interface\"},{\"association\":null,\"attachment\":{\"attachTime\":\"2020-11-26T23:46:04.000Z\",\"attachmentId\":\"eni-attach-0e6d150ebbd19966e\",\"deleteOnTermination\":false,\"deviceIndex\":1,\"status\":\"attached\",\"networkCardIndex\":0},\"description\":\"MINHAEC2AAAAAA\",\"groups\":[{\"groupName\":\"minhaec2\",\"groupId\":\"sg-0fb295a327d9b4835\"},{\"groupName\":\"default\",\"groupId\":\"sg-88105fa0\"}],\"ipv6Addresses\":[],\"macAddress\":\"06:0a:62:00:64:5f\",\"networkInterfaceId\":\"eni-09a604c0ec356b06f\",\"ownerId\":\"0123456789012\",\"privateDnsName\":\"ip-172-31-70-9.ec2.internal\",\"privateIpAddress\":\"172.31.70.9\",\"privateIpAddresses\":[{\"association\":null,\"primary\":true,\"privateDnsName\":\"ip-172-31-70-9.ec2.internal\",\"privateIpAddress\":\"172.31.70.9\"}],\"sourceDestCheck\":true,\"status\":\"in-use\",\"subnetId\":\"subnet-cad1f2f4\",\"vpcId\":\"vpc-2d96be57\",\"interfaceType\":\"interface\"}],\"outpostArn\":null,\"rootDeviceName\":\"/dev/xvda\",\"rootDeviceType\":\"ebs\",\"securityGroups\":[{\"groupName\":\"minhaec2\",\"groupId\":\"sg-0fb295a327d9b4835\"}],\"sourceDestCheck\":true,\"spotInstanceRequestId\":null,\"sriovNetSupport\":null,\"stateReason\":{\"code\":\"Client.UserInitiatedShutdown\",\"message\":\"Client.UserInitiatedShutdown: User initiated shutdown\"},\"tags\":[{\"key\":\"projeto\",\"value\":\"meetup\"},{\"key\":\"Name\",\"value\":\"Minha\"},{\"key\":\"CentroCusto\",\"value\":\"TI\"},{\"key\":\"Setor\",\"value\":\"Desenvolvimento\"}],\"virtualizationType\":\"hvm\",\"cpuOptions\":{\"coreCount\":2,\"threadsPerCore\":1},\"capacityReservationId\":null,\"capacityReservationSpecification\":{\"capacityReservationPreference\":\"open\",\"capacityReservationTarget\":null},\"hibernationOptions\":{\"configured\":false},\"licenses\":[],\"metadataOptions\":{\"state\":\"applied\",\"httpTokens\":\"optional\",\"httpPutResponseHopLimit\":1,\"httpEndpoint\":\"enabled\"},\"enclaveOptions\":{\"enabled\":false},\"bootMode\":null},\"supplementaryConfiguration\":{},\"tags\":{\"projeto\":\"meetup\",\"Setor\":\"Desenvolvimento\",\"CentroCusto\":\"TI\",\"Name\":\"Minha\"},\"configurationItemVersion\":\"1.3\",\"configurationItemCaptureTime\":\"2023-04-27T15:03:11.636Z\",\"configurationStateId\":1682607791636,\"awsAccountId\":\"0123456789012\",\"configurationItemStatus\":\"OK\",\"resourceType\":\"AWS::EC2::Instance\",\"resourceId\":\"i-042dd005362091826\",\"resourceName\":null,\"ARN\":\"arn:aws:ec2:us-east-1:0123456789012:instance/i-042dd005362091826\",\"awsRegion\":\"us-east-1\",\"availabilityZone\":\"us-east-1e\",\"configurationStateMd5Hash\":\"\",\"resourceCreationTime\":\"2023-04-27T14:57:16.000Z\"},\"notificationCreationTime\":\"2023-04-27T15:03:13.332Z\",\"messageType\":\"ConfigurationItemChangeNotification\",\"recordVersion\":\"1.3\"}", + "ruleParameters":"{\"desiredInstanceType\": \"t2.micro\"}", + "resultToken":"eyJlbmNyeXB0ZWREYXRhIjpbLTQxLDEsLTU3LC0zMCwtMTIxLDUzLDUyLDQ1LC01NywtOCw3MywtODEsLTExNiwtMTAyLC01MiwxMTIsLTQ3LDU4LDY1LC0xMjcsMTAyLDUsLTY5LDQ0LC0xNSwxMTQsNDEsLTksMTExLC0zMCw2NSwtNzUsLTM1LDU0LDEwNSwtODksODYsNDAsLTEwNSw5OCw2NSwtMTE5LC02OSwyNCw2NiwtMjAsODAsLTExMiwtNzgsLTgwLDQzLC01NywzMCwtMjUsODIsLTEwLDMsLTQsLTg1LC01MywtMzcsLTkwLC04OCwtOTgsLTk4LC00MSwxOSwxMTYsNjIsLTIzLC0xMjEsLTEwOCw1NywtNTgsLTUyLDI5LDEwMSwxMjIsLTU2LC03MSwtODEsLTQ3LDc3LC0yMiwtMTI0LC0zLC04NiwtMTIyLC00MCwtODksLTEwMSw1NywtMTI3LC0zNywtMzcsLTMxLC05OCwtMzEsMTEsLTEyNSwwLDEwOCwtMzIsNjQsNjIsLTIyLDAsNDcsLTEwNiwtMTAwLDEwNCwxNCw1OCwxMjIsLTEwLC01MCwtOTAsLTgwLC01MCwtNSw2NSwwLC0yNSw4NSw4Miw3LDkzLDEyMiwtODIsLTExNiwtNzksLTQ0LDcyLC03MywtNjksMTQsLTU2LDk0LDkwLDExNCwtMjksLTExOSwtNzEsODgsMTA3LDEwNywxMTAsLTcsMTI3LC0xMjUsLTU3LC0xMjYsLTEyMCw2OSwtMTI3LC03NiwtMTE5LDcxLDEsLTY4LDEwNywxMTMsLTU2LDg3LC0xMDIsLTE2LDEwOCwtMTA3LC00MywtOTQsLTEwNiwzLDkwLDE0LDcyLC0xMiwtMTE2LC03Myw4MCwtMTIyLDQ0LC0xMDQsMTIsNzQsNTcsLTEwLC0xMDUsLTExMiwtMzYsMjgsLTQ1LDk3LDExLC00OSwtMTEsNjEsMzYsLTE3LC03NCw1MCw0LC0yNiwxMDQsLTI4LC0xMjUsMjQsNzAsLTg1LC00Niw5MiwtMTAzLC00MSwtMTA2LDY5LDEyMiwyMSwtMjUsODAsOTksLTkzLC01NiwtMjUsLTQ3LC0xMjMsLTU5LC0xMjQsLTUyLC0xNiwxMjcsLTM4LC0xNiwxMDEsMTE5LDEwNywyNywxMCwtNDYsLTg3LC0xMiwtMzksMTQsNDUsMiw3MCwxMDcsMTA0LC00LC02OSwtMTIsNTksLTEyNiwtOTEsMTI3LDU0LDEwNiwtMTI2LC0xMTYsLTEwMiw3Miw4MSw1MCw3NSwtNTEsMTA4LDQxLC0zLC02LC00NSwxMDMsLTg2LDM3LC00NiwtMzIsLTExMSwxMjQsMTExLDg3LDU0LC03NiwxMjIsLTUsLTM2LC04OCw5LC0xMTMsMTE2LC01OSw4Myw3NywyOCwxMiwtNjUsLTExMywtNzksLTEyOCw4MiwtMTE4LC04MywtMTI0LDMxLDk5LC05MCwtOTksMTYsLTEyMywyMSwtMTE0LC05OCwtMTE2LC0xMTksMiwtNzMsNDYsODIsLTEzLDU0LDcxLC00MiwyNSw3NCw3MywtODYsOTQsNDYsOTksOTMsLTgyLDU1LDY1LC05OCw0OSwtNjAsMTEyLDEwMSwyMiw2OSwtMTYsNzcsLTk0LC01OSwtNDYsMTE1LDMwLC00Myw5Myw4OCwtMjgsMzgsNiw4NCwzMSwtMTAxLDMyLC0yMiwtNjMsLTk1LDExNCwtNzUsMTE0LDM2LC04NCw0MCwtNDQsLTEzLDU5LDcyLC0xLC0xMDMsMzEsMTA1LDY5LDY5LDc3LC02NCwtNTYsMTE4LDEzLC0xMTQsODAsOTksLTUzLDI1LDQyLDk0LDczLC04MCwyNSwzOCwyNCwtMTcsNjYsLTExOCwtMjMsMTE5LDkwLDEyMSwxMTgsLTUxLDUxLC0xMiwtNzYsLTUxLDksLTIxLDExNCwtMzcsLTY0LC0yLC0xMjYsLTk1LDYzLDczLC00MSwtMzQsLTkwLC0yMiw1OSwtNzksMzAsLTQsLTEsLTUsMTIsMzksLTk5LC0xMDUsLTEwNCwtNjEsNjUsLTc0LDE5LC0xMywtNjAsLTI4LC04LDQsLTgsMTIxLC0xMTgsMTIyLC02NSwtMjEsMjMsMTcsLTg0LDQwLC05MiwxNCwtMTI2LC02MCwtNzksLTUzLDM3LC04Myw2NSwxMDQsLTM2LC02MCwtMTEwLC0zMywtMTE3LDYsMTA3LDEsLTMsOTMsNzgsLTk1LC0xMjIsNTMsMTA4LC00OSwtNDksMjQsLTY1LDgzLDEyNSwtNzcsLTE5LC04MSwzNCwtNjcsLTQzLC03MCwtMjYsMTgsMTA0LDY1LDQsLTEyNiw0NCwtMTE5LDUyLC00NiwyMiw2NywxMTMsMTE4LC0zMywzNCwtOTYsMTIxLDE5LC0yLC0zNSwwLC04MiwxNyw2NiwtMjcsNjksLTM2LC0xNCw1NiwtOTcsLTE2LDEyMywyOCwtOTUsLTMyLC02MywtNjksNzAsNjQsLTMzLC0xMDAsNDMsLTExMywxMDUsMTAwLDEwOCwtNjAsNDAsLTIsLTk2LC0xMjQsMzcsLTQ1LC0xMjQsLTY4LC02OSwtMTIzLDE3LC02LDg2LC01OSwtOTQsMTEwLDczLDU3LC0xMTYsMTA3LC00MSwtOTQsLTExOCwtMTI2LDEwLC04MCwtNzAsMTAyLDg4LC0xMjYsODcsLTI3LC0xMDEsLTk0LC0zNSwtMTA2LC02LC03MiwtODYsNTAsMTE2LC0yOCw5MCwxMywtMTIwLDYsMjcsOTIsNTYsLTkwLDM5LDQ5LC0xMywtODYsLTI1LC04NiwxMTMsLTEzLDQxLC0xMTksOTQsLTk0LC0xMDMsLTgzLC02MCwxMjcsLTE1LC0zOSwxMTksLTk1LDI3LDQ0LDExNiwxMDksNywtMTAyLC0xNyw0OCwtODIsLTMxLC04LC02OSwzNSw5NCw1NCwtNTUsMSwtMTE5LDU3LC0xMDgsLTMsLTkxLC0xMjIsLTUzLC04OCw0LC05NywtMzUsMTI2LDExOSw1OSwtMSw4NSw3MywtNTgsLTEyMCwtNjQsMTE5LC0xMTIsOTIsMTksOSwtNjYsLTkyLDEwOCwtMTEsLTQyLDExMSwtMTA0LC0xMjAsMjcsLTEwMywtNjksMTksMTExLDEyLDIzLDEwNyw1NCw0MSwtMjYsNjAsLTMxLC01XSwibWF0ZXJpYWxTZXRTZXJpYWxOdW1iZXIiOjEsIml2UGFyYW1ldGVyU3BlYyI6eyJpdiI6Wy05NSwzMiwxMDgsOTEsMzUsLTgyLC0zNywyNCwtNDQsLTExNSwtODIsLTEyOCwtMTIyLDMsNTMsLTI0XX19", + "eventLeftScope":false, + "executionRoleArn":"arn:aws:iam::0123456789012:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig", + "configRuleArn":"arn:aws:config:us-east-1:0123456789012:config-rule/config-rule-i9y8j9", + "configRuleName":"MyRule", + "configRuleId":"config-rule-i9y8j9", + "accountId":"0123456789012", + "evaluationMode":"DETECTIVE" + } diff --git a/examples/event_sources/src/aws_config_rule_oversized.json b/examples/event_sources/src/aws_config_rule_oversized.json new file mode 100644 index 00000000000..5eaef4e0015 --- /dev/null +++ b/examples/event_sources/src/aws_config_rule_oversized.json @@ -0,0 +1,12 @@ +{ + "invokingEvent": "{\"configurationItemSummary\": {\"changeType\": \"UPDATE\",\"configurationItemVersion\": \"1.2\",\"configurationItemCaptureTime\":\"2016-10-06T16:46:16.261Z\",\"configurationStateId\": 0,\"awsAccountId\":\"123456789012\",\"configurationItemStatus\": \"OK\",\"resourceType\": \"AWS::EC2::Instance\",\"resourceId\":\"i-00000000\",\"resourceName\":null,\"ARN\":\"arn:aws:ec2:us-west-2:123456789012:instance/i-00000000\",\"awsRegion\": \"us-west-2\",\"availabilityZone\":\"us-west-2a\",\"configurationStateMd5Hash\":\"8f1ee69b287895a0f8bc5753eca68e96\",\"resourceCreationTime\":\"2016-10-06T16:46:10.489Z\"},\"messageType\":\"OversizedConfigurationItemChangeNotification\", \"notificationCreationTime\": \"2016-10-06T16:46:16.261Z\", \"recordVersion\": \"1.0\"}", + "ruleParameters": "{\"myParameterKey\":\"myParameterValue\"}", + "resultToken": "myResultToken", + "eventLeftScope": false, + "executionRoleArn": "arn:aws:iam::123456789012:role/config-role", + "configRuleArn": "arn:aws:config:us-east-2:123456789012:config-rule/config-rule-ec2-managed-instance-inventory", + "configRuleName": "change-triggered-config-rule", + "configRuleId": "config-rule-0123456", + "accountId": "123456789012", + "version": "1.0" +} diff --git a/examples/event_sources/src/aws_config_rule_scheduled.json b/examples/event_sources/src/aws_config_rule_scheduled.json new file mode 100644 index 00000000000..f21ed9fe57f --- /dev/null +++ b/examples/event_sources/src/aws_config_rule_scheduled.json @@ -0,0 +1,13 @@ +{ + "version":"1.0", + "invokingEvent":"{\"awsAccountId\":\"0123456789012\",\"notificationCreationTime\":\"2023-04-27T13:26:17.741Z\",\"messageType\":\"ScheduledNxotification\",\"recordVersion\":\"1.0\"}", + "ruleParameters":"{\"test\":\"x\"}", + "resultToken":"eyJlbmNyeXB0ZWREYXRhIjpbLTQyLDEyNiw1MiwtMzcsLTI5LDExNCwxMjYsLTk3LDcxLDIyLC0xMTAsMTEyLC0zMSwtOTMsLTQ5LC0xMDEsODIsMyw1NCw0OSwzLC02OSwtNzEsLTcyLDYyLDgxLC03MiwtODEsNTAsMzUsLTUwLC03NSwtMTE4LC0xMTgsNzcsMTIsLTEsMTQsMTIwLC03MCwxMTAsLTMsNTAsLTYwLDEwNSwtNTcsNDUsMTAyLC0xMDksLTYxLC0xMDEsLTYxLDQsNDcsLTg0LC0yNSwxMTIsNTQsLTcxLC0xMDksNDUsMTksMTIzLC0yNiwxMiwtOTYsLTczLDU0LC0xMDksOTIsNDgsLTU5LC04MywtMzIsODIsLTM2LC05MCwxOSw5OCw3Nyw3OCw0MCw4MCw3OCwtMTA1LDg3LC0xMTMsLTExNiwtNzIsMzAsLTY4LC00MCwtODksMTA5LC0xMDgsLTEyOCwyMiw3Miw3NywtMjEsNzYsODksOTQsLTU5LDgxLC0xMjEsLTEwNywtNjcsNjMsLTcsODIsLTg5LC00NiwtMzQsLTkyLDEyMiwtOTAsMTcsLTEyMywyMCwtODUsLTU5LC03MCw4MSwyNyw2Miw3NCwtODAsODAsMzcsNDAsMTE2LDkxLC0yNCw1MSwtNDEsLTc5LDI4LDEyMCw1MywtMTIyLC04MywxMjYsLTc4LDI1LC05OCwtMzYsMTMsMzIsODYsLTI1LDQ4LDMsLTEwMiwtMTYsMjQsLTMsODUsNDQsLTI4LDE0LDIyLDI3LC0xMjIsMTE4LDEwMSw3Myw1LDE4LDU4LC02NCwyMywtODYsLTExNCwyNCwwLDEwMCwyLDExNywtNjIsLTExOSwtMTI4LDE4LDY1LDkwLDE0LC0xMDIsMjEsODUsMTAwLDExNyw1NSwyOSwxMjcsNTQsNzcsNzIsNzQsMzIsNzgsMywtMTExLDExOCwtNzAsLTg2LDEyNywtNzQsNjAsMjIsNDgsMzcsODcsMTMsMCwtMTA1LDUsLTEyMiwtNzEsLTEwMCwxMDQsLTEyNiwtMTYsNzksLTMwLDEyMCw3NywtNzYsLTQxLC0xMDksMiw5NywtMTAxLC0xLDE1LDEyMywxMTksMTA4LDkxLC0yMCwtMTI1LC05NiwyLC05MiwtMTUsLTY3LC03NiwxMjEsMTA0LDEwNSw2NCwtNjIsMTAyLDgsNCwxMjEsLTQ1LC04MCwtODEsLTgsMTE4LDQ0LC04MiwtNDEsLTg0LDczLC0zNiwxMTcsODAsLTY5LC03MywxNCwtMTgsNzIsMzEsLTUsLTExMSwtMTI3LC00MywzNCwtOCw1NywxMDMsLTQyLDE4LC0zMywxMTcsLTI2LC0xMjQsLTEyNCwxNSw4OCwyMywxNiwtNTcsNTQsLTYsLTEwMiwxMTYsLTk5LC00NSwxMDAsLTM1LDg3LDM3LDYsOTgsMiwxMTIsNjAsLTMzLDE3LDI2LDk5LC0xMDUsNDgsLTEwNCwtMTE5LDc4LDYsLTU4LDk1LDksNDEsLTE2LDk2LDQxLC0yMiw5Niw3MiwxMTYsLTk1LC0xMDUsLTM2LC0xMjMsLTU1LDkxLC00NiwtNywtOTIsMzksNDUsODQsMTYsLTEyNCwtMTIyLC02OCwxLC0yOCwxMjIsLTYwLDgyLDEwMywtNTQsLTkyLDI3LC05OSwtMTI4LDY1LDcsLTcyLC0xMjcsNjIsLTIyLDIsLTExLDE4LC04OSwtMTA2LC03NCw3MSw4NiwtMTE2LC0yNSwtMTE1LC05Niw1NywtMzQsMjIsLTEyNCwtMTI1LC00LC00MSw0MiwtNTcsLTEwMyw0NSw3OCwxNCwtMTA2LDExMSw5OCwtOTQsLTcxLDUsNzUsMTksLTEyNCwtMzAsMzQsLTUwLDc1LC04NCwtNTAsLTU2LDUxLC0xNSwtMzYsNjEsLTk0LC03OSwtNDUsMTI2LC03NywtMTA1LC0yLC05MywtNiw4LC0zLDYsLTQyLDQ2LDEyNSw1LC05OCwxMyw2NywtMTAsLTEzLC05NCwtNzgsLTEyNywxMjEsLTI2LC04LC0xMDEsLTkxLDEyMSwtNDAsLTEyNCwtNjQsODQsLTcyLDYzLDE5LC04NF0sIm1hdGVyaWFsU2V0U2VyaWFsTnVtYmVyIjoxLCJpdlBhcmFtZXRlclNwZWMiOnsiaXYiOlszLC0xMCwtODUsMTE0LC05MCwxMTUsNzcsNTUsNTQsMTUsMzgsODQsLTExNiwxNCwtNDAsMjhdfX0=", + "eventLeftScope":false, + "executionRoleArn":"arn:aws:iam::0123456789012:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig", + "configRuleArn":"arn:aws:config:us-east-1:0123456789012:config-rule/config-rule-pdmyw1", + "configRuleName":"rule-ec2-test", + "configRuleId":"config-rule-pdmyw1", + "accountId":"0123456789012", + "evaluationMode":"DETECTIVE" + } diff --git a/tests/events/awsConfigRuleConfigurationChanged.json b/tests/events/awsConfigRuleConfigurationChanged.json new file mode 100644 index 00000000000..cbf7abf67aa --- /dev/null +++ b/tests/events/awsConfigRuleConfigurationChanged.json @@ -0,0 +1,13 @@ +{ + "version":"1.0", + "invokingEvent":"{\"configurationItemDiff\":{\"changedProperties\":{\"Configuration.InstanceType\":{\"previousValue\":\"t2.micro\",\"updatedValue\":\"t2.medium\",\"changeType\":\"UPDATE\"},\"Configuration.State.Name\":{\"previousValue\":\"running\",\"updatedValue\":\"stopped\",\"changeType\":\"UPDATE\"},\"Configuration.StateTransitionReason\":{\"previousValue\":\"\",\"updatedValue\":\"User initiated (2023-04-27 15:01:07 GMT)\",\"changeType\":\"UPDATE\"},\"Configuration.StateReason\":{\"previousValue\":null,\"updatedValue\":{\"code\":\"Client.UserInitiatedShutdown\",\"message\":\"Client.UserInitiatedShutdown: User initiated shutdown\"},\"changeType\":\"CREATE\"},\"Configuration.CpuOptions.CoreCount\":{\"previousValue\":1,\"updatedValue\":2,\"changeType\":\"UPDATE\"}},\"changeType\":\"UPDATE\"},\"configurationItem\":{\"relatedEvents\":[],\"relationships\":[{\"resourceId\":\"eipalloc-0ebb4367662263cc1\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::EIP\",\"name\":\"Is attached to ElasticIp\"},{\"resourceId\":\"eni-034dd31c4b17ada8c\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::NetworkInterface\",\"name\":\"Contains NetworkInterface\"},{\"resourceId\":\"eni-09a604c0ec356b06f\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::NetworkInterface\",\"name\":\"Contains NetworkInterface\"},{\"resourceId\":\"sg-0fb295a327d9b4835\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::SecurityGroup\",\"name\":\"Is associated with SecurityGroup\"},{\"resourceId\":\"subnet-cad1f2f4\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::Subnet\",\"name\":\"Is contained in Subnet\"},{\"resourceId\":\"vol-0a288b5eb9fea4b30\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::Volume\",\"name\":\"Is attached to Volume\"},{\"resourceId\":\"vpc-2d96be57\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::VPC\",\"name\":\"Is contained in Vpc\"}],\"configuration\":{\"amiLaunchIndex\":0,\"imageId\":\"ami-09d95fab7fff3776c\",\"instanceId\":\"i-042dd005362091826\",\"instanceType\":\"t2.medium\",\"kernelId\":null,\"keyName\":\"mihaec2\",\"launchTime\":\"2023-04-27T14:57:16.000Z\",\"monitoring\":{\"state\":\"disabled\"},\"placement\":{\"availabilityZone\":\"us-east-1e\",\"affinity\":null,\"groupName\":\"\",\"partitionNumber\":null,\"hostId\":null,\"tenancy\":\"default\",\"spreadDomain\":null,\"hostResourceGroupArn\":null},\"platform\":null,\"privateDnsName\":\"ip-172-31-78-41.ec2.internal\",\"privateIpAddress\":\"172.31.78.41\",\"productCodes\":[],\"publicDnsName\":\"ec2-3-232-229-57.compute-1.amazonaws.com\",\"publicIpAddress\":\"3.232.229.57\",\"ramdiskId\":null,\"state\":{\"code\":80,\"name\":\"stopped\"},\"stateTransitionReason\":\"User initiated (2023-04-27 15:01:07 GMT)\",\"subnetId\":\"subnet-cad1f2f4\",\"vpcId\":\"vpc-2d96be57\",\"architecture\":\"x86_64\",\"blockDeviceMappings\":[{\"deviceName\":\"/dev/xvda\",\"ebs\":{\"attachTime\":\"2020-05-30T15:21:58.000Z\",\"deleteOnTermination\":true,\"status\":\"attached\",\"volumeId\":\"vol-0a288b5eb9fea4b30\"}}],\"clientToken\":\"\",\"ebsOptimized\":false,\"enaSupport\":true,\"hypervisor\":\"xen\",\"iamInstanceProfile\":{\"arn\":\"arn:aws:iam::0123456789012:instance-profile/AmazonSSMRoleForInstancesQuickSetup\",\"id\":\"AIPAS5S4WFUBL72S3QXW5\"},\"instanceLifecycle\":null,\"elasticGpuAssociations\":[],\"elasticInferenceAcceleratorAssociations\":[],\"networkInterfaces\":[{\"association\":{\"carrierIp\":null,\"ipOwnerId\":\"0123456789012\",\"publicDnsName\":\"ec2-3-232-229-57.compute-1.amazonaws.com\",\"publicIp\":\"3.232.229.57\"},\"attachment\":{\"attachTime\":\"2020-05-30T15:21:57.000Z\",\"attachmentId\":\"eni-attach-0a7e75dc9c1c291a0\",\"deleteOnTermination\":true,\"deviceIndex\":0,\"status\":\"attached\",\"networkCardIndex\":0},\"description\":\"\",\"groups\":[{\"groupName\":\"minhaec2\",\"groupId\":\"sg-0fb295a327d9b4835\"}],\"ipv6Addresses\":[],\"macAddress\":\"06:cf:00:c2:17:db\",\"networkInterfaceId\":\"eni-034dd31c4b17ada8c\",\"ownerId\":\"0123456789012\",\"privateDnsName\":\"ip-172-31-78-41.ec2.internal\",\"privateIpAddress\":\"172.31.78.41\",\"privateIpAddresses\":[{\"association\":{\"carrierIp\":null,\"ipOwnerId\":\"0123456789012\",\"publicDnsName\":\"ec2-3-232-229-57.compute-1.amazonaws.com\",\"publicIp\":\"3.232.229.57\"},\"primary\":true,\"privateDnsName\":\"ip-172-31-78-41.ec2.internal\",\"privateIpAddress\":\"172.31.78.41\"}],\"sourceDestCheck\":true,\"status\":\"in-use\",\"subnetId\":\"subnet-cad1f2f4\",\"vpcId\":\"vpc-2d96be57\",\"interfaceType\":\"interface\"},{\"association\":null,\"attachment\":{\"attachTime\":\"2020-11-26T23:46:04.000Z\",\"attachmentId\":\"eni-attach-0e6d150ebbd19966e\",\"deleteOnTermination\":false,\"deviceIndex\":1,\"status\":\"attached\",\"networkCardIndex\":0},\"description\":\"MINHAEC2AAAAAA\",\"groups\":[{\"groupName\":\"minhaec2\",\"groupId\":\"sg-0fb295a327d9b4835\"},{\"groupName\":\"default\",\"groupId\":\"sg-88105fa0\"}],\"ipv6Addresses\":[],\"macAddress\":\"06:0a:62:00:64:5f\",\"networkInterfaceId\":\"eni-09a604c0ec356b06f\",\"ownerId\":\"0123456789012\",\"privateDnsName\":\"ip-172-31-70-9.ec2.internal\",\"privateIpAddress\":\"172.31.70.9\",\"privateIpAddresses\":[{\"association\":null,\"primary\":true,\"privateDnsName\":\"ip-172-31-70-9.ec2.internal\",\"privateIpAddress\":\"172.31.70.9\"}],\"sourceDestCheck\":true,\"status\":\"in-use\",\"subnetId\":\"subnet-cad1f2f4\",\"vpcId\":\"vpc-2d96be57\",\"interfaceType\":\"interface\"}],\"outpostArn\":null,\"rootDeviceName\":\"/dev/xvda\",\"rootDeviceType\":\"ebs\",\"securityGroups\":[{\"groupName\":\"minhaec2\",\"groupId\":\"sg-0fb295a327d9b4835\"}],\"sourceDestCheck\":true,\"spotInstanceRequestId\":null,\"sriovNetSupport\":null,\"stateReason\":{\"code\":\"Client.UserInitiatedShutdown\",\"message\":\"Client.UserInitiatedShutdown: User initiated shutdown\"},\"tags\":[{\"key\":\"projeto\",\"value\":\"meetup\"},{\"key\":\"Name\",\"value\":\"Minha\"},{\"key\":\"CentroCusto\",\"value\":\"TI\"},{\"key\":\"Setor\",\"value\":\"Desenvolvimento\"}],\"virtualizationType\":\"hvm\",\"cpuOptions\":{\"coreCount\":2,\"threadsPerCore\":1},\"capacityReservationId\":null,\"capacityReservationSpecification\":{\"capacityReservationPreference\":\"open\",\"capacityReservationTarget\":null},\"hibernationOptions\":{\"configured\":false},\"licenses\":[],\"metadataOptions\":{\"state\":\"applied\",\"httpTokens\":\"optional\",\"httpPutResponseHopLimit\":1,\"httpEndpoint\":\"enabled\"},\"enclaveOptions\":{\"enabled\":false},\"bootMode\":null},\"supplementaryConfiguration\":{},\"tags\":{\"projeto\":\"meetup\",\"Setor\":\"Desenvolvimento\",\"CentroCusto\":\"TI\",\"Name\":\"Minha\"},\"configurationItemVersion\":\"1.3\",\"configurationItemCaptureTime\":\"2023-04-27T15:03:11.636Z\",\"configurationStateId\":1682607791636,\"awsAccountId\":\"0123456789012\",\"configurationItemStatus\":\"OK\",\"resourceType\":\"AWS::EC2::Instance\",\"resourceId\":\"i-042dd005362091826\",\"resourceName\":null,\"ARN\":\"arn:aws:ec2:us-east-1:0123456789012:instance/i-042dd005362091826\",\"awsRegion\":\"us-east-1\",\"availabilityZone\":\"us-east-1e\",\"configurationStateMd5Hash\":\"\",\"resourceCreationTime\":\"2023-04-27T14:57:16.000Z\"},\"notificationCreationTime\":\"2023-04-27T15:03:13.332Z\",\"messageType\":\"ConfigurationItemChangeNotification\",\"recordVersion\":\"1.3\"}", + "ruleParameters":"{\"desiredInstanceType\": \"t2.micro\"}", + "resultToken":"eyJlbmNyeXB0ZWREYXRhIjpbLTQxLDEsLTU3LC0zMCwtMTIxLDUzLDUyLDQ1LC01NywtOCw3MywtODEsLTExNiwtMTAyLC01MiwxMTIsLTQ3LDU4LDY1LC0xMjcsMTAyLDUsLTY5LDQ0LC0xNSwxMTQsNDEsLTksMTExLC0zMCw2NSwtNzUsLTM1LDU0LDEwNSwtODksODYsNDAsLTEwNSw5OCw2NSwtMTE5LC02OSwyNCw2NiwtMjAsODAsLTExMiwtNzgsLTgwLDQzLC01NywzMCwtMjUsODIsLTEwLDMsLTQsLTg1LC01MywtMzcsLTkwLC04OCwtOTgsLTk4LC00MSwxOSwxMTYsNjIsLTIzLC0xMjEsLTEwOCw1NywtNTgsLTUyLDI5LDEwMSwxMjIsLTU2LC03MSwtODEsLTQ3LDc3LC0yMiwtMTI0LC0zLC04NiwtMTIyLC00MCwtODksLTEwMSw1NywtMTI3LC0zNywtMzcsLTMxLC05OCwtMzEsMTEsLTEyNSwwLDEwOCwtMzIsNjQsNjIsLTIyLDAsNDcsLTEwNiwtMTAwLDEwNCwxNCw1OCwxMjIsLTEwLC01MCwtOTAsLTgwLC01MCwtNSw2NSwwLC0yNSw4NSw4Miw3LDkzLDEyMiwtODIsLTExNiwtNzksLTQ0LDcyLC03MywtNjksMTQsLTU2LDk0LDkwLDExNCwtMjksLTExOSwtNzEsODgsMTA3LDEwNywxMTAsLTcsMTI3LC0xMjUsLTU3LC0xMjYsLTEyMCw2OSwtMTI3LC03NiwtMTE5LDcxLDEsLTY4LDEwNywxMTMsLTU2LDg3LC0xMDIsLTE2LDEwOCwtMTA3LC00MywtOTQsLTEwNiwzLDkwLDE0LDcyLC0xMiwtMTE2LC03Myw4MCwtMTIyLDQ0LC0xMDQsMTIsNzQsNTcsLTEwLC0xMDUsLTExMiwtMzYsMjgsLTQ1LDk3LDExLC00OSwtMTEsNjEsMzYsLTE3LC03NCw1MCw0LC0yNiwxMDQsLTI4LC0xMjUsMjQsNzAsLTg1LC00Niw5MiwtMTAzLC00MSwtMTA2LDY5LDEyMiwyMSwtMjUsODAsOTksLTkzLC01NiwtMjUsLTQ3LC0xMjMsLTU5LC0xMjQsLTUyLC0xNiwxMjcsLTM4LC0xNiwxMDEsMTE5LDEwNywyNywxMCwtNDYsLTg3LC0xMiwtMzksMTQsNDUsMiw3MCwxMDcsMTA0LC00LC02OSwtMTIsNTksLTEyNiwtOTEsMTI3LDU0LDEwNiwtMTI2LC0xMTYsLTEwMiw3Miw4MSw1MCw3NSwtNTEsMTA4LDQxLC0zLC02LC00NSwxMDMsLTg2LDM3LC00NiwtMzIsLTExMSwxMjQsMTExLDg3LDU0LC03NiwxMjIsLTUsLTM2LC04OCw5LC0xMTMsMTE2LC01OSw4Myw3NywyOCwxMiwtNjUsLTExMywtNzksLTEyOCw4MiwtMTE4LC04MywtMTI0LDMxLDk5LC05MCwtOTksMTYsLTEyMywyMSwtMTE0LC05OCwtMTE2LC0xMTksMiwtNzMsNDYsODIsLTEzLDU0LDcxLC00MiwyNSw3NCw3MywtODYsOTQsNDYsOTksOTMsLTgyLDU1LDY1LC05OCw0OSwtNjAsMTEyLDEwMSwyMiw2OSwtMTYsNzcsLTk0LC01OSwtNDYsMTE1LDMwLC00Myw5Myw4OCwtMjgsMzgsNiw4NCwzMSwtMTAxLDMyLC0yMiwtNjMsLTk1LDExNCwtNzUsMTE0LDM2LC04NCw0MCwtNDQsLTEzLDU5LDcyLC0xLC0xMDMsMzEsMTA1LDY5LDY5LDc3LC02NCwtNTYsMTE4LDEzLC0xMTQsODAsOTksLTUzLDI1LDQyLDk0LDczLC04MCwyNSwzOCwyNCwtMTcsNjYsLTExOCwtMjMsMTE5LDkwLDEyMSwxMTgsLTUxLDUxLC0xMiwtNzYsLTUxLDksLTIxLDExNCwtMzcsLTY0LC0yLC0xMjYsLTk1LDYzLDczLC00MSwtMzQsLTkwLC0yMiw1OSwtNzksMzAsLTQsLTEsLTUsMTIsMzksLTk5LC0xMDUsLTEwNCwtNjEsNjUsLTc0LDE5LC0xMywtNjAsLTI4LC04LDQsLTgsMTIxLC0xMTgsMTIyLC02NSwtMjEsMjMsMTcsLTg0LDQwLC05MiwxNCwtMTI2LC02MCwtNzksLTUzLDM3LC04Myw2NSwxMDQsLTM2LC02MCwtMTEwLC0zMywtMTE3LDYsMTA3LDEsLTMsOTMsNzgsLTk1LC0xMjIsNTMsMTA4LC00OSwtNDksMjQsLTY1LDgzLDEyNSwtNzcsLTE5LC04MSwzNCwtNjcsLTQzLC03MCwtMjYsMTgsMTA0LDY1LDQsLTEyNiw0NCwtMTE5LDUyLC00NiwyMiw2NywxMTMsMTE4LC0zMywzNCwtOTYsMTIxLDE5LC0yLC0zNSwwLC04MiwxNyw2NiwtMjcsNjksLTM2LC0xNCw1NiwtOTcsLTE2LDEyMywyOCwtOTUsLTMyLC02MywtNjksNzAsNjQsLTMzLC0xMDAsNDMsLTExMywxMDUsMTAwLDEwOCwtNjAsNDAsLTIsLTk2LC0xMjQsMzcsLTQ1LC0xMjQsLTY4LC02OSwtMTIzLDE3LC02LDg2LC01OSwtOTQsMTEwLDczLDU3LC0xMTYsMTA3LC00MSwtOTQsLTExOCwtMTI2LDEwLC04MCwtNzAsMTAyLDg4LC0xMjYsODcsLTI3LC0xMDEsLTk0LC0zNSwtMTA2LC02LC03MiwtODYsNTAsMTE2LC0yOCw5MCwxMywtMTIwLDYsMjcsOTIsNTYsLTkwLDM5LDQ5LC0xMywtODYsLTI1LC04NiwxMTMsLTEzLDQxLC0xMTksOTQsLTk0LC0xMDMsLTgzLC02MCwxMjcsLTE1LC0zOSwxMTksLTk1LDI3LDQ0LDExNiwxMDksNywtMTAyLC0xNyw0OCwtODIsLTMxLC04LC02OSwzNSw5NCw1NCwtNTUsMSwtMTE5LDU3LC0xMDgsLTMsLTkxLC0xMjIsLTUzLC04OCw0LC05NywtMzUsMTI2LDExOSw1OSwtMSw4NSw3MywtNTgsLTEyMCwtNjQsMTE5LC0xMTIsOTIsMTksOSwtNjYsLTkyLDEwOCwtMTEsLTQyLDExMSwtMTA0LC0xMjAsMjcsLTEwMywtNjksMTksMTExLDEyLDIzLDEwNyw1NCw0MSwtMjYsNjAsLTMxLC01XSwibWF0ZXJpYWxTZXRTZXJpYWxOdW1iZXIiOjEsIml2UGFyYW1ldGVyU3BlYyI6eyJpdiI6Wy05NSwzMiwxMDgsOTEsMzUsLTgyLC0zNywyNCwtNDQsLTExNSwtODIsLTEyOCwtMTIyLDMsNTMsLTI0XX19", + "eventLeftScope":false, + "executionRoleArn":"arn:aws:iam::0123456789012:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig", + "configRuleArn":"arn:aws:config:us-east-1:0123456789012:config-rule/config-rule-i9y8j9", + "configRuleName":"MyRule", + "configRuleId":"config-rule-i9y8j9", + "accountId":"0123456789012", + "evaluationMode":"DETECTIVE" + } diff --git a/tests/events/awsConfigRuleOversizedConfiguration.json b/tests/events/awsConfigRuleOversizedConfiguration.json new file mode 100644 index 00000000000..5eaef4e0015 --- /dev/null +++ b/tests/events/awsConfigRuleOversizedConfiguration.json @@ -0,0 +1,12 @@ +{ + "invokingEvent": "{\"configurationItemSummary\": {\"changeType\": \"UPDATE\",\"configurationItemVersion\": \"1.2\",\"configurationItemCaptureTime\":\"2016-10-06T16:46:16.261Z\",\"configurationStateId\": 0,\"awsAccountId\":\"123456789012\",\"configurationItemStatus\": \"OK\",\"resourceType\": \"AWS::EC2::Instance\",\"resourceId\":\"i-00000000\",\"resourceName\":null,\"ARN\":\"arn:aws:ec2:us-west-2:123456789012:instance/i-00000000\",\"awsRegion\": \"us-west-2\",\"availabilityZone\":\"us-west-2a\",\"configurationStateMd5Hash\":\"8f1ee69b287895a0f8bc5753eca68e96\",\"resourceCreationTime\":\"2016-10-06T16:46:10.489Z\"},\"messageType\":\"OversizedConfigurationItemChangeNotification\", \"notificationCreationTime\": \"2016-10-06T16:46:16.261Z\", \"recordVersion\": \"1.0\"}", + "ruleParameters": "{\"myParameterKey\":\"myParameterValue\"}", + "resultToken": "myResultToken", + "eventLeftScope": false, + "executionRoleArn": "arn:aws:iam::123456789012:role/config-role", + "configRuleArn": "arn:aws:config:us-east-2:123456789012:config-rule/config-rule-ec2-managed-instance-inventory", + "configRuleName": "change-triggered-config-rule", + "configRuleId": "config-rule-0123456", + "accountId": "123456789012", + "version": "1.0" +} diff --git a/tests/events/awsConfigRuleScheduled.json b/tests/events/awsConfigRuleScheduled.json new file mode 100644 index 00000000000..02ce2a0700c --- /dev/null +++ b/tests/events/awsConfigRuleScheduled.json @@ -0,0 +1,13 @@ +{ + "version":"1.0", + "invokingEvent":"{\"awsAccountId\":\"0123456789012\",\"notificationCreationTime\":\"2023-04-27T13:26:17.741Z\",\"messageType\":\"ScheduledNotification\",\"recordVersion\":\"1.0\"}", + "ruleParameters":"{\"test\":\"x\"}", + "resultToken":"eyJlbmNyeXB0ZWREYXRhIjpbLTQyLDEyNiw1MiwtMzcsLTI5LDExNCwxMjYsLTk3LDcxLDIyLC0xMTAsMTEyLC0zMSwtOTMsLTQ5LC0xMDEsODIsMyw1NCw0OSwzLC02OSwtNzEsLTcyLDYyLDgxLC03MiwtODEsNTAsMzUsLTUwLC03NSwtMTE4LC0xMTgsNzcsMTIsLTEsMTQsMTIwLC03MCwxMTAsLTMsNTAsLTYwLDEwNSwtNTcsNDUsMTAyLC0xMDksLTYxLC0xMDEsLTYxLDQsNDcsLTg0LC0yNSwxMTIsNTQsLTcxLC0xMDksNDUsMTksMTIzLC0yNiwxMiwtOTYsLTczLDU0LC0xMDksOTIsNDgsLTU5LC04MywtMzIsODIsLTM2LC05MCwxOSw5OCw3Nyw3OCw0MCw4MCw3OCwtMTA1LDg3LC0xMTMsLTExNiwtNzIsMzAsLTY4LC00MCwtODksMTA5LC0xMDgsLTEyOCwyMiw3Miw3NywtMjEsNzYsODksOTQsLTU5LDgxLC0xMjEsLTEwNywtNjcsNjMsLTcsODIsLTg5LC00NiwtMzQsLTkyLDEyMiwtOTAsMTcsLTEyMywyMCwtODUsLTU5LC03MCw4MSwyNyw2Miw3NCwtODAsODAsMzcsNDAsMTE2LDkxLC0yNCw1MSwtNDEsLTc5LDI4LDEyMCw1MywtMTIyLC04MywxMjYsLTc4LDI1LC05OCwtMzYsMTMsMzIsODYsLTI1LDQ4LDMsLTEwMiwtMTYsMjQsLTMsODUsNDQsLTI4LDE0LDIyLDI3LC0xMjIsMTE4LDEwMSw3Myw1LDE4LDU4LC02NCwyMywtODYsLTExNCwyNCwwLDEwMCwyLDExNywtNjIsLTExOSwtMTI4LDE4LDY1LDkwLDE0LC0xMDIsMjEsODUsMTAwLDExNyw1NSwyOSwxMjcsNTQsNzcsNzIsNzQsMzIsNzgsMywtMTExLDExOCwtNzAsLTg2LDEyNywtNzQsNjAsMjIsNDgsMzcsODcsMTMsMCwtMTA1LDUsLTEyMiwtNzEsLTEwMCwxMDQsLTEyNiwtMTYsNzksLTMwLDEyMCw3NywtNzYsLTQxLC0xMDksMiw5NywtMTAxLC0xLDE1LDEyMywxMTksMTA4LDkxLC0yMCwtMTI1LC05NiwyLC05MiwtMTUsLTY3LC03NiwxMjEsMTA0LDEwNSw2NCwtNjIsMTAyLDgsNCwxMjEsLTQ1LC04MCwtODEsLTgsMTE4LDQ0LC04MiwtNDEsLTg0LDczLC0zNiwxMTcsODAsLTY5LC03MywxNCwtMTgsNzIsMzEsLTUsLTExMSwtMTI3LC00MywzNCwtOCw1NywxMDMsLTQyLDE4LC0zMywxMTcsLTI2LC0xMjQsLTEyNCwxNSw4OCwyMywxNiwtNTcsNTQsLTYsLTEwMiwxMTYsLTk5LC00NSwxMDAsLTM1LDg3LDM3LDYsOTgsMiwxMTIsNjAsLTMzLDE3LDI2LDk5LC0xMDUsNDgsLTEwNCwtMTE5LDc4LDYsLTU4LDk1LDksNDEsLTE2LDk2LDQxLC0yMiw5Niw3MiwxMTYsLTk1LC0xMDUsLTM2LC0xMjMsLTU1LDkxLC00NiwtNywtOTIsMzksNDUsODQsMTYsLTEyNCwtMTIyLC02OCwxLC0yOCwxMjIsLTYwLDgyLDEwMywtNTQsLTkyLDI3LC05OSwtMTI4LDY1LDcsLTcyLC0xMjcsNjIsLTIyLDIsLTExLDE4LC04OSwtMTA2LC03NCw3MSw4NiwtMTE2LC0yNSwtMTE1LC05Niw1NywtMzQsMjIsLTEyNCwtMTI1LC00LC00MSw0MiwtNTcsLTEwMyw0NSw3OCwxNCwtMTA2LDExMSw5OCwtOTQsLTcxLDUsNzUsMTksLTEyNCwtMzAsMzQsLTUwLDc1LC04NCwtNTAsLTU2LDUxLC0xNSwtMzYsNjEsLTk0LC03OSwtNDUsMTI2LC03NywtMTA1LC0yLC05MywtNiw4LC0zLDYsLTQyLDQ2LDEyNSw1LC05OCwxMyw2NywtMTAsLTEzLC05NCwtNzgsLTEyNywxMjEsLTI2LC04LC0xMDEsLTkxLDEyMSwtNDAsLTEyNCwtNjQsODQsLTcyLDYzLDE5LC04NF0sIm1hdGVyaWFsU2V0U2VyaWFsTnVtYmVyIjoxLCJpdlBhcmFtZXRlclNwZWMiOnsiaXYiOlszLC0xMCwtODUsMTE0LC05MCwxMTUsNzcsNTUsNTQsMTUsMzgsODQsLTExNiwxNCwtNDAsMjhdfX0=", + "eventLeftScope":false, + "executionRoleArn":"arn:aws:iam::0123456789012:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig", + "configRuleArn":"arn:aws:config:us-east-1:0123456789012:config-rule/config-rule-pdmyw1", + "configRuleName":"rule-ec2-test", + "configRuleId":"config-rule-pdmyw1", + "accountId":"0123456789012", + "evaluationMode":"DETECTIVE" + } diff --git a/tests/functional/test_data_classes.py b/tests/functional/test_data_classes.py index 23f4b18e53d..a811a779255 100644 --- a/tests/functional/test_data_classes.py +++ b/tests/functional/test_data_classes.py @@ -14,6 +14,7 @@ APIGatewayProxyEvent, APIGatewayProxyEventV2, AppSyncResolverEvent, + AWSConfigRuleEvent, CloudWatchDashboardCustomWidgetEvent, CloudWatchLogsEvent, CodePipelineJobEvent, @@ -2044,6 +2045,176 @@ def test_api_gateway_route_arn_parser(): assert details.arn == arn + "/" +def test_aws_config_rule_configuration_changed(): + """Check AWS Config ConfigurationItemChangeNotification event""" + event = AWSConfigRuleEvent(load_event("awsConfigRuleConfigurationChanged.json")) + + invoking_event = json.loads(event["invokingEvent"]) + + assert event.rule_parameters == json.loads(event["ruleParameters"]) + assert event.raw_invoking_event == event["invokingEvent"] + assert event.result_token == event["resultToken"] + assert event.event_left_scope == event["eventLeftScope"] + assert event.execution_role_arn == event["executionRoleArn"] + assert event.config_rule_arn == event["configRuleArn"] + assert event.config_rule_name == event["configRuleName"] + assert event.config_rule_id == event["configRuleId"] + assert event.accountid == event["accountId"] + assert event.version == event["version"] + assert event.evalution_mode == event["evaluationMode"] + assert event.invoking_event.message_type == invoking_event["messageType"] + assert event.invoking_event.raw_configuration_item == invoking_event["configurationItem"] + assert event.invoking_event.record_version == invoking_event["recordVersion"] + assert event.invoking_event.notification_creation_time == invoking_event["notificationCreationTime"] + assert event.invoking_event.configuration_item_diff == invoking_event["configurationItemDiff"] + assert ( + event.invoking_event.configuration_item.related_events == invoking_event["configurationItem"]["relatedEvents"] + ) + assert event.invoking_event.configuration_item.relationships == invoking_event["configurationItem"]["relationships"] + assert event.invoking_event.configuration_item.configuration == invoking_event["configurationItem"]["configuration"] + assert ( + event.invoking_event.configuration_item.supplementary_configuration + == invoking_event["configurationItem"]["supplementaryConfiguration"] + ) + assert event.invoking_event.configuration_item.tags == invoking_event["configurationItem"]["tags"] + assert ( + event.invoking_event.configuration_item.configuration_item_version + == invoking_event["configurationItem"]["configurationItemVersion"] + ) + assert ( + event.invoking_event.configuration_item.configuration_item_capture_time + == invoking_event["configurationItem"]["configurationItemCaptureTime"] + ) + assert ( + event.invoking_event.configuration_item.configuration_state_id + == invoking_event["configurationItem"]["configurationStateId"] + ) + assert event.invoking_event.configuration_item.accountid == invoking_event["configurationItem"]["awsAccountId"] + assert ( + event.invoking_event.configuration_item.configuration_item_status + == invoking_event["configurationItem"]["configurationItemStatus"] + ) + assert event.invoking_event.configuration_item.resource_type == invoking_event["configurationItem"]["resourceType"] + assert event.invoking_event.configuration_item.resource_id == invoking_event["configurationItem"]["resourceId"] + assert event.invoking_event.configuration_item.resource_name == invoking_event["configurationItem"]["resourceName"] + assert event.invoking_event.configuration_item.resource_arn == invoking_event["configurationItem"]["ARN"] + assert event.invoking_event.configuration_item.region == invoking_event["configurationItem"]["awsRegion"] + assert ( + event.invoking_event.configuration_item.availability_zone + == invoking_event["configurationItem"]["availabilityZone"] + ) + assert ( + event.invoking_event.configuration_item.configuration_state_md5_hash + == invoking_event["configurationItem"]["configurationStateMd5Hash"] + ) + assert ( + event.invoking_event.configuration_item.resource_creation_time + == invoking_event["configurationItem"]["resourceCreationTime"] + ) + + +def test_aws_config_rule_oversized_configuration(): + """Check AWS Config OversizedConfigurationItemChangeNotification event""" + event = AWSConfigRuleEvent(load_event("awsConfigRuleOversizedConfiguration.json")) + + invoking_event = json.loads(event["invokingEvent"]) + + assert event.rule_parameters == json.loads(event["ruleParameters"]) + assert event.raw_invoking_event == event["invokingEvent"] + assert event.result_token == event["resultToken"] + assert event.event_left_scope == event["eventLeftScope"] + assert event.execution_role_arn == event["executionRoleArn"] + assert event.config_rule_arn == event["configRuleArn"] + assert event.config_rule_name == event["configRuleName"] + assert event.config_rule_id == event["configRuleId"] + assert event.accountid == event["accountId"] + assert event.version == event["version"] + assert event.invoking_event.message_type == invoking_event["messageType"] + assert event.invoking_event.notification_creation_time == invoking_event["notificationCreationTime"] + assert event.invoking_event.record_version == invoking_event["recordVersion"] + assert event.invoking_event.raw_configuration_item_summary == invoking_event["configurationItemSummary"] + assert ( + event.invoking_event.configuration_item_summary.change_type + == invoking_event["configurationItemSummary"]["changeType"] + ) + assert ( + event.invoking_event.configuration_item_summary.configuration_item_version + == invoking_event["configurationItemSummary"]["configurationItemVersion"] + ) + assert ( + event.invoking_event.configuration_item_summary.configuration_item_capture_time + == invoking_event["configurationItemSummary"]["configurationItemCaptureTime"] + ) + assert ( + event.invoking_event.configuration_item_summary.configuration_state_id + == invoking_event["configurationItemSummary"]["configurationStateId"] + ) + assert ( + event.invoking_event.configuration_item_summary.accountid + == invoking_event["configurationItemSummary"]["awsAccountId"] + ) + assert ( + event.invoking_event.configuration_item_summary.configuration_item_status + == invoking_event["configurationItemSummary"]["configurationItemStatus"] + ) + assert ( + event.invoking_event.configuration_item_summary.resource_type + == invoking_event["configurationItemSummary"]["resourceType"] + ) + assert ( + event.invoking_event.configuration_item_summary.resource_id + == invoking_event["configurationItemSummary"]["resourceId"] + ) + assert ( + event.invoking_event.configuration_item_summary.resource_name + == invoking_event["configurationItemSummary"]["resourceName"] + ) + assert ( + event.invoking_event.configuration_item_summary.resource_arn + == invoking_event["configurationItemSummary"]["ARN"] + ) + assert ( + event.invoking_event.configuration_item_summary.region + == invoking_event["configurationItemSummary"]["awsRegion"] + ) + assert ( + event.invoking_event.configuration_item_summary.availability_zone + == invoking_event["configurationItemSummary"]["availabilityZone"] + ) + assert ( + event.invoking_event.configuration_item_summary.configuration_state_md5_hash + == invoking_event["configurationItemSummary"]["configurationStateMd5Hash"] + ) + assert ( + event.invoking_event.configuration_item_summary.resource_creation_time + == invoking_event["configurationItemSummary"]["resourceCreationTime"] + ) + + +def test_aws_config_rule_scheduled(): + """Check AWS Config ScheduledNotification event""" + event = AWSConfigRuleEvent(load_event("awsConfigRuleScheduled.json")) + + invoking_event = json.loads(event["invokingEvent"]) + + assert event.rule_parameters == json.loads(event["ruleParameters"]) + assert event.raw_invoking_event == event["invokingEvent"] + assert event.result_token == event["resultToken"] + assert event.event_left_scope == event["eventLeftScope"] + assert event.execution_role_arn == event["executionRoleArn"] + assert event.config_rule_arn == event["configRuleArn"] + assert event.config_rule_name == event["configRuleName"] + assert event.config_rule_id == event["configRuleId"] + assert event.accountid == event["accountId"] + assert event.version == event["version"] + assert event.evalution_mode == event["evaluationMode"] + assert event.invoking_event.message_type == invoking_event["messageType"] + assert event.invoking_event.accountid == invoking_event["awsAccountId"] + assert event.invoking_event.notification_creation_time == invoking_event["notificationCreationTime"] + assert event.invoking_event.message_type == invoking_event["messageType"] + assert event.invoking_event.record_version == invoking_event["recordVersion"] + + def test_vpc_lattice_event(): event = VPCLatticeEvent(load_event("vpcLatticeEvent.json")) From 58335579fde694ff26d336061c6243900aa46929 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Jun 2023 23:16:53 +0200 Subject: [PATCH 34/41] chore(deps): bump aws-actions/configure-aws-credentials from 2.1.0 to 2.2.0 (#2469) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/dispatch_analytics.yml | 2 +- .github/workflows/reusable_deploy_v2_layer_stack.yml | 2 +- .github/workflows/reusable_deploy_v2_sar.yml | 4 ++-- .github/workflows/reusable_publish_docs.yml | 2 +- .github/workflows/run-e2e-tests.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/dispatch_analytics.yml b/.github/workflows/dispatch_analytics.yml index fd35f66c9fc..43dfd02f26c 100644 --- a/.github/workflows/dispatch_analytics.yml +++ b/.github/workflows/dispatch_analytics.yml @@ -40,7 +40,7 @@ jobs: environment: analytics steps: - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@5727f247b64f324ec403ac56ae05e220fd02b65f # v2.1.0 + uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 with: aws-region: eu-central-1 role-to-assume: ${{ secrets.AWS_ANALYTICS_ROLE_ARN }} diff --git a/.github/workflows/reusable_deploy_v2_layer_stack.yml b/.github/workflows/reusable_deploy_v2_layer_stack.yml index 47eb1680ccd..04abcfaee1b 100644 --- a/.github/workflows/reusable_deploy_v2_layer_stack.yml +++ b/.github/workflows/reusable_deploy_v2_layer_stack.yml @@ -126,7 +126,7 @@ jobs: - name: Install poetry run: pipx install poetry - name: aws credentials - uses: aws-actions/configure-aws-credentials@5727f247b64f324ec403ac56ae05e220fd02b65f # v2.1.0 + uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 with: aws-region: ${{ matrix.region }} role-to-assume: ${{ secrets.AWS_LAYERS_ROLE_ARN }} diff --git a/.github/workflows/reusable_deploy_v2_sar.yml b/.github/workflows/reusable_deploy_v2_sar.yml index 3a54ae97579..3fd83681e6a 100644 --- a/.github/workflows/reusable_deploy_v2_sar.yml +++ b/.github/workflows/reusable_deploy_v2_sar.yml @@ -70,12 +70,12 @@ jobs: - name: Checkout uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: AWS credentials - uses: aws-actions/configure-aws-credentials@5727f247b64f324ec403ac56ae05e220fd02b65f # v2.1.0 + uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 with: aws-region: ${{ env.AWS_REGION }} role-to-assume: ${{ secrets.AWS_LAYERS_ROLE_ARN }} - name: AWS credentials SAR role - uses: aws-actions/configure-aws-credentials@5727f247b64f324ec403ac56ae05e220fd02b65f # v2.1.0 + uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 id: aws-credentials-sar-role with: aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }} diff --git a/.github/workflows/reusable_publish_docs.yml b/.github/workflows/reusable_publish_docs.yml index 5e0027154c4..fd327e1a7b2 100644 --- a/.github/workflows/reusable_publish_docs.yml +++ b/.github/workflows/reusable_publish_docs.yml @@ -93,7 +93,7 @@ jobs: keep_files: true destination_dir: latest/api - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@5727f247b64f324ec403ac56ae05e220fd02b65f + uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 with: aws-region: us-east-1 role-to-assume: ${{ secrets.AWS_DOCS_ROLE_ARN }} diff --git a/.github/workflows/run-e2e-tests.yml b/.github/workflows/run-e2e-tests.yml index 4a93bb88b14..a85b578a5c6 100644 --- a/.github/workflows/run-e2e-tests.yml +++ b/.github/workflows/run-e2e-tests.yml @@ -68,7 +68,7 @@ jobs: - name: Install dependencies run: make dev - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@5727f247b64f324ec403ac56ae05e220fd02b65f # v2.1.0 + uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 with: role-to-assume: ${{ secrets.AWS_TEST_ROLE_ARN }} aws-region: ${{ env.AWS_DEFAULT_REGION }} From 947bf9f48e7621a20a9eefad90b33c126447fce8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Jun 2023 23:17:32 +0200 Subject: [PATCH 35/41] chore(deps-dev): bump cfn-lint from 0.77.8 to 0.77.9 (#2472) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index d6b3a2d1bca..3a3865afb60 100644 --- a/poetry.lock +++ b/poetry.lock @@ -352,13 +352,13 @@ files = [ [[package]] name = "cfn-lint" -version = "0.77.8" +version = "0.77.9" description = "Checks CloudFormation templates for practices and behaviour that could potentially be improved" optional = false python-versions = ">=3.7, <=4.0, !=4.0" files = [ - {file = "cfn-lint-0.77.8.tar.gz", hash = "sha256:34364e687670f8c7e8d77155baddd18c26dadc5e188fd6bdd2af260dbe14404d"}, - {file = "cfn_lint-0.77.8-py3-none-any.whl", hash = "sha256:f20bd659837c7352f605b34bc520c7a38ebb079fd6996b645fe87e14b2c79718"}, + {file = "cfn-lint-0.77.9.tar.gz", hash = "sha256:7c1e631b723b521234d92d4081934291b256dba28d723ddb7ff105215fe40020"}, + {file = "cfn_lint-0.77.9-py3-none-any.whl", hash = "sha256:f95b503f7465ee1f2f89ddf32289ea03a517f08c366bb8e6a5d6773a11e5a1aa"}, ] [package.dependencies] @@ -2939,4 +2939,4 @@ validation = ["fastjsonschema"] [metadata] lock-version = "2.0" python-versions = "^3.7.4" -content-hash = "5317bebeb3cd902772ccbbb9e302988b98a0c19923958efee657a90799c86c23" +content-hash = "ed11607d28040ca8f2926f1b2c81d8c98d92a40138633d83f0a7fa2c4ae72b32" diff --git a/pyproject.toml b/pyproject.toml index a0465e458f1..1ff9f899523 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -100,7 +100,7 @@ all = ["pydantic", "aws-xray-sdk", "fastjsonschema"] aws-sdk = ["boto3"] [tool.poetry.group.dev.dependencies] -cfn-lint = "0.77.8" +cfn-lint = "0.77.9" mypy = "^1.1.1" types-python-dateutil = "^2.8.19.6" httpx = ">=0.23.3,<0.25.0" From 9c15a1543aecdf60607049afd4c5b180214a55d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Jun 2023 21:19:15 +0000 Subject: [PATCH 36/41] chore(deps-dev): bump flake8-comprehensions from 3.12.0 to 3.13.0 (#2471) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3a3865afb60..8b306be4dc5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -753,13 +753,13 @@ test = ["pytest"] [[package]] name = "flake8-comprehensions" -version = "3.12.0" +version = "3.13.0" description = "A flake8 plugin to help you write better list/set/dict comprehensions." optional = false python-versions = ">=3.7" files = [ - {file = "flake8_comprehensions-3.12.0-py3-none-any.whl", hash = "sha256:013234637ec7dfcb7cd2900578fb53c512f81db909cefe371c019232695c362d"}, - {file = "flake8_comprehensions-3.12.0.tar.gz", hash = "sha256:419ef1a6e8de929203791a5e8ff5e3906caeba13eb3290eebdbf88a9078d502e"}, + {file = "flake8_comprehensions-3.13.0-py3-none-any.whl", hash = "sha256:cc0d6dbb336ff4e9cdf4eb605a3f719ea59261f2d6ba52034871a173c40e1f60"}, + {file = "flake8_comprehensions-3.13.0.tar.gz", hash = "sha256:83cf98e816c9e23360f36aaf47de59a5b21437fdff8a056c46e2ad49f81861bf"}, ] [package.dependencies] @@ -2939,4 +2939,4 @@ validation = ["fastjsonschema"] [metadata] lock-version = "2.0" python-versions = "^3.7.4" -content-hash = "ed11607d28040ca8f2926f1b2c81d8c98d92a40138633d83f0a7fa2c4ae72b32" +content-hash = "9e699211cb7fc61b0ae57e387bcd52f8580d10bc2d6d853740600e57a84eddf4" diff --git a/pyproject.toml b/pyproject.toml index 1ff9f899523..7c8acc9d4aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,7 @@ flake8 = [ { version = ">=5", python= ">=3.8"}, ] flake8-builtins = "^2.1.0" -flake8-comprehensions = "^3.12.0" +flake8-comprehensions = "^3.13.0" flake8-debugger = "^4.0.0" flake8-fixme = "^1.1.1" flake8-variables-names = "^0.0.5" From 80dfdd092d79f381765b9e0414f3bfbc96c4448a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Jun 2023 21:22:44 +0000 Subject: [PATCH 37/41] chore(deps-dev): bump mkdocs-material from 9.1.15 to 9.1.16 (#2470) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index 8b306be4dc5..00e97f65146 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1507,13 +1507,13 @@ mkdocs = ">=0.17" [[package]] name = "mkdocs-material" -version = "9.1.15" +version = "9.1.16" description = "Documentation that simply works" optional = false python-versions = ">=3.7" files = [ - {file = "mkdocs_material-9.1.15-py3-none-any.whl", hash = "sha256:b49e12869ab464558e2dd3c5792da5b748a7e0c48ee83b4d05715f98125a7a39"}, - {file = "mkdocs_material-9.1.15.tar.gz", hash = "sha256:8513ab847c9a541ed3d11a3a7eed556caf72991ee786c31c5aac6691a121088a"}, + {file = "mkdocs_material-9.1.16-py3-none-any.whl", hash = "sha256:f9e62558a6b01ffac314423cbc223d970c25fbc78999860226245b64e64d6751"}, + {file = "mkdocs_material-9.1.16.tar.gz", hash = "sha256:1021bfea20f00a9423530c8c2ae9be3c78b80f5a527b3f822e6de3d872e5ab79"}, ] [package.dependencies] @@ -2939,4 +2939,4 @@ validation = ["fastjsonschema"] [metadata] lock-version = "2.0" python-versions = "^3.7.4" -content-hash = "9e699211cb7fc61b0ae57e387bcd52f8580d10bc2d6d853740600e57a84eddf4" +content-hash = "a500f22b8aaff4988f49bab206a1dfe5440286ce7ef66e3df235ca81b766810e" diff --git a/pyproject.toml b/pyproject.toml index 7c8acc9d4aa..a8ba47444fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,7 +82,7 @@ mypy-boto3-s3 = "^1.26.153" mypy-boto3-xray = "^1.26.122" types-requests = "^2.31.0" typing-extensions = "^4.6.2" -mkdocs-material = "^9.1.15" +mkdocs-material = "^9.1.16" filelock = "^3.12.2" checksumdir = "^1.2.0" mypy-boto3-appconfigdata = "^1.26.70" From c1ce6faa416de4052f0794fe2a6523497076bcc3 Mon Sep 17 00:00:00 2001 From: Abbas Yadollahi Date: Fri, 16 Jun 2023 01:56:33 -0700 Subject: [PATCH 38/41] docs(event_sources): fix DynamoDB stream event docstring (#2468) --- aws_lambda_powertools/utilities/data_classes/common.py | 2 +- .../utilities/data_classes/dynamo_db_stream_event.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aws_lambda_powertools/utilities/data_classes/common.py b/aws_lambda_powertools/utilities/data_classes/common.py index ce02a4c11b0..8e2cea7a5cf 100644 --- a/aws_lambda_powertools/utilities/data_classes/common.py +++ b/aws_lambda_powertools/utilities/data_classes/common.py @@ -16,7 +16,7 @@ def __init__(self, data: Dict[str, Any], json_deserializer: Optional[Callable] = data : Dict[str, Any] Lambda Event Source Event payload json_deserializer : Callable, optional - function to deserialize `str`, `bytes`, bytearray` containing a JSON document to a Python `obj`, + function to deserialize `str`, `bytes`, `bytearray` containing a JSON document to a Python `obj`, by default json.loads """ self._data = data diff --git a/aws_lambda_powertools/utilities/data_classes/dynamo_db_stream_event.py b/aws_lambda_powertools/utilities/data_classes/dynamo_db_stream_event.py index e62e307d67a..a609dee8214 100644 --- a/aws_lambda_powertools/utilities/data_classes/dynamo_db_stream_event.py +++ b/aws_lambda_powertools/utilities/data_classes/dynamo_db_stream_event.py @@ -39,7 +39,7 @@ def deserialize(self, value: Dict) -> Any: -------- ------ {'NULL': True} None {'BOOL': True/False} True/False - {'N': str(value)} str(value) + {'N': Decimal(value)} Decimal(value) {'S': string} string {'B': bytes} bytes {'NS': [str(value)]} set([str(value)]) From d652dc2eb8fef87dd21ee54228887f741cf59a29 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Fri, 16 Jun 2023 10:19:53 +0100 Subject: [PATCH 39/41] fix(idempotency): treat missing idempotency key as non-idempotent transaction (no-op) when raise_on_no_idempotency_key is False (#2477) * bug: fix missing idempotency key * fix return * chore: add e2e test for optional idempotency key * chore: fix e2e third payload * docs: clarify operations Signed-off-by: Heitor Lessa * chore: clarify warning Signed-off-by: Heitor Lessa * chore: strip extra space Signed-off-by: Heitor Lessa * chore: ignore long warning line --------- Signed-off-by: Heitor Lessa Co-authored-by: heitorlessa Co-authored-by: Heitor Lessa --- .../utilities/idempotency/base.py | 5 ++- .../utilities/idempotency/persistence/base.py | 41 ++++++++++++++++--- docs/utilities/idempotency.md | 5 +++ .../optional_idempotency_key_handler.py | 17 ++++++++ tests/e2e/idempotency/infrastructure.py | 1 + .../idempotency/test_idempotency_dynamodb.py | 35 ++++++++++++++++ .../idempotency/test_idempotency.py | 8 ++-- 7 files changed, 99 insertions(+), 13 deletions(-) create mode 100644 tests/e2e/idempotency/handlers/optional_idempotency_key_handler.py diff --git a/aws_lambda_powertools/utilities/idempotency/base.py b/aws_lambda_powertools/utilities/idempotency/base.py index e22bdf59abd..db303084375 100644 --- a/aws_lambda_powertools/utilities/idempotency/base.py +++ b/aws_lambda_powertools/utilities/idempotency/base.py @@ -111,7 +111,8 @@ def _process_idempotency(self): except IdempotencyItemAlreadyExistsError: # Now we know the item already exists, we can retrieve it record = self._get_idempotency_record() - return self._handle_for_status(record) + if record is not None: + return self._handle_for_status(record) except Exception as exc: raise IdempotencyPersistenceLayerError( "Failed to save in progress record to idempotency store", exc @@ -138,7 +139,7 @@ def _get_remaining_time_in_millis(self) -> Optional[int]: return None - def _get_idempotency_record(self) -> DataRecord: + def _get_idempotency_record(self) -> Optional[DataRecord]: """ Retrieve the idempotency record from the persistence layer. diff --git a/aws_lambda_powertools/utilities/idempotency/persistence/base.py b/aws_lambda_powertools/utilities/idempotency/persistence/base.py index cad60cbe2b7..41da4fd10c8 100644 --- a/aws_lambda_powertools/utilities/idempotency/persistence/base.py +++ b/aws_lambda_powertools/utilities/idempotency/persistence/base.py @@ -161,7 +161,7 @@ def configure(self, config: IdempotencyConfig, function_name: Optional[str] = No self._cache = LRUDict(max_items=config.local_cache_max_items) self.hash_function = getattr(hashlib, config.hash_function) - def _get_hashed_idempotency_key(self, data: Dict[str, Any]) -> str: + def _get_hashed_idempotency_key(self, data: Dict[str, Any]) -> Optional[str]: """ Extract idempotency key and return a hashed representation @@ -182,7 +182,12 @@ def _get_hashed_idempotency_key(self, data: Dict[str, Any]) -> str: if self.is_missing_idempotency_key(data=data): if self.raise_on_no_idempotency_key: raise IdempotencyKeyError("No data found to create a hashed idempotency_key") - warnings.warn(f"No value found for idempotency_key. jmespath: {self.event_key_jmespath}", stacklevel=2) + + warnings.warn( + f"No idempotency key value found. Skipping persistence layer and validation operations. jmespath: {self.event_key_jmespath}", # noqa: E501 + stacklevel=2, + ) + return None generated_hash = self._generate_hash(data=data) return f"{self.function_name}#{generated_hash}" @@ -315,10 +320,16 @@ def save_success(self, data: Dict[str, Any], result: dict) -> None: result: dict The response from function """ + idempotency_key = self._get_hashed_idempotency_key(data=data) + if idempotency_key is None: + # If the idempotency key is None, no data will be saved in the Persistence Layer. + # See: https://github.com/awslabs/aws-lambda-powertools-python/issues/2465 + return None + response_data = json.dumps(result, cls=Encoder, sort_keys=True) data_record = DataRecord( - idempotency_key=self._get_hashed_idempotency_key(data=data), + idempotency_key=idempotency_key, status=STATUS_CONSTANTS["COMPLETED"], expiry_timestamp=self._get_expiry_timestamp(), response_data=response_data, @@ -343,8 +354,15 @@ def save_inprogress(self, data: Dict[str, Any], remaining_time_in_millis: Option remaining_time_in_millis: Optional[int] If expiry of in-progress invocations is enabled, this will contain the remaining time available in millis """ + + idempotency_key = self._get_hashed_idempotency_key(data=data) + if idempotency_key is None: + # If the idempotency key is None, no data will be saved in the Persistence Layer. + # See: https://github.com/awslabs/aws-lambda-powertools-python/issues/2465 + return None + data_record = DataRecord( - idempotency_key=self._get_hashed_idempotency_key(data=data), + idempotency_key=idempotency_key, status=STATUS_CONSTANTS["INPROGRESS"], expiry_timestamp=self._get_expiry_timestamp(), payload_hash=self._get_hashed_payload(data=data), @@ -381,7 +399,14 @@ def delete_record(self, data: Dict[str, Any], exception: Exception): exception The exception raised by the function """ - data_record = DataRecord(idempotency_key=self._get_hashed_idempotency_key(data=data)) + + idempotency_key = self._get_hashed_idempotency_key(data=data) + if idempotency_key is None: + # If the idempotency key is None, no data will be saved in the Persistence Layer. + # See: https://github.com/awslabs/aws-lambda-powertools-python/issues/2465 + return None + + data_record = DataRecord(idempotency_key=idempotency_key) logger.debug( f"Function raised an exception ({type(exception).__name__}). Clearing in progress record in persistence " @@ -391,7 +416,7 @@ def delete_record(self, data: Dict[str, Any], exception: Exception): self._delete_from_cache(idempotency_key=data_record.idempotency_key) - def get_record(self, data: Dict[str, Any]) -> DataRecord: + def get_record(self, data: Dict[str, Any]) -> Optional[DataRecord]: """ Retrieve idempotency key for data provided, fetch from persistence store, and convert to DataRecord. @@ -414,6 +439,10 @@ def get_record(self, data: Dict[str, Any]) -> DataRecord: """ idempotency_key = self._get_hashed_idempotency_key(data=data) + if idempotency_key is None: + # If the idempotency key is None, no data will be saved in the Persistence Layer. + # See: https://github.com/awslabs/aws-lambda-powertools-python/issues/2465 + return None cached_record = self._retrieve_from_cache(idempotency_key=idempotency_key) if cached_record: diff --git a/docs/utilities/idempotency.md b/docs/utilities/idempotency.md index a0f42b4f304..7bbb279a3e2 100644 --- a/docs/utilities/idempotency.md +++ b/docs/utilities/idempotency.md @@ -3,6 +3,8 @@ title: Idempotency description: Utility --- + + The idempotency utility provides a simple solution to convert your Lambda functions into idempotent operations which are safe to retry. @@ -853,6 +855,9 @@ If you want to enforce that an idempotency key is required, you can set **`raise This means that we will raise **`IdempotencyKeyError`** if the evaluation of **`event_key_jmespath`** is `None`. +???+ warning + To prevent errors, transactions will not be treated as idempotent if **`raise_on_no_idempotency_key`** is set to `False` and the evaluation of **`event_key_jmespath`** is `None`. Therefore, no data will be fetched, stored, or deleted in the idempotency storage layer. + === "app.py" ```python hl_lines="9-10 13" diff --git a/tests/e2e/idempotency/handlers/optional_idempotency_key_handler.py b/tests/e2e/idempotency/handlers/optional_idempotency_key_handler.py new file mode 100644 index 00000000000..f1b7052041f --- /dev/null +++ b/tests/e2e/idempotency/handlers/optional_idempotency_key_handler.py @@ -0,0 +1,17 @@ +import os +import uuid + +from aws_lambda_powertools.utilities.idempotency import ( + DynamoDBPersistenceLayer, + IdempotencyConfig, + idempotent, +) + +TABLE_NAME = os.getenv("IdempotencyTable", "") +persistence_layer = DynamoDBPersistenceLayer(table_name=TABLE_NAME) +config = IdempotencyConfig(event_key_jmespath='headers."X-Idempotency-Key"', use_local_cache=True) + + +@idempotent(config=config, persistence_store=persistence_layer) +def lambda_handler(event, context): + return {"request": str(uuid.uuid4())} diff --git a/tests/e2e/idempotency/infrastructure.py b/tests/e2e/idempotency/infrastructure.py index 00d3761b829..692e0e8ce81 100644 --- a/tests/e2e/idempotency/infrastructure.py +++ b/tests/e2e/idempotency/infrastructure.py @@ -16,6 +16,7 @@ def create_resources(self): table.grant_read_write_data(functions["TtlCacheTimeoutHandler"]) table.grant_read_write_data(functions["ParallelExecutionHandler"]) table.grant_read_write_data(functions["FunctionThreadSafetyHandler"]) + table.grant_read_write_data(functions["OptionalIdempotencyKeyHandler"]) def _create_dynamodb_table(self) -> Table: table = dynamodb.Table( diff --git a/tests/e2e/idempotency/test_idempotency_dynamodb.py b/tests/e2e/idempotency/test_idempotency_dynamodb.py index f82a6c84441..e5d3eb4aeb3 100644 --- a/tests/e2e/idempotency/test_idempotency_dynamodb.py +++ b/tests/e2e/idempotency/test_idempotency_dynamodb.py @@ -27,6 +27,11 @@ def function_thread_safety_handler_fn_arn(infrastructure: dict) -> str: return infrastructure.get("FunctionThreadSafetyHandlerArn", "") +@pytest.fixture +def optional_idempotency_key_fn_arn(infrastructure: dict) -> str: + return infrastructure.get("OptionalIdempotencyKeyHandlerArn", "") + + @pytest.fixture def idempotency_table_name(infrastructure: dict) -> str: return infrastructure.get("DynamoDBTable", "") @@ -132,3 +137,33 @@ def test_idempotent_function_thread_safety(function_thread_safety_handler_fn_arn # we use set() here because we want to compare the elements regardless of their order in the array assert set(first_execution_response) == set(second_execution_response) + + +@pytest.mark.xdist_group(name="idempotency") +def test_optional_idempotency_key(optional_idempotency_key_fn_arn: str): + # GIVEN two payloads where only one has the expected idempotency key + payload = json.dumps({"headers": {"X-Idempotency-Key": "here"}}) + payload_without = json.dumps({"headers": {}}) + + # WHEN + # we make one request with an idempotency key + first_execution, _ = data_fetcher.get_lambda_response(lambda_arn=optional_idempotency_key_fn_arn, payload=payload) + first_execution_response = first_execution["Payload"].read().decode("utf-8") + + # and two others without the idempotency key + second_execution, _ = data_fetcher.get_lambda_response( + lambda_arn=optional_idempotency_key_fn_arn, payload=payload_without + ) + second_execution_response = second_execution["Payload"].read().decode("utf-8") + + third_execution, _ = data_fetcher.get_lambda_response( + lambda_arn=optional_idempotency_key_fn_arn, payload=payload_without + ) + third_execution_response = third_execution["Payload"].read().decode("utf-8") + + # THEN + # we should treat 2nd and 3rd requests with NULL idempotency key as non-idempotent transactions + # that is, no cache, no calls to persistent store, etc. + assert first_execution_response != second_execution_response + assert first_execution_response != third_execution_response + assert second_execution_response != third_execution_response diff --git a/tests/functional/idempotency/test_idempotency.py b/tests/functional/idempotency/test_idempotency.py index 358a8dd76a1..1cde1979d64 100644 --- a/tests/functional/idempotency/test_idempotency.py +++ b/tests/functional/idempotency/test_idempotency.py @@ -2,7 +2,6 @@ import datetime import sys import warnings -from hashlib import md5 from unittest.mock import MagicMock import jmespath @@ -995,8 +994,7 @@ def test_default_no_raise_on_missing_idempotency_key( hashed_key = persistence_store._get_hashed_idempotency_key({}) # THEN return the hash of None - expected_value = f"test-func.{function_name}#" + md5(json_serialize(None).encode()).hexdigest() - assert expected_value == hashed_key + assert hashed_key is None @pytest.mark.parametrize( @@ -1093,7 +1091,7 @@ def lambda_handler(event, context): # WHEN handling the idempotent call # AND save_inprogress raises a ClientError with pytest.raises(IdempotencyPersistenceLayerError) as e: - lambda_handler({}, lambda_context) + lambda_handler({"data": "some"}, lambda_context) # THEN idempotent should raise an IdempotencyPersistenceLayerError # AND append downstream exception details @@ -1363,7 +1361,7 @@ def two(data): assert one(data=mock_event) == "one" assert two(data=mock_event) == "two" - assert len(persistence_store.client.method_calls) == 4 + assert len(persistence_store.client.method_calls) == 0 def test_invalid_dynamodb_persistence_layer(): From 24d986022b76be4d1a2c22acfae203f38bb83550 Mon Sep 17 00:00:00 2001 From: Heitor Lessa Date: Fri, 16 Jun 2023 11:49:20 +0200 Subject: [PATCH 40/41] docs(idempotency): new sequence flow when idempotency key is optional (#2480) --- docs/utilities/idempotency.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/utilities/idempotency.md b/docs/utilities/idempotency.md index 7bbb279a3e2..4caa91250c8 100644 --- a/docs/utilities/idempotency.md +++ b/docs/utilities/idempotency.md @@ -649,6 +649,36 @@ sequenceDiagram Idempotent request during and after Lambda timeouts +#### Optional idempotency key + +
+```mermaid +sequenceDiagram + participant Client + participant Lambda + participant Persistence Layer + alt request with idempotency key + Client->>Lambda: Invoke (event) + Lambda->>Persistence Layer: Get or set idempotency_key=hash(payload) + activate Persistence Layer + Note over Lambda,Persistence Layer: Set record status to INPROGRESS.
Prevents concurrent invocations
with the same payload + Lambda-->>Lambda: Call your function + Lambda->>Persistence Layer: Update record with result + deactivate Persistence Layer + Persistence Layer-->>Persistence Layer: Update record + Note over Lambda,Persistence Layer: Set record status to COMPLETE.
New invocations with the same payload
now return the same result + Lambda-->>Client: Response sent to client + else request(s) without idempotency key + Client->>Lambda: Invoke (event) + Note over Lambda: Idempotency key is missing + Note over Persistence Layer: Skips any operation to fetch, update, and delete + Lambda-->>Lambda: Call your function + Lambda-->>Client: Response sent to client + end +``` +Optional idempotency key +
+ ## Advanced ### Persistence layers From e0ddbb97744822406c3de7c12f1a438844f676c8 Mon Sep 17 00:00:00 2001 From: "Powertools for AWS Lambda (Python) bot" Date: Fri, 16 Jun 2023 10:21:21 +0000 Subject: [PATCH 41/41] chore: version bump --- aws_lambda_powertools/shared/version.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aws_lambda_powertools/shared/version.py b/aws_lambda_powertools/shared/version.py index 1c0d9617d85..042e888f43f 100644 --- a/aws_lambda_powertools/shared/version.py +++ b/aws_lambda_powertools/shared/version.py @@ -1,3 +1,3 @@ """Exposes version constant to avoid circular dependencies.""" -VERSION = "2.16.2" +VERSION = "2.17.0" diff --git a/pyproject.toml b/pyproject.toml index a8ba47444fd..0dec76a5f65 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "aws_lambda_powertools" -version = "2.16.2" +version = "2.17.0" description = "Powertools for AWS Lambda (Python) is a developer toolkit to implement Serverless best practices and increase developer velocity." authors = ["Amazon Web Services"] include = ["aws_lambda_powertools/py.typed", "THIRD-PARTY-LICENSES"]