diff --git a/.github/workflows/bootstrap_region.yml b/.github/workflows/bootstrap_region.yml
index 3cc96d3113f..349a00fa38c 100644
--- a/.github/workflows/bootstrap_region.yml
+++ b/.github/workflows/bootstrap_region.yml
@@ -45,7 +45,7 @@ jobs:
steps:
- id: credentials
name: AWS Credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
aws-region: ${{ inputs.region }}
role-to-assume: ${{ secrets.REGION_IAM_ROLE }}
@@ -91,14 +91,14 @@ jobs:
steps:
- id: credentials
name: AWS Credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
aws-region: us-east-1
role-to-assume: ${{ secrets.REGION_IAM_ROLE }}
mask-aws-account-id: true
- id: go-setup
name: Setup Go
- uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
+ uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
- id: go-env
name: Go Env
run: go env
diff --git a/.github/workflows/dispatch_analytics.yml b/.github/workflows/dispatch_analytics.yml
index ddc4294b262..0d9612f5643 100644
--- a/.github/workflows/dispatch_analytics.yml
+++ b/.github/workflows/dispatch_analytics.yml
@@ -43,7 +43,7 @@ jobs:
statuses: read
steps:
- name: Configure AWS credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
aws-region: eu-central-1
role-to-assume: ${{ secrets.AWS_LAYERS_ROLE_ARN }}
diff --git a/.github/workflows/layer_govcloud.yml b/.github/workflows/layer_govcloud.yml
index 3a98ceca223..b58475b22b7 100644
--- a/.github/workflows/layer_govcloud.yml
+++ b/.github/workflows/layer_govcloud.yml
@@ -59,7 +59,7 @@ jobs:
environment: Prod (Readonly)
steps:
- name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
role-to-assume: ${{ secrets.AWS_IAM_ROLE }}
aws-region: us-east-1
@@ -69,14 +69,14 @@ jobs:
aws --region us-east-1 lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:017000801446:layer:${{ matrix.layer }}-${{ matrix.arch }}:${{ inputs.version }} --query 'Content.Location' | xargs curl -L -o ${{ matrix.layer }}_${{ matrix.arch }}.zip
aws --region us-east-1 lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:017000801446:layer:${{ matrix.layer }}-${{ matrix.arch }}:${{ inputs.version }} > ${{ matrix.layer }}_${{ matrix.arch }}.json
- name: Store Zip
- uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
+ uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: ${{ matrix.layer }}_${{ matrix.arch }}.zip
path: ${{ matrix.layer }}_${{ matrix.arch }}.zip
retention-days: 1
if-no-files-found: error
- name: Store Metadata
- uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
+ uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: ${{ matrix.layer }}_${{ matrix.arch }}.json
path: ${{ matrix.layer }}_${{ matrix.arch }}.json
@@ -116,7 +116,7 @@ jobs:
SHA=$(jq -r '.Content.CodeSha256' '${{ matrix.layer }}_${{ matrix.arch }}.json')
test "$(openssl dgst -sha256 -binary ${{ matrix.layer }}_${{ matrix.arch }}.zip | openssl enc -base64)" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1
- name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
role-to-assume: ${{ secrets.AWS_IAM_ROLE }}
aws-region: us-gov-east-1
@@ -185,7 +185,7 @@ jobs:
SHA=$(jq -r '.Content.CodeSha256' '${{ matrix.layer }}_${{ matrix.arch }}.json')
test "$(openssl dgst -sha256 -binary ${{ matrix.layer }}_${{ matrix.arch }}.zip | openssl enc -base64)" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1
- name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
role-to-assume: ${{ secrets.AWS_IAM_ROLE }}
aws-region: us-gov-west-1
diff --git a/.github/workflows/layer_govcloud_python313.yml b/.github/workflows/layer_govcloud_python313.yml
index 40a25eac2e9..e7aa8896631 100644
--- a/.github/workflows/layer_govcloud_python313.yml
+++ b/.github/workflows/layer_govcloud_python313.yml
@@ -55,7 +55,7 @@ jobs:
environment: Prod (Readonly)
steps:
- name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
role-to-assume: ${{ secrets.AWS_IAM_ROLE }}
aws-region: us-east-1
@@ -65,14 +65,14 @@ jobs:
aws --region us-east-1 lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:017000801446:layer:${{ matrix.layer }}-${{ matrix.arch }}:${{ inputs.version }} --query 'Content.Location' | xargs curl -L -o ${{ matrix.layer }}_${{ matrix.arch }}.zip
aws --region us-east-1 lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:017000801446:layer:${{ matrix.layer }}-${{ matrix.arch }}:${{ inputs.version }} > ${{ matrix.layer }}_${{ matrix.arch }}.json
- name: Store Zip
- uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
+ uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: ${{ matrix.layer }}_${{ matrix.arch }}.zip
path: ${{ matrix.layer }}_${{ matrix.arch }}.zip
retention-days: 1
if-no-files-found: error
- name: Store Metadata
- uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
+ uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: ${{ matrix.layer }}_${{ matrix.arch }}.json
path: ${{ matrix.layer }}_${{ matrix.arch }}.json
@@ -108,7 +108,7 @@ jobs:
SHA=$(jq -r '.Content.CodeSha256' '${{ matrix.layer }}_${{ matrix.arch }}.json')
test "$(openssl dgst -sha256 -binary ${{ matrix.layer }}_${{ matrix.arch }}.zip | openssl enc -base64)" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1
- name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
role-to-assume: ${{ secrets.AWS_IAM_ROLE }}
aws-region: us-gov-east-1
@@ -173,7 +173,7 @@ jobs:
SHA=$(jq -r '.Content.CodeSha256' '${{ matrix.layer }}_${{ matrix.arch }}.json')
test "$(openssl dgst -sha256 -binary ${{ matrix.layer }}_${{ matrix.arch }}.zip | openssl enc -base64)" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1
- name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
role-to-assume: ${{ secrets.AWS_IAM_ROLE }}
aws-region: us-gov-west-1
diff --git a/.github/workflows/layer_govcloud_verify.yml b/.github/workflows/layer_govcloud_verify.yml
index 2395183c111..2313dfc3fdd 100644
--- a/.github/workflows/layer_govcloud_verify.yml
+++ b/.github/workflows/layer_govcloud_verify.yml
@@ -39,7 +39,7 @@ jobs:
environment: Prod (Readonly)
steps:
- name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
role-to-assume: ${{ secrets.AWS_IAM_ROLE }}
aws-region: us-east-1
@@ -69,7 +69,7 @@ jobs:
environment: GovCloud Prod (East)
steps:
- name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
role-to-assume: ${{ secrets.AWS_IAM_ROLE }}
aws-region: us-gov-east-1
@@ -100,7 +100,7 @@ jobs:
environment: GovCloud Prod (West)
steps:
- name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
role-to-assume: ${{ secrets.AWS_IAM_ROLE }}
aws-region: us-gov-east-1
diff --git a/.github/workflows/layer_rename.yml b/.github/workflows/layer_rename.yml
index 0db7d9a37a3..bfe3ffa817c 100644
--- a/.github/workflows/layer_rename.yml
+++ b/.github/workflows/layer_rename.yml
@@ -56,7 +56,7 @@ jobs:
environment: layer-prod
steps:
- name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
role-to-assume: ${{ secrets.AWS_LAYERS_ROLE_ARN }}
aws-region: us-east-1
@@ -66,14 +66,14 @@ jobs:
aws --region us-east-1 lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:017000801446:layer:${{ matrix.layer }}-x86:${{ inputs.version }} --query 'Content.Location' | xargs curl -L -o ${{ matrix.layer }}_x86_64.zip
aws --region us-east-1 lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:017000801446:layer:${{ matrix.layer }}-x86:${{ inputs.version }} > ${{ matrix.layer }}_x86_64.json
- name: Store Zip
- uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
+ uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: ${{ matrix.layer }}_x86_64.zip
path: ${{ matrix.layer }}_x86_64.zip
retention-days: 1
if-no-files-found: error
- name: Store Metadata
- uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
+ uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: ${{ matrix.layer }}_x86_64.json
path: ${{ matrix.layer }}_x86_64.json
@@ -140,7 +140,7 @@ jobs:
SHA=$(jq -r '.Content.CodeSha256' ${{ matrix.layer }}_x86_64.json)
test $(openssl dgst -sha256 -binary ${{ matrix.layer }}_x86_64.zip | openssl enc -base64) == $SHA && echo "SHA OK: ${SHA}" || exit 1
- name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
role-to-assume: ${{ secrets.AWS_LAYERS_ROLE_ARN }}
aws-region: ${{ matrix.region }}
diff --git a/.github/workflows/ossf_scorecard.yml b/.github/workflows/ossf_scorecard.yml
index 473db555bb0..df43f225871 100644
--- a/.github/workflows/ossf_scorecard.yml
+++ b/.github/workflows/ossf_scorecard.yml
@@ -35,7 +35,7 @@ jobs:
repo_token: ${{ secrets.SCORECARD_TOKEN }} # read-only fine-grained token to read branch protection settings
- name: "Upload results"
- uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
+ uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: SARIF file
path: results.sarif
diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml
index ea8d298ff5c..b0f1f37ccd8 100644
--- a/.github/workflows/pre-release.yml
+++ b/.github/workflows/pre-release.yml
@@ -126,7 +126,7 @@ jobs:
- name: Install poetry
run: pipx install git+https://github.com/python-poetry/poetry@bd500dd3bdfaec3de6894144c9cedb3a9358be84 # v2.0.1
- name: Set up Python
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
+ uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: "3.12"
cache: "poetry"
@@ -164,7 +164,7 @@ jobs:
- name: Install poetry
run: pipx install git+https://github.com/python-poetry/poetry@bd500dd3bdfaec3de6894144c9cedb3a9358be84 # v2.0.1
- name: Set up Python
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
+ uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: "3.12"
cache: "poetry"
@@ -232,7 +232,7 @@ jobs:
- name: Upload to PyPi prod
if: ${{ !inputs.skip_pypi }}
- uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.3
+ uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
# Creates a PR with the latest version we've just released
# since our trunk is protected against any direct pushes from automation
diff --git a/.github/workflows/publish_v2_layer.yml b/.github/workflows/publish_v2_layer.yml
index 59518cd0c54..38da26cbf9b 100644
--- a/.github/workflows/publish_v2_layer.yml
+++ b/.github/workflows/publish_v2_layer.yml
@@ -101,11 +101,11 @@ jobs:
- name: Install poetry
run: pipx install git+https://github.com/python-poetry/poetry@bd500dd3bdfaec3de6894144c9cedb3a9358be84 # v2.0.1
- name: Setup Node.js
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
+ uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
with:
node-version: "16.12"
- name: Setup python
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
+ uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: "3.12"
cache: "pip"
@@ -117,14 +117,14 @@ jobs:
pip install --require-hashes -r requirements.txt
- name: Set up QEMU
- uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v2.0.0
+ uses: docker/setup-qemu-action@4574d27a4764455b42196d70a065bc6853246a25 # v2.0.0
with:
platforms: arm64
# 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@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
+ uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0
with:
install: true
driver: docker
@@ -146,7 +146,7 @@ jobs:
- name: zip output
run: zip -r cdk.out.zip cdk.out
- name: Archive CDK artifacts
- uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
+ uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: cdk-layer-artefact
path: layer/cdk.out.zip
diff --git a/.github/workflows/publish_v3_layer.yml b/.github/workflows/publish_v3_layer.yml
index 66cfd0b07c7..90805f9434e 100644
--- a/.github/workflows/publish_v3_layer.yml
+++ b/.github/workflows/publish_v3_layer.yml
@@ -33,6 +33,9 @@ on:
latest_published_version:
description: "Latest PyPi published version to rebuild latest docs for, e.g. 3.0.0, 3.0.0a1 (pre-release)"
required: true
+ layer_documentation_version:
+ description: "Version to be updated in our documentation. e.g. if the current layer number is 3, this value must be 4."
+ required: true
source_code_artifact_name:
description: "Artifact name to restore sealed source code"
type: string
@@ -52,6 +55,10 @@ on:
type: string
description: "Latest PyPi published version to rebuild latest docs for, e.g. 3.0.0, 3.0.0a1 (pre-release)"
required: true
+ layer_documentation_version:
+ type: string
+ description: "Version to be updated in our documentation. e.g. if the current layer number is 3, this value must be 4."
+ required: true
pre_release:
description: "Publishes documentation using a pre-release tag (3.0.0a1)."
default: false
@@ -106,11 +113,11 @@ jobs:
pipx install git+https://github.com/python-poetry/poetry@bd500dd3bdfaec3de6894144c9cedb3a9358be84 # v2.0.1
pipx inject poetry git+https://github.com/python-poetry/poetry-plugin-export@8c83d26603ca94f2e203bfded7b6d7f530960e06 # v1.8.0
- name: Setup Node.js
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
+ uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
with:
node-version: "18.20.4"
- name: Setup python
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
+ uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
@@ -122,14 +129,14 @@ jobs:
pip install --require-hashes -r requirements.txt
- name: Set up QEMU
- uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v2.0.0
+ uses: docker/setup-qemu-action@4574d27a4764455b42196d70a065bc6853246a25 # v2.0.0
with:
platforms: arm64
# 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@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
+ uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0
with:
install: true
driver: docker
@@ -151,7 +158,7 @@ jobs:
- name: zip output
run: zip -r cdk.py${{ matrix.python-version }}.out.zip cdk.out
- name: Archive CDK artifacts
- uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
+ uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: cdk-layer-artifact-py${{ matrix.python-version }}
path: layer_v3/cdk.py${{ matrix.python-version }}.out.zip
@@ -257,29 +264,20 @@ jobs:
integrity_hash: ${{ inputs.source_code_integrity_hash }}
artifact_name: ${{ inputs.source_code_artifact_name }}
- # UNCOMMENT THIS
- # - name: Download CDK layer artifacts
- # uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
- # with:
- # path: cdk-layer-stack
- # pattern: cdk-layer-stack-* # merge all Layer artifacts created per region earlier (reusable_deploy_v2_layer_stack.yml; step "Save Layer ARN artifact")
- # merge-multiple: true
- # - name: Replace layer versions in documentation
- # run: |
- # ls -la cdk-layer-stack/
- # ./layer_v3/scripts/update_layer_arn.sh cdk-layer-stack
+ - name: Replace layer versions in documentation
+ run: ./layer_v3/scripts/update_layer_arn_v3.sh ${{ inputs.layer_documentation_version }}
# NOTE: It felt unnecessary creating yet another PR to update changelog w/ latest tag
# since this is the only step in the release where we update docs from a temp branch
- # - name: Update changelog with latest tag
- # run: make changelog
- # - name: Create PR
- # id: create-pr
- # uses: ./.github/actions/create-pr
- # with:
- # files: "docs/index.md examples CHANGELOG.md"
- # temp_branch_prefix: "ci-layer-docs"
- # pull_request_title: "chore(ci): layer docs update"
- # github_token: ${{ secrets.GITHUB_TOKEN }}
+ - name: Update changelog with latest tag
+ run: make changelog
+ - name: Create PR
+ id: create-pr
+ uses: ./.github/actions/create-pr
+ with:
+ files: "docs/index.md docs/includes/_layer_homepage_arm64.md docs/includes/_layer_homepage_x86.md examples CHANGELOG.md"
+ temp_branch_prefix: "ci-layer-docs"
+ pull_request_title: "chore(ci): layer docs update"
+ github_token: ${{ secrets.GITHUB_TOKEN }}
prepare_docs_alias:
runs-on: ubuntu-latest
diff --git a/.github/workflows/quality_check.yml b/.github/workflows/quality_check.yml
index 4b6a7fa2c8c..fcb4c8143c6 100644
--- a/.github/workflows/quality_check.yml
+++ b/.github/workflows/quality_check.yml
@@ -56,11 +56,13 @@ jobs:
- name: Install poetry
run: pipx install poetry
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
+ uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: make dev-quality-code
+ - name: Checking third-party library licenses
+ run: make check-licenses
- name: Formatting and Linting
run: make lint
- name: Static type checking
@@ -74,7 +76,7 @@ jobs:
- name: Complexity baseline
run: make complexity-baseline
- name: Upload coverage to Codecov
- uses: codecov/codecov-action@1e68e06f1dbfde0e4cefc87efeba9e4643565303 # 5.1.2
+ uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # 5.3.1
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage.xml
diff --git a/.github/workflows/quality_code_cdk_constructor.yml b/.github/workflows/quality_code_cdk_constructor.yml
index e4826ce8f52..c9c923be16b 100644
--- a/.github/workflows/quality_code_cdk_constructor.yml
+++ b/.github/workflows/quality_code_cdk_constructor.yml
@@ -46,18 +46,18 @@ jobs:
- name: Install poetry
run: pipx install poetry
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
+ uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: ${{ matrix.python-version }}
cache: "poetry"
- name: Set up QEMU
- uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v2.0.0
+ uses: docker/setup-qemu-action@4574d27a4764455b42196d70a065bc6853246a25 # v2.0.0
with:
platforms: arm64
# 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@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
+ uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0
with:
install: true
driver: docker
diff --git a/.github/workflows/record_pr.yml b/.github/workflows/record_pr.yml
index 2ee18fa74b0..1f0b6ef23c0 100644
--- a/.github/workflows/record_pr.yml
+++ b/.github/workflows/record_pr.yml
@@ -53,7 +53,7 @@ jobs:
script: |
const script = require('.github/scripts/save_pr_details.js')
await script({github, context, core})
- - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
+ - uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: pr
path: pr.txt
diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml
index 473968803b0..53698e4fb3e 100644
--- a/.github/workflows/release-drafter.yml
+++ b/.github/workflows/release-drafter.yml
@@ -27,6 +27,6 @@ jobs:
permissions:
contents: write # create release in draft mode
steps:
- - uses: release-drafter/release-drafter@3f0f87098bd6b5c5b9a36d49c41d998ea58f9348 # v5.20.1
+ - uses: release-drafter/release-drafter@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v5.20.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/release-v3.yml b/.github/workflows/release-v3.yml
index a7bbaeaf660..4cbc2dbaee0 100644
--- a/.github/workflows/release-v3.yml
+++ b/.github/workflows/release-v3.yml
@@ -39,6 +39,10 @@ on:
description: "Version to be released in PyPi, Docs, and Lambda Layer, e.g. v3.0.0, v3.0.0a0 (pre-release)"
default: v3.0.0
required: true
+ layer_documentation_version:
+ description: "Lambda layer version to be updated in our documentation. e.g. if the current layer number is 3, this value must be 4."
+ type: string
+ required: true
skip_pypi:
description: "Skip publishing to PyPi as it can't publish more than once. Useful for semi-failed releases"
default: false
@@ -131,7 +135,7 @@ jobs:
- name: Install poetry
run: pipx install git+https://github.com/python-poetry/poetry@bd500dd3bdfaec3de6894144c9cedb3a9358be84 # v2.0.1
- name: Set up Python
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
+ uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: "3.12"
cache: "poetry"
@@ -169,7 +173,7 @@ jobs:
- name: Install poetry
run: pipx install git+https://github.com/python-poetry/poetry@bd500dd3bdfaec3de6894144c9cedb3a9358be84 # v2.0.1
- name: Set up Python
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
+ uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: "3.12"
cache: "poetry"
@@ -237,12 +241,12 @@ jobs:
- name: Upload to PyPi prod
if: ${{ !inputs.skip_pypi }}
- uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.3
+ uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
# PyPi test maintenance affected us numerous times, leaving for history purposes
# - name: Upload to PyPi test
# if: ${{ !inputs.skip_pypi }}
- # uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.3
+ # uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
# with:
# repository-url: https://test.pypi.org/legacy/
@@ -342,6 +346,7 @@ jobs:
uses: ./.github/workflows/publish_v3_layer.yml
with:
latest_published_version: ${{ needs.seal.outputs.RELEASE_VERSION }}
+ layer_documentation_version: ${{ inputs.layer_documentation_version }}
pre_release: ${{ inputs.pre_release }}
source_code_artifact_name: ${{ needs.seal.outputs.artifact_name }}
source_code_integrity_hash: ${{ needs.seal.outputs.integrity_hash }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 7a4cdbe9bb6..f7f859feb9a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -131,7 +131,7 @@ jobs:
- name: Install poetry
run: pipx install git+https://github.com/python-poetry/poetry@bd500dd3bdfaec3de6894144c9cedb3a9358be84 # v2.0.1
- name: Set up Python
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
+ uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: "3.12"
cache: "poetry"
@@ -169,7 +169,7 @@ jobs:
- name: Install poetry
run: pipx install git+https://github.com/python-poetry/poetry@bd500dd3bdfaec3de6894144c9cedb3a9358be84 # v2.0.1
- name: Set up Python
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
+ uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: "3.12"
cache: "poetry"
@@ -237,12 +237,12 @@ jobs:
- name: Upload to PyPi prod
if: ${{ !inputs.skip_pypi }}
- uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.3
+ uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
# PyPi test maintenance affected us numerous times, leaving for history purposes
# - name: Upload to PyPi test
# if: ${{ !inputs.skip_pypi }}
- # uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.3
+ # uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
# with:
# repository-url: https://test.pypi.org/legacy/
diff --git a/.github/workflows/reusable_deploy_v2_layer_stack.yml b/.github/workflows/reusable_deploy_v2_layer_stack.yml
index 0ab175242cc..c973a589991 100644
--- a/.github/workflows/reusable_deploy_v2_layer_stack.yml
+++ b/.github/workflows/reusable_deploy_v2_layer_stack.yml
@@ -153,17 +153,17 @@ jobs:
- name: Install poetry
run: pipx install git+https://github.com/python-poetry/poetry@bd500dd3bdfaec3de6894144c9cedb3a9358be84 # v2.0.1
- name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
aws-region: ${{ matrix.region }}
role-to-assume: ${{ secrets.AWS_LAYERS_ROLE_ARN }}
mask-aws-account-id: true
- name: Setup Node.js
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
+ uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
with:
node-version: "16.12"
- name: Setup python
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
+ uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: "3.12"
cache: "pip"
@@ -198,7 +198,7 @@ jobs:
cat cdk-layer-stack/${{ matrix.region }}-layer-version.txt
- name: Save Layer ARN artifact
if: ${{ inputs.stage == 'PROD' }}
- uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
+ uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: cdk-layer-stack-${{ matrix.region }}
path: ./layer/cdk-layer-stack/* # NOTE: upload-artifact does not inherit working-directory setting.
diff --git a/.github/workflows/reusable_deploy_v2_sar.yml b/.github/workflows/reusable_deploy_v2_sar.yml
index 0f4a3f3e231..64158f630bf 100644
--- a/.github/workflows/reusable_deploy_v2_sar.yml
+++ b/.github/workflows/reusable_deploy_v2_sar.yml
@@ -90,7 +90,7 @@ jobs:
artifact_name: ${{ inputs.source_code_artifact_name }}
- name: Configure AWS credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
aws-region: ${{ env.AWS_REGION }}
role-to-assume: ${{ secrets.AWS_LAYERS_ROLE_ARN }}
@@ -101,7 +101,7 @@ jobs:
# we then jump to our specific SAR Account with the correctly scoped IAM Role
# this allows us to have a single trail when a release occurs for a given layer (beta+prod+SAR beta+SAR prod)
- name: AWS credentials SAR role
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
id: aws-credentials-sar-role
with:
aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }}
@@ -113,7 +113,7 @@ jobs:
mask-aws-account-id: true
- name: Setup Node.js
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
+ uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Download artifact
diff --git a/.github/workflows/reusable_deploy_v3_layer_stack.yml b/.github/workflows/reusable_deploy_v3_layer_stack.yml
index 27bab40f0db..a9348f48169 100644
--- a/.github/workflows/reusable_deploy_v3_layer_stack.yml
+++ b/.github/workflows/reusable_deploy_v3_layer_stack.yml
@@ -157,17 +157,17 @@ jobs:
pipx install git+https://github.com/python-poetry/poetry@bd500dd3bdfaec3de6894144c9cedb3a9358be84 # v2.0.1
pipx inject poetry git+https://github.com/python-poetry/poetry-plugin-export@8c83d26603ca94f2e203bfded7b6d7f530960e06 # v1.8.0
- name: Configure AWS credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
aws-region: ${{ matrix.region }}
role-to-assume: ${{ secrets.AWS_LAYERS_ROLE_ARN }}
mask-aws-account-id: true
- name: Setup Node.js
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
+ uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
with:
node-version: "18.20.4"
- name: Setup python
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
+ uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
@@ -209,7 +209,7 @@ jobs:
cat cdk-layer-stack/${{steps.constants.outputs.LAYER_VERSION}}
- name: Save Layer ARN artifact
if: ${{ inputs.stage == 'PROD' }}
- uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
+ uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: cdk-layer-stack-${{ matrix.region }}-${{ matrix.python-version }}
path: ./layer_v3/cdk-layer-stack/* # NOTE: upload-artifact does not inherit working-directory setting.
diff --git a/.github/workflows/reusable_deploy_v3_sar.yml b/.github/workflows/reusable_deploy_v3_sar.yml
index b5d110e95d6..61a3a4cae51 100644
--- a/.github/workflows/reusable_deploy_v3_sar.yml
+++ b/.github/workflows/reusable_deploy_v3_sar.yml
@@ -87,7 +87,7 @@ jobs:
- name: Configure AWS credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
aws-region: ${{ env.AWS_REGION }}
role-to-assume: ${{ secrets.AWS_LAYERS_ROLE_ARN }}
@@ -98,7 +98,7 @@ jobs:
# we then jump to our specific SAR Account with the correctly scoped IAM Role
# this allows us to have a single trail when a release occurs for a given layer (beta+prod+SAR beta+SAR prod)
- name: AWS credentials SAR role
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
id: aws-credentials-sar-role
with:
aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }}
@@ -109,7 +109,7 @@ jobs:
role-to-assume: ${{ secrets.AWS_SAR_V2_ROLE_ARN }}
mask-aws-account-id: true
- name: Setup Node.js
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
+ uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Download artifact
diff --git a/.github/workflows/reusable_publish_docs.yml b/.github/workflows/reusable_publish_docs.yml
index 036ff89ef40..e16feab9415 100644
--- a/.github/workflows/reusable_publish_docs.yml
+++ b/.github/workflows/reusable_publish_docs.yml
@@ -51,7 +51,7 @@ jobs:
- name: Install poetry
run: pipx install poetry
- name: Set up Python
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
+ uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: "3.12"
cache: "poetry"
@@ -79,14 +79,11 @@ jobs:
poetry run mike set-default --push latest
- name: Configure AWS credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
aws-region: us-east-1
role-to-assume: ${{ secrets.AWS_DOCS_ROLE_ARN }}
mask-aws-account-id: true
- - name: Copy API Docs
- run: |
- cp -r api site/
- name: Deploy Docs (Version)
env:
VERSION: ${{ inputs.version }}
diff --git a/.github/workflows/run-e2e-tests.yml b/.github/workflows/run-e2e-tests.yml
index 361a6ac8eb4..555f7b7a2af 100644
--- a/.github/workflows/run-e2e-tests.yml
+++ b/.github/workflows/run-e2e-tests.yml
@@ -56,13 +56,13 @@ jobs:
- name: Install poetry
run: pipx install poetry
- name: "Use Python"
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
+ uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: ${{ matrix.version }}
architecture: "x64"
cache: "poetry"
- name: Setup Node.js
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
+ uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
with:
node-version: "20.10.0"
- name: Install CDK CLI
@@ -72,7 +72,7 @@ jobs:
- name: Install dependencies
run: make dev-quality-code
- name: Configure AWS credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
role-to-assume: ${{ secrets.AWS_TEST_ROLE_ARN }}
aws-region: ${{ env.AWS_DEFAULT_REGION }}
diff --git a/.github/workflows/secure_workflows.yml b/.github/workflows/secure_workflows.yml
index 4512de6d3b4..4344f150595 100644
--- a/.github/workflows/secure_workflows.yml
+++ b/.github/workflows/secure_workflows.yml
@@ -32,7 +32,7 @@ jobs:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Ensure 3rd party workflows have SHA pinned
- uses: zgosalvez/github-actions-ensure-sha-pinned-actions@64418826697dcd77c93a8e4a1f7601a1942e57b5 # v3.0.18
+ uses: zgosalvez/github-actions-ensure-sha-pinned-actions@6eb1abde32fed00453b0d03497f4ba4fecba146d # v3.0.21
with:
allowlist: |
slsa-framework/slsa-github-generator
diff --git a/.github/workflows/update_ssm.yml b/.github/workflows/update_ssm.yml
index 2f8492dcb89..7ff47695015 100644
--- a/.github/workflows/update_ssm.yml
+++ b/.github/workflows/update_ssm.yml
@@ -66,7 +66,7 @@ jobs:
run: |
echo 'CONVERTED_REGION=${{ matrix.region }}' | tr 'a-z\-' 'A-Z_' >> "$GITHUB_OUTPUT"
- id: creds
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ uses: aws-actions/configure-aws-credentials@4fc4975a852c8cd99761e2de1f4ba73402e44dd9 # v4.0.3
with:
aws-region: ${{ matrix.region }}
role-to-assume: ${{ secrets[format('{0}', steps.transform.outputs.CONVERTED_REGION)] }}
diff --git a/.gitignore b/.gitignore
index 990f6517fe9..9f244805f60 100644
--- a/.gitignore
+++ b/.gitignore
@@ -314,4 +314,7 @@ examples/**/sam/.aws-sam
cdk.out
# NOTE: different accounts will be used for E2E thus creating unnecessary git clutter
-cdk.context.json
\ No newline at end of file
+cdk.context.json
+
+# vim
+*.swp
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3b64fd7bc13..2ee352d2403 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,107 @@
## Bug Fixes
+* **docs:** typo in a service name in Event Handler ([#5944](https://github.com/aws-powertools/powertools-lambda-python/issues/5944))
+* **logger:** child logger must respect log level ([#5950](https://github.com/aws-powertools/powertools-lambda-python/issues/5950))
+
+## Code Refactoring
+
+* **metrics:** Improve type annotations for metrics decorator ([#6000](https://github.com/aws-powertools/powertools-lambda-python/issues/6000))
+
+## Documentation
+
+* **api:** migrating the event handler utility to mkdocstrings ([#6023](https://github.com/aws-powertools/powertools-lambda-python/issues/6023))
+* **api:** migrating the metrics utility to mkdocstrings ([#6022](https://github.com/aws-powertools/powertools-lambda-python/issues/6022))
+* **api:** migrating the logger utility to mkdocstrings ([#6021](https://github.com/aws-powertools/powertools-lambda-python/issues/6021))
+* **api:** migrating the Middleware Factory utility to mkdocstrings ([#6019](https://github.com/aws-powertools/powertools-lambda-python/issues/6019))
+* **api:** migrating the tracer utility to mkdocstrings ([#6017](https://github.com/aws-powertools/powertools-lambda-python/issues/6017))
+* **api:** migrating the batch utility to mkdocstrings ([#6016](https://github.com/aws-powertools/powertools-lambda-python/issues/6016))
+* **api:** migrating the event source data classes utility to mkdocstrings ([#6015](https://github.com/aws-powertools/powertools-lambda-python/issues/6015))
+* **api:** migrating the data masking utility to mkdocstrings ([#6013](https://github.com/aws-powertools/powertools-lambda-python/issues/6013))
+* **api:** migrating the AppConfig utility to mkdocstrings ([#6008](https://github.com/aws-powertools/powertools-lambda-python/issues/6008))
+* **api:** migrating the idempotency utility to mkdocstrings ([#6007](https://github.com/aws-powertools/powertools-lambda-python/issues/6007))
+* **api:** migrating the jmespath utility to mkdocstrings ([#6006](https://github.com/aws-powertools/powertools-lambda-python/issues/6006))
+* **api:** migrating the parameters utility to mkdocstrings ([#6005](https://github.com/aws-powertools/powertools-lambda-python/issues/6005))
+* **api:** migrating the parser utility to mkdocstrings ([#6004](https://github.com/aws-powertools/powertools-lambda-python/issues/6004))
+* **api:** migrating the streaming utility to mkdocstrings ([#6003](https://github.com/aws-powertools/powertools-lambda-python/issues/6003))
+* **api:** migrating the typing utility to mkdocstrings ([#5996](https://github.com/aws-powertools/powertools-lambda-python/issues/5996))
+* **api:** migrating the validation utility to mkdocstrings ([#5972](https://github.com/aws-powertools/powertools-lambda-python/issues/5972))
+* **layer:** update layer version number - v3.5.0 ([#5952](https://github.com/aws-powertools/powertools-lambda-python/issues/5952))
+
+## Features
+
+* **event_source:** add class APIGatewayAuthorizerResponseWebSocket ([#6058](https://github.com/aws-powertools/powertools-lambda-python/issues/6058))
+* **logger:** add clear_state method ([#5956](https://github.com/aws-powertools/powertools-lambda-python/issues/5956))
+* **metrics:** disable metrics flush via environment variables ([#6046](https://github.com/aws-powertools/powertools-lambda-python/issues/6046))
+* **openapi:** enhance support for tuple return type validation ([#5997](https://github.com/aws-powertools/powertools-lambda-python/issues/5997))
+
+## Maintenance
+
+* **ci:** new pre-release 3.5.1a0 ([#5945](https://github.com/aws-powertools/powertools-lambda-python/issues/5945))
+* **ci:** new pre-release 3.5.1a1 ([#5954](https://github.com/aws-powertools/powertools-lambda-python/issues/5954))
+* **ci:** new pre-release 3.5.1a8 ([#6061](https://github.com/aws-powertools/powertools-lambda-python/issues/6061))
+* **ci:** new pre-release 3.5.1a4 ([#6018](https://github.com/aws-powertools/powertools-lambda-python/issues/6018))
+* **ci:** install & configure mkdocstrings plugin ([#5959](https://github.com/aws-powertools/powertools-lambda-python/issues/5959))
+* **ci:** remove pdoc3 library ([#6024](https://github.com/aws-powertools/powertools-lambda-python/issues/6024))
+* **ci:** new pre-release 3.5.1a9 ([#6069](https://github.com/aws-powertools/powertools-lambda-python/issues/6069))
+* **ci:** new pre-release 3.5.1a7 ([#6044](https://github.com/aws-powertools/powertools-lambda-python/issues/6044))
+* **ci:** new pre-release 3.5.1a5 ([#6026](https://github.com/aws-powertools/powertools-lambda-python/issues/6026))
+* **ci:** add new script to bump Lambda layer version ([#6001](https://github.com/aws-powertools/powertools-lambda-python/issues/6001))
+* **ci:** new pre-release 3.5.1a3 ([#5998](https://github.com/aws-powertools/powertools-lambda-python/issues/5998))
+* **ci:** new pre-release 3.5.1a2 ([#5970](https://github.com/aws-powertools/powertools-lambda-python/issues/5970))
+* **ci:** new pre-release 3.5.1a6 ([#6033](https://github.com/aws-powertools/powertools-lambda-python/issues/6033))
+* **deps:** bump actions/setup-node from 4.1.0 to 4.2.0 ([#5963](https://github.com/aws-powertools/powertools-lambda-python/issues/5963))
+* **deps:** bump pypa/gh-action-pypi-publish from 1.12.3 to 1.12.4 ([#5980](https://github.com/aws-powertools/powertools-lambda-python/issues/5980))
+* **deps:** bump actions/setup-go from 5.2.0 to 5.3.0 ([#5978](https://github.com/aws-powertools/powertools-lambda-python/issues/5978))
+* **deps:** bump squidfunk/mkdocs-material from `41942f7` to `471695f` in /docs ([#5979](https://github.com/aws-powertools/powertools-lambda-python/issues/5979))
+* **deps:** bump actions/upload-artifact from 4.5.0 to 4.6.0 ([#5962](https://github.com/aws-powertools/powertools-lambda-python/issues/5962))
+* **deps:** bump zgosalvez/github-actions-ensure-sha-pinned-actions from 3.0.18 to 3.0.20 ([#5977](https://github.com/aws-powertools/powertools-lambda-python/issues/5977))
+* **deps:** bump release-drafter/release-drafter from 6.0.0 to 6.1.0 ([#5976](https://github.com/aws-powertools/powertools-lambda-python/issues/5976))
+* **deps:** bump docker/setup-buildx-action from 3.8.0 to 3.9.0 ([#6042](https://github.com/aws-powertools/powertools-lambda-python/issues/6042))
+* **deps:** bump docker/setup-qemu-action from 3.3.0 to 3.4.0 ([#6043](https://github.com/aws-powertools/powertools-lambda-python/issues/6043))
+* **deps:** bump codecov/codecov-action from 5.1.2 to 5.3.1 ([#5964](https://github.com/aws-powertools/powertools-lambda-python/issues/5964))
+* **deps:** bump docker/setup-qemu-action from 3.2.0 to 3.3.0 ([#5961](https://github.com/aws-powertools/powertools-lambda-python/issues/5961))
+* **deps:** bump actions/setup-python from 5.3.0 to 5.4.0 ([#5960](https://github.com/aws-powertools/powertools-lambda-python/issues/5960))
+* **deps:** bump squidfunk/mkdocs-material from `7e841df` to `c62453b` in /docs ([#6052](https://github.com/aws-powertools/powertools-lambda-python/issues/6052))
+* **deps:** bump zgosalvez/github-actions-ensure-sha-pinned-actions from 3.0.20 to 3.0.21 ([#6064](https://github.com/aws-powertools/powertools-lambda-python/issues/6064))
+* **deps:** bump squidfunk/mkdocs-material from `471695f` to `7e841df` in /docs ([#6012](https://github.com/aws-powertools/powertools-lambda-python/issues/6012))
+* **deps:** bump aws-actions/configure-aws-credentials from 4.0.2 to 4.0.3 ([#5975](https://github.com/aws-powertools/powertools-lambda-python/issues/5975))
+* **deps-dev:** bump mkdocstrings-python from 1.13.0 to 1.14.2 ([#6011](https://github.com/aws-powertools/powertools-lambda-python/issues/6011))
+* **deps-dev:** bump mkdocs-material from 9.6.1 to 9.6.2 ([#6009](https://github.com/aws-powertools/powertools-lambda-python/issues/6009))
+* **deps-dev:** bump mkdocstrings-python from 1.14.2 to 1.14.4 ([#6025](https://github.com/aws-powertools/powertools-lambda-python/issues/6025))
+* **deps-dev:** bump boto3-stubs from 1.36.10 to 1.36.11 ([#6010](https://github.com/aws-powertools/powertools-lambda-python/issues/6010))
+* **deps-dev:** bump boto3-stubs from 1.36.10 to 1.36.12 ([#6014](https://github.com/aws-powertools/powertools-lambda-python/issues/6014))
+* **deps-dev:** bump mkdocstrings-python from 1.14.4 to 1.14.5 ([#6032](https://github.com/aws-powertools/powertools-lambda-python/issues/6032))
+* **deps-dev:** bump cfn-lint from 1.23.1 to 1.24.0 ([#6030](https://github.com/aws-powertools/powertools-lambda-python/issues/6030))
+* **deps-dev:** bump cdklabs-generative-ai-cdk-constructs from 0.1.290 to 0.1.291 ([#6031](https://github.com/aws-powertools/powertools-lambda-python/issues/6031))
+* **deps-dev:** bump boto3-stubs from 1.36.12 to 1.36.14 ([#6029](https://github.com/aws-powertools/powertools-lambda-python/issues/6029))
+* **deps-dev:** bump ruff from 0.9.5 to 0.9.6 ([#6066](https://github.com/aws-powertools/powertools-lambda-python/issues/6066))
+* **deps-dev:** bump aws-cdk-lib from 2.177.0 to 2.178.0 ([#6038](https://github.com/aws-powertools/powertools-lambda-python/issues/6038))
+* **deps-dev:** bump mkdocs-material from 9.5.50 to 9.6.1 ([#5966](https://github.com/aws-powertools/powertools-lambda-python/issues/5966))
+* **deps-dev:** bump black from 24.10.0 to 25.1.0 ([#5968](https://github.com/aws-powertools/powertools-lambda-python/issues/5968))
+* **deps-dev:** bump ruff from 0.9.3 to 0.9.4 ([#5969](https://github.com/aws-powertools/powertools-lambda-python/issues/5969))
+* **deps-dev:** bump ruff from 0.9.4 to 0.9.5 ([#6039](https://github.com/aws-powertools/powertools-lambda-python/issues/6039))
+* **deps-dev:** bump cfn-lint from 1.22.7 to 1.23.1 ([#5967](https://github.com/aws-powertools/powertools-lambda-python/issues/5967))
+* **deps-dev:** bump aws-cdk-aws-lambda-python-alpha from 2.177.0a0 to 2.178.0a0 ([#6041](https://github.com/aws-powertools/powertools-lambda-python/issues/6041))
+* **deps-dev:** bump isort from 5.13.2 to 6.0.0 ([#5965](https://github.com/aws-powertools/powertools-lambda-python/issues/5965))
+* **deps-dev:** bump aws-cdk from 2.177.0 to 2.178.0 ([#6040](https://github.com/aws-powertools/powertools-lambda-python/issues/6040))
+* **deps-dev:** bump aws-cdk from 2.178.0 to 2.178.1 ([#6053](https://github.com/aws-powertools/powertools-lambda-python/issues/6053))
+* **deps-dev:** bump aws-cdk-lib from 2.178.0 to 2.178.1 ([#6047](https://github.com/aws-powertools/powertools-lambda-python/issues/6047))
+* **deps-dev:** bump aws-cdk-aws-lambda-python-alpha from 2.178.0a0 to 2.178.1a0 ([#6048](https://github.com/aws-powertools/powertools-lambda-python/issues/6048))
+* **deps-dev:** bump boto3-stubs from 1.36.14 to 1.36.15 ([#6049](https://github.com/aws-powertools/powertools-lambda-python/issues/6049))
+* **deps-dev:** bump cdklabs-generative-ai-cdk-constructs from 0.1.291 to 0.1.292 ([#6051](https://github.com/aws-powertools/powertools-lambda-python/issues/6051))
+* **deps-dev:** bump mkdocstrings-python from 1.14.5 to 1.14.6 ([#6050](https://github.com/aws-powertools/powertools-lambda-python/issues/6050))
+* **deps-dev:** bump boto3-stubs from 1.36.14 to 1.36.16 ([#6057](https://github.com/aws-powertools/powertools-lambda-python/issues/6057))
+* **deps-dev:** bump mkdocs-material from 9.6.2 to 9.6.3 ([#6065](https://github.com/aws-powertools/powertools-lambda-python/issues/6065))
+* **deps-dev:** bump coverage from 7.6.10 to 7.6.11 ([#6067](https://github.com/aws-powertools/powertools-lambda-python/issues/6067))
+* **deps-dev:** bump mypy from 1.14.1 to 1.15.0 ([#6028](https://github.com/aws-powertools/powertools-lambda-python/issues/6028))
+* **docs:** enable privacy plugin in docs ([#6036](https://github.com/aws-powertools/powertools-lambda-python/issues/6036))
+
+
+
+## [v3.5.0] - 2025-01-28
+## Bug Fixes
+
* **event_handler:** fixes typo in variable name `fronzen_openapi_extensions` ([#5929](https://github.com/aws-powertools/powertools-lambda-python/issues/5929))
* **event_handler:** add tests for PEP 563 compatibility with OpenAPI ([#5886](https://github.com/aws-powertools/powertools-lambda-python/issues/5886))
* **event_handler:** fix forward references resolution in OpenAPI ([#5885](https://github.com/aws-powertools/powertools-lambda-python/issues/5885))
@@ -27,24 +128,29 @@
## Maintenance
+* version bump
+* **ci:** adding poetry export plugin to support v2 ([#5941](https://github.com/aws-powertools/powertools-lambda-python/issues/5941))
+* **ci:** adding poetry export plugin to support v2 ([#5938](https://github.com/aws-powertools/powertools-lambda-python/issues/5938))
* **ci:** adjust token permission ([#5867](https://github.com/aws-powertools/powertools-lambda-python/issues/5867))
* **ci:** new pre-release 3.4.2a0 ([#5873](https://github.com/aws-powertools/powertools-lambda-python/issues/5873))
* **ci:** make `pyproject.toml` fully compatible with Poetryv2 ([#5902](https://github.com/aws-powertools/powertools-lambda-python/issues/5902))
-* **ci:** fix permissions for gh pages ([#5866](https://github.com/aws-powertools/powertools-lambda-python/issues/5866))
* **ci:** drop support for Python 3.8 ([#5896](https://github.com/aws-powertools/powertools-lambda-python/issues/5896))
-* **deps:** bump squidfunk/mkdocs-material from `ba73db5` to `41942f7` in /docs ([#5890](https://github.com/aws-powertools/powertools-lambda-python/issues/5890))
+* **ci:** update poetry version to v2 ([#5936](https://github.com/aws-powertools/powertools-lambda-python/issues/5936))
+* **ci:** fix permissions for gh pages ([#5866](https://github.com/aws-powertools/powertools-lambda-python/issues/5866))
* **deps:** bump pydantic from 2.10.5 to 2.10.6 ([#5918](https://github.com/aws-powertools/powertools-lambda-python/issues/5918))
-* **deps-dev:** bump cfn-lint from 1.22.5 to 1.22.6 ([#5900](https://github.com/aws-powertools/powertools-lambda-python/issues/5900))
+* **deps:** bump squidfunk/mkdocs-material from `ba73db5` to `41942f7` in /docs ([#5890](https://github.com/aws-powertools/powertools-lambda-python/issues/5890))
+* **deps-dev:** bump boto3-stubs from 1.36.4 to 1.36.5 ([#5919](https://github.com/aws-powertools/powertools-lambda-python/issues/5919))
+* **deps-dev:** bump boto3-stubs from 1.36.4 to 1.36.6 ([#5923](https://github.com/aws-powertools/powertools-lambda-python/issues/5923))
* **deps-dev:** bump cfn-lint from 1.22.6 to 1.22.7 ([#5910](https://github.com/aws-powertools/powertools-lambda-python/issues/5910))
* **deps-dev:** bump testcontainers from 3.7.1 to 4.9.1 ([#5907](https://github.com/aws-powertools/powertools-lambda-python/issues/5907))
* **deps-dev:** bump pytest-benchmark from 4.0.0 to 5.1.0 ([#5909](https://github.com/aws-powertools/powertools-lambda-python/issues/5909))
-* **deps-dev:** bump ruff from 0.9.2 to 0.9.3 ([#5911](https://github.com/aws-powertools/powertools-lambda-python/issues/5911))
+* **deps-dev:** bump aws-cdk from 2.176.0 to 2.177.0 ([#5930](https://github.com/aws-powertools/powertools-lambda-python/issues/5930))
* **deps-dev:** bump pytest-cov from 5.0.0 to 6.0.0 ([#5908](https://github.com/aws-powertools/powertools-lambda-python/issues/5908))
-* **deps-dev:** bump pytest-asyncio from 0.24.0 to 0.25.2 ([#5920](https://github.com/aws-powertools/powertools-lambda-python/issues/5920))
-* **deps-dev:** bump boto3-stubs from 1.36.4 to 1.36.5 ([#5919](https://github.com/aws-powertools/powertools-lambda-python/issues/5919))
-* **deps-dev:** bump boto3-stubs from 1.36.4 to 1.36.6 ([#5923](https://github.com/aws-powertools/powertools-lambda-python/issues/5923))
+* **deps-dev:** bump aws-cdk-lib from 2.176.0 to 2.177.0 ([#5931](https://github.com/aws-powertools/powertools-lambda-python/issues/5931))
+* **deps-dev:** bump cfn-lint from 1.22.5 to 1.22.6 ([#5900](https://github.com/aws-powertools/powertools-lambda-python/issues/5900))
+* **deps-dev:** bump boto3-stubs from 1.36.6 to 1.36.7 ([#5932](https://github.com/aws-powertools/powertools-lambda-python/issues/5932))
* **deps-dev:** bump boto3-stubs from 1.36.2 to 1.36.3 ([#5894](https://github.com/aws-powertools/powertools-lambda-python/issues/5894))
-* **deps-dev:** bump aws-cdk from 2.176.0 to 2.177.0 ([#5930](https://github.com/aws-powertools/powertools-lambda-python/issues/5930))
+* **deps-dev:** bump pytest-asyncio from 0.24.0 to 0.25.2 ([#5920](https://github.com/aws-powertools/powertools-lambda-python/issues/5920))
* **deps-dev:** bump mkdocs-material from 9.5.49 to 9.5.50 ([#5889](https://github.com/aws-powertools/powertools-lambda-python/issues/5889))
* **deps-dev:** bump aws-cdk-aws-lambda-python-alpha from 2.175.1a0 to 2.176.0a0 ([#5882](https://github.com/aws-powertools/powertools-lambda-python/issues/5882))
* **deps-dev:** bump boto3-stubs from 1.36.1 to 1.36.2 ([#5881](https://github.com/aws-powertools/powertools-lambda-python/issues/5881))
@@ -55,9 +161,9 @@
* **deps-dev:** bump sentry-sdk from 2.19.2 to 2.20.0 ([#5870](https://github.com/aws-powertools/powertools-lambda-python/issues/5870))
* **deps-dev:** bump boto3-stubs from 1.35.97 to 1.35.99 ([#5874](https://github.com/aws-powertools/powertools-lambda-python/issues/5874))
* **deps-dev:** bump cfn-lint from 1.22.4 to 1.22.5 ([#5872](https://github.com/aws-powertools/powertools-lambda-python/issues/5872))
-* **deps-dev:** bump aws-cdk-lib from 2.176.0 to 2.177.0 ([#5931](https://github.com/aws-powertools/powertools-lambda-python/issues/5931))
-* **deps-dev:** bump boto3-stubs from 1.36.6 to 1.36.7 ([#5932](https://github.com/aws-powertools/powertools-lambda-python/issues/5932))
* **deps-dev:** bump aws-cdk-aws-lambda-python-alpha from 2.176.0a0 to 2.177.0a0 ([#5933](https://github.com/aws-powertools/powertools-lambda-python/issues/5933))
+* **deps-dev:** bump cdklabs-generative-ai-cdk-constructs from 0.1.289 to 0.1.290 ([#5917](https://github.com/aws-powertools/powertools-lambda-python/issues/5917))
+* **deps-dev:** bump ruff from 0.9.2 to 0.9.3 ([#5911](https://github.com/aws-powertools/powertools-lambda-python/issues/5911))
@@ -5933,7 +6039,8 @@
* Merge pull request [#5](https://github.com/aws-powertools/powertools-lambda-python/issues/5) from jfuss/feat/python38
-[Unreleased]: https://github.com/aws-powertools/powertools-lambda-python/compare/v3.4.1...HEAD
+[Unreleased]: https://github.com/aws-powertools/powertools-lambda-python/compare/v3.5.0...HEAD
+[v3.5.0]: https://github.com/aws-powertools/powertools-lambda-python/compare/v3.4.1...v3.5.0
[v3.4.1]: https://github.com/aws-powertools/powertools-lambda-python/compare/v3.4.0...v3.4.1
[v3.4.0]: https://github.com/aws-powertools/powertools-lambda-python/compare/v3.3.0...v3.4.0
[v3.3.0]: https://github.com/aws-powertools/powertools-lambda-python/compare/v3.2.0...v3.3.0
diff --git a/Makefile b/Makefile
index f9111bd9394..4bb1e78390c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
-.PHONY: target dev format lint test coverage-html pr build build-docs build-docs-api build-docs-website
-.PHONY: docs-local docs-api-local security-baseline complexity-baseline release-prod release-test release
+.PHONY: target dev format lint test coverage-html pr build build-docs build-docs-website check-licenses
+.PHONY: docs-local security-baseline complexity-baseline release-prod release-test release
target:
@$(MAKE) pr
@@ -21,6 +21,10 @@ dev-gitpod:
poetry install --extras "all redis datamasking"
pre-commit install
+# Running licensecheck with zero to break the pipeline if there is an invalid license
+check-licenses:
+ poetry run licensecheck -u poetry:dev --zero
+
format:
poetry run black aws_lambda_powertools tests examples
@@ -55,7 +59,7 @@ coverage-html:
pre-commit:
pre-commit run --show-diff-on-failure
-pr: lint lint-docs mypy pre-commit test security-baseline complexity-baseline
+pr: lint lint-docs mypy pre-commit check-licenses test security-baseline complexity-baseline
build: pr
poetry build
@@ -65,14 +69,6 @@ release-docs:
rm -rf site api
@echo "Updating website docs"
poetry run mike deploy --push --update-aliases ${VERSION} ${ALIAS}
- @echo "Building API docs"
- @$(MAKE) build-docs-api VERSION=${VERSION}
-
-build-docs-api:
- poetry run pdoc --html --output-dir ./api/ ./aws_lambda_powertools --force
- mv -f ./api/aws_lambda_powertools/* ./api/
- rm -rf ./api/aws_lambda_powertools
- mkdir ${VERSION} && cp -R api ${VERSION}
docs-local:
poetry run mkdocs serve
@@ -81,9 +77,6 @@ docs-local-docker:
docker build -t squidfunk/mkdocs-material ./docs/
docker run --rm -it -p 8000:8000 -v ${PWD}:/docs squidfunk/mkdocs-material
-docs-api-local:
- poetry run pdoc --http : aws_lambda_powertools
-
security-baseline:
poetry run bandit --baseline bandit.baseline -r aws_lambda_powertools
diff --git a/aws_lambda_powertools/event_handler/api_gateway.py b/aws_lambda_powertools/event_handler/api_gateway.py
index 1485c563a06..4e2be256ecb 100644
--- a/aws_lambda_powertools/event_handler/api_gateway.py
+++ b/aws_lambda_powertools/event_handler/api_gateway.py
@@ -313,10 +313,10 @@ def __init__(
middlewares: list[Callable[..., Response]] | None = None,
):
"""
+ Internally used Route Configuration
Parameters
----------
-
method: str
The HTTP method, example "GET"
path: str
@@ -908,6 +908,8 @@ def build(self, event: ResponseEventT, cors: CORSConfig | None = None) -> dict[s
class BaseRouter(ABC):
+ """Base class for Routing"""
+
current_event: BaseProxyEvent
lambda_context: LambdaContext
context: dict
@@ -1459,7 +1461,7 @@ def _registered_api_adapter(app: ApiGatewayResolver, next_middleware: Callable[.
class ApiGatewayResolver(BaseRouter):
- """API Gateway and ALB proxy resolver
+ """API Gateway, VPC Laticce, Bedrock and ALB proxy resolver
Examples
--------
@@ -2570,6 +2572,8 @@ def register_exception_handler(func: Callable):
class APIGatewayRestResolver(ApiGatewayResolver):
+ """Amazon API Gateway REST and HTTP API v1 payload resolver"""
+
current_event: APIGatewayProxyEvent
def __init__(
@@ -2650,6 +2654,8 @@ def _compile_regex(rule: str, base_regex: str = _ROUTE_REGEX):
class APIGatewayHttpResolver(ApiGatewayResolver):
+ """Amazon API Gateway HTTP API v2 payload resolver"""
+
current_event: APIGatewayProxyEventV2
def __init__(
@@ -2685,6 +2691,8 @@ def _get_base_path(self) -> str:
class ALBResolver(ApiGatewayResolver):
+ """Amazon Application Load Balancer (ALB) resolver"""
+
current_event: ALBEvent
def __init__(
diff --git a/aws_lambda_powertools/event_handler/middlewares/base.py b/aws_lambda_powertools/event_handler/middlewares/base.py
index 3998c7c80bd..5b4f82b405f 100644
--- a/aws_lambda_powertools/event_handler/middlewares/base.py
+++ b/aws_lambda_powertools/event_handler/middlewares/base.py
@@ -26,7 +26,7 @@ class BaseMiddlewareHandler(Generic[EventHandlerInstance], ABC):
This is the middleware handler function where middleware logic is implemented.
The next middleware handler is represented by `next_middleware`, returning a Response object.
- Examples
+ Example
--------
**Correlation ID Middleware**
diff --git a/aws_lambda_powertools/event_handler/middlewares/openapi_validation.py b/aws_lambda_powertools/event_handler/middlewares/openapi_validation.py
index a73fd454458..555ec519bf6 100644
--- a/aws_lambda_powertools/event_handler/middlewares/openapi_validation.py
+++ b/aws_lambda_powertools/event_handler/middlewares/openapi_validation.py
@@ -37,7 +37,7 @@ class OpenAPIValidationMiddleware(BaseMiddlewareHandler):
Lambda handler. It also validates the response against the OpenAPI schema defined by the Lambda handler. It
should not be used directly, but rather through the `enable_validation` parameter of the `ApiGatewayResolver`.
- Examples
+ Example
--------
```python
diff --git a/aws_lambda_powertools/event_handler/middlewares/schema_validation.py b/aws_lambda_powertools/event_handler/middlewares/schema_validation.py
index c31d15bec03..c24fff0cbe0 100644
--- a/aws_lambda_powertools/event_handler/middlewares/schema_validation.py
+++ b/aws_lambda_powertools/event_handler/middlewares/schema_validation.py
@@ -18,7 +18,7 @@
class SchemaValidationMiddleware(BaseMiddlewareHandler):
"""Middleware to validate API request and response against JSON Schema using the [Validation utility](https://docs.powertools.aws.dev/lambda/python/latest/utilities/validation/).
- Examples
+ Example
--------
**Validating incoming event**
diff --git a/aws_lambda_powertools/event_handler/openapi/params.py b/aws_lambda_powertools/event_handler/openapi/params.py
index ffcef8b5096..1d6b5da145c 100644
--- a/aws_lambda_powertools/event_handler/openapi/params.py
+++ b/aws_lambda_powertools/event_handler/openapi/params.py
@@ -879,8 +879,6 @@ def get_flat_dependant(
----------
dependant: Dependant
The dependant model to flatten
- skip_repeats: bool
- If True, child Dependents already visited will be skipped to avoid duplicates
visited: list[CacheKey], optional
Keeps track of visited Dependents to avoid infinite recursion. Defaults to empty list.
@@ -932,7 +930,12 @@ def analyze_param(
ModelField | None
The type annotation and the Pydantic field representing the parameter
"""
- field_info, type_annotation = get_field_info_and_type_annotation(annotation, value, is_path_param)
+ field_info, type_annotation = get_field_info_and_type_annotation(
+ annotation,
+ value,
+ is_path_param,
+ is_response_param,
+ )
# If the value is a FieldInfo, we use it as the FieldInfo for the parameter
if isinstance(value, FieldInfo):
@@ -962,7 +965,12 @@ def analyze_param(
return field
-def get_field_info_and_type_annotation(annotation, value, is_path_param: bool) -> tuple[FieldInfo | None, Any]:
+def get_field_info_and_type_annotation(
+ annotation,
+ value,
+ is_path_param: bool,
+ is_response_param: bool,
+) -> tuple[FieldInfo | None, Any]:
"""
Get the FieldInfo and type annotation from an annotation and value.
"""
@@ -976,6 +984,10 @@ def get_field_info_and_type_annotation(annotation, value, is_path_param: bool) -
# If the annotation is a Response type, we recursively call this function with the inner type
elif get_origin(annotation) is Response:
field_info, type_annotation = get_field_info_response_type(annotation, value)
+ # If the response param is a tuple with two elements, we use the first element as the type annotation,
+ # just like we did in the APIGateway._to_response
+ elif is_response_param and get_origin(annotation) is tuple and len(get_args(annotation)) == 2:
+ field_info, type_annotation = get_field_info_tuple_type(annotation, value)
# If the annotation is not an Annotated type, we use it as the type annotation
else:
type_annotation = annotation
@@ -983,12 +995,22 @@ def get_field_info_and_type_annotation(annotation, value, is_path_param: bool) -
return field_info, type_annotation
+def get_field_info_tuple_type(annotation, value) -> tuple[FieldInfo | None, Any]:
+ (inner_type, _) = get_args(annotation)
+
+ # If the inner type is an Annotated type, we need to extract the type annotation and the FieldInfo
+ if get_origin(inner_type) is Annotated:
+ return get_field_info_annotated_type(inner_type, value, False)
+
+ return None, inner_type
+
+
def get_field_info_response_type(annotation, value) -> tuple[FieldInfo | None, Any]:
# Example: get_args(Response[inner_type]) == (inner_type,) # noqa: ERA001
(inner_type,) = get_args(annotation)
# Recursively resolve the inner type
- return get_field_info_and_type_annotation(inner_type, value, False)
+ return get_field_info_and_type_annotation(inner_type, value, False, True)
def get_field_info_annotated_type(annotation, value, is_path_param: bool) -> tuple[FieldInfo | None, Any]:
diff --git a/aws_lambda_powertools/event_handler/openapi/swagger_ui/html.py b/aws_lambda_powertools/event_handler/openapi/swagger_ui/html.py
index 70d98743bcf..6bcbcff50a4 100644
--- a/aws_lambda_powertools/event_handler/openapi/swagger_ui/html.py
+++ b/aws_lambda_powertools/event_handler/openapi/swagger_ui/html.py
@@ -22,7 +22,7 @@ def generate_swagger_html(
spec: str
The OpenAPI spec
swagger_js: str
- Swagger UI JavaScript source code or URL
+ Swagger UI JavaScript source code or URL
swagger_css: str
Swagger UI CSS source code or URL
swagger_base_url: str
diff --git a/aws_lambda_powertools/logging/__init__.py b/aws_lambda_powertools/logging/__init__.py
index 2c9532ef540..38dd68c1caa 100644
--- a/aws_lambda_powertools/logging/__init__.py
+++ b/aws_lambda_powertools/logging/__init__.py
@@ -1,5 +1,4 @@
-"""Logging utility
-"""
+"""Logging utility"""
from .logger import Logger
diff --git a/aws_lambda_powertools/logging/exceptions.py b/aws_lambda_powertools/logging/exceptions.py
index 65b30906edf..488234608f0 100644
--- a/aws_lambda_powertools/logging/exceptions.py
+++ b/aws_lambda_powertools/logging/exceptions.py
@@ -1,2 +1,6 @@
class InvalidLoggerSamplingRateError(Exception):
+ """
+ Logger configured with Invalid Sampling value
+ """
+
pass
diff --git a/aws_lambda_powertools/logging/formatter.py b/aws_lambda_powertools/logging/formatter.py
index 824c5c0ef16..f04f7c87e73 100644
--- a/aws_lambda_powertools/logging/formatter.py
+++ b/aws_lambda_powertools/logging/formatter.py
@@ -273,17 +273,17 @@ def append_context_keys(self, **additional_keys: Any) -> Generator[None, None, N
"""
Context manager to temporarily add logging keys.
- Parameters:
+ Parameters
-----------
- **keys: Any
+ **additional_keys: Any
Key-value pairs to include in the log context during the lifespan of the context manager.
- Example:
+ Example
--------
- >>> logger = Logger(service="example_service")
- >>> with logger.append_context_keys(user_id="123", operation="process"):
- >>> logger.info("Log with context")
- >>> logger.info("Log without context")
+ logger = Logger(service="example_service")
+ with logger.append_context_keys(user_id="123", operation="process"):
+ logger.info("Log with context")
+ logger.info("Log without context")
"""
# Add keys to the context
self.append_keys(**additional_keys)
diff --git a/aws_lambda_powertools/logging/logger.py b/aws_lambda_powertools/logging/logger.py
index c242f5c9bd4..840d068d438 100644
--- a/aws_lambda_powertools/logging/logger.py
+++ b/aws_lambda_powertools/logging/logger.py
@@ -1,3 +1,9 @@
+"""
+Logger utility
+!!! abstract "Usage Documentation"
+ [`Logger`](../../core/logger.md)
+"""
+
from __future__ import annotations
import functools
@@ -82,7 +88,7 @@ class Logger:
by default "INFO"
child: bool, optional
create a child Logger named ., False by default
- sample_rate: float, optional
+ sampling_rate: float, optional
sample rate for debug calls within execution context defaults to 0.0
stream: sys.stdout, optional
valid output for a logging stream, by default sys.stdout
@@ -103,7 +109,6 @@ class Logger:
use_datetime_directive: bool, optional
Interpret `datefmt` as a format string for `datetime.datetime.strftime`, rather than
`time.strftime`.
-
See https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior . This
also supports a custom %F directive for milliseconds.
use_rfc3339: bool, optional
@@ -116,7 +121,6 @@ class Logger:
by default json.loads
json_default : Callable, optional
function to coerce unserializable values, by default `str()`
-
Only used when no custom formatter is set
utc : bool, optional
set logging timestamp to UTC, by default False to continue to use local time as per stdlib
@@ -222,6 +226,7 @@ def __init__(
choice=sampling_rate,
env=os.getenv(constants.LOGGER_LOG_SAMPLING_RATE),
)
+ self._default_log_keys: dict[str, Any] = {"service": self.service, "sampling_rate": self.sampling_rate}
self.child = child
self.logger_formatter = logger_formatter
self._stream = stream or sys.stdout
@@ -231,7 +236,6 @@ def __init__(
self._is_deduplication_disabled = resolve_truthy_env_var_choice(
env=os.getenv(constants.LOGGER_LOG_DEDUPLICATION_ENV, "false"),
)
- self._default_log_keys = {"service": self.service, "sampling_rate": self.sampling_rate}
self._logger = self._get_logger()
# NOTE: This is primarily to improve UX, so IDEs can autocomplete LambdaPowertoolsFormatter options
@@ -285,7 +289,11 @@ def _init_logger(
# b) different sampling mechanisms
# c) multiple messages from being logged as handlers can be duplicated
is_logger_preconfigured = getattr(self._logger, LOGGER_ATTRIBUTE_PRECONFIGURED, False)
- if self.child or is_logger_preconfigured:
+ if self.child:
+ self.setLevel(log_level)
+ return
+
+ if is_logger_preconfigured:
return
self.setLevel(log_level)
@@ -586,21 +594,31 @@ def append_context_keys(self, **additional_keys: Any) -> Generator[None, None, N
"""
Context manager to temporarily add logging keys.
- Parameters:
+ Parameters
-----------
- **keys: Any
+ **additional_keys: Any
Key-value pairs to include in the log context during the lifespan of the context manager.
- Example:
+ Example
--------
- >>> logger = Logger(service="example_service")
- >>> with logger.append_context_keys(user_id="123", operation="process"):
- >>> logger.info("Log with context")
- >>> logger.info("Log without context")
+ **Logging with contextual keys**
+
+ logger = Logger(service="example_service")
+ with logger.append_context_keys(user_id="123", operation="process"):
+ logger.info("Log with context")
+ logger.info("Log without context")
"""
with self.registered_formatter.append_context_keys(**additional_keys):
yield
+ def clear_state(self) -> None:
+ """Removes all custom keys that were appended to the Logger."""
+ # Clear all custom keys from the formatter
+ self.registered_formatter.clear_state()
+
+ # Reset to default keys
+ self.structure_logs(**self._default_log_keys)
+
# These specific thread-safe methods are necessary to manage shared context in concurrent environments.
# They prevent race conditions and ensure data consistency across multiple threads.
def thread_safe_append_keys(self, **additional_keys: object) -> None:
diff --git a/aws_lambda_powertools/metrics/__init__.py b/aws_lambda_powertools/metrics/__init__.py
index cafd348b8ec..be88ee59258 100644
--- a/aws_lambda_powertools/metrics/__init__.py
+++ b/aws_lambda_powertools/metrics/__init__.py
@@ -1,5 +1,4 @@
-"""CloudWatch Embedded Metric Format utility
-"""
+"""CloudWatch Embedded Metric Format utility"""
from aws_lambda_powertools.metrics.base import MetricResolution, MetricUnit, single_metric
from aws_lambda_powertools.metrics.exceptions import (
diff --git a/aws_lambda_powertools/metrics/base.py b/aws_lambda_powertools/metrics/base.py
index 7304afa5a42..32325e5ce29 100644
--- a/aws_lambda_powertools/metrics/base.py
+++ b/aws_lambda_powertools/metrics/base.py
@@ -1,3 +1,9 @@
+"""
+Metrics utility
+!!! abstract "Usage Documentation"
+ [`Metrics`](../../core/metrics.md)
+"""
+
from __future__ import annotations
import datetime
diff --git a/aws_lambda_powertools/metrics/functions.py b/aws_lambda_powertools/metrics/functions.py
index 14c68e88275..75bf0855e18 100644
--- a/aws_lambda_powertools/metrics/functions.py
+++ b/aws_lambda_powertools/metrics/functions.py
@@ -1,5 +1,6 @@
from __future__ import annotations
+import os
from datetime import datetime
from aws_lambda_powertools.metrics.provider.cloudwatch_emf.exceptions import (
@@ -8,6 +9,7 @@
)
from aws_lambda_powertools.metrics.provider.cloudwatch_emf.metric_properties import MetricResolution, MetricUnit
from aws_lambda_powertools.shared import constants
+from aws_lambda_powertools.shared.functions import strtobool
def extract_cloudwatch_metric_resolution_value(metric_resolutions: list, resolution: int | MetricResolution) -> int:
@@ -134,3 +136,28 @@ def convert_timestamp_to_emf_format(timestamp: int | datetime) -> int:
# Returning zero represents the initial date of epoch time,
# which will be skipped by Amazon CloudWatch.
return 0
+
+
+def is_metrics_disabled() -> bool:
+ """
+ Determine if metrics should be disabled based on environment variables.
+
+ Returns:
+ bool: True if metrics are disabled, False otherwise.
+
+ Rules:
+ - If POWERTOOLS_DEV is True and POWERTOOLS_METRICS_DISABLED is True: Disable metrics
+ - If POWERTOOLS_METRICS_DISABLED is True: Disable metrics
+ - If POWERTOOLS_DEV is True and POWERTOOLS_METRICS_DISABLED is not set: Disable metrics
+ """
+
+ is_dev_mode = strtobool(os.getenv(constants.POWERTOOLS_DEV_ENV, "false"))
+ is_metrics_disabled = strtobool(os.getenv(constants.METRICS_DISABLED_ENV, "false"))
+
+ disable_conditions = [
+ is_metrics_disabled,
+ is_metrics_disabled and is_dev_mode,
+ is_dev_mode and os.getenv(constants.METRICS_DISABLED_ENV) is None,
+ ]
+
+ return any(disable_conditions)
diff --git a/aws_lambda_powertools/metrics/metrics.py b/aws_lambda_powertools/metrics/metrics.py
index 8674f053bd4..a6493f25516 100644
--- a/aws_lambda_powertools/metrics/metrics.py
+++ b/aws_lambda_powertools/metrics/metrics.py
@@ -1,7 +1,7 @@
# NOTE: keeps for compatibility
from __future__ import annotations
-from typing import TYPE_CHECKING, Any
+from typing import TYPE_CHECKING, Any, Callable
from aws_lambda_powertools.metrics.provider.cloudwatch_emf.cloudwatch import AmazonCloudWatchEMFProvider
@@ -47,6 +47,8 @@ def lambda_handler():
metric namespace
POWERTOOLS_SERVICE_NAME : str
service name used for default dimension
+ POWERTOOLS_METRICS_DISABLED: bool
+ Powertools metrics disabled (e.g. `"true", "True", "TRUE"`)
Parameters
----------
@@ -149,8 +151,8 @@ def log_metrics(
capture_cold_start_metric: bool = False,
raise_on_empty_metrics: bool = False,
default_dimensions: dict[str, str] | None = None,
- **kwargs,
- ):
+ **kwargs: dict[str, Any],
+ ) -> Callable[..., Any]:
return self.provider.log_metrics(
lambda_handler=lambda_handler,
capture_cold_start_metric=capture_cold_start_metric,
diff --git a/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py b/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py
index cd9a90a0d19..65c5b619f57 100644
--- a/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py
+++ b/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py
@@ -15,6 +15,7 @@
convert_timestamp_to_emf_format,
extract_cloudwatch_metric_resolution_value,
extract_cloudwatch_metric_unit_value,
+ is_metrics_disabled,
validate_emf_timestamp,
)
from aws_lambda_powertools.metrics.provider.base import BaseProvider
@@ -77,6 +78,7 @@ def __init__(
self.default_dimensions = default_dimensions or {}
self.namespace = resolve_env_var_choice(choice=namespace, env=os.getenv(constants.METRICS_NAMESPACE_ENV))
self.service = resolve_env_var_choice(choice=service, env=os.getenv(constants.SERVICE_NAME_ENV))
+
self.metadata_set = metadata_set if metadata_set is not None else {}
self.timestamp: int | None = None
@@ -127,6 +129,7 @@ def add_metric(
MetricResolutionError
When metric resolution is not supported by CloudWatch
"""
+
if not isinstance(value, numbers.Number):
raise MetricValueError(f"{value} is not a valid number")
@@ -268,6 +271,7 @@ def add_dimension(self, name: str, value: str) -> None:
value : str
Dimension value
"""
+
logger.debug(f"Adding dimension: {name}:{value}")
if len(self.dimension_set) == MAX_DIMENSIONS:
raise SchemaValidationError(
@@ -330,7 +334,7 @@ def set_timestamp(self, timestamp: int | datetime.datetime):
"""
Set the timestamp for the metric.
- Parameters:
+ Parameters
-----------
timestamp: int | datetime.datetime
The timestamp to create the metric.
@@ -374,7 +378,7 @@ def flush_metrics(self, raise_on_empty_metrics: bool = False) -> None:
"If application metrics should never be empty, consider using 'raise_on_empty_metrics'",
stacklevel=2,
)
- else:
+ elif not is_metrics_disabled():
logger.debug("Flushing existing metrics")
metrics = self.serialize_metric_set()
print(json.dumps(metrics, separators=(",", ":")))
diff --git a/aws_lambda_powertools/metrics/provider/datadog/datadog.py b/aws_lambda_powertools/metrics/provider/datadog/datadog.py
index d79782363f4..3e88523df38 100644
--- a/aws_lambda_powertools/metrics/provider/datadog/datadog.py
+++ b/aws_lambda_powertools/metrics/provider/datadog/datadog.py
@@ -10,6 +10,7 @@
from typing import TYPE_CHECKING, Any
from aws_lambda_powertools.metrics.exceptions import MetricValueError, SchemaValidationError
+from aws_lambda_powertools.metrics.functions import is_metrics_disabled
from aws_lambda_powertools.metrics.provider import BaseProvider
from aws_lambda_powertools.metrics.provider.datadog.warnings import DatadogDataValidationWarning
from aws_lambda_powertools.shared import constants
@@ -87,10 +88,6 @@ def add_metric(
Timestamp in int for the metrics, default = time.time()
tags: list[str]
In format like ["tag:value", "tag2:value2"]
- args: Any
- extra args will be dropped for compatibility
- kwargs: Any
- extra kwargs will be converted into tags, e.g., add_metrics(sales=sam) -> tags=['sales:sam']
Examples
--------
@@ -103,7 +100,6 @@ def add_metric(
>>> sales='sam'
>>> )
"""
-
# validating metric name
if not self._validate_datadog_metric_name(name):
docs = "https://docs.datadoghq.com/metrics/custom_metrics/#naming-custom-metrics"
@@ -184,6 +180,7 @@ def flush_metrics(self, raise_on_empty_metrics: bool = False) -> None:
raise_on_empty_metrics : bool, optional
raise exception if no metrics are emitted, by default False
"""
+
if not raise_on_empty_metrics and len(self.metric_set) == 0:
warnings.warn(
"No application metrics to publish. The cold-start metric may be published if enabled. "
@@ -204,7 +201,7 @@ def flush_metrics(self, raise_on_empty_metrics: bool = False) -> None:
timestamp=metric_item["e"],
tags=metric_item["t"],
)
- else:
+ elif not is_metrics_disabled():
# dd module not found: flush to log, this format can be recognized via datadog log forwarder
# https://github.com/Datadog/datadog-lambda-python/blob/main/datadog_lambda/metric.py#L77
for metric_item in metrics:
diff --git a/aws_lambda_powertools/middleware_factory/__init__.py b/aws_lambda_powertools/middleware_factory/__init__.py
index b44d49d6987..ebdb338cc15 100644
--- a/aws_lambda_powertools/middleware_factory/__init__.py
+++ b/aws_lambda_powertools/middleware_factory/__init__.py
@@ -1,4 +1,7 @@
-""" Utilities to enhance middlewares """
+"""Utilities to enhance middleware
+!!! abstract "Usage Documentation"
+ [`Middleware Factory`](../utilities/middleware_factory.md)
+"""
from .factory import lambda_handler_decorator
diff --git a/aws_lambda_powertools/shared/constants.py b/aws_lambda_powertools/shared/constants.py
index 9652e09a0b2..199f37d99bb 100644
--- a/aws_lambda_powertools/shared/constants.py
+++ b/aws_lambda_powertools/shared/constants.py
@@ -40,6 +40,7 @@
METRICS_NAMESPACE_ENV: str = "POWERTOOLS_METRICS_NAMESPACE"
DATADOG_FLUSH_TO_LOG: str = "DD_FLUSH_TO_LOG"
SERVICE_NAME_ENV: str = "POWERTOOLS_SERVICE_NAME"
+METRICS_DISABLED_ENV: str = "POWERTOOLS_METRICS_DISABLED"
# If the timestamp of log event is more than 2 hours in future, the log event is skipped.
# If the timestamp of log event is more than 14 days in past, the log event is skipped.
# See https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AgentReference.html
diff --git a/aws_lambda_powertools/shared/version.py b/aws_lambda_powertools/shared/version.py
index fedce557921..5c4a4e39ba8 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 = "3.4.2a0"
+VERSION = "3.6.0"
diff --git a/aws_lambda_powertools/tracing/__init__.py b/aws_lambda_powertools/tracing/__init__.py
index 1031ae4aec6..71a9d54a37f 100644
--- a/aws_lambda_powertools/tracing/__init__.py
+++ b/aws_lambda_powertools/tracing/__init__.py
@@ -1,5 +1,4 @@
-"""Tracing utility
-"""
+"""Tracing utility"""
from .extensions import aiohttp_trace_config
from .tracer import Tracer
diff --git a/aws_lambda_powertools/tracing/base.py b/aws_lambda_powertools/tracing/base.py
index 74b146ad6e8..e095287ce62 100644
--- a/aws_lambda_powertools/tracing/base.py
+++ b/aws_lambda_powertools/tracing/base.py
@@ -1,3 +1,9 @@
+"""
+Tracing utility
+!!! abstract "Usage Documentation"
+ [`Tracer`](../../core/tracer.md)
+"""
+
from __future__ import annotations
import abc
diff --git a/aws_lambda_powertools/utilities/batch/base.py b/aws_lambda_powertools/utilities/batch/base.py
index 1c70d4a7adc..2cb74296ca0 100644
--- a/aws_lambda_powertools/utilities/batch/base.py
+++ b/aws_lambda_powertools/utilities/batch/base.py
@@ -1,5 +1,7 @@
"""
Batch processing utilities
+!!! abstract "Usage Documentation"
+ [`Batch processing`](../../utilities/batch.md)
"""
from __future__ import annotations
diff --git a/aws_lambda_powertools/utilities/batch/decorators.py b/aws_lambda_powertools/utilities/batch/decorators.py
index f23d64d0ce3..0cba41f98fe 100644
--- a/aws_lambda_powertools/utilities/batch/decorators.py
+++ b/aws_lambda_powertools/utilities/batch/decorators.py
@@ -51,9 +51,8 @@ def async_batch_processor(
processor: AsyncBatchProcessor
Batch Processor to handle partial failure cases
- Examples
+ Example
--------
- **Processes Lambda's event with a BasePartialProcessor**
>>> from aws_lambda_powertools.utilities.batch import async_batch_processor, AsyncBatchProcessor
>>> from aws_lambda_powertools.utilities.data_classes.sqs_event import SQSRecord
>>>
@@ -119,7 +118,7 @@ def batch_processor(
processor: BatchProcessor
Batch Processor to handle partial failure cases
- Examples
+ Example
--------
**Processes Lambda's event with a BatchProcessor**
@@ -180,7 +179,7 @@ def process_partial_response(
result: PartialItemFailureResponse
Lambda Partial Batch Response
- Examples
+ Example
--------
**Processes Lambda's SQS event**
@@ -244,7 +243,7 @@ def async_process_partial_response(
result: PartialItemFailureResponse
Lambda Partial Batch Response
- Examples
+ Example
--------
**Processes Lambda's SQS event**
diff --git a/aws_lambda_powertools/utilities/batch/sqs_fifo_partial_processor.py b/aws_lambda_powertools/utilities/batch/sqs_fifo_partial_processor.py
index d493e43bd93..2e680e2f04e 100644
--- a/aws_lambda_powertools/utilities/batch/sqs_fifo_partial_processor.py
+++ b/aws_lambda_powertools/utilities/batch/sqs_fifo_partial_processor.py
@@ -21,7 +21,7 @@ class SqsFifoPartialProcessor(BatchProcessor):
Stops processing records when the first record fails. The remaining records are reported as failed items.
Example
- _______
+ -------
## Process batch triggered by a FIFO SQS
diff --git a/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py b/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py
index 5143b9df88e..f77cb467996 100644
--- a/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py
+++ b/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py
@@ -5,7 +5,7 @@
import warnings
from typing import Any, overload
-from typing_extensions import deprecated
+from typing_extensions import deprecated, override
from aws_lambda_powertools.utilities.data_classes.common import (
BaseRequestContext,
@@ -28,9 +28,10 @@ def __init__(
aws_account_id: str,
api_id: str,
stage: str,
- http_method: str,
+ http_method: str | None,
resource: str,
partition: str = "aws",
+ is_websocket_authorizer: bool = False,
):
self.partition = partition
self.region = region
@@ -40,39 +41,54 @@ def __init__(
self.http_method = http_method
# Remove matching "/" from `resource`.
self.resource = resource.lstrip("/")
+ self.is_websocket_authorizer = is_websocket_authorizer
@property
def arn(self) -> str:
"""Build an arn from its parts
eg: arn:aws:execute-api:us-east-1:123456789012:abcdef123/test/GET/request"""
- return (
- f"arn:{self.partition}:execute-api:{self.region}:{self.aws_account_id}:{self.api_id}/{self.stage}/"
- f"{self.http_method}/{self.resource}"
- )
+ base_arn = f"arn:{self.partition}:execute-api:{self.region}:{self.aws_account_id}:{self.api_id}/{self.stage}"
+
+ if not self.is_websocket_authorizer:
+ return f"{base_arn}/{self.http_method}/{self.resource}"
+ else:
+ return f"{base_arn}/{self.resource}"
-def parse_api_gateway_arn(arn: str) -> APIGatewayRouteArn:
+def parse_api_gateway_arn(arn: str, is_websocket_authorizer: bool = False) -> APIGatewayRouteArn:
"""Parses a gateway route arn as a APIGatewayRouteArn class
Parameters
----------
arn : str
ARN string for a methodArn or a routeArn
+ is_websocket_authorizer: bool
+ If it's a API Gateway Websocket
+
Returns
-------
APIGatewayRouteArn
"""
arn_parts = arn.split(":")
api_gateway_arn_parts = arn_parts[5].split("/")
+
+ if not is_websocket_authorizer:
+ http_method = api_gateway_arn_parts[2]
+ resource = "/".join(api_gateway_arn_parts[3:]) if len(api_gateway_arn_parts) >= 4 else ""
+ else:
+ http_method = None
+ resource = "/".join(api_gateway_arn_parts[2:])
+
return APIGatewayRouteArn(
partition=arn_parts[1],
region=arn_parts[3],
aws_account_id=arn_parts[4],
api_id=api_gateway_arn_parts[0],
stage=api_gateway_arn_parts[1],
- http_method=api_gateway_arn_parts[2],
+ http_method=http_method,
# conditional allow us to handle /path/{proxy+} resources, as their length changes.
- resource="/".join(api_gateway_arn_parts[3:]) if len(api_gateway_arn_parts) >= 4 else "",
+ resource=resource,
+ is_websocket_authorizer=is_websocket_authorizer,
)
@@ -512,13 +528,14 @@ def _add_route(self, effect: str, http_method: str, resource: str, conditions: l
raise ValueError(f"Invalid resource path: {resource}. Path should match {self.path_regex}")
resource_arn = APIGatewayRouteArn(
- self.region,
- self.aws_account_id,
- self.api_id,
- self.stage,
- http_method,
- resource,
- self.partition,
+ region=self.region,
+ aws_account_id=self.aws_account_id,
+ api_id=self.api_id,
+ stage=self.stage,
+ http_method=http_method,
+ resource=resource,
+ partition=self.partition,
+ is_websocket_authorizer=False,
).arn
route = {"resourceArn": resource_arn, "conditions": conditions}
@@ -617,3 +634,127 @@ def asdict(self) -> dict[str, Any]:
response["context"] = self.context
return response
+
+
+class APIGatewayAuthorizerResponseWebSocket(APIGatewayAuthorizerResponse):
+ """The IAM Policy Response required for API Gateway WebSocket APIs
+
+ Based on: - https://github.com/awslabs/aws-apigateway-lambda-authorizer-blueprints/blob/\
+ master/blueprints/python/api-gateway-authorizer-python.py
+
+ Documentation:
+ -------------
+ - https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-lambda-authorizer.html
+ - https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html
+ """
+
+ @staticmethod
+ def from_route_arn(
+ arn: str,
+ principal_id: str,
+ context: dict | None = None,
+ usage_identifier_key: str | None = None,
+ ) -> APIGatewayAuthorizerResponseWebSocket:
+ parsed_arn = parse_api_gateway_arn(arn, is_websocket_authorizer=True)
+ return APIGatewayAuthorizerResponseWebSocket(
+ principal_id,
+ parsed_arn.region,
+ parsed_arn.aws_account_id,
+ parsed_arn.api_id,
+ parsed_arn.stage,
+ context,
+ usage_identifier_key,
+ )
+
+ # Note: we need ignore[override] because we are removing the http_method field
+ @override
+ def _add_route(self, effect: str, resource: str, conditions: list[dict] | None = None): # type: ignore[override]
+ """Adds a route to the internal lists of allowed or denied routes. Each object in
+ the internal list contains a resource ARN and a condition statement. The condition
+ statement can be null."""
+ resource_arn = APIGatewayRouteArn(
+ region=self.region,
+ aws_account_id=self.aws_account_id,
+ api_id=self.api_id,
+ stage=self.stage,
+ http_method=None,
+ resource=resource,
+ partition=self.partition,
+ is_websocket_authorizer=True,
+ ).arn
+
+ route = {"resourceArn": resource_arn, "conditions": conditions}
+
+ if effect.lower() == "allow":
+ self._allow_routes.append(route)
+ else: # deny
+ self._deny_routes.append(route)
+
+ @override
+ def allow_all_routes(self):
+ """Adds a '*' allow to the policy to authorize access to all methods of an API"""
+ self._add_route(effect="Allow", resource="*")
+
+ @override
+ def deny_all_routes(self):
+ """Adds a '*' allow to the policy to deny access to all methods of an API"""
+
+ self._add_route(effect="Deny", resource="*")
+
+ # Note: we need ignore[override] because we are removing the http_method field
+ @override
+ def allow_route(self, resource: str, conditions: list[dict] | None = None): # type: ignore[override]
+ """
+ Add an API Gateway Websocket method to the list of allowed methods for the policy.
+
+ This method adds an API Gateway Websocket method Resource path) to the list of
+ allowed methods for the policy. It optionally includes conditions for the policy statement.
+
+ Parameters
+ ----------
+ resource : str
+ The API Gateway resource path to allow.
+ conditions : list[dict] | None, optional
+ A list of condition dictionaries to apply to the policy statement.
+ Default is None.
+
+ Notes
+ -----
+ For more information on AWS policy conditions, see:
+ https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html#Condition
+
+ Example
+ --------
+ >>> policy = APIGatewayAuthorizerResponseWebSocket(...)
+ >>> policy.allow_route("/api/users", [{"StringEquals": {"aws:RequestTag/Environment": "Production"}}])
+ """
+ self._add_route(effect="Allow", resource=resource, conditions=conditions)
+
+ # Note: we need ignore[override] because we are removing the http_method field
+ @override
+ def deny_route(self, resource: str, conditions: list[dict] | None = None): # type: ignore[override]
+ """
+ Add an API Gateway Websocket method to the list of allowed methods for the policy.
+
+ This method adds an API Gateway Websocket method Resource path) to the list of
+ denied methods for the policy. It optionally includes conditions for the policy statement.
+
+ Parameters
+ ----------
+ resource : str
+ The API Gateway resource path to allow.
+ conditions : list[dict] | None, optional
+ A list of condition dictionaries to apply to the policy statement.
+ Default is None.
+
+ Notes
+ -----
+ For more information on AWS policy conditions, see:
+ https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html#Condition
+
+ Example
+ --------
+ >>> policy = APIGatewayAuthorizerResponseWebSocket(...)
+ >>> policy.deny_route("/api/users", [{"StringEquals": {"aws:RequestTag/Environment": "Production"}}])
+ """
+ self._add_route(effect="Deny", resource=resource, conditions=conditions)
diff --git a/aws_lambda_powertools/utilities/data_classes/common.py b/aws_lambda_powertools/utilities/data_classes/common.py
index ec4335b9ee8..8374bf5ee08 100644
--- a/aws_lambda_powertools/utilities/data_classes/common.py
+++ b/aws_lambda_powertools/utilities/data_classes/common.py
@@ -1,3 +1,9 @@
+"""
+Base class for Event Source Data Classes
+!!! abstract "Usage Documentation"
+ [`Data classes`](../utilities/data_classes.md)
+"""
+
from __future__ import annotations
import base64
diff --git a/aws_lambda_powertools/utilities/data_masking/base.py b/aws_lambda_powertools/utilities/data_masking/base.py
index 9b80e50bd58..c5fd6f274e7 100644
--- a/aws_lambda_powertools/utilities/data_masking/base.py
+++ b/aws_lambda_powertools/utilities/data_masking/base.py
@@ -1,9 +1,16 @@
+"""
+Base class for Data Masking
+!!! abstract "Usage Documentation"
+ [`Data masking`](../../utilities/data_masking.md)
+"""
+
from __future__ import annotations
import functools
import logging
import warnings
-from typing import TYPE_CHECKING, Any, Callable, Mapping, Sequence, overload
+from copy import deepcopy
+from typing import TYPE_CHECKING, Any, Callable, Mapping, Sequence
from jsonpath_ng.ext import parse
@@ -12,6 +19,7 @@
DataMaskingUnsupportedTypeError,
)
from aws_lambda_powertools.utilities.data_masking.provider import BaseProvider
+from aws_lambda_powertools.warnings import PowertoolsUserWarning
if TYPE_CHECKING:
from numbers import Number
@@ -24,8 +32,9 @@ class DataMasking:
The DataMasking class orchestrates erasing, encrypting, and decrypting
for the base provider.
- Example:
- ```
+ Example
+ -------
+ ```python
from aws_lambda_powertools.utilities.data_masking.base import DataMasking
def lambda_handler(event, context):
@@ -60,11 +69,39 @@ def encrypt(
provider_options: dict | None = None,
**encryption_context: str,
) -> str:
+ """
+ Encrypt data using the configured encryption provider.
+
+ Parameters
+ ----------
+ data : dict, Mapping, Sequence, or Number
+ The data to encrypt.
+ provider_options : dict, optional
+ Provider-specific options for encryption.
+ **encryption_context : str
+ Additional key-value pairs for encryption context.
+
+ Returns
+ -------
+ str
+ The encrypted data as a base64-encoded string.
+
+ Example
+ --------
+
+ encryption_provider = AWSEncryptionSDKProvider(keys=[KMS_KEY_ARN])
+ data_masker = DataMasking(provider=encryption_provider)
+ encrypted = data_masker.encrypt({"secret": "value"})
+ """
return self._apply_action(
data=data,
fields=None,
action=self.provider.encrypt,
provider_options=provider_options or {},
+ dynamic_mask=None,
+ custom_mask=None,
+ regex_pattern=None,
+ mask_format=None,
**encryption_context,
)
@@ -74,28 +111,91 @@ def decrypt(
provider_options: dict | None = None,
**encryption_context: str,
) -> Any:
+ """
+ Decrypt data using the configured encryption provider.
+
+ Parameters
+ ----------
+ data : dict, Mapping, Sequence, or Number
+ The data to encrypt.
+ provider_options : dict, optional
+ Provider-specific options for encryption.
+ **encryption_context : str
+ Additional key-value pairs for encryption context.
+
+ Returns
+ -------
+ str
+ The encrypted data as a base64-encoded string.
+
+ Example
+ --------
+
+ encryption_provider = AWSEncryptionSDKProvider(keys=[KMS_KEY_ARN])
+ data_masker = DataMasking(provider=encryption_provider)
+ encrypted = data_masker.decrypt(encrypted_data)
+ """
+
return self._apply_action(
data=data,
fields=None,
action=self.provider.decrypt,
provider_options=provider_options or {},
+ dynamic_mask=None,
+ custom_mask=None,
+ regex_pattern=None,
+ mask_format=None,
**encryption_context,
)
- @overload
- def erase(self, data, fields: None) -> str: ...
-
- @overload
- def erase(self, data: list, fields: list[str]) -> list[str]: ...
-
- @overload
- def erase(self, data: tuple, fields: list[str]) -> tuple[str]: ...
+ def erase(
+ self,
+ data: Any,
+ fields: list[str] | None = None,
+ *,
+ dynamic_mask: bool | None = None,
+ custom_mask: str | None = None,
+ regex_pattern: str | None = None,
+ mask_format: str | None = None,
+ masking_rules: dict | None = None,
+ ) -> Any:
+ """
+ Erase or mask sensitive data in the input.
- @overload
- def erase(self, data: dict, fields: list[str]) -> dict: ...
+ Parameters
+ ----------
+ data : Any
+ The data to be erased or masked.
+ fields : list of str, optional
+ List of field names to be erased or masked.
+ dynamic_mask : bool, optional
+ Whether to use dynamic masking.
+ custom_mask : str, optional
+ Custom mask to apply instead of the default.
+ regex_pattern : str, optional
+ Regular expression pattern for identifying data to mask.
+ mask_format : str, optional
+ Format string for the mask.
+ masking_rules : dict, optional
+ Dictionary of custom masking rules.
- def erase(self, data: Sequence | Mapping, fields: list[str] | None = None) -> str | list[str] | tuple[str] | dict:
- return self._apply_action(data=data, fields=fields, action=self.provider.erase)
+ Returns
+ -------
+ Any
+ The data with sensitive information erased or masked.
+ """
+ if masking_rules:
+ return self._apply_masking_rules(data=data, masking_rules=masking_rules)
+ else:
+ return self._apply_action(
+ data=data,
+ fields=fields,
+ action=self.provider.erase,
+ dynamic_mask=dynamic_mask,
+ custom_mask=custom_mask,
+ regex_pattern=regex_pattern,
+ mask_format=mask_format,
+ )
def _apply_action(
self,
@@ -103,8 +203,12 @@ def _apply_action(
fields: list[str] | None,
action: Callable,
provider_options: dict | None = None,
- **encryption_context: str,
- ):
+ dynamic_mask: bool | None = None,
+ custom_mask: str | None = None,
+ regex_pattern: str | None = None,
+ mask_format: str | None = None,
+ **kwargs: Any,
+ ) -> Any:
"""
Helper method to determine whether to apply a given action to the entire input data
or to specific fields if the 'fields' argument is specified.
@@ -120,8 +224,6 @@ def _apply_action(
and returns the modified value.
provider_options : dict
Provider specific keyword arguments to propagate; used as an escape hatch.
- encryption_context: str
- Encryption context to use in encrypt and decrypt operations.
Returns
-------
@@ -136,11 +238,23 @@ def _apply_action(
fields=fields,
action=action,
provider_options=provider_options,
- **encryption_context,
+ dynamic_mask=dynamic_mask,
+ custom_mask=custom_mask,
+ regex_pattern=regex_pattern,
+ mask_format=mask_format,
+ **kwargs,
)
else:
logger.debug(f"Running action {action.__name__} with the entire data")
- return action(data=data, provider_options=provider_options, **encryption_context)
+ return action(
+ data=data,
+ provider_options=provider_options,
+ dynamic_mask=dynamic_mask,
+ custom_mask=custom_mask,
+ regex_pattern=regex_pattern,
+ mask_format=mask_format,
+ **kwargs,
+ )
def _apply_action_to_fields(
self,
@@ -148,6 +262,10 @@ def _apply_action_to_fields(
fields: list,
action: Callable,
provider_options: dict | None = None,
+ dynamic_mask: bool | None = None,
+ custom_mask: str | None = None,
+ regex_pattern: str | None = None,
+ mask_format: str | None = None,
**encryption_context: str,
) -> dict | str:
"""
@@ -194,8 +312,10 @@ def _apply_action_to_fields(
new_dict = {'a': {'b': {'c': '*****'}}, 'x': {'y': '*****'}}
```
"""
+ if not fields:
+ raise ValueError("Fields parameter cannot be empty")
- data_parsed: dict = self._normalize_data_to_parse(fields, data)
+ data_parsed: dict = self._normalize_data_to_parse(data)
# For in-place updates, json_parse accepts a callback function
# this function must receive 3 args: field_value, fields, field_name
@@ -204,6 +324,10 @@ def _apply_action_to_fields(
self._call_action,
action=action,
provider_options=provider_options,
+ dynamic_mask=dynamic_mask,
+ custom_mask=custom_mask,
+ regex_pattern=regex_pattern,
+ mask_format=mask_format,
**encryption_context, # type: ignore[arg-type]
)
@@ -225,12 +349,6 @@ def _apply_action_to_fields(
# For in-place updates, json_parse accepts a callback function
# that receives 3 args: field_value, fields, field_name
# We create a partial callback to pre-populate known provider options (action, provider opts, enc ctx)
- update_callback = functools.partial(
- self._call_action,
- action=action,
- provider_options=provider_options,
- **encryption_context, # type: ignore[arg-type]
- )
json_parse.update(
data_parsed,
@@ -239,6 +357,59 @@ def _apply_action_to_fields(
return data_parsed
+ def _apply_masking_rules(self, data: dict, masking_rules: dict) -> dict:
+ """
+ Apply masking rules to data, supporting both simple field names and complex path expressions.
+
+ Args:
+ data: The dictionary containing data to mask
+ masking_rules: Dictionary mapping field names or path expressions to masking rules
+
+ Returns:
+ dict: The masked data dictionary
+ """
+ result = deepcopy(data)
+
+ for path, rule in masking_rules.items():
+ try:
+ jsonpath_expr = parse(f"$.{path}")
+ matches = jsonpath_expr.find(result)
+
+ if not matches:
+ warnings.warn(f"No matches found for path: {path}", stacklevel=2)
+ continue
+
+ for match in matches:
+ try:
+ value = match.value
+ if value is not None:
+ masked_value = self.provider.erase(str(value), **rule)
+ match.full_path.update(result, masked_value)
+
+ except Exception as e:
+ warnings.warn(
+ f"Error masking value for path {path}: {str(e)}",
+ category=PowertoolsUserWarning,
+ stacklevel=2,
+ )
+ continue
+
+ except Exception as e:
+ warnings.warn(f"Error processing path {path}: {str(e)}", category=PowertoolsUserWarning, stacklevel=2)
+ continue
+
+ return result
+
+ def _mask_nested_field(self, data: dict, field_path: str, mask_function):
+ keys = field_path.split(".")
+ current = data
+ for key in keys[:-1]:
+ current = current.get(key, {})
+ if not isinstance(current, dict):
+ return
+ if keys[-1] in current:
+ current[keys[-1]] = self.provider.erase(current[keys[-1]], **mask_function)
+
@staticmethod
def _call_action(
field_value: Any,
@@ -246,6 +417,10 @@ def _call_action(
field_name: str,
action: Callable,
provider_options: dict[str, Any] | None = None,
+ dynamic_mask: bool | None = None,
+ custom_mask: str | None = None,
+ regex_pattern: str | None = None,
+ mask_format: str | None = None,
**encryption_context,
) -> None:
"""
@@ -263,13 +438,18 @@ def _call_action(
Returns:
- fields[field_name]: Returns the processed field value
"""
- fields[field_name] = action(field_value, provider_options=provider_options, **encryption_context)
+ fields[field_name] = action(
+ field_value,
+ provider_options=provider_options,
+ dynamic_mask=dynamic_mask,
+ custom_mask=custom_mask,
+ regex_pattern=regex_pattern,
+ mask_format=mask_format,
+ **encryption_context,
+ )
return fields[field_name]
- def _normalize_data_to_parse(self, fields: list, data: str | dict) -> dict:
- if not fields:
- raise ValueError("No fields specified.")
-
+ def _normalize_data_to_parse(self, data: str | dict) -> dict:
if isinstance(data, str):
# Parse JSON string as dictionary
data_parsed = self.json_deserializer(data)
diff --git a/aws_lambda_powertools/utilities/data_masking/provider/base.py b/aws_lambda_powertools/utilities/data_masking/provider/base.py
index 28bc8384f8d..16fa22d16b8 100644
--- a/aws_lambda_powertools/utilities/data_masking/provider/base.py
+++ b/aws_lambda_powertools/utilities/data_masking/provider/base.py
@@ -2,18 +2,22 @@
import functools
import json
-from typing import Any, Callable, Iterable
+import re
+from typing import Any, Callable
from aws_lambda_powertools.utilities.data_masking.constants import DATA_MASKING_STRING
+PRESERVE_CHARS = set("-_. ")
+_regex_cache = {}
+
class BaseProvider:
"""
The BaseProvider class serves as an abstract base class for data masking providers.
- Examples
+ Example
--------
- ```
+ ```python
from aws_lambda_powertools.utilities._data_masking.provider import BaseProvider
from aws_lambda_powertools.utilities.data_masking import DataMasking
@@ -24,7 +28,7 @@ def encrypt(self, data) -> str:
def decrypt(self, data) -> Any:
# Implementation logic for data decryption
- def erase(self, data) -> str | Iterable:
+ def erase(self, data) -> Any | Iterable:
# Implementation logic for data masking
pass
@@ -63,19 +67,123 @@ def decrypt(self, data, provider_options: dict | None = None, **encryption_conte
"""
raise NotImplementedError("Subclasses must implement decrypt()")
- def erase(self, data, **kwargs) -> Iterable[str]:
- """
- This method irreversibly erases data.
-
- If the data to be erased is of type `str`, `dict`, or `bytes`,
- this method will return an erased string, i.e. "*****".
-
- If the data to be erased is of an iterable type like `list`, `tuple`,
- or `set`, this method will return a new object of the same type as the
- input data but with each element replaced by the string "*****".
- """
- if isinstance(data, (str, dict, bytes)):
- return DATA_MASKING_STRING
+ def erase(
+ self,
+ data: Any,
+ dynamic_mask: bool | None = None,
+ custom_mask: str | None = None,
+ regex_pattern: str | None = None,
+ mask_format: str | None = None,
+ masking_rules: dict | None = None,
+ **kwargs,
+ ) -> Any:
+
+ result: Any = DATA_MASKING_STRING
+
+ if not any([dynamic_mask, custom_mask, regex_pattern, mask_format, masking_rules]):
+ if isinstance(data, (str, int, float, dict, bytes)):
+ return DATA_MASKING_STRING
+ elif isinstance(data, (list, tuple, set)):
+ return type(data)([DATA_MASKING_STRING] * len(data))
+ else:
+ return DATA_MASKING_STRING
+
+ if isinstance(data, (str, int, float)):
+ result = self._mask_primitive(str(data), dynamic_mask, custom_mask, regex_pattern, mask_format)
+ elif isinstance(data, dict):
+ result = self._mask_dict(
+ data,
+ dynamic_mask,
+ custom_mask,
+ regex_pattern,
+ mask_format,
+ masking_rules,
+ )
elif isinstance(data, (list, tuple, set)):
- return type(data)([DATA_MASKING_STRING] * len(data))
- return DATA_MASKING_STRING
+ result = self._mask_iterable(
+ data,
+ dynamic_mask,
+ custom_mask,
+ regex_pattern,
+ mask_format,
+ masking_rules,
+ )
+
+ return result
+
+ def _mask_primitive(
+ self,
+ data: str,
+ dynamic_mask: bool | None,
+ custom_mask: str | None,
+ regex_pattern: str | None,
+ mask_format: str | None,
+ ) -> str:
+ if regex_pattern and mask_format:
+ return self._regex_mask(data, regex_pattern, mask_format)
+ elif custom_mask:
+ return self._pattern_mask(data, custom_mask)
+
+ return self._custom_erase(data)
+
+ def _mask_dict(
+ self,
+ data: dict,
+ dynamic_mask: bool | None,
+ custom_mask: str | None,
+ regex_pattern: str | None,
+ mask_format: str | None,
+ masking_rules: dict | None,
+ ) -> dict:
+ return {
+ k: self.erase(
+ v,
+ dynamic_mask=dynamic_mask,
+ custom_mask=custom_mask,
+ regex_pattern=regex_pattern,
+ mask_format=mask_format,
+ masking_rules=masking_rules,
+ )
+ for k, v in data.items()
+ }
+
+ def _mask_iterable(
+ self,
+ data: list | tuple | set,
+ dynamic_mask: bool | None,
+ custom_mask: str | None,
+ regex_pattern: str | None,
+ mask_format: str | None,
+ masking_rules: dict | None,
+ ) -> list | tuple | set:
+ masked_data = [
+ self.erase(
+ item,
+ dynamic_mask=dynamic_mask,
+ custom_mask=custom_mask,
+ regex_pattern=regex_pattern,
+ mask_format=mask_format,
+ masking_rules=masking_rules,
+ )
+ for item in data
+ ]
+ return type(data)(masked_data)
+
+ def _pattern_mask(self, data: str, pattern: str) -> str:
+ """Apply pattern masking to string data."""
+ return pattern[: len(data)] if len(pattern) >= len(data) else pattern
+
+ def _regex_mask(self, data: str, regex_pattern: str, mask_format: str) -> str:
+ """Apply regex masking to string data."""
+ try:
+ if regex_pattern not in _regex_cache:
+ _regex_cache[regex_pattern] = re.compile(regex_pattern)
+ return _regex_cache[regex_pattern].sub(mask_format, data)
+ except re.error:
+ return data
+
+ def _custom_erase(self, data: str) -> str:
+ if not data:
+ return ""
+
+ return "".join("*" if char not in PRESERVE_CHARS else char for char in data)
diff --git a/aws_lambda_powertools/utilities/data_masking/provider/kms/aws_encryption_sdk.py b/aws_lambda_powertools/utilities/data_masking/provider/kms/aws_encryption_sdk.py
index 497b67c6edd..07d48efe569 100644
--- a/aws_lambda_powertools/utilities/data_masking/provider/kms/aws_encryption_sdk.py
+++ b/aws_lambda_powertools/utilities/data_masking/provider/kms/aws_encryption_sdk.py
@@ -48,9 +48,9 @@ class AWSEncryptionSDKProvider(BaseProvider):
"""
The AWSEncryptionSDKProvider is used as a provider for the DataMasking class.
- Usage
+ Example
-------
- ```
+ ```python
from aws_lambda_powertools.utilities.data_masking import DataMasking
from aws_lambda_powertools.utilities.data_masking.providers.kms.aws_encryption_sdk import (
AWSEncryptionSDKProvider,
@@ -142,17 +142,17 @@ def encrypt(self, data: Any, provider_options: dict | None = None, **encryption_
Parameters
-------
- data : Any
- The data to be encrypted.
- provider_options : dict
- Additional options for the aws_encryption_sdk.EncryptionSDKClient
- **encryption_context : str
- Additional keyword arguments collected into a dictionary.
+ data: Any
+ The data to be encrypted.
+ provider_options: dict
+ Additional options for the aws_encryption_sdk.EncryptionSDKClient
+ **encryption_context: str
+ Additional keyword arguments collected into a dictionary.
Returns
-------
- ciphertext : str
- The encrypted data, as a base64-encoded string.
+ ciphertext: str
+ The encrypted data, as a base64-encoded string.
"""
provider_options = provider_options or {}
self._validate_encryption_context(encryption_context)
@@ -179,15 +179,15 @@ def decrypt(self, data: str, provider_options: dict | None = None, **encryption_
Parameters
-------
- data : str
- The encrypted data, as a base64-encoded string
- provider_options
- Additional options for the aws_encryption_sdk.EncryptionSDKClient
+ data: str
+ The encrypted data, as a base64-encoded string
+ provider_options
+ Additional options for the aws_encryption_sdk.EncryptionSDKClient
Returns
-------
- ciphertext : bytes
- The decrypted data in bytes
+ ciphertext: bytes
+ The decrypted data in bytes
"""
provider_options = provider_options or {}
self._validate_encryption_context(encryption_context)
diff --git a/aws_lambda_powertools/utilities/feature_flags/appconfig.py b/aws_lambda_powertools/utilities/feature_flags/appconfig.py
index 794530eee47..2becf16d0fd 100644
--- a/aws_lambda_powertools/utilities/feature_flags/appconfig.py
+++ b/aws_lambda_powertools/utilities/feature_flags/appconfig.py
@@ -1,3 +1,8 @@
+"""Advanced feature flags utility
+!!! abstract "Usage Documentation"
+ [`Feature Flags`](../../utilities/feature_flags.md)
+"""
+
from __future__ import annotations
import logging
diff --git a/aws_lambda_powertools/utilities/feature_flags/base.py b/aws_lambda_powertools/utilities/feature_flags/base.py
index cd2d65fa211..03394f8ced3 100644
--- a/aws_lambda_powertools/utilities/feature_flags/base.py
+++ b/aws_lambda_powertools/utilities/feature_flags/base.py
@@ -28,7 +28,8 @@ def get_configuration(self) -> dict[str, Any]:
dict[str, Any]
parsed JSON dictionary
- **Example**
+ Example
+ -------
```python
{
diff --git a/aws_lambda_powertools/utilities/feature_flags/comparators.py b/aws_lambda_powertools/utilities/feature_flags/comparators.py
index 47354f26e73..0d836d19b11 100644
--- a/aws_lambda_powertools/utilities/feature_flags/comparators.py
+++ b/aws_lambda_powertools/utilities/feature_flags/comparators.py
@@ -56,6 +56,8 @@ def compare_time_range(context_value: Any, condition_value: dict) -> bool:
end_time = current_time.replace(hour=int(end_hour), minute=int(end_min))
if int(end_hour) < int(start_hour):
+ # In normal circumstances, we need to assert **both** conditions
+ """
# When the end hour is smaller than start hour, it means we are crossing a day's boundary.
# In this case we need to assert that current_time is **either** on one side or the other side of the boundary
#
@@ -69,10 +71,9 @@ def compare_time_range(context_value: Any, condition_value: dict) -> bool:
# │ │ │
# └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
# │
-
+ """
return (start_time <= current_time) or (current_time <= end_time)
else:
- # In normal circumstances, we need to assert **both** conditions
return start_time <= current_time <= end_time
diff --git a/aws_lambda_powertools/utilities/feature_flags/feature_flags.py b/aws_lambda_powertools/utilities/feature_flags/feature_flags.py
index ae0cae6d31c..6fb8d51753a 100644
--- a/aws_lambda_powertools/utilities/feature_flags/feature_flags.py
+++ b/aws_lambda_powertools/utilities/feature_flags/feature_flags.py
@@ -179,7 +179,8 @@ def get_configuration(self) -> dict:
dict[str, dict]
parsed JSON dictionary
- **Example**
+ Example
+ -------
```python
{
@@ -251,7 +252,7 @@ def evaluate(self, *, name: str, context: dict[str, Any] | None = None, default:
Can be boolean or any JSON values for non-boolean features.
- Examples
+ Example
--------
```python
@@ -343,7 +344,8 @@ def get_enabled_features(self, *, context: dict[str, Any] | None = None) -> list
list[str]
list of all feature names that either matches context or have True as default
- **Example**
+ Example
+ -------
```python
["premium_features", "my_feature_two", "always_true_feature"]
@@ -400,8 +402,8 @@ def validation_exception_handler(self, exc_class: Exception | list[Exception]):
exc_class : Exception | list[Exception]
One or more exceptions to catch
- Examples
- --------
+ Example
+ -------
```python
feature_flags = FeatureFlags(store=app_config)
diff --git a/aws_lambda_powertools/utilities/idempotency/base.py b/aws_lambda_powertools/utilities/idempotency/base.py
index 0841fb7500f..eb4fe0eab5f 100644
--- a/aws_lambda_powertools/utilities/idempotency/base.py
+++ b/aws_lambda_powertools/utilities/idempotency/base.py
@@ -1,3 +1,9 @@
+"""
+Base for Idempotency utility
+!!! abstract "Usage Documentation"
+ [`Idempotency`](../../utilities/idempotency.md)
+"""
+
from __future__ import annotations
import datetime
diff --git a/aws_lambda_powertools/utilities/idempotency/idempotency.py b/aws_lambda_powertools/utilities/idempotency/idempotency.py
index 1305d0a5405..6aec2572fb1 100644
--- a/aws_lambda_powertools/utilities/idempotency/idempotency.py
+++ b/aws_lambda_powertools/utilities/idempotency/idempotency.py
@@ -61,20 +61,20 @@ def idempotent(
key_prefix: str | Optional
Custom prefix for idempotency key: key_prefix#hash
- Examples
+ Example
--------
**Processes Lambda's event in an idempotent manner**
- >>> from aws_lambda_powertools.utilities.idempotency import (
- >>> idempotent, DynamoDBPersistenceLayer, IdempotencyConfig
- >>> )
- >>>
- >>> idem_config=IdempotencyConfig(event_key_jmespath="body")
- >>> persistence_layer = DynamoDBPersistenceLayer(table_name="idempotency_store")
- >>>
- >>> @idempotent(config=idem_config, persistence_store=persistence_layer)
- >>> def handler(event, context):
- >>> return {"StatusCode": 200}
+ from aws_lambda_powertools.utilities.idempotency import (
+ idempotent, DynamoDBPersistenceLayer, IdempotencyConfig
+ )
+
+ idem_config=IdempotencyConfig(event_key_jmespath="body")
+ persistence_layer = DynamoDBPersistenceLayer(table_name="idempotency_store")
+
+ @idempotent(config=idem_config, persistence_store=persistence_layer)
+ def handler(event, context):
+ return {"StatusCode": 200}
"""
# Skip idempotency controls when POWERTOOLS_IDEMPOTENCY_DISABLED has a truthy value
@@ -136,7 +136,7 @@ def idempotent_function(
key_prefix: str | Optional
Custom prefix for idempotency key: key_prefix#hash
- Examples
+ Example
--------
**Processes an order in an idempotent manner**
diff --git a/aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py b/aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py
index 23ef222b5c8..0b04ec135c7 100644
--- a/aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py
+++ b/aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py
@@ -76,7 +76,7 @@ def __init__(
boto3_client : DynamoDBClient, optional
Boto3 DynamoDB Client to use, boto3_session and boto_config will be ignored if both are provided
- Examples
+ Example
--------
**Create a DynamoDB persistence layer with custom settings**
diff --git a/aws_lambda_powertools/utilities/idempotency/persistence/redis.py b/aws_lambda_powertools/utilities/idempotency/persistence/redis.py
index 06a6548080b..7f27566cc24 100644
--- a/aws_lambda_powertools/utilities/idempotency/persistence/redis.py
+++ b/aws_lambda_powertools/utilities/idempotency/persistence/redis.py
@@ -112,7 +112,7 @@ def __init__(
ssl: bool, optional: default True
set whether to use ssl for Redis connection
- Examples
+ Example
--------
```python
diff --git a/aws_lambda_powertools/utilities/jmespath_utils/__init__.py b/aws_lambda_powertools/utilities/jmespath_utils/__init__.py
index 1bdff7a12ce..c35f9b610cf 100644
--- a/aws_lambda_powertools/utilities/jmespath_utils/__init__.py
+++ b/aws_lambda_powertools/utilities/jmespath_utils/__init__.py
@@ -1,3 +1,9 @@
+"""
+Built-in JMESPath Functions to easily deserialize common encoded JSON payloads in Lambda functions.
+!!! abstract "Usage Documentation"
+ [`JMESPath Functions`](../utilities/jmespath_functions.md)
+"""
+
from __future__ import annotations
import base64
@@ -42,7 +48,7 @@ def query(data: dict | str, envelope: str, jmespath_options: dict | None = None)
Built-in JMESPath functions include: powertools_json, powertools_base64, powertools_base64_gzip
- Examples
+ Example
--------
**Deserialize JSON string and extracts data from body key**
diff --git a/aws_lambda_powertools/utilities/parameters/base.py b/aws_lambda_powertools/utilities/parameters/base.py
index 897cd4ace57..610530f3263 100644
--- a/aws_lambda_powertools/utilities/parameters/base.py
+++ b/aws_lambda_powertools/utilities/parameters/base.py
@@ -1,5 +1,7 @@
"""
Base for Parameter providers
+!!! abstract "Usage Documentation"
+ [`Parameters`](../../utilities/parameters.md)
"""
from __future__ import annotations
diff --git a/aws_lambda_powertools/utilities/parser/__init__.py b/aws_lambda_powertools/utilities/parser/__init__.py
index 29127a3035b..e4e08b790b8 100644
--- a/aws_lambda_powertools/utilities/parser/__init__.py
+++ b/aws_lambda_powertools/utilities/parser/__init__.py
@@ -1,5 +1,4 @@
-"""Advanced event_parser utility
-"""
+"""Advanced event_parser utility"""
from pydantic import BaseModel, Field, ValidationError, field_validator, model_validator
diff --git a/aws_lambda_powertools/utilities/parser/parser.py b/aws_lambda_powertools/utilities/parser/parser.py
index 4f6115255a8..446209880fd 100644
--- a/aws_lambda_powertools/utilities/parser/parser.py
+++ b/aws_lambda_powertools/utilities/parser/parser.py
@@ -1,3 +1,10 @@
+"""
+The Parser utility simplifies data parsing and validation using Pydantic. It allows you to define data models
+in pure Python classes, parse and validate incoming events, and extract only the data you need.
+!!! abstract "Usage Documentation"
+ [`Parser`](../utilities/parser.md)
+"""
+
from __future__ import annotations
import logging
diff --git a/aws_lambda_powertools/utilities/streaming/__init__.py b/aws_lambda_powertools/utilities/streaming/__init__.py
index 8c326b99400..c709a2e3166 100644
--- a/aws_lambda_powertools/utilities/streaming/__init__.py
+++ b/aws_lambda_powertools/utilities/streaming/__init__.py
@@ -1,3 +1,9 @@
+"""
+The streaming utility handles datasets larger than the available memory as streaming data.
+!!! abstract "Usage Documentation"
+ [`Streaming`](../utilities/streaming.md)
+"""
+
from aws_lambda_powertools.utilities.streaming.s3_object import S3Object
__all__ = ["S3Object"]
diff --git a/aws_lambda_powertools/utilities/typing/__init__.py b/aws_lambda_powertools/utilities/typing/__init__.py
index a6c80395a88..22f907025fc 100644
--- a/aws_lambda_powertools/utilities/typing/__init__.py
+++ b/aws_lambda_powertools/utilities/typing/__init__.py
@@ -1,5 +1,7 @@
"""
Typing for developer ease in the IDE
+!!! abstract "Usage Documentation"
+ [`Typing`](../utilities/typing.md)
"""
from .lambda_context import LambdaContext
diff --git a/aws_lambda_powertools/utilities/validation/__init__.py b/aws_lambda_powertools/utilities/validation/__init__.py
index 45d076ff207..d19581a1258 100644
--- a/aws_lambda_powertools/utilities/validation/__init__.py
+++ b/aws_lambda_powertools/utilities/validation/__init__.py
@@ -1,5 +1,7 @@
"""
Simple validator to enforce incoming/outgoing event conforms with JSON Schema
+!!! abstract "Usage Documentation"
+ [`Validation`](../utilities/validation.md)
"""
from .exceptions import (
diff --git a/aws_lambda_powertools/utilities/validation/exceptions.py b/aws_lambda_powertools/utilities/validation/exceptions.py
index 9a1c3de22a3..8f8f77df64f 100644
--- a/aws_lambda_powertools/utilities/validation/exceptions.py
+++ b/aws_lambda_powertools/utilities/validation/exceptions.py
@@ -19,7 +19,7 @@ def __init__(
rule: str | None = None,
rule_definition: Any | None = None,
):
- """
+ """When serialization fail schema validation
Parameters
----------
diff --git a/docs/Dockerfile b/docs/Dockerfile
index 2da27006b13..46941467a98 100644
--- a/docs/Dockerfile
+++ b/docs/Dockerfile
@@ -1,5 +1,5 @@
# v9.1.18
-FROM squidfunk/mkdocs-material@sha256:41942f7a2f5163aacd0e866e076d95db4f26550b97d76c1594c04250cbb580e9
+FROM squidfunk/mkdocs-material@sha256:c62453b1ba229982c6325a71165c1a3007c11bd3dd470e7a1446c5783bd145b4
# pip-compile --generate-hashes --output-file=requirements.txt requirements.in
COPY requirements.txt /tmp/
RUN pip install --require-hashes -r /tmp/requirements.txt
diff --git a/docs/api_doc/batch/base.md b/docs/api_doc/batch/base.md
new file mode 100644
index 00000000000..adec8fb2b8e
--- /dev/null
+++ b/docs/api_doc/batch/base.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.batch.base
diff --git a/docs/api_doc/batch/decorators.md b/docs/api_doc/batch/decorators.md
new file mode 100644
index 00000000000..739f8475c05
--- /dev/null
+++ b/docs/api_doc/batch/decorators.md
@@ -0,0 +1,3 @@
+
+::: aws_lambda_powertools.utilities.batch.decorators
+::: aws_lambda_powertools.utilities.batch.sqs_fifo_partial_processor
diff --git a/docs/api_doc/batch/exceptions.md b/docs/api_doc/batch/exceptions.md
new file mode 100644
index 00000000000..a77226fb0d9
--- /dev/null
+++ b/docs/api_doc/batch/exceptions.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.batch.exceptions
diff --git a/docs/api_doc/data_classes.md b/docs/api_doc/data_classes.md
new file mode 100644
index 00000000000..47090024306
--- /dev/null
+++ b/docs/api_doc/data_classes.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.data_classes.common
diff --git a/docs/api_doc/data_masking/base.md b/docs/api_doc/data_masking/base.md
new file mode 100644
index 00000000000..f53f55f4c39
--- /dev/null
+++ b/docs/api_doc/data_masking/base.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.data_masking.base
diff --git a/docs/api_doc/data_masking/exceptions.md b/docs/api_doc/data_masking/exceptions.md
new file mode 100644
index 00000000000..7c640463e64
--- /dev/null
+++ b/docs/api_doc/data_masking/exceptions.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.data_masking.exceptions
diff --git a/docs/api_doc/data_masking/provider.md b/docs/api_doc/data_masking/provider.md
new file mode 100644
index 00000000000..406c360c495
--- /dev/null
+++ b/docs/api_doc/data_masking/provider.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.data_masking.provider
diff --git a/docs/api_doc/event_handler/api_gateway.md b/docs/api_doc/event_handler/api_gateway.md
new file mode 100644
index 00000000000..2d30a6c38c7
--- /dev/null
+++ b/docs/api_doc/event_handler/api_gateway.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.event_handler.api_gateway
diff --git a/docs/api_doc/event_handler/appsync.md b/docs/api_doc/event_handler/appsync.md
new file mode 100644
index 00000000000..dd1ec4c12bb
--- /dev/null
+++ b/docs/api_doc/event_handler/appsync.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.event_handler.appsync
diff --git a/docs/api_doc/event_handler/middleware.md b/docs/api_doc/event_handler/middleware.md
new file mode 100644
index 00000000000..cd1fed521f2
--- /dev/null
+++ b/docs/api_doc/event_handler/middleware.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.event_handler.middlewares
diff --git a/docs/api_doc/event_handler/openapi.md b/docs/api_doc/event_handler/openapi.md
new file mode 100644
index 00000000000..02c64c429f1
--- /dev/null
+++ b/docs/api_doc/event_handler/openapi.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.event_handler.openapi
diff --git a/docs/api_doc/feature_flags/appconfig.md b/docs/api_doc/feature_flags/appconfig.md
new file mode 100644
index 00000000000..fad198ef15c
--- /dev/null
+++ b/docs/api_doc/feature_flags/appconfig.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.feature_flags.appconfig
diff --git a/docs/api_doc/feature_flags/base.md b/docs/api_doc/feature_flags/base.md
new file mode 100644
index 00000000000..aef629bac52
--- /dev/null
+++ b/docs/api_doc/feature_flags/base.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.feature_flags.base
diff --git a/docs/api_doc/feature_flags/comparators.md b/docs/api_doc/feature_flags/comparators.md
new file mode 100644
index 00000000000..0286336529e
--- /dev/null
+++ b/docs/api_doc/feature_flags/comparators.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.feature_flags.comparators
diff --git a/docs/api_doc/feature_flags/exceptions.md b/docs/api_doc/feature_flags/exceptions.md
new file mode 100644
index 00000000000..ad9d20a7731
--- /dev/null
+++ b/docs/api_doc/feature_flags/exceptions.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.feature_flags.exceptions
diff --git a/docs/api_doc/feature_flags/feature_flags.md b/docs/api_doc/feature_flags/feature_flags.md
new file mode 100644
index 00000000000..dacffe23460
--- /dev/null
+++ b/docs/api_doc/feature_flags/feature_flags.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.feature_flags.feature_flags
diff --git a/docs/api_doc/feature_flags/schema.md b/docs/api_doc/feature_flags/schema.md
new file mode 100644
index 00000000000..7998f31f4f2
--- /dev/null
+++ b/docs/api_doc/feature_flags/schema.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.feature_flags.schema
diff --git a/docs/api_doc/idempotency/base.md b/docs/api_doc/idempotency/base.md
new file mode 100644
index 00000000000..f93ab9e82f6
--- /dev/null
+++ b/docs/api_doc/idempotency/base.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.idempotency.base
diff --git a/docs/api_doc/idempotency/config.md b/docs/api_doc/idempotency/config.md
new file mode 100644
index 00000000000..2c3ca67eb83
--- /dev/null
+++ b/docs/api_doc/idempotency/config.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.idempotency.config
diff --git a/docs/api_doc/idempotency/exceptions.md b/docs/api_doc/idempotency/exceptions.md
new file mode 100644
index 00000000000..674b004ae24
--- /dev/null
+++ b/docs/api_doc/idempotency/exceptions.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.idempotency.exceptions
diff --git a/docs/api_doc/idempotency/persistence.md b/docs/api_doc/idempotency/persistence.md
new file mode 100644
index 00000000000..a18181c103b
--- /dev/null
+++ b/docs/api_doc/idempotency/persistence.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.idempotency.persistence
diff --git a/docs/api_doc/idempotency/serialization.md b/docs/api_doc/idempotency/serialization.md
new file mode 100644
index 00000000000..014c187151c
--- /dev/null
+++ b/docs/api_doc/idempotency/serialization.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.idempotency.serialization
diff --git a/docs/api_doc/jmespath_functions.md b/docs/api_doc/jmespath_functions.md
new file mode 100644
index 00000000000..c4e539faf13
--- /dev/null
+++ b/docs/api_doc/jmespath_functions.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.jmespath_utils
diff --git a/docs/api_doc/logger/datadog_formatter.md b/docs/api_doc/logger/datadog_formatter.md
new file mode 100644
index 00000000000..3d037d18214
--- /dev/null
+++ b/docs/api_doc/logger/datadog_formatter.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.logging.formatters.datadog
diff --git a/docs/api_doc/logger/exceptions.md b/docs/api_doc/logger/exceptions.md
new file mode 100644
index 00000000000..531a6bd8773
--- /dev/null
+++ b/docs/api_doc/logger/exceptions.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.logging.exceptions
diff --git a/docs/api_doc/logger/formatter.md b/docs/api_doc/logger/formatter.md
new file mode 100644
index 00000000000..064b6e4b546
--- /dev/null
+++ b/docs/api_doc/logger/formatter.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.logging.formatter
diff --git a/docs/api_doc/logger/lambda_context.md b/docs/api_doc/logger/lambda_context.md
new file mode 100644
index 00000000000..eec5841c6e4
--- /dev/null
+++ b/docs/api_doc/logger/lambda_context.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.logging.lambda_context
diff --git a/docs/api_doc/logger/logger.md b/docs/api_doc/logger/logger.md
new file mode 100644
index 00000000000..d688d106d75
--- /dev/null
+++ b/docs/api_doc/logger/logger.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.logging.logger
diff --git a/docs/api_doc/metrics/base.md b/docs/api_doc/metrics/base.md
new file mode 100644
index 00000000000..2fac9156233
--- /dev/null
+++ b/docs/api_doc/metrics/base.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.metrics.base
diff --git a/docs/api_doc/metrics/exceptions.md b/docs/api_doc/metrics/exceptions.md
new file mode 100644
index 00000000000..285a2654342
--- /dev/null
+++ b/docs/api_doc/metrics/exceptions.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.metrics.exceptions
diff --git a/docs/api_doc/metrics/metrics.md b/docs/api_doc/metrics/metrics.md
new file mode 100644
index 00000000000..ec268279335
--- /dev/null
+++ b/docs/api_doc/metrics/metrics.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.metrics.metrics
diff --git a/docs/api_doc/metrics/provider_datadog.md b/docs/api_doc/metrics/provider_datadog.md
new file mode 100644
index 00000000000..70836789d43
--- /dev/null
+++ b/docs/api_doc/metrics/provider_datadog.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.metrics.provider.datadog.datadog
diff --git a/docs/api_doc/metrics/provider_emf.md b/docs/api_doc/metrics/provider_emf.md
new file mode 100644
index 00000000000..610e2c83db0
--- /dev/null
+++ b/docs/api_doc/metrics/provider_emf.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.metrics.provider.cloudwatch_emf.cloudwatch
diff --git a/docs/api_doc/middleware_factory.md b/docs/api_doc/middleware_factory.md
new file mode 100644
index 00000000000..8d5f5221c11
--- /dev/null
+++ b/docs/api_doc/middleware_factory.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.middleware_factory
diff --git a/docs/api_doc/parameters/appconfig.md b/docs/api_doc/parameters/appconfig.md
new file mode 100644
index 00000000000..24e188b5bc1
--- /dev/null
+++ b/docs/api_doc/parameters/appconfig.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.parameters.appconfig
diff --git a/docs/api_doc/parameters/base.md b/docs/api_doc/parameters/base.md
new file mode 100644
index 00000000000..73e9b153a4f
--- /dev/null
+++ b/docs/api_doc/parameters/base.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.parameters.base
diff --git a/docs/api_doc/parameters/dynamodb.md b/docs/api_doc/parameters/dynamodb.md
new file mode 100644
index 00000000000..3ecceee765e
--- /dev/null
+++ b/docs/api_doc/parameters/dynamodb.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.parameters.dynamodb
diff --git a/docs/api_doc/parameters/secrets.md b/docs/api_doc/parameters/secrets.md
new file mode 100644
index 00000000000..2929cb4975d
--- /dev/null
+++ b/docs/api_doc/parameters/secrets.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.parameters.secrets
diff --git a/docs/api_doc/parameters/ssm.md b/docs/api_doc/parameters/ssm.md
new file mode 100644
index 00000000000..040c65a3858
--- /dev/null
+++ b/docs/api_doc/parameters/ssm.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.parameters.ssm
diff --git a/docs/api_doc/parser.md b/docs/api_doc/parser.md
new file mode 100644
index 00000000000..be52cde0b7d
--- /dev/null
+++ b/docs/api_doc/parser.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.parser.parser
diff --git a/docs/api_doc/streaming.md b/docs/api_doc/streaming.md
new file mode 100644
index 00000000000..f87aa7dfa18
--- /dev/null
+++ b/docs/api_doc/streaming.md
@@ -0,0 +1,5 @@
+
+::: aws_lambda_powertools.utilities.streaming.s3_object
+::: aws_lambda_powertools.utilities.streaming.transformations.csv
+::: aws_lambda_powertools.utilities.streaming.transformations.gzip
+::: aws_lambda_powertools.utilities.streaming.transformations.zip
diff --git a/docs/api_doc/tracer/base.md b/docs/api_doc/tracer/base.md
new file mode 100644
index 00000000000..3973deb4c5d
--- /dev/null
+++ b/docs/api_doc/tracer/base.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.tracing.base
diff --git a/docs/api_doc/tracer/tracing.md b/docs/api_doc/tracer/tracing.md
new file mode 100644
index 00000000000..336f2e05cbc
--- /dev/null
+++ b/docs/api_doc/tracer/tracing.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.tracing.tracer
diff --git a/docs/api_doc/typing.md b/docs/api_doc/typing.md
new file mode 100644
index 00000000000..7f54981d128
--- /dev/null
+++ b/docs/api_doc/typing.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.typing
diff --git a/docs/api_doc/validation.md b/docs/api_doc/validation.md
new file mode 100644
index 00000000000..1cdba7b5fa1
--- /dev/null
+++ b/docs/api_doc/validation.md
@@ -0,0 +1,2 @@
+
+::: aws_lambda_powertools.utilities.validation
diff --git a/docs/core/event_handler/api_gateway.md b/docs/core/event_handler/api_gateway.md
index 1f9618839f9..f2a60697740 100644
--- a/docs/core/event_handler/api_gateway.md
+++ b/docs/core/event_handler/api_gateway.md
@@ -3,11 +3,11 @@ title: REST API
description: Core utility
---
-Event handler for Amazon API Gateway REST and HTTP APIs, Application Loader Balancer (ALB), Lambda Function URLs, and VPC Lattice.
+Event handler for Amazon API Gateway REST and HTTP APIs, Application Load Balancer (ALB), Lambda Function URLs, and VPC Lattice.
## Key Features
-* Lightweight routing to reduce boilerplate for API Gateway REST/HTTP API, ALB and Lambda Function URLs.
+* Lightweight routing to reduce boilerplate for API Gateway REST/HTTP API, ALB and Lambda Function URLs
* Support for CORS, binary and Gzip compression, Decimals JSON encoding and bring your own JSON serializer
* Built-in integration with [Event Source Data Classes utilities](../../utilities/data_classes.md){target="_blank"} for self-documented event schema
* Works with micro function (one or a few routes) and monolithic functions (all routes)
diff --git a/docs/core/logger.md b/docs/core/logger.md
index 9915f7cc4b4..27fb532ad00 100644
--- a/docs/core/logger.md
+++ b/docs/core/logger.md
@@ -274,13 +274,15 @@ You can remove any additional key from Logger state using `remove_keys`.
#### Clearing all state
+##### Decorator with clear_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){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.
???+ danger "Danger: This can have unintended side effects if you use Layers"
- Lambda Layers code is imported before the Lambda handler.
+ Lambda Layers code is imported before the Lambda handler. When a Lambda function starts, it first imports and executes all code in the Layers (including any global scope code) before proceeding to the function's own code.
This means that `clear_state=True` will instruct Logger to remove any keys previously added before Lambda handler execution proceeds.
@@ -304,6 +306,27 @@ Logger is commonly initialized in the global scope. Due to [Lambda Execution Con
--8<-- "examples/logger/src/clear_state_event_two.json"
```
+##### clear_state method
+
+You can call `clear_state()` as a method explicitly within your code to clear appended keys at any point during the execution of your Lambda invocation.
+
+=== "clear_state_method.py"
+
+ ```python hl_lines="12"
+ --8<-- "examples/logger/src/clear_state_method.py"
+ ```
+=== "Output before clear_state()"
+
+ ```json hl_lines="9 17"
+ --8<-- "examples/logger/src/before_clear_state.json"
+ ```
+
+=== "Output after clear_state()"
+
+ ```json hl_lines="4"
+ --8<-- "examples/logger/src/after_clear_state.json"
+ ```
+
### Accessing currently configured keys
You can view all currently configured keys from the Logger state using the `get_current_keys()` method. This method is useful when you need to avoid overwriting keys that are already configured.
diff --git a/docs/core/metrics.md b/docs/core/metrics.md
index 6fdcf1fa043..88f0292231d 100644
--- a/docs/core/metrics.md
+++ b/docs/core/metrics.md
@@ -34,12 +34,16 @@ If you're new to Amazon CloudWatch, there are five terminologies you must be awa
???+ tip
All examples shared in this documentation are available within the [project repository](https://github.com/aws-powertools/powertools-lambda-python/tree/develop/examples){target="_blank"}.
-Metric has two global settings that will be used across all metrics emitted:
+Metric has three global settings that will be used across all metrics emitted:
-| Setting | Description | Environment variable | Constructor parameter |
-| -------------------- | ------------------------------------------------------------------------------- | ------------------------------ | --------------------- |
-| **Metric namespace** | Logical container where all metrics will be placed e.g. `ServerlessAirline` | `POWERTOOLS_METRICS_NAMESPACE` | `namespace` |
-| **Service** | Optionally, sets **service** metric dimension across all metrics e.g. `payment` | `POWERTOOLS_SERVICE_NAME` | `service` |
+| Setting | Description | Environment variable | Constructor parameter |
+| ------------------------------- | ------------------------------------------------------------------------------- | ------------------------------ | --------------------- |
+| **Metric namespace** | Logical container where all metrics will be placed e.g. `ServerlessAirline` | `POWERTOOLS_METRICS_NAMESPACE` | `namespace` |
+| **Service** | Optionally, sets **service** metric dimension across all metrics e.g. `payment` | `POWERTOOLS_SERVICE_NAME` | `service` |
+| **Disable Powertools Metrics** | Optionally, disables all Powertools metrics. | `POWERTOOLS_METRICS_DISABLED` | N/A |
+
+???+ info
+ `POWERTOOLS_METRICS_DISABLED` will not disable default metrics created by AWS services.
???+ tip
Use your application or main service as the metric namespace to easily group all metrics.
@@ -79,7 +83,7 @@ You can create metrics using `add_metric`, and you can create dimensions for all
CloudWatch EMF supports a max of 100 metrics per batch. Metrics utility will flush all metrics when adding the 100th metric. Subsequent metrics (101th+) will be aggregated into a new EMF object, for your convenience.
???+ warning "Warning: Do not create metrics or dimensions outside the handler"
- Metrics or dimensions added in the global scope will only be added during cold start. Disregard if you that's the intended behavior.
+ Metrics or dimensions added in the global scope will only be added during cold start. Disregard if that's the intended behavior.
### Adding high-resolution metrics
diff --git a/docs/core/metrics/datadog.md b/docs/core/metrics/datadog.md
index 3cf38e1c425..c5b9fdc35b8 100644
--- a/docs/core/metrics/datadog.md
+++ b/docs/core/metrics/datadog.md
@@ -23,7 +23,7 @@ stateDiagram-v2
DatadogExtension --> Datadog: async
state LambdaExtension {
- DatadogExtension
+ DatadogExtension
}
```
@@ -174,10 +174,14 @@ This has the advantage of keeping cold start metric separate from your applicati
You can use any of the following environment variables to configure `DatadogMetrics`:
-| Setting | Description | Environment variable | Constructor parameter |
-| -------------------- | -------------------------------------------------------------------------------- | ------------------------------ | --------------------- |
-| **Metric namespace** | Logical container where all metrics will be placed e.g. `ServerlessAirline` | `POWERTOOLS_METRICS_NAMESPACE` | `namespace` |
-| **Flush to log** | Use this when you want to flush metrics to be exported through Datadog Forwarder | `DD_FLUSH_TO_LOG` | `flush_to_log` |
+| Setting | Description | Environment variable | Constructor parameter |
+| ------------------------------ | -------------------------------------------------------------------------------- | ------------------------------ | --------------------- |
+| **Metric namespace** | Logical container where all metrics will be placed e.g. `ServerlessAirline` | `POWERTOOLS_METRICS_NAMESPACE` | `namespace` |
+| **Flush to log** | Use this when you want to flush metrics to be exported through Datadog Forwarder | `DD_FLUSH_TO_LOG` | `flush_to_log` |
+| **Disable Powertools Metrics** | Optionally, disables all Powertools metrics. | `POWERTOOLS_METRICS_DISABLED` | N/A |
+
+???+ info
+ `POWERTOOLS_METRICS_DISABLED` will not disable default metrics created by AWS services.
## Advanced
diff --git a/docs/includes/_layer_homepage_arm64.md b/docs/includes/_layer_homepage_arm64.md
index b92ff1c19be..b6d57fed27d 100644
--- a/docs/includes/_layer_homepage_arm64.md
+++ b/docs/includes/_layer_homepage_arm64.md
@@ -5,168 +5,168 @@
| Region | Layer ARN |
| -------------------- | --------------------------------------------------------------------------------------------------------------- |
- | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
- | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:6**{: .copyMe}:clipboard: |
+ | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-arm64:7**{: .copyMe}:clipboard: |
=== "Python 3.10"
| Region | Layer ARN |
| -------------------- | --------------------------------------------------------------------------------------------------------------- |
- | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
- | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:6**{: .copyMe}:clipboard: |
+ | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-arm64:7**{: .copyMe}:clipboard: |
=== "Python 3.11"
| Region | Layer ARN |
| -------------------- | --------------------------------------------------------------------------------------------------------------- |
- | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
- | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:6**{: .copyMe}:clipboard: |
+ | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-arm64:7**{: .copyMe}:clipboard: |
=== "Python 3.12"
| Region | Layer ARN |
| -------------------- | --------------------------------------------------------------------------------------------------------------- |
- | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
- | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6**{: .copyMe}:clipboard: |
+ | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7**{: .copyMe}:clipboard: |
=== "Python 3.13"
| Region | Layer ARN |
| -------------------- | --------------------------------------------------------------------------------------------------------------- |
- | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
- | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:6**{: .copyMe}:clipboard: |
+ | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
+ | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:7**{: .copyMe}:clipboard: |
diff --git a/docs/includes/_layer_homepage_x86.md b/docs/includes/_layer_homepage_x86.md
index 6bcc0de4a5b..2fddfd4cbda 100644
--- a/docs/includes/_layer_homepage_x86.md
+++ b/docs/includes/_layer_homepage_x86.md
@@ -5,173 +5,173 @@
| Region | Layer ARN |
| -------------------- | --------------------------------------------------------------------------------------------------------- |
- | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`ca-west-1`** | **arn:aws:lambda:ca-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:6**{: .copyMe}:clipboard: |
+ | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ca-west-1`** | **arn:aws:lambda:ca-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python39-x86_64:7**{: .copyMe}:clipboard: |
=== "Python 3.10"
| Region | Layer ARN |
| -------------------- | --------------------------------------------------------------------------------------------------------- |
- | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`ca-west-1`** | **arn:aws:lambda:ca-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:6**{: .copyMe}:clipboard: |
+ | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ca-west-1`** | **arn:aws:lambda:ca-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python310-x86_64:7**{: .copyMe}:clipboard: |
=== "Python 3.11"
| Region | Layer ARN |
| -------------------- | --------------------------------------------------------------------------------------------------------- |
- | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`ca-west-1`** | **arn:aws:lambda:ca-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:6**{: .copyMe}:clipboard: |
+ | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ca-west-1`** | **arn:aws:lambda:ca-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python311-x86_64:7**{: .copyMe}:clipboard: |
=== "Python 3.12"
| Region | Layer ARN |
| -------------------- | --------------------------------------------------------------------------------------------------------- |
- | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`ca-west-1`** | **arn:aws:lambda:ca-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6**{: .copyMe}:clipboard: |
+ | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ca-west-1`** | **arn:aws:lambda:ca-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7**{: .copyMe}:clipboard: |
=== "Python 3.13"
| Region | Layer ARN |
| -------------------- | --------------------------------------------------------------------------------------------------------- |
- | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`ca-west-1`** | **arn:aws:lambda:ca-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
- | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:6**{: .copyMe}:clipboard: |
+ | **`af-south-1`** | **arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-east-1`** | **arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-1`** | **arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-2`** | **arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-northeast-3`** | **arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-1`** | **arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-south-2`** | **arn:aws:lambda:ap-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-1`** | **arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-2`** | **arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-3`** | **arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-4`** | **arn:aws:lambda:ap-southeast-4:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ap-southeast-5`** | **arn:aws:lambda:ap-southeast-5:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ca-central-1`** | **arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`ca-west-1`** | **arn:aws:lambda:ca-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-1`** | **arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-central-2`** | **arn:aws:lambda:eu-central-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-north-1`** | **arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-1`** | **arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-south-2`** | **arn:aws:lambda:eu-south-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-1`** | **arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-2`** | **arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`eu-west-3`** | **arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`il-central-1`** | **arn:aws:lambda:il-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`me-central-1`** | **arn:aws:lambda:me-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`me-south-1`** | **arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`sa-east-1`** | **arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-east-1`** | **arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-east-2`** | **arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-west-1`** | **arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
+ | **`us-west-2`** | **arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-x86_64:7**{: .copyMe}:clipboard: |
diff --git a/docs/index.md b/docs/index.md
index aff525011f7..4f5c165f287 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -69,8 +69,8 @@ You can install Powertools for AWS Lambda (Python) using your favorite dependenc
| Architecture | Layer ARN |
| ------------ | --------------------------------------------------------------------------------------------------------- |
- | x86_64 | __arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-{python_version}-x86_64:6__{: .copyMe}:clipboard: |
- | ARM | __arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-{python_version}-arm64:6__{: .copyMe}:clipboard: |
+ | x86_64 | __arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-{python_version}-x86_64:7__{: .copyMe}:clipboard: |
+ | ARM | __arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-{python_version}-arm64:7__{: .copyMe}:clipboard: |
=== "AWS Console"
@@ -205,7 +205,7 @@ You can install Powertools for AWS Lambda (Python) using your favorite dependenc
You can use AWS CLI to generate a pre-signed URL to download the contents of our Lambda Layer.
```bash title="AWS CLI command to download Lambda Layer content"
- aws lambda get-layer-version-by-arn --arn arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6 --region eu-west-1
+ aws lambda get-layer-version-by-arn --arn arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7 --region eu-west-1
```
You'll find the pre-signed URL under `Location` key as part of the CLI command output.
@@ -220,15 +220,15 @@ You can install Powertools for AWS Lambda (Python) using your favorite dependenc
| Architecture | Layer ARN |
| ------------ | --------------------------------------------------------------------------------------------------------- |
- | x86_64 | __arn:aws-us-gov:lambda:us-gov-east-1:165087284144:layer:AWSLambdaPowertoolsPythonV3-{python_version}-x86_64:6__{: .copyMe}:clipboard: |
- | ARM | __arn:aws-us-gov:lambda:us-gov-east-1:165087284144:layer:AWSLambdaPowertoolsPythonV3-{python_version}-arm64:6__{: .copyMe}:clipboard: |
+ | x86_64 | __arn:aws-us-gov:lambda:us-gov-east-1:165087284144:layer:AWSLambdaPowertoolsPythonV3-{python_version}-x86_64:7__{: .copyMe}:clipboard: |
+ | ARM | __arn:aws-us-gov:lambda:us-gov-east-1:165087284144:layer:AWSLambdaPowertoolsPythonV3-{python_version}-arm64:7__{: .copyMe}:clipboard: |
**AWS GovCloud (us-gov-west-1)**
| Architecture | Layer ARN |
| ------------ | --------------------------------------------------------------------------------------------------------- |
- | x86_64 | __arn:aws-us-gov:lambda:us-gov-west-1:165093116878:layer:AWSLambdaPowertoolsPythonV3-{python_version}-x86_64:6__{: .copyMe}:clipboard: |
- | ARM | __arn:aws-us-gov:lambda:us-gov-west-1:165093116878:layer:AWSLambdaPowertoolsPythonV3-{python_version}-arm64:6__{: .copyMe}:clipboard: |
+ | x86_64 | __arn:aws-us-gov:lambda:us-gov-west-1:165093116878:layer:AWSLambdaPowertoolsPythonV3-{python_version}-x86_64:7__{: .copyMe}:clipboard: |
+ | ARM | __arn:aws-us-gov:lambda:us-gov-west-1:165093116878:layer:AWSLambdaPowertoolsPythonV3-{python_version}-arm64:7__{: .copyMe}:clipboard: |
=== "Serverless Application Repository (SAR)"
@@ -319,7 +319,7 @@ In this context, `[aws-sdk]` is an alias to the `boto3` package. Due to dependen
The pre-signed URL to download this Lambda Layer will be within `Location` key in the CLI output. The CLI output will also contain the Powertools for AWS Lambda version it contains.
```bash title="AWS CLI command to download Lambda Layer content"
-aws lambda get-layer-version-by-arn --arn arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6 --region eu-west-1
+aws lambda get-layer-version-by-arn --arn arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7 --region eu-west-1
```
#### SAR
@@ -432,6 +432,7 @@ When `POWERTOOLS_DEV` is set to a truthy value (`1`, `true`), it'll have the fol
| __Logger__ | Increase JSON indentation to 4. This will ease local debugging when running functions locally under emulators or direct calls while not affecting unit tests.
However, Amazon CloudWatch Logs view will degrade as each new line is treated as a new message. |
| __Event Handler__ | Enable full traceback errors in the response, indent request/responses, and CORS in dev mode (`*`). |
| __Tracer__ | Future-proof safety to disables tracing operations in non-Lambda environments. This already happens automatically in the Tracer utility. |
+| __Metrics__ | Disables Powertools metrics emission by default.
However, this can be overridden by explicitly setting POWERTOOLS_METRICS_DISABLED=false, which takes precedence over the dev mode setting. |
## Debug mode
diff --git a/docs/utilities/data_classes.md b/docs/utilities/data_classes.md
index 5d102e69784..57bd2584ae5 100644
--- a/docs/utilities/data_classes.md
+++ b/docs/utilities/data_classes.md
@@ -131,12 +131,18 @@ It is used for [API Gateway Rest API Lambda Authorizer payload](https://docs.aws
Use **`APIGatewayAuthorizerRequestEvent`** for type `REQUEST` and **`APIGatewayAuthorizerTokenEvent`** for type `TOKEN`.
-=== "app.py"
+=== "Rest APIs"
- ```python hl_lines="2-4 8"
+ ```python hl_lines="2-4 8 18"
--8<-- "examples/event_sources/src/apigw_authorizer_request.py"
```
+=== "WebSocket APIs"
+
+ ```python hl_lines="2-4 8 18"
+ --8<-- "examples/event_sources/src/apigw_authorizer_request_websocket.py"
+ ```
+
=== "API Gateway Authorizer Request Example Event"
```json hl_lines="3 11"
diff --git a/docs/utilities/data_masking.md b/docs/utilities/data_masking.md
index 162292e79a0..94e470aa965 100644
--- a/docs/utilities/data_masking.md
+++ b/docs/utilities/data_masking.md
@@ -43,7 +43,7 @@ stateDiagram-v2
## Terminology
-**Erasing** replaces sensitive information **irreversibly** with a non-sensitive placeholder _(`*****`)_. This operation replaces data in-memory, making it a one-way action.
+**Erasing** replaces sensitive information **irreversibly** with a non-sensitive placeholder _(`*****`)_, or with a customized mask. This operation replaces data in-memory, making it a one-way action.
**Encrypting** transforms plaintext into ciphertext using an encryption algorithm and a cryptographic key. It allows you to encrypt any sensitive data, so only allowed personnel to decrypt it. Learn more about encryption [here](https://aws.amazon.com/blogs/security/importance-of-encryption-and-how-aws-can-help/){target="_blank"}.
@@ -117,6 +117,52 @@ Erasing will remove the original data and replace it with a `*****`. This means
--8<-- "examples/data_masking/src/getting_started_erase_data_output.json"
```
+#### Custom masking
+
+The `erase` method also supports additional flags for more advanced and flexible masking:
+
+=== "dynamic_mask"
+
+ (bool) Enables dynamic masking behavior when set to `True`, by maintaining the original length and structure of the text replacing with *.
+
+ > Expression: `data_masker.erase(data, fields=["address.zip"], dynamic_mask=True)`
+
+ > Field result: `'street': '*** **** **'`
+
+=== "custom_mask"
+
+ (str) Specifies a simple pattern for masking data. This pattern is applied directly to the input string, replacing all the original characters. For example, with a `custom_mask` of "XX-XX" applied to "12345", the result would be "XX-XX".
+
+ > Expression: `data_masker.erase(data, fields=["address.zip"], custom_mask="XX")`
+
+ > Field result: `'zip': 'XX'`
+
+=== "regex_pattern & mask_format"
+
+ (str) `regex_pattern` defines a regular expression pattern used to identify parts of the input string that should be masked. This allows for more complex and flexible masking rules. It's used in conjunction with `mask_format`.
+ `mask_format` specifies the format to use when replacing parts of the string matched by `regex_pattern`. It can include placeholders (like \1, \2) to refer to captured groups in the regex pattern, allowing some parts of the original string to be preserved.
+
+ > Expression: `data_masker.erase(data, fields=["email"], regex_pattern=r"(.)(.*)(@.*)", mask_format=r"\1****\3")`
+
+ > Field result: `'email': 'j****@example.com'`
+
+=== "masking_rules"
+
+ (dict) Allows you to apply different masking rules (flags) for each data field.
+ ```python hl_lines="20"
+ --8<-- "examples/data_masking/src/custom_data_masking.py"
+ ```
+=== "Input example"
+
+ ```json
+ --8<-- "examples/data_masking/src/payload_custom_masking.json"
+ ```
+=== "Masking rules output example"
+
+ ```json hl_lines="4 5 10 21"
+ --8<-- "examples/data_masking/src/output_custom_masking.json"
+ ```
+
### Encrypting data
???+ note "About static typing and encryption"
diff --git a/examples/data_masking/src/custom_data_masking.py b/examples/data_masking/src/custom_data_masking.py
new file mode 100644
index 00000000000..7b96f6f379f
--- /dev/null
+++ b/examples/data_masking/src/custom_data_masking.py
@@ -0,0 +1,22 @@
+from __future__ import annotations
+
+from aws_lambda_powertools.utilities.data_masking import DataMasking
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+data_masker = DataMasking()
+
+
+def lambda_handler(event: dict, context: LambdaContext) -> dict:
+ data: dict = event.get("body", {})
+
+ # Masking rules for each field
+ masking_rules = {
+ "email": {"regex_pattern": "(.)(.*)(@.*)", "mask_format": r"\1****\3"},
+ "age": {"dynamic_mask": True},
+ "address.zip": {"custom_mask": "xxx"},
+ "$.other_address[?(@.postcode > 12000)]": {"custom_mask": "Masked"},
+ }
+
+ result = data_masker.erase(data, masking_rules=masking_rules)
+
+ return result
diff --git a/examples/data_masking/src/output_custom_masking.json b/examples/data_masking/src/output_custom_masking.json
new file mode 100644
index 00000000000..0571da99808
--- /dev/null
+++ b/examples/data_masking/src/output_custom_masking.json
@@ -0,0 +1,29 @@
+{
+ "id": 1,
+ "name": "John Doe",
+ "age": "**",
+ "email": "j****@example.com",
+ "address": {
+ "street": "123 Main St",
+ "city": "Anytown",
+ "state": "CA",
+ "zip": "xxx",
+ "postcode": 12345,
+ "product": {
+ "name": "Car"
+ }
+ },
+ "other_address": [
+ {
+ "postcode": 11345,
+ "street": "123 Any Drive"
+ },
+ "Masked"
+ ],
+ "company_address": {
+ "street": "456 ACME Ave",
+ "city": "Anytown",
+ "state": "CA",
+ "zip": "12345"
+ }
+}
\ No newline at end of file
diff --git a/examples/data_masking/src/payload_custom_masking.json b/examples/data_masking/src/payload_custom_masking.json
new file mode 100644
index 00000000000..d50b715ffa4
--- /dev/null
+++ b/examples/data_masking/src/payload_custom_masking.json
@@ -0,0 +1,34 @@
+{
+ "body": {
+ "id": 1,
+ "name": "Jane Doe",
+ "age": 30,
+ "email": "janedoe@example.com",
+ "address": {
+ "street": "123 Main St",
+ "city": "Anytown",
+ "state": "CA",
+ "zip": "12345",
+ "postcode": 12345,
+ "product": {
+ "name": "Car"
+ }
+ },
+ "other_address": [
+ {
+ "postcode": 11345,
+ "street": "123 Any Drive"
+ },
+ {
+ "postcode": 67890,
+ "street": "100 Main Street,"
+ }
+ ],
+ "company_address": {
+ "street": "456 ACME Ave",
+ "city": "Anytown",
+ "state": "CA",
+ "zip": "12345"
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/event_sources/src/apigw_authorizer_request_websocket.py b/examples/event_sources/src/apigw_authorizer_request_websocket.py
new file mode 100644
index 00000000000..441d27c483d
--- /dev/null
+++ b/examples/event_sources/src/apigw_authorizer_request_websocket.py
@@ -0,0 +1,29 @@
+from aws_lambda_powertools.utilities.data_classes import event_source
+from aws_lambda_powertools.utilities.data_classes.api_gateway_authorizer_event import (
+ APIGatewayAuthorizerRequestEvent,
+ APIGatewayAuthorizerResponseWebSocket,
+)
+
+
+@event_source(data_class=APIGatewayAuthorizerRequestEvent)
+def lambda_handler(event: APIGatewayAuthorizerRequestEvent, context):
+ # Simple auth check (replace with your actual auth logic)
+ is_authorized = event.headers.get("HeaderAuth1") == "headerValue1"
+
+ if not is_authorized:
+ return {"principalId": "", "policyDocument": {"Version": "2012-10-17", "Statement": []}}
+
+ arn = event.parsed_arn
+
+ policy = APIGatewayAuthorizerResponseWebSocket(
+ principal_id="user",
+ context={"user": "example"},
+ region=arn.region,
+ aws_account_id=arn.aws_account_id,
+ api_id=arn.api_id,
+ stage=arn.stage,
+ )
+
+ policy.allow_all_routes()
+
+ return policy.asdict()
diff --git a/examples/homepage/install/arm64/amplify.txt b/examples/homepage/install/arm64/amplify.txt
index 7621a2b88f7..58180d6debd 100644
--- a/examples/homepage/install/arm64/amplify.txt
+++ b/examples/homepage/install/arm64/amplify.txt
@@ -6,7 +6,7 @@
? 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:AWSLambdaPowertoolsPythonV3-python312-arm64:6
+? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7
❯ amplify push -y
@@ -17,5 +17,5 @@ General information
- 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:AWSLambdaPowertoolsPythonV3-python312-arm64:6
+? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7
? Do you want to edit the local lambda function now? No
diff --git a/examples/homepage/install/arm64/cdk_arm64.py b/examples/homepage/install/arm64/cdk_arm64.py
index 2115eb70b54..933d8e9b709 100644
--- a/examples/homepage/install/arm64/cdk_arm64.py
+++ b/examples/homepage/install/arm64/cdk_arm64.py
@@ -10,7 +10,7 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
powertools_layer = aws_lambda.LayerVersion.from_layer_version_arn(
self,
id="lambda-powertools",
- layer_version_arn=f"arn:aws:lambda:{Aws.REGION}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6",
+ layer_version_arn=f"arn:aws:lambda:{Aws.REGION}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7",
)
aws_lambda.Function(
self,
diff --git a/examples/homepage/install/arm64/pulumi_arm64.py b/examples/homepage/install/arm64/pulumi_arm64.py
index 401e64a19ec..69aa28b8ada 100644
--- a/examples/homepage/install/arm64/pulumi_arm64.py
+++ b/examples/homepage/install/arm64/pulumi_arm64.py
@@ -22,7 +22,7 @@
pulumi.Output.concat(
"arn:aws:lambda:",
aws.get_region_output().name,
- ":017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6",
+ ":017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7",
),
],
tracing_config={"mode": "Active"},
diff --git a/examples/homepage/install/arm64/sam.yaml b/examples/homepage/install/arm64/sam.yaml
index 47596af46b9..8f66f7b2654 100644
--- a/examples/homepage/install/arm64/sam.yaml
+++ b/examples/homepage/install/arm64/sam.yaml
@@ -9,4 +9,4 @@ Resources:
Runtime: python3.12
Handler: app.lambda_handler
Layers:
- - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6
+ - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7
diff --git a/examples/homepage/install/arm64/serverless.yml b/examples/homepage/install/arm64/serverless.yml
index 0f312201c51..41814b8953a 100644
--- a/examples/homepage/install/arm64/serverless.yml
+++ b/examples/homepage/install/arm64/serverless.yml
@@ -10,4 +10,4 @@ functions:
handler: lambda_function.lambda_handler
architecture: arm64
layers:
- - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6
+ - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7
diff --git a/examples/homepage/install/arm64/terraform.tf b/examples/homepage/install/arm64/terraform.tf
index 504bad85045..938f1a7e0eb 100644
--- a/examples/homepage/install/arm64/terraform.tf
+++ b/examples/homepage/install/arm64/terraform.tf
@@ -34,7 +34,7 @@ resource "aws_lambda_function" "test_lambda" {
role = aws_iam_role.iam_for_lambda.arn
handler = "index.test"
runtime = "python3.12"
- layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:6"]
+ layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-arm64:7"]
architectures = ["arm64"]
source_code_hash = filebase64sha256("lambda_function_payload.zip")
diff --git a/examples/homepage/install/x86_64/amplify.txt b/examples/homepage/install/x86_64/amplify.txt
index 7e115842900..545cb731d19 100644
--- a/examples/homepage/install/x86_64/amplify.txt
+++ b/examples/homepage/install/x86_64/amplify.txt
@@ -6,7 +6,7 @@
? 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:AWSLambdaPowertoolsPythonV3-python312-x86_64:6
+? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7
❯ amplify push -y
@@ -17,5 +17,5 @@ General information
- 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:AWSLambdaPowertoolsPythonV3-python312-x86_64:6
+? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7
? Do you want to edit the local lambda function now? No
diff --git a/examples/homepage/install/x86_64/cdk_x86.py b/examples/homepage/install/x86_64/cdk_x86.py
index cada7ccc549..c42687f00ca 100644
--- a/examples/homepage/install/x86_64/cdk_x86.py
+++ b/examples/homepage/install/x86_64/cdk_x86.py
@@ -10,7 +10,7 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
powertools_layer = aws_lambda.LayerVersion.from_layer_version_arn(
self,
id="lambda-powertools",
- layer_version_arn=f"arn:aws:lambda:{Aws.REGION}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6",
+ layer_version_arn=f"arn:aws:lambda:{Aws.REGION}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7",
)
aws_lambda.Function(
self,
diff --git a/examples/homepage/install/x86_64/pulumi_x86.py b/examples/homepage/install/x86_64/pulumi_x86.py
index 4e71b4124ce..8093a4d067c 100644
--- a/examples/homepage/install/x86_64/pulumi_x86.py
+++ b/examples/homepage/install/x86_64/pulumi_x86.py
@@ -22,7 +22,7 @@
pulumi.Output.concat(
"arn:aws:lambda:",
aws.get_region_output().name,
- ":017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6",
+ ":017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7",
),
],
tracing_config={"mode": "Active"},
diff --git a/examples/homepage/install/x86_64/sam.yaml b/examples/homepage/install/x86_64/sam.yaml
index 227cb925ba3..59bc71c2474 100644
--- a/examples/homepage/install/x86_64/sam.yaml
+++ b/examples/homepage/install/x86_64/sam.yaml
@@ -8,4 +8,4 @@ Resources:
Runtime: python3.12
Handler: app.lambda_handler
Layers:
- - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6
+ - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7
diff --git a/examples/homepage/install/x86_64/serverless.yml b/examples/homepage/install/x86_64/serverless.yml
index 377eb759288..850fcf36bac 100644
--- a/examples/homepage/install/x86_64/serverless.yml
+++ b/examples/homepage/install/x86_64/serverless.yml
@@ -10,4 +10,4 @@ functions:
handler: lambda_function.lambda_handler
architecture: arm64
layers:
- - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6
+ - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7
diff --git a/examples/homepage/install/x86_64/terraform.tf b/examples/homepage/install/x86_64/terraform.tf
index 39ba18c9ac8..a1a37fb475a 100644
--- a/examples/homepage/install/x86_64/terraform.tf
+++ b/examples/homepage/install/x86_64/terraform.tf
@@ -34,7 +34,7 @@ resource "aws_lambda_function" "test_lambda" {
role = aws_iam_role.iam_for_lambda.arn
handler = "index.test"
runtime = "python3.12"
- layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6"]
+ layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7"]
source_code_hash = filebase64sha256("lambda_function_payload.zip")
}
diff --git a/examples/logger/sam/template.yaml b/examples/logger/sam/template.yaml
index f37909f5324..ede8c940ad8 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://docs.powertools.aws.dev/lambda/python/latest/#lambda-layer
- - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6
+ - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7
Resources:
LoggerLambdaHandlerExample:
diff --git a/examples/logger/src/after_clear_state.json b/examples/logger/src/after_clear_state.json
new file mode 100644
index 00000000000..54dd72ed41e
--- /dev/null
+++ b/examples/logger/src/after_clear_state.json
@@ -0,0 +1,7 @@
+{
+ "level": "INFO",
+ "location": "lambda_handler:126",
+ "message": "State after clearing - only show default keys",
+ "timestamp": "2025-01-30 13:56:03,158-0300",
+ "service": "payment"
+}
\ No newline at end of file
diff --git a/examples/logger/src/before_clear_state.json b/examples/logger/src/before_clear_state.json
new file mode 100644
index 00000000000..a710dbde0d6
--- /dev/null
+++ b/examples/logger/src/before_clear_state.json
@@ -0,0 +1,20 @@
+{
+ "logs": [
+ {
+ "level": "INFO",
+ "location": "lambda_handler:122",
+ "message": "Starting order processing",
+ "timestamp": "2025-01-30 13:56:03,157-0300",
+ "service": "payment",
+ "order_id": "12345"
+ },
+ {
+ "level": "INFO",
+ "location": "lambda_handler:124",
+ "message": "Final state before clearing",
+ "timestamp": "2025-01-30 13:56:03,157-0300",
+ "service": "payment",
+ "order_id": "12345"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/examples/logger/src/clear_state_method.py b/examples/logger/src/clear_state_method.py
new file mode 100644
index 00000000000..1564b4c2c39
--- /dev/null
+++ b/examples/logger/src/clear_state_method.py
@@ -0,0 +1,15 @@
+from aws_lambda_powertools import Logger
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+logger = Logger(service="payment", level="DEBUG")
+
+
+def lambda_handler(event: dict, context: LambdaContext) -> str:
+ try:
+ logger.append_keys(order_id="12345")
+ logger.info("Starting order processing")
+ finally:
+ logger.info("Final state before clearing")
+ logger.clear_state()
+ logger.info("State after clearing - only show default keys")
+ return "Completed"
diff --git a/examples/metrics/sam/template.yaml b/examples/metrics/sam/template.yaml
index 77bdfa93782..2d57768fc88 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://docs.powertools.aws.dev/lambda/python/latest/#lambda-layer
- - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6
+ - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7
Resources:
CaptureLambdaHandlerExample:
diff --git a/examples/metrics_datadog/sam/template.yaml b/examples/metrics_datadog/sam/template.yaml
index b34eccbd337..99d1fc35874 100644
--- a/examples/metrics_datadog/sam/template.yaml
+++ b/examples/metrics_datadog/sam/template.yaml
@@ -20,7 +20,7 @@ Globals:
Layers:
# Find the latest Layer version in the official documentation
# https://docs.powertools.aws.dev/lambda/python/latest/#lambda-layer
- - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6
+ - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7
# Find the latest Layer version in the Datadog official documentation
# Datadog SDK
diff --git a/examples/tracer/sam/template.yaml b/examples/tracer/sam/template.yaml
index 9596c5307f5..8091369bb84 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://docs.powertools.aws.dev/lambda/python/latest/#lambda-layer
- - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:6
+ - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-python312-x86_64:7
Resources:
CaptureLambdaHandlerExample:
diff --git a/layer_v3/scripts/update_layer_arn_v3.sh b/layer_v3/scripts/update_layer_arn_v3.sh
new file mode 100755
index 00000000000..42f4a3dd5bf
--- /dev/null
+++ b/layer_v3/scripts/update_layer_arn_v3.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# This script is run during the publish_v3_layer.yml CI job,
+# and it is responsible for replacing the layer ARN in our documentation.
+# Our pipeline must generate the same layer number for all commercial regions + gov cloud
+# If this doesn't happens, we have an error and we must fix it in the deployment.
+#
+# see .github/workflows/reusable_deploy_v3_layer_stack.yml
+
+
+# Get the new version number from the first command-line argument
+new_version=$1
+if [ -z "$new_version" ]; then
+ echo "Usage: $0 "
+ exit 1
+fi
+
+# Find all files with specified extensions in ./docs and ./examples directories
+# -type f: only find files (not directories)
+# \( ... \): group conditions
+# -o: logical OR
+# -print0: use null character as separator (handles filenames with spaces)
+find ./docs ./examples -type f \( -name "*.md" -o -name "*.py" -o -name "*.yaml" -o -name "*.txt" -o -name "*.tf" -o -name "*.yml" \) -print0 | while IFS= read -r -d '' file; do
+ echo "Processing file: $file"
+
+ # Use sed to replace the version number in the Lambda layer ARN
+ # -i: edit files in-place without creating a backup
+ # -E: use extended regular expressions
+ # The regex matches the layer name and replaces only the version number at the end
+ sed -i -E "s/(AWSLambdaPowertoolsPythonV3-python[0-9]+-((arm64)|(x86_64)):)[0-9]+/\1$new_version/g" "$file"
+ if [ $? -eq 0 ]; then
+ echo "Updated $file successfully"
+ grep "arn:aws:lambda:" "$file"
+ else
+ echo "Error processing $file"
+ fi
+done
+echo "Layer version update attempt completed."
diff --git a/mkdocs.yml b/mkdocs.yml
index 13930db6133..36704cdf857 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -62,6 +62,61 @@ nav:
# - Overview: contributing/tracks/overview.md
# - Casual to regular contributor: contributing/tracks/casual_regular_contributor.md
# - Customer to advocate: contributing/tracks/customer_advocate.md
+ - API Documentation:
+ - Batch Processing:
+ - Base: api_doc/batch/base.md
+ - Decorators: api_doc/batch/decorators.md
+ - Exceptions: api_doc/batch/exceptions.md
+ - Event Source Data Classes: api_doc/data_classes.md
+ - Data Masking:
+ - Base: api_doc/data_masking/base.md
+ - Exception: api_doc/data_masking/exceptions.md
+ - Provider: api_doc/data_masking/provider.md
+ - Event Handler:
+ - AppSync: api_doc/event_handler/appsync.md
+ - Middleware: api_doc/event_handler/middleware.md
+ - OpenAPI: api_doc/event_handler/openapi.md
+ - REST: api_doc/event_handler/api_gateway.md
+ - Feature Flags:
+ - AppConfig: api_doc/feature_flags/appconfig.md
+ - Base: api_doc/feature_flags/base.md
+ - Comparators: api_doc/feature_flags/comparators.md
+ - Exceptions: api_doc/feature_flags/exceptions.md
+ - Feature flags: api_doc/feature_flags/feature_flags.md
+ - Schema: api_doc/feature_flags/schema.md
+ - Idempotency:
+ - Base: api_doc/idempotency/base.md
+ - Config: api_doc/idempotency/config.md
+ - Exceptions: api_doc/idempotency/exceptions.md
+ - Persistence: api_doc/idempotency/persistence.md
+ - Serialization: api_doc/idempotency/serialization.md
+ - JMESPath Functions: api_doc/jmespath_functions.md
+ - Logger:
+ - DataDog Formatter: api_doc/logger/datadog_formatter.md
+ - Exceptions: api_doc/logger/exceptions.md
+ - Formatter: api_doc/logger/formatter.md
+ - Lambda Context: api_doc/logger/lambda_context.md
+ - Logger: api_doc/logger/logger.md
+ - Metrics:
+ - Base: api_doc/metrics/base.md
+ - Exceptions: api_doc/metrics/exceptions.md
+ - Providers:
+ - EMF: api_doc/metrics/provider_emf.md
+ - DataDog: api_doc/metrics/provider_datadog.md
+ - Middleware Factory: api_doc/middleware_factory.md
+ - Parameters:
+ - Base: api_doc/parameters/base.md
+ - AppConfig: api_doc/parameters/appconfig.md
+ - DynamoDB: api_doc/parameters/dynamodb.md
+ - SSM: api_doc/parameters/ssm.md
+ - Secrets: api_doc/parameters/secrets.md
+ - Parser: api_doc/parser.md
+ - Streaming: api_doc/streaming.md
+ - Tracer:
+ - Base: api_doc/tracer/base.md
+ - Tracing: api_doc/tracer/tracing.md
+ - Typing: api_doc/typing.md
+ - Validation: api_doc/validation.md
theme:
name: material
@@ -134,8 +189,42 @@ markdown_extensions:
copyright: Copyright © 2023 Amazon Web Services
plugins:
+ - privacy
- git-revision-date
- search
+ - mkdocstrings:
+ default_handler: python
+ enable_inventory: true
+ handlers:
+ python:
+ import:
+ - https://docs.python.org/3/objects.inv
+ options:
+ # Headings
+ #heading_level: 2
+ #show_root_heading: true
+ #show_root_toc_entry: true
+ #show_root_full_path: true
+ #show_root_members_full_path: false
+ #show_object_full_path: false
+ show_category_heading: false
+ # Members
+ filters: ["!^_"]
+ group_by_category: true
+ members_order: alphabetical
+ show_submodules: true
+ # Docstrings
+ docstring_style: numpy
+ docstring_options:
+ ignore_init_summary: true
+ docstring_section_style: spacy
+ merge_init_into_class: true
+ show_if_no_docstring: false
+ # Signature
+ show_signature: true
+ show_signature_annotations: true
+ separate_signature: true
+ summary: true
extra_css:
- stylesheets/extra.css
diff --git a/noxfile.py b/noxfile.py
index 7b73fd0dc59..4710bcbca2c 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -140,6 +140,8 @@ def test_with_aws_encryption_sdk_as_required_package(session: nox.Session):
folders=[
f"{PREFIX_TESTS_FUNCTIONAL}/data_masking/_aws_encryption_sdk/",
f"{PREFIX_TESTS_UNIT}/data_masking/_aws_encryption_sdk/",
+ f"{PREFIX_TESTS_FUNCTIONAL}/data_masking/required_dependencies/",
+ f"{PREFIX_TESTS_UNIT}/data_masking/required_dependencies/",
],
extras="datamasking",
)
diff --git a/package-lock.json b/package-lock.json
index 533997328f3..ad8c05249dc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,13 +11,13 @@
"package-lock.json": "^1.0.0"
},
"devDependencies": {
- "aws-cdk": "^2.177.0"
+ "aws-cdk": "^2.178.1"
}
},
"node_modules/aws-cdk": {
- "version": "2.177.0",
- "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.177.0.tgz",
- "integrity": "sha512-TiBoyE5wMB5q4jX1bELwkklgbs5eLY1Phjfnb4Mof0K9tOSRJ9UEq6xEamF0esMS+TuYU7a/ESTpmKX3iYqA3w==",
+ "version": "2.178.1",
+ "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.178.1.tgz",
+ "integrity": "sha512-64z9ARFI90jhX6sfjqqJghGxkfh1T4STxY3ccuRY8OxzAK1FY6XLjKBxSyXi9jJFa3v9nN57x7W32u4hZDj6gw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
diff --git a/package.json b/package.json
index fb58778db5a..2698f422ad5 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "aws-lambda-powertools-python-e2e",
"version": "1.0.0",
"devDependencies": {
- "aws-cdk": "^2.177.0"
+ "aws-cdk": "^2.178.1"
},
"dependencies": {
"package-lock.json": "^1.0.0"
diff --git a/poetry.lock b/poetry.lock
index 0cc1a03a5ae..168d83758ca 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand.
[[package]]
name = "annotated-types"
@@ -6,12 +6,10 @@ version = "0.7.0"
description = "Reusable constraint types to use with typing.Annotated"
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
files = [
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
]
-markers = {main = "extra == \"parser\" or extra == \"all\""}
[[package]]
name = "anyio"
@@ -19,7 +17,6 @@ version = "4.8.0"
description = "High level compatibility layer for multiple asynchronous event loop implementations"
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"},
{file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"},
@@ -36,13 +33,23 @@ doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)",
test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"]
trio = ["trio (>=0.26.1)"]
+[[package]]
+name = "appdirs"
+version = "1.4.4"
+description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
+optional = false
+python-versions = "*"
+files = [
+ {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
+ {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
+]
+
[[package]]
name = "argcomplete"
version = "3.5.3"
description = "Bash tab completion for argparse"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "argcomplete-3.5.3-py3-none-any.whl", hash = "sha256:2ab2c4a215c59fd6caaff41a869480a23e8f6a5f910b266c1808037f4e375b61"},
{file = "argcomplete-3.5.3.tar.gz", hash = "sha256:c12bf50eded8aebb298c7b7da7a5ff3ee24dffd9f5281867dfe1424b58c55392"},
@@ -57,33 +64,29 @@ version = "5.0.1"
description = "Timeout context manager for asyncio programs"
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
files = [
{file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"},
{file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"},
]
-markers = {main = "extra == \"redis\" and python_full_version < \"3.11.3\"", dev = "python_full_version < \"3.11.3\""}
[[package]]
name = "attrs"
-version = "24.3.0"
+version = "23.2.0"
description = "Classes Without Boilerplate"
optional = false
-python-versions = ">=3.8"
-groups = ["main", "dev"]
+python-versions = ">=3.7"
files = [
- {file = "attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"},
- {file = "attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff"},
+ {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"},
+ {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"},
]
-markers = {main = "extra == \"all\" or extra == \"datamasking\""}
[package.extras]
-benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
-tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
+cov = ["attrs[tests]", "coverage[toml] (>=5.3)"]
+dev = ["attrs[tests]", "pre-commit"]
+docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"]
+tests = ["attrs[tests-no-zope]", "zope-interface"]
+tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"]
+tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"]
[[package]]
name = "aws-cdk-asset-awscli-v1"
@@ -91,7 +94,6 @@ version = "2.2.221"
description = "A library that contains the AWS CLI for use in Lambda Layers"
optional = false
python-versions = "~=3.8"
-groups = ["dev"]
files = [
{file = "aws_cdk.asset_awscli_v1-2.2.221-py3-none-any.whl", hash = "sha256:66a83e4116b6a7a0041f99f7bca7d0ea354c9ab2e17a938a3dcec50f7272f5d9"},
{file = "aws_cdk_asset_awscli_v1-2.2.221.tar.gz", hash = "sha256:7ea0366c8090dc396fed85baddbcf48ac4a088c1bf606cd776138e6526679108"},
@@ -108,7 +110,6 @@ version = "2.1.3"
description = "A Lambda Layer that contains kubectl v1.20"
optional = false
python-versions = "~=3.8"
-groups = ["dev"]
files = [
{file = "aws_cdk.asset_kubectl_v20-2.1.3-py3-none-any.whl", hash = "sha256:d5612e5bd03c215a28ce53193b1144ecf4e93b3b6779563c046a8a74d83a3979"},
{file = "aws_cdk_asset_kubectl_v20-2.1.3.tar.gz", hash = "sha256:237cd8530d9e8be0bbc7159af927dbb6b7f91bf3f4099c8ef4d9a213b34264be"},
@@ -125,7 +126,6 @@ version = "2.1.0"
description = "@aws-cdk/asset-node-proxy-agent-v6"
optional = false
python-versions = "~=3.8"
-groups = ["dev"]
files = [
{file = "aws_cdk.asset_node_proxy_agent_v6-2.1.0-py3-none-any.whl", hash = "sha256:24a388b69a44d03bae6dbf864c4e25ba650d4b61c008b4568b94ffbb9a69e40e"},
{file = "aws_cdk_asset_node_proxy_agent_v6-2.1.0.tar.gz", hash = "sha256:1f292c0631f86708ba4ee328b3a2b229f7e46ea1c79fbde567ee9eb119c2b0e2"},
@@ -142,7 +142,6 @@ version = "2.114.1a0"
description = "This module is deprecated. All constructs are now available under aws-cdk-lib/aws-apigatewayv2"
optional = false
python-versions = "~=3.8"
-groups = ["dev"]
files = [
{file = "aws-cdk.aws-apigatewayv2-alpha-2.114.1a0.tar.gz", hash = "sha256:9e8c3131f4fa3e0926eb3d76aeacd578a6aa51f95b39c10a86112c991bb75864"},
{file = "aws_cdk.aws_apigatewayv2_alpha-2.114.1a0-py3-none-any.whl", hash = "sha256:a101ce56d846976ad1c8020054dfe73fd9f45afdbe71f2a297acc84c1a201403"},
@@ -161,7 +160,6 @@ version = "2.114.1a0"
description = "This module is deprecated. All constructs are now available under aws-cdk-lib/aws-apigatewayv2-authorizers"
optional = false
python-versions = "~=3.8"
-groups = ["dev"]
files = [
{file = "aws-cdk.aws-apigatewayv2-authorizers-alpha-2.114.1a0.tar.gz", hash = "sha256:ee290e2ed0f1506dbbb12b3b8963f50b379121759077002c265977fbaf18fd9f"},
{file = "aws_cdk.aws_apigatewayv2_authorizers_alpha-2.114.1a0-py3-none-any.whl", hash = "sha256:2576e1ce06dab314020bff50f5d59b8715a7adf18106eac811028c22f61c9baa"},
@@ -181,7 +179,6 @@ version = "2.114.1a0"
description = "This module is deprecated. All constructs are now available under aws-cdk-lib/aws-apigatewayv2-integrations"
optional = false
python-versions = "~=3.8"
-groups = ["dev"]
files = [
{file = "aws-cdk.aws-apigatewayv2-integrations-alpha-2.114.1a0.tar.gz", hash = "sha256:19e1824b577683e7d3c2b01fd58c176ebe4c7b8d1b4af4cfdc3893d3ffbac9af"},
{file = "aws_cdk.aws_apigatewayv2_integrations_alpha-2.114.1a0-py3-none-any.whl", hash = "sha256:1e440a70e6b4cbe077c95ffdd3fd0cfb3962f90762ea2e973eaa2ab7719ccb2c"},
@@ -201,7 +198,6 @@ version = "2.59.0a0"
description = "The CDK Construct Library for AWS::AppSync"
optional = false
python-versions = "~=3.7"
-groups = ["dev"]
files = [
{file = "aws-cdk.aws-appsync-alpha-2.59.0a0.tar.gz", hash = "sha256:f5c7773b70b759efd576561dc3d71af5762a6f7cbc9ee9eef5e538c7ab3dccc7"},
{file = "aws_cdk.aws_appsync_alpha-2.59.0a0-py3-none-any.whl", hash = "sha256:ecc235f1f70d404c8d03cf250be0227becd14c468f8c43b6d9df334a1d60c8e2"},
@@ -216,18 +212,17 @@ typeguard = ">=2.13.3,<2.14.0"
[[package]]
name = "aws-cdk-aws-lambda-python-alpha"
-version = "2.177.0a0"
+version = "2.178.1a0"
description = "The CDK Construct Library for AWS Lambda in Python"
optional = false
python-versions = "~=3.8"
-groups = ["dev"]
files = [
- {file = "aws_cdk.aws_lambda_python_alpha-2.177.0a0-py3-none-any.whl", hash = "sha256:5aacc26970e30909b372fd2e8b98ce7197b8074d78ec4f1d900a8ddd02bc5114"},
- {file = "aws_cdk_aws_lambda_python_alpha-2.177.0a0.tar.gz", hash = "sha256:0137957603cd91b473de3a455bf4d95de4ba60c1ba9f25f62d3edeb965202c4e"},
+ {file = "aws_cdk.aws_lambda_python_alpha-2.178.1a0-py3-none-any.whl", hash = "sha256:15560cc63d85f51dc09b42deb60066cd5cd1d9cb7d744f7808833f58d6a8ab8a"},
+ {file = "aws_cdk_aws_lambda_python_alpha-2.178.1a0.tar.gz", hash = "sha256:5a044728935bd584f15cc168491e5424e550135f5729ee7fd29e48e6ce41434b"},
]
[package.dependencies]
-aws-cdk-lib = ">=2.177.0,<3.0.0"
+aws-cdk-lib = ">=2.178.1,<3.0.0"
constructs = ">=10.0.0,<11.0.0"
jsii = ">=1.106.0,<2.0.0"
publication = ">=0.0.3"
@@ -235,14 +230,13 @@ typeguard = ">=2.13.3,<4.3.0"
[[package]]
name = "aws-cdk-cloud-assembly-schema"
-version = "39.2.7"
+version = "39.2.9"
description = "Cloud Assembly Schema"
optional = false
python-versions = "~=3.8"
-groups = ["dev"]
files = [
- {file = "aws_cdk.cloud_assembly_schema-39.2.7-py3-none-any.whl", hash = "sha256:80330f993605d65d00369f38cb8ac99ad757ef7158985656a77ac5b2712c565c"},
- {file = "aws_cdk_cloud_assembly_schema-39.2.7.tar.gz", hash = "sha256:980250fb7ef871ea12b58ebb91df5b83da10f69810917bdcd8e0c1d02411516c"},
+ {file = "aws_cdk.cloud_assembly_schema-39.2.9-py3-none-any.whl", hash = "sha256:3d16bbe45a463e5327b3d618e1501a2f4ecc6a8764dea71b045e431976135bc8"},
+ {file = "aws_cdk_cloud_assembly_schema-39.2.9.tar.gz", hash = "sha256:ed82fc47eee25888fedeb3f668d61e7fb22b0afa393d5ae5cc9e44e75113b85b"},
]
[package.dependencies]
@@ -252,14 +246,13 @@ typeguard = ">=2.13.3,<4.3.0"
[[package]]
name = "aws-cdk-lib"
-version = "2.177.0"
+version = "2.178.1"
description = "Version 2 of the AWS Cloud Development Kit library"
optional = false
python-versions = "~=3.8"
-groups = ["dev"]
files = [
- {file = "aws_cdk_lib-2.177.0-py3-none-any.whl", hash = "sha256:acdf06aaf52367a64b4bf88381e8272cb7b5961c242020ace822c79749e53cac"},
- {file = "aws_cdk_lib-2.177.0.tar.gz", hash = "sha256:5e51c48da31555beb38243bb2882e98ee9fe1796466ba9f8d3088701b47965e5"},
+ {file = "aws_cdk_lib-2.178.1-py3-none-any.whl", hash = "sha256:882feb0ae77fadc8fb8951649d12608bd2d776f6730e1c21cd6655615a234ae2"},
+ {file = "aws_cdk_lib-2.178.1.tar.gz", hash = "sha256:c5ae0305d0c20093941ab77e7c6847d5ec8baaf98469c4b04901a0d2a3746f32"},
]
[package.dependencies]
@@ -278,8 +271,6 @@ version = "4.0.0"
description = "AWS Encryption SDK implementation for Python"
optional = true
python-versions = "*"
-groups = ["main"]
-markers = "extra == \"all\" or extra == \"datamasking\""
files = [
{file = "aws-encryption-sdk-4.0.0.tar.gz", hash = "sha256:57df8b5c1b9f18db4373c6e8e65563791063a71be93d0849950ed365272db354"},
{file = "aws_encryption_sdk-4.0.0-py2.py3-none-any.whl", hash = "sha256:a94483785dff2cd166ccb8f3a15cdfe5cba7a3717f6604543c816a3a32f7c412"},
@@ -300,7 +291,6 @@ version = "0.4.3"
description = "AWS signature version 4 signing process for the python requests module"
optional = false
python-versions = "*"
-groups = ["dev"]
files = [
{file = "aws-requests-auth-0.4.3.tar.gz", hash = "sha256:33593372018b960a31dbbe236f89421678b885c35f0b6a7abfae35bb77e069b2"},
{file = "aws_requests_auth-0.4.3-py2.py3-none-any.whl", hash = "sha256:646bc37d62140ea1c709d20148f5d43197e6bd2d63909eb36fa4bb2345759977"},
@@ -315,7 +305,6 @@ version = "1.94.0"
description = "AWS SAM Translator is a library that transform SAM templates into AWS CloudFormation templates"
optional = false
python-versions = "!=4.0,<=4.0,>=3.8"
-groups = ["dev"]
files = [
{file = "aws_sam_translator-1.94.0-py3-none-any.whl", hash = "sha256:100e33eeffcfa81f7c45cadeb0ee29596ce829f6b4d2745140f04fa19a41f539"},
{file = "aws_sam_translator-1.94.0.tar.gz", hash = "sha256:8ec258d9f7ece72ef91c81f4edb45a2db064c16844b6afac90c575893beaa391"},
@@ -336,8 +325,6 @@ version = "2.14.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."
optional = true
python-versions = ">=3.7"
-groups = ["main"]
-markers = "extra == \"tracer\" or extra == \"all\""
files = [
{file = "aws_xray_sdk-2.14.0-py2.py3-none-any.whl", hash = "sha256:cfbe6feea3d26613a2a869d14c9246a844285c97087ad8f296f901633554ad94"},
{file = "aws_xray_sdk-2.14.0.tar.gz", hash = "sha256:aab843c331af9ab9ba5cefb3a303832a19db186140894a523edafc024cc0493c"},
@@ -353,7 +340,6 @@ version = "2.16.0"
description = "Internationalization utilities"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"},
{file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"},
@@ -368,7 +354,6 @@ version = "1.8.2"
description = "Security oriented static analyser for python code."
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "bandit-1.8.2-py3-none-any.whl", hash = "sha256:df6146ad73dd30e8cbda4e29689ddda48364e36ff655dbfc86998401fcf1721f"},
{file = "bandit-1.8.2.tar.gz", hash = "sha256:e00ad5a6bc676c0954669fe13818024d66b70e42cf5adb971480cf3b671e835f"},
@@ -389,34 +374,33 @@ yaml = ["PyYAML"]
[[package]]
name = "black"
-version = "24.10.0"
+version = "25.1.0"
description = "The uncompromising code formatter."
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
-files = [
- {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"},
- {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"},
- {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"},
- {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"},
- {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"},
- {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"},
- {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"},
- {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"},
- {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"},
- {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"},
- {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"},
- {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"},
- {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"},
- {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"},
- {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"},
- {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"},
- {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"},
- {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"},
- {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"},
- {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"},
- {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"},
- {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"},
+files = [
+ {file = "black-25.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:759e7ec1e050a15f89b770cefbf91ebee8917aac5c20483bc2d80a6c3a04df32"},
+ {file = "black-25.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e519ecf93120f34243e6b0054db49c00a35f84f195d5bce7e9f5cfc578fc2da"},
+ {file = "black-25.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:055e59b198df7ac0b7efca5ad7ff2516bca343276c466be72eb04a3bcc1f82d7"},
+ {file = "black-25.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:db8ea9917d6f8fc62abd90d944920d95e73c83a5ee3383493e35d271aca872e9"},
+ {file = "black-25.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a39337598244de4bae26475f77dda852ea00a93bd4c728e09eacd827ec929df0"},
+ {file = "black-25.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96c1c7cd856bba8e20094e36e0f948718dc688dba4a9d78c3adde52b9e6c2299"},
+ {file = "black-25.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce2e264d59c91e52d8000d507eb20a9aca4a778731a08cfff7e5ac4a4bb7096"},
+ {file = "black-25.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:172b1dbff09f86ce6f4eb8edf9dede08b1fce58ba194c87d7a4f1a5aa2f5b3c2"},
+ {file = "black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b"},
+ {file = "black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc"},
+ {file = "black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f"},
+ {file = "black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba"},
+ {file = "black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f"},
+ {file = "black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3"},
+ {file = "black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171"},
+ {file = "black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18"},
+ {file = "black-25.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1ee0a0c330f7b5130ce0caed9936a904793576ef4d2b98c40835d6a65afa6a0"},
+ {file = "black-25.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3df5f1bf91d36002b0a75389ca8663510cf0531cca8aa5c1ef695b46d98655f"},
+ {file = "black-25.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9e6827d563a2c820772b32ce8a42828dc6790f095f441beef18f96aa6f8294e"},
+ {file = "black-25.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:bacabb307dca5ebaf9c118d2d2f6903da0d62c9faa82bd21a33eecc319559355"},
+ {file = "black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717"},
+ {file = "black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666"},
]
[package.dependencies]
@@ -436,18 +420,17 @@ uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "boto3"
-version = "1.36.7"
+version = "1.36.10"
description = "The AWS SDK for Python"
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
files = [
- {file = "boto3-1.36.7-py3-none-any.whl", hash = "sha256:ab501f75557863e2d2c9fa731e4fe25c45f35e0d92ea0ee11a4eaa63929d3ede"},
- {file = "boto3-1.36.7.tar.gz", hash = "sha256:ae98634efa7b47ced1b0d7342e2940b32639eee913f33ab406590b8ed55ee94b"},
+ {file = "boto3-1.36.10-py3-none-any.whl", hash = "sha256:5f8d5c2024a2d1411d3d67abb7357ec7d4c6162e3f1c396dc9b79d042cfd0a80"},
+ {file = "boto3-1.36.10.tar.gz", hash = "sha256:d2f1010db699326b26fbd465d91c4b49177c9d995d7e72c0f31335f139efa0d2"},
]
[package.dependencies]
-botocore = ">=1.36.7,<1.37.0"
+botocore = ">=1.36.10,<1.37.0"
jmespath = ">=0.7.1,<2.0.0"
s3transfer = ">=0.11.0,<0.12.0"
@@ -456,14 +439,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"]
[[package]]
name = "boto3-stubs"
-version = "1.36.7"
-description = "Type annotations for boto3 1.36.7 generated with mypy-boto3-builder 8.8.0"
+version = "1.36.16"
+description = "Type annotations for boto3 1.36.16 generated with mypy-boto3-builder 8.9.0"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
- {file = "boto3_stubs-1.36.7-py3-none-any.whl", hash = "sha256:d5d3f1f537c4d317f1f11b1cb4ce8f427822204936e29419b43c709ec54758ea"},
- {file = "boto3_stubs-1.36.7.tar.gz", hash = "sha256:197bdbacd3a9085c6310a06f21616f30f6103ed8be67705962620ac4587ba1fb"},
+ {file = "boto3_stubs-1.36.16-py3-none-any.whl", hash = "sha256:43ac9229ac239de16c37087a6fed145a1afda95c926cebfd4c292c29aab43720"},
+ {file = "boto3_stubs-1.36.16.tar.gz", hash = "sha256:9fe8b6dc3d6b33ccc4241bd7e281f11525a45743a6b0bf4da93554b9a47f07d1"},
]
[package.dependencies]
@@ -530,7 +512,7 @@ bedrock-data-automation-runtime = ["mypy-boto3-bedrock-data-automation-runtime (
bedrock-runtime = ["mypy-boto3-bedrock-runtime (>=1.36.0,<1.37.0)"]
billing = ["mypy-boto3-billing (>=1.36.0,<1.37.0)"]
billingconductor = ["mypy-boto3-billingconductor (>=1.36.0,<1.37.0)"]
-boto3 = ["boto3 (==1.36.7)"]
+boto3 = ["boto3 (==1.36.16)"]
braket = ["mypy-boto3-braket (>=1.36.0,<1.37.0)"]
budgets = ["mypy-boto3-budgets (>=1.36.0,<1.37.0)"]
ce = ["mypy-boto3-ce (>=1.36.0,<1.37.0)"]
@@ -893,37 +875,35 @@ xray = ["mypy-boto3-xray (>=1.36.0,<1.37.0)"]
[[package]]
name = "botocore"
-version = "1.36.7"
+version = "1.36.10"
description = "Low-level, data-driven core of boto 3."
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
files = [
- {file = "botocore-1.36.7-py3-none-any.whl", hash = "sha256:a6c6772d777af2957ac9975207fac1ccc4ce101408b85e9b5e3c5ba0bb949102"},
- {file = "botocore-1.36.7.tar.gz", hash = "sha256:9abc64bde5e7d8f814ea91d6fc0a8142511fc96427c19fe9209677c20a0c9e6e"},
+ {file = "botocore-1.36.10-py3-none-any.whl", hash = "sha256:45c8a6e01dc18d44a13ba688f1d60ad562db8154b08c46b412387ea040a741c2"},
+ {file = "botocore-1.36.10.tar.gz", hash = "sha256:d27bb73f0ea81395527a6298ac0a7ea5b2958094169f7cf7d48e3f4e4bc21b65"},
]
[package.dependencies]
jmespath = ">=0.7.1,<2.0.0"
python-dateutil = ">=2.1,<3.0.0"
urllib3 = [
- {version = ">=1.25.4,<1.27", markers = "python_version < \"3.10\""},
{version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""},
+ {version = ">=1.25.4,<1.27", markers = "python_version < \"3.10\""},
]
[package.extras]
-crt = ["awscrt (==0.23.4)"]
+crt = ["awscrt (==0.23.8)"]
[[package]]
name = "botocore-stubs"
-version = "1.36.7"
+version = "1.36.9"
description = "Type annotations and code completion for botocore"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
- {file = "botocore_stubs-1.36.7-py3-none-any.whl", hash = "sha256:77052e3a86a3f77383c638db63379652bafac3a2b310954392e0cfb3dacd3dad"},
- {file = "botocore_stubs-1.36.7.tar.gz", hash = "sha256:51c51da5379d3e4c4cb7e3dbe8451f572ecbfe6a5ced3a76a6b958941ef72409"},
+ {file = "botocore_stubs-1.36.9-py3-none-any.whl", hash = "sha256:76fc0651fc4e7d9a83de944d109f4d779a064265c5f243699718e1d06104efd9"},
+ {file = "botocore_stubs-1.36.9.tar.gz", hash = "sha256:786857fc9f4e11f16b62e0383b8d60a3a03a9ac10fe23d57d1fa726e77626535"},
]
[package.dependencies]
@@ -938,8 +918,6 @@ version = "0.16.1"
description = "Python module to generate and modify bytecode"
optional = true
python-versions = ">=3.8"
-groups = ["main"]
-markers = "extra == \"datadog\""
files = [
{file = "bytecode-0.16.1-py3-none-any.whl", hash = "sha256:1d4b61ed6bade4bff44127c8283bef8131a664ce4dbe09d64a88caf329939f35"},
{file = "bytecode-0.16.1.tar.gz", hash = "sha256:8fbbb637c880f339e564858bc6c7984ede67ae97bc71343379a535a9a4baf398"},
@@ -954,7 +932,6 @@ version = "24.1.2"
description = "Composable complex class support for attrs and dataclasses."
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "cattrs-24.1.2-py3-none-any.whl", hash = "sha256:67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0"},
{file = "cattrs-24.1.2.tar.gz", hash = "sha256:8028cfe1ff5382df59dd36474a86e02d817b06eaf8af84555441bac915d2ef85"},
@@ -977,14 +954,13 @@ ujson = ["ujson (>=5.7.0)"]
[[package]]
name = "cdk-nag"
-version = "2.35.2"
+version = "2.35.11"
description = "Check CDK v2 applications for best practices using a combination on available rule packs."
optional = false
python-versions = "~=3.8"
-groups = ["dev"]
files = [
- {file = "cdk_nag-2.35.2-py3-none-any.whl", hash = "sha256:5348d4595622d67f841bbd7a490f28fa9fa3ae59193381e43b508780785b1004"},
- {file = "cdk_nag-2.35.2.tar.gz", hash = "sha256:af58a7ef38784c1398f856136f76057e68f74837fcd3bb655b78b4fba379ca60"},
+ {file = "cdk_nag-2.35.11-py3-none-any.whl", hash = "sha256:9d3320035da387d8edf043fab6d671c958d38be42580821a2fb569091036c718"},
+ {file = "cdk_nag-2.35.11.tar.gz", hash = "sha256:7f9241bfb32f17b1079a3ecd3d0a0fbd773b4317ddc85952cb7fbfbc2d724fe8"},
]
[package.dependencies]
@@ -996,19 +972,18 @@ typeguard = ">=2.13.3,<4.3.0"
[[package]]
name = "cdklabs-generative-ai-cdk-constructs"
-version = "0.1.290"
+version = "0.1.292"
description = "AWS Generative AI CDK Constructs is a library for well-architected generative AI patterns."
optional = false
python-versions = "~=3.8"
-groups = ["dev"]
files = [
- {file = "cdklabs.generative_ai_cdk_constructs-0.1.290-py3-none-any.whl", hash = "sha256:3297a25ee2acbf6e70ee100a7e712023b076ea688820e53fa352b1c05a769cf0"},
- {file = "cdklabs_generative_ai_cdk_constructs-0.1.290.tar.gz", hash = "sha256:693f732e8552d28100b5da918a17cb19fd19b25b81040faf11688a24afbe42c0"},
+ {file = "cdklabs.generative_ai_cdk_constructs-0.1.292-py3-none-any.whl", hash = "sha256:ad154f14928c6d9f900e07964c844522837608e0fc5489c85f6f40e70af0d1e1"},
+ {file = "cdklabs_generative_ai_cdk_constructs-0.1.292.tar.gz", hash = "sha256:ccfdf292b3da036e920071d4555365cfc96fdbede85cbeee0c1acfbde8a89db4"},
]
[package.dependencies]
-aws-cdk-lib = ">=2.176.0,<3.0.0"
-cdk-nag = ">=2.35.0,<3.0.0"
+aws-cdk-lib = ">=2.177.0,<3.0.0"
+cdk-nag = ">=2.35.10,<3.0.0"
constructs = ">=10.3.0,<11.0.0"
jsii = ">=1.106.0,<2.0.0"
publication = ">=0.0.3"
@@ -1020,7 +995,6 @@ version = "2024.12.14"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
-groups = ["main", "dev"]
files = [
{file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"},
{file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"},
@@ -1032,7 +1006,6 @@ version = "1.17.1"
description = "Foreign Function Interface for Python calling C code."
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
files = [
{file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
{file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
@@ -1102,21 +1075,19 @@ files = [
{file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
{file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
]
-markers = {main = "(extra == \"all\" or extra == \"datamasking\") and platform_python_implementation != \"PyPy\"", dev = "platform_python_implementation != \"PyPy\""}
[package.dependencies]
pycparser = "*"
[[package]]
name = "cfn-lint"
-version = "1.22.7"
+version = "1.24.0"
description = "Checks CloudFormation templates for practices and behaviour that could potentially be improved"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
- {file = "cfn_lint-1.22.7-py3-none-any.whl", hash = "sha256:6ae732fd11cba6b01ce577fe4d985c407166010faf385eb5b30236916b02ad29"},
- {file = "cfn_lint-1.22.7.tar.gz", hash = "sha256:0cd99a217c3f197939b15dd0badfa49e90142d315c78e644f07bb8d943dd1b3e"},
+ {file = "cfn_lint-1.24.0-py3-none-any.whl", hash = "sha256:b8ca01ba384587aa7c0e09bf71cb4fa6993bd6da56498139f316e238f47d4eb8"},
+ {file = "cfn_lint-1.24.0.tar.gz", hash = "sha256:8b081808aa3a2f60abf9ef4ce05b1f270adab5b81124376f2f8e95c2fd767fb6"},
]
[package.dependencies]
@@ -1140,7 +1111,6 @@ version = "3.4.1"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
python-versions = ">=3.7"
-groups = ["main", "dev"]
files = [
{file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"},
{file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"},
@@ -1242,7 +1212,6 @@ version = "8.1.8"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.7"
-groups = ["dev"]
files = [
{file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"},
{file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"},
@@ -1257,7 +1226,6 @@ version = "0.4.6"
description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
-groups = ["dev"]
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
@@ -1269,7 +1237,6 @@ version = "6.9.0"
description = "Add colours to the output of Python's logging module."
optional = false
python-versions = ">=3.6"
-groups = ["dev"]
files = [
{file = "colorlog-6.9.0-py3-none-any.whl", hash = "sha256:5906e71acd67cb07a71e779c47c4bcb45fb8c2993eebe9e5adcd6a6f1b283eff"},
{file = "colorlog-6.9.0.tar.gz", hash = "sha256:bfba54a1b93b94f54e1f4fe48395725a3d92fd2a4af702f6bd70946bdc0c6ac2"},
@@ -1287,7 +1254,6 @@ version = "10.4.2"
description = "A programming model for software-defined state"
optional = false
python-versions = "~=3.8"
-groups = ["dev"]
files = [
{file = "constructs-10.4.2-py3-none-any.whl", hash = "sha256:1f0f59b004edebfde0f826340698b8c34611f57848139b7954904c61645f13c1"},
{file = "constructs-10.4.2.tar.gz", hash = "sha256:ce54724360fffe10bab27d8a081844eb81f5ace7d7c62c84b719c49f164d5307"},
@@ -1300,74 +1266,68 @@ typeguard = ">=2.13.3,<2.14.0"
[[package]]
name = "coverage"
-version = "7.6.10"
+version = "7.6.11"
description = "Code coverage measurement for Python"
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
-files = [
- {file = "coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78"},
- {file = "coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c"},
- {file = "coverage-7.6.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3b204c11e2b2d883946fe1d97f89403aa1811df28ce0447439178cc7463448a"},
- {file = "coverage-7.6.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32ee6d8491fcfc82652a37109f69dee9a830e9379166cb73c16d8dc5c2915165"},
- {file = "coverage-7.6.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675cefc4c06e3b4c876b85bfb7c59c5e2218167bbd4da5075cbe3b5790a28988"},
- {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f4f620668dbc6f5e909a0946a877310fb3d57aea8198bde792aae369ee1c23b5"},
- {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4eea95ef275de7abaef630c9b2c002ffbc01918b726a39f5a4353916ec72d2f3"},
- {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e2f0280519e42b0a17550072861e0bc8a80a0870de260f9796157d3fca2733c5"},
- {file = "coverage-7.6.10-cp310-cp310-win32.whl", hash = "sha256:bc67deb76bc3717f22e765ab3e07ee9c7a5e26b9019ca19a3b063d9f4b874244"},
- {file = "coverage-7.6.10-cp310-cp310-win_amd64.whl", hash = "sha256:0f460286cb94036455e703c66988851d970fdfd8acc2a1122ab7f4f904e4029e"},
- {file = "coverage-7.6.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3"},
- {file = "coverage-7.6.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43"},
- {file = "coverage-7.6.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132"},
- {file = "coverage-7.6.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f"},
- {file = "coverage-7.6.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994"},
- {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99"},
- {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd"},
- {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377"},
- {file = "coverage-7.6.10-cp311-cp311-win32.whl", hash = "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8"},
- {file = "coverage-7.6.10-cp311-cp311-win_amd64.whl", hash = "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609"},
- {file = "coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853"},
- {file = "coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078"},
- {file = "coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0"},
- {file = "coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50"},
- {file = "coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022"},
- {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b"},
- {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0"},
- {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852"},
- {file = "coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359"},
- {file = "coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247"},
- {file = "coverage-7.6.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9"},
- {file = "coverage-7.6.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b"},
- {file = "coverage-7.6.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690"},
- {file = "coverage-7.6.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18"},
- {file = "coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c"},
- {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd"},
- {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e"},
- {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694"},
- {file = "coverage-7.6.10-cp313-cp313-win32.whl", hash = "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6"},
- {file = "coverage-7.6.10-cp313-cp313-win_amd64.whl", hash = "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e"},
- {file = "coverage-7.6.10-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe"},
- {file = "coverage-7.6.10-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273"},
- {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8"},
- {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098"},
- {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb"},
- {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0"},
- {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf"},
- {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2"},
- {file = "coverage-7.6.10-cp313-cp313t-win32.whl", hash = "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312"},
- {file = "coverage-7.6.10-cp313-cp313t-win_amd64.whl", hash = "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d"},
- {file = "coverage-7.6.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:656c82b8a0ead8bba147de9a89bda95064874c91a3ed43a00e687f23cc19d53a"},
- {file = "coverage-7.6.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccc2b70a7ed475c68ceb548bf69cec1e27305c1c2606a5eb7c3afff56a1b3b27"},
- {file = "coverage-7.6.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5e37dc41d57ceba70956fa2fc5b63c26dba863c946ace9705f8eca99daecdc4"},
- {file = "coverage-7.6.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0aa9692b4fdd83a4647eeb7db46410ea1322b5ed94cd1715ef09d1d5922ba87f"},
- {file = "coverage-7.6.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa744da1820678b475e4ba3dfd994c321c5b13381d1041fe9c608620e6676e25"},
- {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0b1818063dc9e9d838c09e3a473c1422f517889436dd980f5d721899e66f315"},
- {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:59af35558ba08b758aec4d56182b222976330ef8d2feacbb93964f576a7e7a90"},
- {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7ed2f37cfce1ce101e6dffdfd1c99e729dd2ffc291d02d3e2d0af8b53d13840d"},
- {file = "coverage-7.6.10-cp39-cp39-win32.whl", hash = "sha256:4bcc276261505d82f0ad426870c3b12cb177752834a633e737ec5ee79bbdff18"},
- {file = "coverage-7.6.10-cp39-cp39-win_amd64.whl", hash = "sha256:457574f4599d2b00f7f637a0700a6422243b3565509457b2dbd3f50703e11f59"},
- {file = "coverage-7.6.10-pp39.pp310-none-any.whl", hash = "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f"},
- {file = "coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23"},
+files = [
+ {file = "coverage-7.6.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eafea49da254a8289bed3fab960f808b322eda5577cb17a3733014928bbfbebd"},
+ {file = "coverage-7.6.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5a3f7cbbcb4ad95067a6525f83a6fc78d9cbc1e70f8abaeeaeaa72ef34f48fc3"},
+ {file = "coverage-7.6.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de6b079b39246a7da9a40cfa62d5766bd52b4b7a88cf5a82ec4c45bf6e152306"},
+ {file = "coverage-7.6.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:60d4ad09dfc8c36c4910685faafcb8044c84e4dae302e86c585b3e2e7778726c"},
+ {file = "coverage-7.6.11-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e433b6e3a834a43dae2889adc125f3fa4c66668df420d8e49bc4ee817dd7a70"},
+ {file = "coverage-7.6.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ac5d92e2cc121a13270697e4cb37e1eb4511ac01d23fe1b6c097facc3b46489e"},
+ {file = "coverage-7.6.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5128f3ba694c0a1bde55fc480090392c336236c3e1a10dad40dc1ab17c7675ff"},
+ {file = "coverage-7.6.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:397489c611b76302dfa1d9ea079e138dddc4af80fc6819d5f5119ec8ca6c0e47"},
+ {file = "coverage-7.6.11-cp310-cp310-win32.whl", hash = "sha256:c7719a5e1dc93883a6b319bc0374ecd46fb6091ed659f3fbe281ab991634b9b0"},
+ {file = "coverage-7.6.11-cp310-cp310-win_amd64.whl", hash = "sha256:c27df03730059118b8a923cfc8b84b7e9976742560af528242f201880879c1da"},
+ {file = "coverage-7.6.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:532fe139691af134aa8b54ed60dd3c806aa81312d93693bd2883c7b61592c840"},
+ {file = "coverage-7.6.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0b0f272901a5172090c0802053fbc503cdc3fa2612720d2669a98a7384a7bec"},
+ {file = "coverage-7.6.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4bda710139ea646890d1c000feb533caff86904a0e0638f85e967c28cb8eec50"},
+ {file = "coverage-7.6.11-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a165b09e7d5f685bf659063334a9a7b1a2d57b531753d3e04bd442b3cfe5845b"},
+ {file = "coverage-7.6.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ff136607689c1c87f43d24203b6d2055b42030f352d5176f9c8b204d4235ef27"},
+ {file = "coverage-7.6.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:050172741de03525290e67f0161ae5f7f387c88fca50d47fceb4724ceaa591d2"},
+ {file = "coverage-7.6.11-cp311-cp311-win32.whl", hash = "sha256:27700d859be68e4fb2e7bf774cf49933dcac6f81a9bc4c13bd41735b8d26a53b"},
+ {file = "coverage-7.6.11-cp311-cp311-win_amd64.whl", hash = "sha256:cd4839813b09ab1dd1be1bbc74f9a7787615f931f83952b6a9af1b2d3f708bf7"},
+ {file = "coverage-7.6.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:dbb1a822fd858d9853333a7c95d4e70dde9a79e65893138ce32c2ec6457d7a36"},
+ {file = "coverage-7.6.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:61c834cbb80946d6ebfddd9b393a4c46bec92fcc0fa069321fcb8049117f76ea"},
+ {file = "coverage-7.6.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a46d56e99a31d858d6912d31ffa4ede6a325c86af13139539beefca10a1234ce"},
+ {file = "coverage-7.6.11-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b48db06f53d1864fea6dbd855e6d51d41c0f06c212c3004511c0bdc6847b297"},
+ {file = "coverage-7.6.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b6ff5be3b1853e0862da9d349fe87f869f68e63a25f7c37ce1130b321140f963"},
+ {file = "coverage-7.6.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be05bde21d5e6eefbc3a6de6b9bee2b47894b8945342e8663192809c4d1f08ce"},
+ {file = "coverage-7.6.11-cp312-cp312-win32.whl", hash = "sha256:e3b746fa0ffc5b6b8856529de487da8b9aeb4fb394bb58de6502ef45f3434f12"},
+ {file = "coverage-7.6.11-cp312-cp312-win_amd64.whl", hash = "sha256:ac476e6d0128fb7919b3fae726de72b28b5c9644cb4b579e4a523d693187c551"},
+ {file = "coverage-7.6.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c86f4c7a6d1a54a24d804d9684d96e36a62d3ef7c0d7745ae2ea39e3e0293251"},
+ {file = "coverage-7.6.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7eb0504bb307401fd08bc5163a351df301438b3beb88a4fa044681295bbefc67"},
+ {file = "coverage-7.6.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca95d40900cf614e07f00cee8c2fad0371df03ca4d7a80161d84be2ec132b7a4"},
+ {file = "coverage-7.6.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db4b1a69976b1b02acda15937538a1d3fe10b185f9d99920b17a740a0a102e06"},
+ {file = "coverage-7.6.11-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cf96beb05d004e4c51cd846fcdf9eee9eb2681518524b66b2e7610507944c2f"},
+ {file = "coverage-7.6.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:08e5fb93576a6b054d3d326242af5ef93daaac9bb52bc25f12ccbc3fa94227cd"},
+ {file = "coverage-7.6.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:25575cd5a7d2acc46b42711e8aff826027c0e4f80fb38028a74f31ac22aae69d"},
+ {file = "coverage-7.6.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8fa4fffd90ee92f62ff7404b4801b59e8ea8502e19c9bf2d3241ce745b52926c"},
+ {file = "coverage-7.6.11-cp313-cp313-win32.whl", hash = "sha256:0d03c9452d9d1ccfe5d3a5df0427705022a49b356ac212d529762eaea5ef97b4"},
+ {file = "coverage-7.6.11-cp313-cp313-win_amd64.whl", hash = "sha256:fd2fffc8ce8692ce540103dff26279d2af22d424516ddebe2d7e4d6dbb3816b2"},
+ {file = "coverage-7.6.11-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:5e7ac966ab110bd94ee844f2643f196d78fde1cd2450399116d3efdd706e19f5"},
+ {file = "coverage-7.6.11-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ba27a0375c5ef4d2a7712f829265102decd5ff78b96d342ac2fa555742c4f4f"},
+ {file = "coverage-7.6.11-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2778be4f574b39ec9dcd9e5e13644f770351ee0990a0ecd27e364aba95af89b"},
+ {file = "coverage-7.6.11-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5edc16712187139ab635a2e644cc41fc239bc6d245b16124045743130455c652"},
+ {file = "coverage-7.6.11-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df6ff122a0a10a30121d9f0cb3fbd03a6fe05861e4ec47adb9f25e9245aabc19"},
+ {file = "coverage-7.6.11-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ff562952f15eff27247a4c4b03e45ce8a82e3fb197de6a7c54080f9d4ba07845"},
+ {file = "coverage-7.6.11-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4f21e3617f48d683f30cf2a6c8b739c838e600cb1454fe6b2eb486ac2bce8fbd"},
+ {file = "coverage-7.6.11-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6d60577673ba48d8ae8e362e61fd4ad1a640293ffe8991d11c86f195479100b7"},
+ {file = "coverage-7.6.11-cp313-cp313t-win32.whl", hash = "sha256:13100f98497086b359bf56fc035a762c674de8ef526daa389ac8932cb9bff1e0"},
+ {file = "coverage-7.6.11-cp313-cp313t-win_amd64.whl", hash = "sha256:2c81e53782043b323bd34c7de711ed9b4673414eb517eaf35af92185b873839c"},
+ {file = "coverage-7.6.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ff52b4e2ac0080c96e506819586c4b16cdbf46724bda90d308a7330a73cc8521"},
+ {file = "coverage-7.6.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f4679fcc9eb9004fdd1b00231ef1ec7167168071bebc4d66327e28c1979b4449"},
+ {file = "coverage-7.6.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:90de4e9ca4489e823138bd13098af9ac8028cc029f33f60098b5c08c675c7bda"},
+ {file = "coverage-7.6.11-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c96a142057d83ee993eaf71629ca3fb952cda8afa9a70af4132950c2bd3deb9"},
+ {file = "coverage-7.6.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:476f29a258b9cd153f2be5bf5f119d670d2806363595263917bddc167d6e5cce"},
+ {file = "coverage-7.6.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:09d03f48d9025b8a6a116cddcb6c7b8ce80e4fb4c31dd2e124a7c377036ad58e"},
+ {file = "coverage-7.6.11-cp39-cp39-win32.whl", hash = "sha256:bb35ae9f134fbd9cf7302a9654d5a1e597c974202678082dcc569eb39a8cde03"},
+ {file = "coverage-7.6.11-cp39-cp39-win_amd64.whl", hash = "sha256:f382004fa4c93c01016d9226b9d696a08c53f6818b7ad59b4e96cb67e863353a"},
+ {file = "coverage-7.6.11-pp39.pp310-none-any.whl", hash = "sha256:adc2d941c0381edfcf3897f94b9f41b1e504902fab78a04b1677f2f72afead4b"},
+ {file = "coverage-7.6.11-py3-none-any.whl", hash = "sha256:f0f334ae844675420164175bf32b04e18a81fe57ad8eb7e0cfd4689d681ffed7"},
+ {file = "coverage-7.6.11.tar.gz", hash = "sha256:e642e6a46a04e992ebfdabed79e46f478ec60e2c528e1e1a074d63800eda4286"},
]
[package.dependencies]
@@ -1382,7 +1342,6 @@ version = "43.0.3"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
optional = false
python-versions = ">=3.7"
-groups = ["main", "dev"]
files = [
{file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"},
{file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"},
@@ -1412,7 +1371,6 @@ files = [
{file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"},
{file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"},
]
-markers = {main = "extra == \"all\" or extra == \"datamasking\""}
[package.dependencies]
cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
@@ -1433,8 +1391,6 @@ version = "0.51.0"
description = "The Datadog Python library"
optional = true
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
-groups = ["main"]
-markers = "extra == \"datadog\""
files = [
{file = "datadog-0.51.0-py2.py3-none-any.whl", hash = "sha256:a9764f091c96af4e0996d4400b168fc5fba380f911d6d672c9dcd4773e29ea3f"},
{file = "datadog-0.51.0.tar.gz", hash = "sha256:3279534f831ae0b4ae2d8ce42ef038b4ab38e667d7ed6ff7437982d7a0cf5250"},
@@ -1445,20 +1401,18 @@ requests = ">=2.6.0"
[[package]]
name = "datadog-lambda"
-version = "6.104.0"
+version = "6.105.0"
description = "The Datadog AWS Lambda Library"
optional = true
python-versions = "<4,>=3.8.0"
-groups = ["main"]
-markers = "extra == \"datadog\""
files = [
- {file = "datadog_lambda-6.104.0-py3-none-any.whl", hash = "sha256:72092f9057764515ef1e2fdf1cf25f82bfa70296411af9121db896e4a35fdf6e"},
- {file = "datadog_lambda-6.104.0.tar.gz", hash = "sha256:eeb2ff0e4387812e7caf17e501d93fea3d85e3f9bb79581fb37556580d5a1c46"},
+ {file = "datadog_lambda-6.105.0-py3-none-any.whl", hash = "sha256:447d13b6f4971da8aa1227e554a1c2f8985b62aaacbb182bc093a7e048cd1fc4"},
+ {file = "datadog_lambda-6.105.0.tar.gz", hash = "sha256:59d7900b2136e14441dc29de4ff778301d2c8175cc26caf3819c648293357fbb"},
]
[package.dependencies]
-datadog = ">=0.41.0,<1.0.0"
-ddtrace = ">=2.17.0"
+datadog = ">=0.51.0,<1.0.0"
+ddtrace = ">=2.20.0"
ujson = ">=5.9.0"
wrapt = ">=1.11.2,<2.0.0"
@@ -1471,8 +1425,6 @@ version = "2.20.0"
description = "Datadog APM client library"
optional = true
python-versions = ">=3.7"
-groups = ["main"]
-markers = "extra == \"datadog\""
files = [
{file = "ddtrace-2.20.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:e1dee099099b95acf7d0e552179925cfec58a52315cc914d153506367b195bc4"},
{file = "ddtrace-2.20.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:9d209bef14caafcd53be8c14e04741d86c08f76496c1bf755e2eaa38605ce3e0"},
@@ -1546,10 +1498,10 @@ files = [
[package.dependencies]
bytecode = [
- {version = ">=0.13.0", markers = "python_version < \"3.11.0\""},
{version = ">=0.16.0", markers = "python_version >= \"3.13.0\""},
{version = ">=0.15.0", markers = "python_version ~= \"3.12.0\""},
{version = ">=0.14.0", markers = "python_version ~= \"3.11.0\""},
+ {version = ">=0.13.0", markers = "python_version < \"3.11.0\""},
]
envier = ">=0.5,<1.0"
legacy-cgi = {version = ">=2.0.0", markers = "python_version >= \"3.13.0\""}
@@ -1569,7 +1521,6 @@ version = "5.1.1"
description = "Decorators for Humans"
optional = false
python-versions = ">=3.5"
-groups = ["dev"]
files = [
{file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
{file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
@@ -1581,8 +1532,6 @@ version = "1.2.18"
description = "Python @deprecated decorator to deprecate old python classes, functions or methods."
optional = true
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
-groups = ["main"]
-markers = "extra == \"datadog\""
files = [
{file = "Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec"},
{file = "deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d"},
@@ -1600,7 +1549,6 @@ version = "0.3.9"
description = "serialize all of Python"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"},
{file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"},
@@ -1616,7 +1564,6 @@ version = "0.5.0"
description = "Python module and CLI for hashing of file system directories."
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "dirhash-0.5.0-py3-none-any.whl", hash = "sha256:523dfd6b058c64f45b31604376926c6e2bd2ea301d0df23095d4055674e38b09"},
{file = "dirhash-0.5.0.tar.gz", hash = "sha256:e60760f0ab2e935d8cb088923ea2c6492398dca42cec785df778985fd4cd5386"},
@@ -1631,7 +1578,6 @@ version = "0.3.9"
description = "Distribution utilities"
optional = false
python-versions = "*"
-groups = ["dev"]
files = [
{file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"},
{file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"},
@@ -1643,7 +1589,6 @@ version = "7.1.0"
description = "A Python library for the Docker Engine API."
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0"},
{file = "docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c"},
@@ -1666,8 +1611,6 @@ version = "0.6.1"
description = "Python application configuration via the environment"
optional = true
python-versions = ">=3.7"
-groups = ["main"]
-markers = "extra == \"datadog\""
files = [
{file = "envier-0.6.1-py3-none-any.whl", hash = "sha256:73609040a76be48bbcb97074d9969666484aa0de706183a6e9ef773156a8a6a9"},
{file = "envier-0.6.1.tar.gz", hash = "sha256:3309a01bb3d8850c9e7a31a5166d5a836846db2faecb79b9cb32654dd50ca9f9"},
@@ -1682,8 +1625,6 @@ version = "1.2.2"
description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
-groups = ["dev"]
-markers = "python_version < \"3.11.0\""
files = [
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
@@ -1698,7 +1639,6 @@ version = "2.1.1"
description = "execnet: rapid multi-Python deployment"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"},
{file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"},
@@ -1713,8 +1653,6 @@ version = "2.21.1"
description = "Fastest Python implementation of JSON schema"
optional = true
python-versions = "*"
-groups = ["main"]
-markers = "extra == \"validation\" or extra == \"all\""
files = [
{file = "fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667"},
{file = "fastjsonschema-2.21.1.tar.gz", hash = "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4"},
@@ -1723,13 +1661,27 @@ files = [
[package.extras]
devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"]
+[[package]]
+name = "fhconfparser"
+version = "2024.1"
+description = "Provides a config language independent way to read a config file."
+optional = false
+python-versions = ">=3.8,<4.0"
+files = [
+ {file = "fhconfparser-2024.1-py3-none-any.whl", hash = "sha256:f6048cb646e69a3422a581bc0102150c2b79fe7ff26b82233e5ef52f72820e3e"},
+ {file = "fhconfparser-2024.1.tar.gz", hash = "sha256:de8af019f0071e614d523985e1d93e0fce20a409d1c64dead03b1b665d4b2e4d"},
+]
+
+[package.dependencies]
+attrs = ">=23.2.0,<24"
+tomli = ">=2.0.1,<3"
+
[[package]]
name = "filelock"
version = "3.17.0"
description = "A platform independent file lock."
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338"},
{file = "filelock-3.17.0.tar.gz", hash = "sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e"},
@@ -1746,7 +1698,6 @@ version = "2.1.0"
description = "Copy your docs directly to the gh-pages branch."
optional = false
python-versions = "*"
-groups = ["dev"]
files = [
{file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"},
{file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"},
@@ -1764,7 +1715,6 @@ version = "4.0.12"
description = "Git Object Database"
optional = false
python-versions = ">=3.7"
-groups = ["dev"]
files = [
{file = "gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf"},
{file = "gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571"},
@@ -1779,7 +1729,6 @@ version = "3.1.44"
description = "GitPython is a Python library used to interact with Git repositories"
optional = false
python-versions = ">=3.7"
-groups = ["dev"]
files = [
{file = "GitPython-3.1.44-py3-none-any.whl", hash = "sha256:9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110"},
{file = "gitpython-3.1.44.tar.gz", hash = "sha256:c87e30b26253bf5418b01b0660f818967f3c503193838337fe5e573331249269"},
@@ -1792,13 +1741,26 @@ gitdb = ">=4.0.1,<5"
doc = ["sphinx (>=7.1.2,<7.2)", "sphinx-autodoc-typehints", "sphinx_rtd_theme"]
test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions"]
+[[package]]
+name = "griffe"
+version = "1.5.6"
+description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API."
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "griffe-1.5.6-py3-none-any.whl", hash = "sha256:b2a3afe497c6c1f952e54a23095ecc09435016293e77af8478ed65df1022a394"},
+ {file = "griffe-1.5.6.tar.gz", hash = "sha256:181f6666d5aceb6cd6e2da5a2b646cfb431e47a0da1fda283845734b67e10944"},
+]
+
+[package.dependencies]
+colorama = ">=0.4"
+
[[package]]
name = "h11"
version = "0.14.0"
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
optional = false
python-versions = ">=3.7"
-groups = ["dev"]
files = [
{file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
@@ -1810,7 +1772,6 @@ version = "1.0.7"
description = "A minimal low-level HTTP client."
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"},
{file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"},
@@ -1832,7 +1793,6 @@ version = "0.28.1"
description = "The next generation HTTP client."
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"},
{file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"},
@@ -1857,7 +1817,6 @@ version = "2.3.0"
description = "HashiCorp Vault API client"
optional = false
python-versions = "<4.0,>=3.8"
-groups = ["dev"]
files = [
{file = "hvac-2.3.0-py3-none-any.whl", hash = "sha256:a3afc5710760b6ee9b3571769df87a0333da45da05a5f9f963e1d3925a84be7d"},
{file = "hvac-2.3.0.tar.gz", hash = "sha256:1b85e3320e8642dd82f234db63253cda169a817589e823713dc5fca83119b1e2"},
@@ -1875,7 +1834,6 @@ version = "3.10"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.6"
-groups = ["main", "dev"]
files = [
{file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
{file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
@@ -1890,7 +1848,6 @@ version = "3.3.0"
description = "Iterative JSON parser with standard Python iterator interfaces"
optional = false
python-versions = "*"
-groups = ["dev"]
files = [
{file = "ijson-3.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7f7a5250599c366369fbf3bc4e176f5daa28eb6bc7d6130d02462ed335361675"},
{file = "ijson-3.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f87a7e52f79059f9c58f6886c262061065eb6f7554a587be7ed3aa63e6b71b34"},
@@ -1994,7 +1951,6 @@ version = "8.6.1"
description = "Read metadata from Python packages"
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"},
{file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"},
@@ -2018,7 +1974,6 @@ version = "6.5.2"
description = "Read resources from Python packages"
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec"},
{file = "importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c"},
@@ -2041,7 +1996,6 @@ version = "2.0.0"
description = "brain-dead simple config-ini parsing"
optional = false
python-versions = ">=3.7"
-groups = ["dev"]
files = [
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
@@ -2049,18 +2003,18 @@ files = [
[[package]]
name = "isort"
-version = "5.13.2"
+version = "6.0.0"
description = "A Python utility / library to sort Python imports."
optional = false
-python-versions = ">=3.8.0"
-groups = ["dev"]
+python-versions = ">=3.9.0"
files = [
- {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
- {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
+ {file = "isort-6.0.0-py3-none-any.whl", hash = "sha256:567954102bb47bb12e0fae62606570faacddd441e45683968c8d1734fb1af892"},
+ {file = "isort-6.0.0.tar.gz", hash = "sha256:75d9d8a1438a9432a7d7b54f2d3b45cad9a4a0fdba43617d9873379704a8bdf1"},
]
[package.extras]
-colors = ["colorama (>=0.4.6)"]
+colors = ["colorama"]
+plugins = ["setuptools"]
[[package]]
name = "jinja2"
@@ -2068,7 +2022,6 @@ version = "3.1.5"
description = "A very fast and expressive template engine."
optional = false
python-versions = ">=3.7"
-groups = ["dev"]
files = [
{file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"},
{file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"},
@@ -2086,7 +2039,6 @@ version = "1.0.1"
description = "JSON Matching Expressions"
optional = false
python-versions = ">=3.7"
-groups = ["main", "dev"]
files = [
{file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"},
{file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"},
@@ -2098,7 +2050,6 @@ version = "1.106.0"
description = "Python client for jsii runtime"
optional = false
python-versions = "~=3.8"
-groups = ["dev"]
files = [
{file = "jsii-1.106.0-py3-none-any.whl", hash = "sha256:5a44d7c3a5a326fa3d9befdb3770b380057e0a61e3804e7c4907f70d76afaaa2"},
{file = "jsii-1.106.0.tar.gz", hash = "sha256:c79c47899f53a7c3c4b20f80d3cd306628fe9ed1852eee970324c71eba1d974e"},
@@ -2119,7 +2070,6 @@ version = "1.33"
description = "Apply JSON-Patches (RFC 6902)"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*"
-groups = ["dev"]
files = [
{file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"},
{file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"},
@@ -2134,10 +2084,10 @@ version = "1.7.0"
description = "A final implementation of JSONPath for Python that aims to be standard compliant, including arithmetic and binary comparison operators and providing clear AST for metaprogramming."
optional = true
python-versions = "*"
-groups = ["main"]
-markers = "extra == \"all\" or extra == \"datamasking\""
files = [
{file = "jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c"},
+ {file = "jsonpath_ng-1.7.0-py2-none-any.whl", hash = "sha256:898c93fc173f0c336784a3fa63d7434297544b7198124a68f9a3ef9597b0ae6e"},
+ {file = "jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6"},
]
[package.dependencies]
@@ -2149,7 +2099,6 @@ version = "3.0.0"
description = "Identify specific nodes in a JSON document (RFC 6901)"
optional = false
python-versions = ">=3.7"
-groups = ["dev"]
files = [
{file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"},
{file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"},
@@ -2161,7 +2110,6 @@ version = "4.23.0"
description = "An implementation of JSON Schema validation for Python"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"},
{file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"},
@@ -2183,7 +2131,6 @@ version = "2024.10.1"
description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"},
{file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"},
@@ -2198,32 +2145,52 @@ version = "2.6.2"
description = "Fork of the standard library cgi and cgitb modules, being deprecated in PEP-594"
optional = true
python-versions = ">=3.10"
-groups = ["main"]
-markers = "extra == \"datadog\" and python_version >= \"3.13.0\""
files = [
{file = "legacy_cgi-2.6.2-py3-none-any.whl", hash = "sha256:a7b83afb1baf6ebeb56522537c5943ef9813cf933f6715e88a803f7edbce0bff"},
{file = "legacy_cgi-2.6.2.tar.gz", hash = "sha256:9952471ceb304043b104c22d00b4f333cac27a6abe446d8a528fc437cf13c85f"},
]
[[package]]
-name = "mako"
-version = "1.3.8"
-description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
+name = "licensecheck"
+version = "2024.3"
+description = "Output the licenses used by dependencies and check if these are compatible with the project license"
optional = false
-python-versions = ">=3.8"
-groups = ["dev"]
+python-versions = "<4.0,>=3.8"
+files = [
+ {file = "licensecheck-2024.3-py3-none-any.whl", hash = "sha256:0baef4c1865e0325a35ff25ed12a0c7094035b7dcfbab9a1abfe43d7735adebe"},
+ {file = "licensecheck-2024.3.tar.gz", hash = "sha256:e838e1c87a7ede553df376ad35a69d7c4b02676df0fba9dd1c6a6866eb0e0ee5"},
+]
+
+[package.dependencies]
+appdirs = ">=1.4.4,<2"
+fhconfparser = ">=2024.1,<2026"
+loguru = ">=0.7.2,<2"
+markdown = ">=3.6,<4"
+packaging = ">=24.0,<25"
+requests = ">=2.31.0,<3"
+requests-cache = ">=1.2.0,<2"
+requirements-parser = ">=0.11.0,<2"
+rich = ">=13.7.1,<14"
+tomli = ">=2.0.1,<3"
+uv = ">=0.3.3,<2"
+
+[[package]]
+name = "loguru"
+version = "0.7.3"
+description = "Python logging made (stupidly) simple"
+optional = false
+python-versions = "<4.0,>=3.5"
files = [
- {file = "Mako-1.3.8-py3-none-any.whl", hash = "sha256:42f48953c7eb91332040ff567eb7eea69b22e7a4affbc5ba8e845e8f730f6627"},
- {file = "mako-1.3.8.tar.gz", hash = "sha256:577b97e414580d3e088d47c2dbbe9594aa7a5146ed2875d4dfa9075af2dd3cc8"},
+ {file = "loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c"},
+ {file = "loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6"},
]
[package.dependencies]
-MarkupSafe = ">=0.9.2"
+colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""}
+win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""}
[package.extras]
-babel = ["Babel"]
-lingua = ["lingua"]
-testing = ["pytest"]
+dev = ["Sphinx (==8.1.3)", "build (==1.2.2)", "colorama (==0.4.5)", "colorama (==0.4.6)", "exceptiongroup (==1.1.3)", "freezegun (==1.1.0)", "freezegun (==1.5.0)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v1.13.0)", "mypy (==v1.4.1)", "myst-parser (==4.0.0)", "pre-commit (==4.0.1)", "pytest (==6.1.2)", "pytest (==8.3.2)", "pytest-cov (==2.12.1)", "pytest-cov (==5.0.0)", "pytest-cov (==6.0.0)", "pytest-mypy-plugins (==1.9.3)", "pytest-mypy-plugins (==3.1.0)", "sphinx-rtd-theme (==3.0.2)", "tox (==3.27.1)", "tox (==4.23.2)", "twine (==6.0.1)"]
[[package]]
name = "mando"
@@ -2231,7 +2198,6 @@ version = "0.7.1"
description = "Create Python CLI apps with little to no effort at all!"
optional = false
python-versions = "*"
-groups = ["dev"]
files = [
{file = "mando-0.7.1-py2.py3-none-any.whl", hash = "sha256:26ef1d70928b6057ee3ca12583d73c63e05c49de8972d620c278a7b206581a8a"},
{file = "mando-0.7.1.tar.gz", hash = "sha256:18baa999b4b613faefb00eac4efadcf14f510b59b924b66e08289aa1de8c3500"},
@@ -2249,7 +2215,6 @@ version = "3.7"
description = "Python implementation of John Gruber's Markdown."
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"},
{file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"},
@@ -2268,7 +2233,6 @@ version = "3.0.0"
description = "Python port of markdown-it. Markdown parsing, done right!"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
{file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
@@ -2293,7 +2257,6 @@ version = "3.0.2"
description = "Safely add untrusted strings to HTML/XML markup."
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"},
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"},
@@ -2364,7 +2327,6 @@ version = "0.1.2"
description = "Markdown URL utilities"
optional = false
python-versions = ">=3.7"
-groups = ["dev"]
files = [
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
@@ -2376,7 +2338,6 @@ version = "1.3.4"
description = "A deep merge function for 🐍."
optional = false
python-versions = ">=3.6"
-groups = ["dev"]
files = [
{file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"},
{file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"},
@@ -2388,7 +2349,6 @@ version = "2.1.3"
description = "Manage multiple versions of your MkDocs-powered documentation"
optional = false
python-versions = "*"
-groups = ["dev"]
files = [
{file = "mike-2.1.3-py3-none-any.whl", hash = "sha256:d90c64077e84f06272437b464735130d380703a76a5738b152932884c60c062a"},
{file = "mike-2.1.3.tar.gz", hash = "sha256:abd79b8ea483fb0275b7972825d3082e5ae67a41820f8d8a0dc7a3f49944e810"},
@@ -2414,7 +2374,6 @@ version = "1.6.1"
description = "Project documentation with Markdown."
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e"},
{file = "mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2"},
@@ -2440,13 +2399,28 @@ watchdog = ">=2.0"
i18n = ["babel (>=2.9.0)"]
min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.4)", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"]
+[[package]]
+name = "mkdocs-autorefs"
+version = "1.3.0"
+description = "Automatically link across pages in MkDocs."
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "mkdocs_autorefs-1.3.0-py3-none-any.whl", hash = "sha256:d180f9778a04e78b7134e31418f238bba56f56d6a8af97873946ff661befffb3"},
+ {file = "mkdocs_autorefs-1.3.0.tar.gz", hash = "sha256:6867764c099ace9025d6ac24fd07b85a98335fbd30107ef01053697c8f46db61"},
+]
+
+[package.dependencies]
+Markdown = ">=3.3"
+markupsafe = ">=2.0.1"
+mkdocs = ">=1.1"
+
[[package]]
name = "mkdocs-get-deps"
version = "0.2.0"
description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"},
{file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"},
@@ -2464,7 +2438,6 @@ version = "0.3.2"
description = "MkDocs plugin for setting revision date from git per markdown file."
optional = false
python-versions = ">=3.4"
-groups = ["dev"]
files = [
{file = "mkdocs_git_revision_date_plugin-0.3.2-py3-none-any.whl", hash = "sha256:2e67956cb01823dd2418e2833f3623dee8604cdf223bddd005fe36226a56f6ef"},
]
@@ -2476,14 +2449,13 @@ mkdocs = ">=0.17"
[[package]]
name = "mkdocs-material"
-version = "9.5.50"
+version = "9.6.3"
description = "Documentation that simply works"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
- {file = "mkdocs_material-9.5.50-py3-none-any.whl", hash = "sha256:f24100f234741f4d423a9d672a909d859668a4f404796be3cf035f10d6050385"},
- {file = "mkdocs_material-9.5.50.tar.gz", hash = "sha256:ae5fe16f3d7c9ccd05bb6916a7da7420cf99a9ce5e33debd9d40403a090d5825"},
+ {file = "mkdocs_material-9.6.3-py3-none-any.whl", hash = "sha256:1125622067e26940806701219303b27c0933e04533560725d97ec26fd16a39cf"},
+ {file = "mkdocs_material-9.6.3.tar.gz", hash = "sha256:c87f7d1c39ce6326da5e10e232aed51bae46252e646755900f4b0fc9192fa832"},
]
[package.dependencies]
@@ -2510,19 +2482,61 @@ version = "1.3.1"
description = "Extension pack for Python Markdown and MkDocs Material."
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"},
{file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"},
]
+[[package]]
+name = "mkdocstrings"
+version = "0.28.0"
+description = "Automatic documentation from sources, for MkDocs."
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "mkdocstrings-0.28.0-py3-none-any.whl", hash = "sha256:84cf3dc910614781fe0fee46ce8006fde7df6cc7cca2e3f799895fb8a9170b39"},
+ {file = "mkdocstrings-0.28.0.tar.gz", hash = "sha256:df20afef1eafe36ba466ae20732509ecb74237653a585f5061937e54b553b4e0"},
+]
+
+[package.dependencies]
+importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""}
+Jinja2 = ">=2.11.1"
+Markdown = ">=3.6"
+MarkupSafe = ">=1.1"
+mkdocs = ">=1.4"
+mkdocs-autorefs = ">=1.3"
+mkdocs-get-deps = ">=0.2"
+pymdown-extensions = ">=6.3"
+typing-extensions = {version = ">=4.1", markers = "python_version < \"3.10\""}
+
+[package.extras]
+crystal = ["mkdocstrings-crystal (>=0.3.4)"]
+python = ["mkdocstrings-python (>=0.5.2)"]
+python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"]
+
+[[package]]
+name = "mkdocstrings-python"
+version = "1.14.6"
+description = "A Python handler for mkdocstrings."
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "mkdocstrings_python-1.14.6-py3-none-any.whl", hash = "sha256:e0ca11b49ac0f23070afb566245f4ff80ea1700e03c9dbc143d70dbf1cae074e"},
+ {file = "mkdocstrings_python-1.14.6.tar.gz", hash = "sha256:3fb6589491614422d781dacca085c0c5a53a7063af37a2fea5864e24e378b03e"},
+]
+
+[package.dependencies]
+griffe = ">=0.49"
+mkdocs-autorefs = ">=1.2"
+mkdocstrings = ">=0.28"
+typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""}
+
[[package]]
name = "mpmath"
version = "1.3.0"
description = "Python library for arbitrary-precision floating-point arithmetic"
optional = false
python-versions = "*"
-groups = ["dev"]
files = [
{file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"},
{file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"},
@@ -2540,7 +2554,6 @@ version = "0.70.17"
description = "better multiprocessing and multithreading in Python"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "multiprocess-0.70.17-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7ddb24e5bcdb64e90ec5543a1f05a39463068b6d3b804aa3f2a4e16ec28562d6"},
{file = "multiprocess-0.70.17-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d729f55198a3579f6879766a6d9b72b42d4b320c0dcb7844afb774d75b573c62"},
@@ -2565,50 +2578,43 @@ dill = ">=0.3.9"
[[package]]
name = "mypy"
-version = "1.14.1"
+version = "1.15.0"
description = "Optional static typing for Python"
optional = false
-python-versions = ">=3.8"
-groups = ["dev"]
-files = [
- {file = "mypy-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52686e37cf13d559f668aa398dd7ddf1f92c5d613e4f8cb262be2fb4fedb0fcb"},
- {file = "mypy-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1fb545ca340537d4b45d3eecdb3def05e913299ca72c290326be19b3804b39c0"},
- {file = "mypy-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90716d8b2d1f4cd503309788e51366f07c56635a3309b0f6a32547eaaa36a64d"},
- {file = "mypy-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ae753f5c9fef278bcf12e1a564351764f2a6da579d4a81347e1d5a15819997b"},
- {file = "mypy-1.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0fe0f5feaafcb04505bcf439e991c6d8f1bf8b15f12b05feeed96e9e7bf1427"},
- {file = "mypy-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:7d54bd85b925e501c555a3227f3ec0cfc54ee8b6930bd6141ec872d1c572f81f"},
- {file = "mypy-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f995e511de847791c3b11ed90084a7a0aafdc074ab88c5a9711622fe4751138c"},
- {file = "mypy-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d64169ec3b8461311f8ce2fd2eb5d33e2d0f2c7b49116259c51d0d96edee48d1"},
- {file = "mypy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba24549de7b89b6381b91fbc068d798192b1b5201987070319889e93038967a8"},
- {file = "mypy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:183cf0a45457d28ff9d758730cd0210419ac27d4d3f285beda038c9083363b1f"},
- {file = "mypy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f2a0ecc86378f45347f586e4163d1769dd81c5a223d577fe351f26b179e148b1"},
- {file = "mypy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:ad3301ebebec9e8ee7135d8e3109ca76c23752bac1e717bc84cd3836b4bf3eae"},
- {file = "mypy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30ff5ef8519bbc2e18b3b54521ec319513a26f1bba19a7582e7b1f58a6e69f14"},
- {file = "mypy-1.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb9f255c18052343c70234907e2e532bc7e55a62565d64536dbc7706a20b78b9"},
- {file = "mypy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b4e3413e0bddea671012b063e27591b953d653209e7a4fa5e48759cda77ca11"},
- {file = "mypy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:553c293b1fbdebb6c3c4030589dab9fafb6dfa768995a453d8a5d3b23784af2e"},
- {file = "mypy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fad79bfe3b65fe6a1efaed97b445c3d37f7be9fdc348bdb2d7cac75579607c89"},
- {file = "mypy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:8fa2220e54d2946e94ab6dbb3ba0a992795bd68b16dc852db33028df2b00191b"},
- {file = "mypy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:92c3ed5afb06c3a8e188cb5da4984cab9ec9a77ba956ee419c68a388b4595255"},
- {file = "mypy-1.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbec574648b3e25f43d23577309b16534431db4ddc09fda50841f1e34e64ed34"},
- {file = "mypy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c6d94b16d62eb3e947281aa7347d78236688e21081f11de976376cf010eb31a"},
- {file = "mypy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4b19b03fdf54f3c5b2fa474c56b4c13c9dbfb9a2db4370ede7ec11a2c5927d9"},
- {file = "mypy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0c911fde686394753fff899c409fd4e16e9b294c24bfd5e1ea4675deae1ac6fd"},
- {file = "mypy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8b21525cb51671219f5307be85f7e646a153e5acc656e5cebf64bfa076c50107"},
- {file = "mypy-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7084fb8f1128c76cd9cf68fe5971b37072598e7c31b2f9f95586b65c741a9d31"},
- {file = "mypy-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8f845a00b4f420f693f870eaee5f3e2692fa84cc8514496114649cfa8fd5e2c6"},
- {file = "mypy-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44bf464499f0e3a2d14d58b54674dee25c031703b2ffc35064bd0df2e0fac319"},
- {file = "mypy-1.14.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c99f27732c0b7dc847adb21c9d47ce57eb48fa33a17bc6d7d5c5e9f9e7ae5bac"},
- {file = "mypy-1.14.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:bce23c7377b43602baa0bd22ea3265c49b9ff0b76eb315d6c34721af4cdf1d9b"},
- {file = "mypy-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:8edc07eeade7ebc771ff9cf6b211b9a7d93687ff892150cb5692e4f4272b0837"},
- {file = "mypy-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3888a1816d69f7ab92092f785a462944b3ca16d7c470d564165fe703b0970c35"},
- {file = "mypy-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46c756a444117c43ee984bd055db99e498bc613a70bbbc120272bd13ca579fbc"},
- {file = "mypy-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:27fc248022907e72abfd8e22ab1f10e903915ff69961174784a3900a8cba9ad9"},
- {file = "mypy-1.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:499d6a72fb7e5de92218db961f1a66d5f11783f9ae549d214617edab5d4dbdbb"},
- {file = "mypy-1.14.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57961db9795eb566dc1d1b4e9139ebc4c6b0cb6e7254ecde69d1552bf7613f60"},
- {file = "mypy-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:07ba89fdcc9451f2ebb02853deb6aaaa3d2239a236669a63ab3801bbf923ef5c"},
- {file = "mypy-1.14.1-py3-none-any.whl", hash = "sha256:b66a60cc4073aeb8ae00057f9c1f64d49e90f918fbcef9a977eb121da8b8f1d1"},
- {file = "mypy-1.14.1.tar.gz", hash = "sha256:7ec88144fe9b510e8475ec2f5f251992690fcf89ccb4500b214b4226abcd32d6"},
+python-versions = ">=3.9"
+files = [
+ {file = "mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13"},
+ {file = "mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559"},
+ {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b"},
+ {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3"},
+ {file = "mypy-1.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b"},
+ {file = "mypy-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828"},
+ {file = "mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f"},
+ {file = "mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5"},
+ {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e"},
+ {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c"},
+ {file = "mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f"},
+ {file = "mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f"},
+ {file = "mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd"},
+ {file = "mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f"},
+ {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464"},
+ {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee"},
+ {file = "mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e"},
+ {file = "mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22"},
+ {file = "mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445"},
+ {file = "mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d"},
+ {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5"},
+ {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036"},
+ {file = "mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357"},
+ {file = "mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf"},
+ {file = "mypy-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078"},
+ {file = "mypy-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba"},
+ {file = "mypy-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5"},
+ {file = "mypy-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b"},
+ {file = "mypy-1.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2"},
+ {file = "mypy-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980"},
+ {file = "mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e"},
+ {file = "mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43"},
]
[package.dependencies]
@@ -2629,7 +2635,6 @@ version = "1.36.0"
description = "Type annotations for boto3 AppConfig 1.36.0 service generated with mypy-boto3-builder 8.8.0"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "mypy_boto3_appconfig-1.36.0-py3-none-any.whl", hash = "sha256:d627de43761a83991a0ab8cd10698d415f94dcc78a567433c7465fc8d1f5cc16"},
{file = "mypy_boto3_appconfig-1.36.0.tar.gz", hash = "sha256:3f38cbd2d7d359da88dc996eeeafa4c1174847909e31a327dd77263dfdfd5424"},
@@ -2644,7 +2649,6 @@ version = "1.36.0"
description = "Type annotations for boto3 AppConfigData 1.36.0 service generated with mypy-boto3-builder 8.8.0"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "mypy_boto3_appconfigdata-1.36.0-py3-none-any.whl", hash = "sha256:68f02ce06ed9597b02154aff64655fc38c42919eda08fddb130ba17e9f70e9cb"},
{file = "mypy_boto3_appconfigdata-1.36.0.tar.gz", hash = "sha256:3436d149833ea69b4260a0f352aac19258d4676c7a21087625906f7da98624c7"},
@@ -2659,7 +2663,6 @@ version = "1.36.0"
description = "Type annotations for boto3 CloudFormation 1.36.0 service generated with mypy-boto3-builder 8.8.0"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "mypy_boto3_cloudformation-1.36.0-py3-none-any.whl", hash = "sha256:3f6cd81739aaf9634c4aa2b92579081038a76e4f2dec306d02eaaf558b332ce9"},
{file = "mypy_boto3_cloudformation-1.36.0.tar.gz", hash = "sha256:acc2c7ae8920f1167be097f6151685fe5aee99be2f890075edf93e05d298e8b0"},
@@ -2674,7 +2677,6 @@ version = "1.36.0"
description = "Type annotations for boto3 CloudWatch 1.36.0 service generated with mypy-boto3-builder 8.8.0"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "mypy_boto3_cloudwatch-1.36.0-py3-none-any.whl", hash = "sha256:2f6cb81c05a1b4be3510e0857b22913a241488bc08f55b0ad96e8b775c144891"},
{file = "mypy_boto3_cloudwatch-1.36.0.tar.gz", hash = "sha256:a370d61522121ab457c443c338a652d0d3e1c22102d9db9f197fd5dcb7e656a4"},
@@ -2689,7 +2691,6 @@ version = "1.36.0"
description = "Type annotations for boto3 DynamoDB 1.36.0 service generated with mypy-boto3-builder 8.8.0"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "mypy_boto3_dynamodb-1.36.0-py3-none-any.whl", hash = "sha256:b782a817ce8956f8d53ac94c85f969dfe51451fc99f16a3b62776f1e0ed3f1ba"},
{file = "mypy_boto3_dynamodb-1.36.0.tar.gz", hash = "sha256:1687e4689236a5391755126e86ec2596d408eb95408c31ac09a3d1eb289d516d"},
@@ -2704,7 +2705,6 @@ version = "1.36.0"
description = "Type annotations for boto3 Lambda 1.36.0 service generated with mypy-boto3-builder 8.8.0"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "mypy_boto3_lambda-1.36.0-py3-none-any.whl", hash = "sha256:8a6693be1352b51e232cee73f73ce36014d19b4777bdf6969c5e707aba424ca1"},
{file = "mypy_boto3_lambda-1.36.0.tar.gz", hash = "sha256:5e9f23702060529aad216a3ce2a2368391a112df07909fbd3aa80d573d84893c"},
@@ -2719,7 +2719,6 @@ version = "1.36.3"
description = "Type annotations for boto3 CloudWatchLogs 1.36.3 service generated with mypy-boto3-builder 8.8.0"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "mypy_boto3_logs-1.36.3-py3-none-any.whl", hash = "sha256:553cb31261eb4484394af9ac965fa33b0d414e927c47768021a0a6ec89625f64"},
{file = "mypy_boto3_logs-1.36.3.tar.gz", hash = "sha256:76d233632a36665094ac888a685fade150c10665ab4cad1b17265037fcadd098"},
@@ -2730,14 +2729,13 @@ typing-extensions = {version = "*", markers = "python_version < \"3.12\""}
[[package]]
name = "mypy-boto3-s3"
-version = "1.36.0"
-description = "Type annotations for boto3 S3 1.36.0 service generated with mypy-boto3-builder 8.8.0"
+version = "1.36.9"
+description = "Type annotations for boto3 S3 1.36.9 service generated with mypy-boto3-builder 8.8.0"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
- {file = "mypy_boto3_s3-1.36.0-py3-none-any.whl", hash = "sha256:a65ccb6be7b7ebf907887268d44975e435b1fc1164fc0a25de310e2b832f7e91"},
- {file = "mypy_boto3_s3-1.36.0.tar.gz", hash = "sha256:80a881847b0e1fbc5edcad8b2870c110e31e7ef128db42402b70c159b7e93d5a"},
+ {file = "mypy_boto3_s3-1.36.9-py3-none-any.whl", hash = "sha256:506edd56892452dff5b673e3c79a11b6f8935076ce4a9daaac4cda708a176201"},
+ {file = "mypy_boto3_s3-1.36.9.tar.gz", hash = "sha256:368c963969eda65bb3a9df61e87510dd8b3247cce59f559c2ec6c43d5796bef5"},
]
[package.dependencies]
@@ -2749,7 +2747,6 @@ version = "1.36.0"
description = "Type annotations for boto3 SecretsManager 1.36.0 service generated with mypy-boto3-builder 8.8.0"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "mypy_boto3_secretsmanager-1.36.0-py3-none-any.whl", hash = "sha256:d7fd56b08afed32ce26f2663ec57f9ea074e1e5149a4388eccb46653e3cb5a66"},
{file = "mypy_boto3_secretsmanager-1.36.0.tar.gz", hash = "sha256:6e1f91cd5b0c1f0533f8cfa91e4755855d39931475e7d1e23ee8dbb2e7163d18"},
@@ -2764,7 +2761,6 @@ version = "1.36.6"
description = "Type annotations for boto3 SSM 1.36.6 service generated with mypy-boto3-builder 8.8.0"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "mypy_boto3_ssm-1.36.6-py3-none-any.whl", hash = "sha256:7f255428d79a8eb0adfde6f21b1b996275295d993157ffe0a6585bfea711583b"},
{file = "mypy_boto3_ssm-1.36.6.tar.gz", hash = "sha256:edc819b7526ab35b105648603839d158b00146af5743fc7784db3227073e1973"},
@@ -2779,7 +2775,6 @@ version = "1.36.0"
description = "Type annotations for boto3 XRay 1.36.0 service generated with mypy-boto3-builder 8.8.0"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "mypy_boto3_xray-1.36.0-py3-none-any.whl", hash = "sha256:b92a06db10f623db4ec0641227f468b7a57c77f8e599846cfddace4b434f70a5"},
{file = "mypy_boto3_xray-1.36.0.tar.gz", hash = "sha256:5ae2b4c333bf2881870ffb96f1d99cd5e7ee1706d071b6923dcd6de6ceb3ac0c"},
@@ -2794,7 +2789,6 @@ version = "1.0.0"
description = "Type system extensions for programs checked with the mypy type checker."
optional = false
python-versions = ">=3.5"
-groups = ["dev"]
files = [
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
@@ -2806,7 +2800,6 @@ version = "3.2.1"
description = "Python package for creating and manipulating graphs and networks"
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"},
{file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"},
@@ -2825,7 +2818,6 @@ version = "2024.10.9"
description = "Flexible test automation."
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "nox-2024.10.9-py3-none-any.whl", hash = "sha256:1d36f309a0a2a853e9bccb76bbef6bb118ba92fa92674d15604ca99adeb29eab"},
{file = "nox-2024.10.9.tar.gz", hash = "sha256:7aa9dc8d1c27e9f45ab046ffd1c3b2c4f7c91755304769df231308849ebded95"},
@@ -2848,8 +2840,6 @@ version = "1.16.0"
description = "OpenTelemetry Python API"
optional = true
python-versions = ">=3.7"
-groups = ["main"]
-markers = "extra == \"datadog\""
files = [
{file = "opentelemetry_api-1.16.0-py3-none-any.whl", hash = "sha256:79e8f0cf88dbdd36b6abf175d2092af1efcaa2e71552d0d2b3b181a9707bf4bc"},
{file = "opentelemetry_api-1.16.0.tar.gz", hash = "sha256:4b0e895a3b1f5e1908043ebe492d33e33f9ccdbe6d02d3994c2f8721a63ddddb"},
@@ -2865,7 +2855,6 @@ version = "24.2"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"},
{file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"},
@@ -2877,7 +2866,6 @@ version = "0.5.7"
description = "Divides large result sets into pages for easier browsing"
optional = false
python-versions = "*"
-groups = ["dev"]
files = [
{file = "paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591"},
{file = "paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945"},
@@ -2893,7 +2881,6 @@ version = "0.12.1"
description = "Utility library for gitignore style pattern matching of file paths."
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
@@ -2905,35 +2892,17 @@ version = "6.1.0"
description = "Python Build Reasonableness"
optional = false
python-versions = ">=2.6"
-groups = ["dev"]
files = [
{file = "pbr-6.1.0-py2.py3-none-any.whl", hash = "sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a"},
{file = "pbr-6.1.0.tar.gz", hash = "sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24"},
]
-[[package]]
-name = "pdoc3"
-version = "0.11.5"
-description = "Auto-generate API documentation for Python projects."
-optional = false
-python-versions = ">=3.9"
-groups = ["dev"]
-files = [
- {file = "pdoc3-0.11.5-py3-none-any.whl", hash = "sha256:b614436239716e1655e538f68a42c62a0bac566e70ddd86c58bc66d6a9ec90a0"},
- {file = "pdoc3-0.11.5.tar.gz", hash = "sha256:fc40607e3f46860ba42c02d30075fe1a52c039b77ffa8e86c1cbc4a8078841b3"},
-]
-
-[package.dependencies]
-mako = "*"
-markdown = ">=3.0"
-
[[package]]
name = "platformdirs"
version = "4.3.6"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"},
{file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"},
@@ -2950,7 +2919,6 @@ version = "1.5.0"
description = "plugin and hook calling mechanisms for python"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
{file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
@@ -2966,8 +2934,6 @@ version = "3.11"
description = "Python Lex & Yacc"
optional = true
python-versions = "*"
-groups = ["main"]
-markers = "extra == \"all\" or extra == \"datamasking\""
files = [
{file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"},
{file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"},
@@ -2979,8 +2945,6 @@ version = "5.29.3"
description = ""
optional = true
python-versions = ">=3.8"
-groups = ["main"]
-markers = "extra == \"datadog\""
files = [
{file = "protobuf-5.29.3-cp310-abi3-win32.whl", hash = "sha256:3ea51771449e1035f26069c4c7fd51fba990d07bc55ba80701c78f886bf9c888"},
{file = "protobuf-5.29.3-cp310-abi3-win_amd64.whl", hash = "sha256:a4fa6f80816a9a0678429e84973f2f98cbc218cca434abe8db2ad0bffc98503a"},
@@ -3001,7 +2965,6 @@ version = "0.0.3"
description = "Publication helps you maintain public-api-friendly modules by preventing unintentional access to private implementation details via introspection."
optional = false
python-versions = "*"
-groups = ["dev"]
files = [
{file = "publication-0.0.3-py2.py3-none-any.whl", hash = "sha256:0248885351febc11d8a1098d5c8e3ab2dabcf3e8c0c96db1e17ecd12b53afbe6"},
{file = "publication-0.0.3.tar.gz", hash = "sha256:68416a0de76dddcdd2930d1c8ef853a743cc96c82416c4e4d3b5d901c6276dc4"},
@@ -3013,7 +2976,6 @@ version = "9.0.0"
description = "Get CPU info with pure Python"
optional = false
python-versions = "*"
-groups = ["dev"]
files = [
{file = "py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690"},
{file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"},
@@ -3025,12 +2987,10 @@ version = "2.22"
description = "C parser in Python"
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
files = [
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
]
-markers = {main = "(extra == \"all\" or extra == \"datamasking\") and platform_python_implementation != \"PyPy\"", dev = "platform_python_implementation != \"PyPy\""}
[[package]]
name = "pydantic"
@@ -3038,12 +2998,10 @@ version = "2.10.6"
description = "Data validation using Python type hints"
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
files = [
{file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"},
{file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"},
]
-markers = {main = "extra == \"parser\" or extra == \"all\""}
[package.dependencies]
annotated-types = ">=0.6.0"
@@ -3060,7 +3018,6 @@ version = "2.27.2"
description = "Core functionality for Pydantic validation and serialization"
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
files = [
{file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"},
{file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"},
@@ -3163,7 +3120,6 @@ files = [
{file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"},
{file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"},
]
-markers = {main = "extra == \"parser\" or extra == \"all\""}
[package.dependencies]
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
@@ -3174,8 +3130,6 @@ version = "2.7.1"
description = "Settings management using Pydantic"
optional = true
python-versions = ">=3.8"
-groups = ["main"]
-markers = "extra == \"all\""
files = [
{file = "pydantic_settings-2.7.1-py3-none-any.whl", hash = "sha256:590be9e6e24d06db33a4262829edef682500ef008565a969c73d39d5f8bfb3fd"},
{file = "pydantic_settings-2.7.1.tar.gz", hash = "sha256:10c9caad35e64bfb3c2fbf70a078c0e25cc92499782e5200747f942a065dec93"},
@@ -3196,7 +3150,6 @@ version = "2.19.1"
description = "Pygments is a syntax highlighting package written in Python."
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"},
{file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"},
@@ -3207,14 +3160,13 @@ windows-terminal = ["colorama (>=0.4.6)"]
[[package]]
name = "pymdown-extensions"
-version = "10.14.1"
+version = "10.14.2"
description = "Extension pack for Python Markdown."
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
- {file = "pymdown_extensions-10.14.1-py3-none-any.whl", hash = "sha256:637951cbfbe9874ba28134fb3ce4b8bcadd6aca89ac4998ec29dcbafd554ae08"},
- {file = "pymdown_extensions-10.14.1.tar.gz", hash = "sha256:b65801996a0cd4f42a3110810c306c45b7313c09b0610a6f773730f2a9e3c96b"},
+ {file = "pymdown_extensions-10.14.2-py3-none-any.whl", hash = "sha256:f45bc5892410e54fd738ab8ccd736098b7ff0cb27fdb4bf24d0a0c6584bc90e1"},
+ {file = "pymdown_extensions-10.14.2.tar.gz", hash = "sha256:7a77b8116dc04193f2c01143760a43387bd9dc4aa05efacb7d838885a7791253"},
]
[package.dependencies]
@@ -3230,7 +3182,6 @@ version = "3.2.1"
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "pyparsing-3.2.1-py3-none-any.whl", hash = "sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1"},
{file = "pyparsing-3.2.1.tar.gz", hash = "sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a"},
@@ -3245,7 +3196,6 @@ version = "8.3.4"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"},
{file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"},
@@ -3264,14 +3214,13 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments
[[package]]
name = "pytest-asyncio"
-version = "0.25.2"
+version = "0.25.3"
description = "Pytest support for asyncio"
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
- {file = "pytest_asyncio-0.25.2-py3-none-any.whl", hash = "sha256:0d0bb693f7b99da304a0634afc0a4b19e49d5e0de2d670f38dc4bfa5727c5075"},
- {file = "pytest_asyncio-0.25.2.tar.gz", hash = "sha256:3f8ef9a98f45948ea91a0ed3dc4268b5326c0e7bce73892acc654df4262ad45f"},
+ {file = "pytest_asyncio-0.25.3-py3-none-any.whl", hash = "sha256:9e89518e0f9bd08928f97a3482fdc4e244df17529460bc038291ccaf8f85c7c3"},
+ {file = "pytest_asyncio-0.25.3.tar.gz", hash = "sha256:fc1da2cf9f125ada7e710b4ddad05518d4cee187ae9412e9ac9271003497f07a"},
]
[package.dependencies]
@@ -3287,7 +3236,6 @@ version = "5.1.0"
description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer."
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "pytest-benchmark-5.1.0.tar.gz", hash = "sha256:9ea661cdc292e8231f7cd4c10b0319e56a2118e2c09d9f50e1b3d150d2aca105"},
{file = "pytest_benchmark-5.1.0-py3-none-any.whl", hash = "sha256:922de2dfa3033c227c96da942d1878191afa135a29485fb942e85dff1c592c89"},
@@ -3308,7 +3256,6 @@ version = "6.0.0"
description = "Pytest plugin for measuring coverage."
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"},
{file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"},
@@ -3327,7 +3274,6 @@ version = "3.14.0"
description = "Thin-wrapper around the mock package for easier use with pytest"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"},
{file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"},
@@ -3345,7 +3291,6 @@ version = "0.7.0"
description = "Pytest Plugin to disable socket calls during tests"
optional = false
python-versions = ">=3.8,<4.0"
-groups = ["dev"]
files = [
{file = "pytest_socket-0.7.0-py3-none-any.whl", hash = "sha256:7e0f4642177d55d317bbd58fc68c6bd9048d6eadb2d46a89307fa9221336ce45"},
{file = "pytest_socket-0.7.0.tar.gz", hash = "sha256:71ab048cbbcb085c15a4423b73b619a8b35d6a307f46f78ea46be51b1b7e11b3"},
@@ -3360,7 +3305,6 @@ version = "3.6.1"
description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7"},
{file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"},
@@ -3381,7 +3325,6 @@ version = "2.9.0.post0"
description = "Extensions to the standard Python datetime module"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
-groups = ["main", "dev"]
files = [
{file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
{file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
@@ -3396,12 +3339,10 @@ version = "1.0.1"
description = "Read key-value pairs from a .env file and set them as environment variables"
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
files = [
{file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"},
{file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"},
]
-markers = {main = "extra == \"all\""}
[package.extras]
cli = ["click (>=5.0)"]
@@ -3412,8 +3353,6 @@ version = "308"
description = "Python for Window Extensions"
optional = false
python-versions = "*"
-groups = ["dev"]
-markers = "sys_platform == \"win32\""
files = [
{file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"},
{file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"},
@@ -3441,7 +3380,6 @@ version = "6.0.2"
description = "YAML parser and emitter for Python"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
{file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
@@ -3504,7 +3442,6 @@ version = "0.1"
description = "A custom YAML tag for referencing environment variables in YAML files. "
optional = false
python-versions = ">=3.6"
-groups = ["dev"]
files = [
{file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"},
{file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"},
@@ -3519,7 +3456,6 @@ version = "6.0.1"
description = "Code Metrics in Python"
optional = false
python-versions = "*"
-groups = ["dev"]
files = [
{file = "radon-6.0.1-py2.py3-none-any.whl", hash = "sha256:632cc032364a6f8bb1010a2f6a12d0f14bc7e5ede76585ef29dc0cecf4cd8859"},
{file = "radon-6.0.1.tar.gz", hash = "sha256:d1ac0053943a893878940fedc8b19ace70386fc9c9bf0a09229a44125ebf45b5"},
@@ -3538,12 +3474,10 @@ version = "5.2.1"
description = "Python client for Redis database and key-value store"
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
files = [
{file = "redis-5.2.1-py3-none-any.whl", hash = "sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4"},
{file = "redis-5.2.1.tar.gz", hash = "sha256:16f2e22dff21d5125e8481515e386711a34cbec50f0e44413dd7d9c060a54e0f"},
]
-markers = {main = "extra == \"redis\""}
[package.dependencies]
async-timeout = {version = ">=4.0.3", markers = "python_full_version < \"3.11.3\""}
@@ -3558,7 +3492,6 @@ version = "0.36.2"
description = "JSON Referencing + Python"
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"},
{file = "referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa"},
@@ -3575,7 +3508,6 @@ version = "2024.11.6"
description = "Alternative regular expression module, to replace re."
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"},
{file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"},
@@ -3679,7 +3611,6 @@ version = "2.32.3"
description = "Python HTTP for Humans."
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
files = [
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
@@ -3695,13 +3626,57 @@ urllib3 = ">=1.21.1,<3"
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
+[[package]]
+name = "requests-cache"
+version = "1.2.1"
+description = "A persistent cache for python requests"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "requests_cache-1.2.1-py3-none-any.whl", hash = "sha256:1285151cddf5331067baa82598afe2d47c7495a1334bfe7a7d329b43e9fd3603"},
+ {file = "requests_cache-1.2.1.tar.gz", hash = "sha256:68abc986fdc5b8d0911318fbb5f7c80eebcd4d01bfacc6685ecf8876052511d1"},
+]
+
+[package.dependencies]
+attrs = ">=21.2"
+cattrs = ">=22.2"
+platformdirs = ">=2.5"
+requests = ">=2.22"
+url-normalize = ">=1.4"
+urllib3 = ">=1.25.5"
+
+[package.extras]
+all = ["boto3 (>=1.15)", "botocore (>=1.18)", "itsdangerous (>=2.0)", "pymongo (>=3)", "pyyaml (>=6.0.1)", "redis (>=3)", "ujson (>=5.4)"]
+bson = ["bson (>=0.5)"]
+docs = ["furo (>=2023.3,<2024.0)", "linkify-it-py (>=2.0,<3.0)", "myst-parser (>=1.0,<2.0)", "sphinx (>=5.0.2,<6.0.0)", "sphinx-autodoc-typehints (>=1.19)", "sphinx-automodapi (>=0.14)", "sphinx-copybutton (>=0.5)", "sphinx-design (>=0.2)", "sphinx-notfound-page (>=0.8)", "sphinxcontrib-apidoc (>=0.3)", "sphinxext-opengraph (>=0.9)"]
+dynamodb = ["boto3 (>=1.15)", "botocore (>=1.18)"]
+json = ["ujson (>=5.4)"]
+mongodb = ["pymongo (>=3)"]
+redis = ["redis (>=3)"]
+security = ["itsdangerous (>=2.0)"]
+yaml = ["pyyaml (>=6.0.1)"]
+
+[[package]]
+name = "requirements-parser"
+version = "0.11.0"
+description = "This is a small Python module for parsing Pip requirement files."
+optional = false
+python-versions = "<4.0,>=3.8"
+files = [
+ {file = "requirements_parser-0.11.0-py3-none-any.whl", hash = "sha256:50379eb50311834386c2568263ae5225d7b9d0867fb55cf4ecc93959de2c2684"},
+ {file = "requirements_parser-0.11.0.tar.gz", hash = "sha256:35f36dc969d14830bf459803da84f314dc3d17c802592e9e970f63d0359e5920"},
+]
+
+[package.dependencies]
+packaging = ">=23.2"
+types-setuptools = ">=69.1.0"
+
[[package]]
name = "retry2"
version = "0.9.5"
description = "Easy to use retry decorator."
optional = false
python-versions = ">=2.6"
-groups = ["dev"]
files = [
{file = "retry2-0.9.5-py2.py3-none-any.whl", hash = "sha256:f7fee13b1e15d0611c462910a6aa72a8919823988dd0412152bc3719c89a4e55"},
]
@@ -3715,7 +3690,6 @@ version = "13.9.4"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
optional = false
python-versions = ">=3.8.0"
-groups = ["dev"]
files = [
{file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"},
{file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"},
@@ -3735,7 +3709,6 @@ version = "0.22.3"
description = "Python bindings to Rust's persistent data structures (rpds)"
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "rpds_py-0.22.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967"},
{file = "rpds_py-0.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37"},
@@ -3844,30 +3817,29 @@ files = [
[[package]]
name = "ruff"
-version = "0.9.3"
+version = "0.9.6"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
-groups = ["dev"]
-files = [
- {file = "ruff-0.9.3-py3-none-linux_armv6l.whl", hash = "sha256:7f39b879064c7d9670197d91124a75d118d00b0990586549949aae80cdc16624"},
- {file = "ruff-0.9.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a187171e7c09efa4b4cc30ee5d0d55a8d6c5311b3e1b74ac5cb96cc89bafc43c"},
- {file = "ruff-0.9.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c59ab92f8e92d6725b7ded9d4a31be3ef42688a115c6d3da9457a5bda140e2b4"},
- {file = "ruff-0.9.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dc153c25e715be41bb228bc651c1e9b1a88d5c6e5ed0194fa0dfea02b026439"},
- {file = "ruff-0.9.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:646909a1e25e0dc28fbc529eab8eb7bb583079628e8cbe738192853dbbe43af5"},
- {file = "ruff-0.9.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a5a46e09355695fbdbb30ed9889d6cf1c61b77b700a9fafc21b41f097bfbba4"},
- {file = "ruff-0.9.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c4bb09d2bbb394e3730d0918c00276e79b2de70ec2a5231cd4ebb51a57df9ba1"},
- {file = "ruff-0.9.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96a87ec31dc1044d8c2da2ebbed1c456d9b561e7d087734336518181b26b3aa5"},
- {file = "ruff-0.9.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb7554aca6f842645022fe2d301c264e6925baa708b392867b7a62645304df4"},
- {file = "ruff-0.9.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cabc332b7075a914ecea912cd1f3d4370489c8018f2c945a30bcc934e3bc06a6"},
- {file = "ruff-0.9.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:33866c3cc2a575cbd546f2cd02bdd466fed65118e4365ee538a3deffd6fcb730"},
- {file = "ruff-0.9.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:006e5de2621304c8810bcd2ee101587712fa93b4f955ed0985907a36c427e0c2"},
- {file = "ruff-0.9.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ba6eea4459dbd6b1be4e6bfc766079fb9b8dd2e5a35aff6baee4d9b1514ea519"},
- {file = "ruff-0.9.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:90230a6b8055ad47d3325e9ee8f8a9ae7e273078a66401ac66df68943ced029b"},
- {file = "ruff-0.9.3-py3-none-win32.whl", hash = "sha256:eabe5eb2c19a42f4808c03b82bd313fc84d4e395133fb3fc1b1516170a31213c"},
- {file = "ruff-0.9.3-py3-none-win_amd64.whl", hash = "sha256:040ceb7f20791dfa0e78b4230ee9dce23da3b64dd5848e40e3bf3ab76468dcf4"},
- {file = "ruff-0.9.3-py3-none-win_arm64.whl", hash = "sha256:800d773f6d4d33b0a3c60e2c6ae8f4c202ea2de056365acfa519aa48acf28e0b"},
- {file = "ruff-0.9.3.tar.gz", hash = "sha256:8293f89985a090ebc3ed1064df31f3b4b56320cdfcec8b60d3295bddb955c22a"},
+files = [
+ {file = "ruff-0.9.6-py3-none-linux_armv6l.whl", hash = "sha256:2f218f356dd2d995839f1941322ff021c72a492c470f0b26a34f844c29cdf5ba"},
+ {file = "ruff-0.9.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b908ff4df65dad7b251c9968a2e4560836d8f5487c2f0cc238321ed951ea0504"},
+ {file = "ruff-0.9.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b109c0ad2ececf42e75fa99dc4043ff72a357436bb171900714a9ea581ddef83"},
+ {file = "ruff-0.9.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1de4367cca3dac99bcbd15c161404e849bb0bfd543664db39232648dc00112dc"},
+ {file = "ruff-0.9.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac3ee4d7c2c92ddfdaedf0bf31b2b176fa7aa8950efc454628d477394d35638b"},
+ {file = "ruff-0.9.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dc1edd1775270e6aa2386119aea692039781429f0be1e0949ea5884e011aa8e"},
+ {file = "ruff-0.9.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4a091729086dffa4bd070aa5dab7e39cc6b9d62eb2bef8f3d91172d30d599666"},
+ {file = "ruff-0.9.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1bbc6808bf7b15796cef0815e1dfb796fbd383e7dbd4334709642649625e7c5"},
+ {file = "ruff-0.9.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:589d1d9f25b5754ff230dce914a174a7c951a85a4e9270613a2b74231fdac2f5"},
+ {file = "ruff-0.9.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc61dd5131742e21103fbbdcad683a8813be0e3c204472d520d9a5021ca8b217"},
+ {file = "ruff-0.9.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5e2d9126161d0357e5c8f30b0bd6168d2c3872372f14481136d13de9937f79b6"},
+ {file = "ruff-0.9.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:68660eab1a8e65babb5229a1f97b46e3120923757a68b5413d8561f8a85d4897"},
+ {file = "ruff-0.9.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c4cae6c4cc7b9b4017c71114115db0445b00a16de3bcde0946273e8392856f08"},
+ {file = "ruff-0.9.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:19f505b643228b417c1111a2a536424ddde0db4ef9023b9e04a46ed8a1cb4656"},
+ {file = "ruff-0.9.6-py3-none-win32.whl", hash = "sha256:194d8402bceef1b31164909540a597e0d913c0e4952015a5b40e28c146121b5d"},
+ {file = "ruff-0.9.6-py3-none-win_amd64.whl", hash = "sha256:03482d5c09d90d4ee3f40d97578423698ad895c87314c4de39ed2af945633caa"},
+ {file = "ruff-0.9.6-py3-none-win_arm64.whl", hash = "sha256:0e2bb706a2be7ddfea4a4af918562fdc1bcb16df255e5fa595bbd800ce322a5a"},
+ {file = "ruff-0.9.6.tar.gz", hash = "sha256:81761592f72b620ec8fa1068a6fd00e98a5ebee342a3642efd84454f3031dca9"},
]
[[package]]
@@ -3876,7 +3848,6 @@ version = "0.11.2"
description = "An Amazon S3 Transfer Manager"
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
files = [
{file = "s3transfer-0.11.2-py3-none-any.whl", hash = "sha256:be6ecb39fadd986ef1701097771f87e4d2f821f27f6071c872143884d2950fbc"},
{file = "s3transfer-0.11.2.tar.gz", hash = "sha256:3b39185cb72f5acc77db1a58b6e25b977f28d20496b6e58d6813d75f464d632f"},
@@ -3894,7 +3865,6 @@ version = "0.0.4"
description = "Flexible recursive directory iterator: scandir meets glob(\"**\", recursive=True)"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "scantree-0.0.4-py3-none-any.whl", hash = "sha256:7616ab65aa6b7f16fcf8e6fa1d9afaa99a27ab72bba05c61b691853b96763174"},
{file = "scantree-0.0.4.tar.gz", hash = "sha256:15bd5cb24483b04db2c70653604e8ea3522e98087db7e38ab8482f053984c0ac"},
@@ -3910,7 +3880,6 @@ version = "2.20.0"
description = "Python client for Sentry (https://sentry.io)"
optional = false
python-versions = ">=3.6"
-groups = ["dev"]
files = [
{file = "sentry_sdk-2.20.0-py2.py3-none-any.whl", hash = "sha256:c359a1edf950eb5e80cffd7d9111f3dbeef57994cb4415df37d39fda2cf22364"},
{file = "sentry_sdk-2.20.0.tar.gz", hash = "sha256:afa82713a92facf847df3c6f63cec71eb488d826a50965def3d7722aa6f0fdab"},
@@ -3966,8 +3935,6 @@ version = "75.8.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = true
python-versions = ">=3.9"
-groups = ["main"]
-markers = "extra == \"datadog\""
files = [
{file = "setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3"},
{file = "setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6"},
@@ -3988,7 +3955,6 @@ version = "1.17.0"
description = "Python 2 and 3 compatibility utilities"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
-groups = ["main", "dev"]
files = [
{file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
{file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
@@ -4000,7 +3966,6 @@ version = "5.0.2"
description = "A pure Python implementation of a sliding window memory map manager"
optional = false
python-versions = ">=3.7"
-groups = ["dev"]
files = [
{file = "smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e"},
{file = "smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5"},
@@ -4012,7 +3977,6 @@ version = "1.3.1"
description = "Sniff out which async library your code is running under"
optional = false
python-versions = ">=3.7"
-groups = ["dev"]
files = [
{file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
@@ -4024,7 +3988,6 @@ version = "5.4.0"
description = "Manage dynamic plugins for Python applications"
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "stevedore-5.4.0-py3-none-any.whl", hash = "sha256:b0be3c4748b3ea7b854b265dcb4caa891015e442416422be16f8b31756107857"},
{file = "stevedore-5.4.0.tar.gz", hash = "sha256:79e92235ecb828fe952b6b8b0c6c87863248631922c8e8e0fa5b17b232c4514d"},
@@ -4039,7 +4002,6 @@ version = "1.13.3"
description = "Computer algebra system (CAS) in Python"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "sympy-1.13.3-py3-none-any.whl", hash = "sha256:54612cf55a62755ee71824ce692986f23c88ffa77207b30c1368eda4a7060f73"},
{file = "sympy-1.13.3.tar.gz", hash = "sha256:b27fd2c6530e0ab39e275fc9b683895367e51d5da91baa8d3d64db2565fec4d9"},
@@ -4057,7 +4019,6 @@ version = "4.9.1"
description = "Python library for throwaway instances of anything that can run in a Docker container"
optional = false
python-versions = "<4.0,>=3.9"
-groups = ["dev"]
files = [
{file = "testcontainers-4.9.1-py3-none-any.whl", hash = "sha256:315fb94b42a383872df530aa45319745278ef0cc18b9cfcdc231a75d14afa5a0"},
{file = "testcontainers-4.9.1.tar.gz", hash = "sha256:37fe9a222549ddb788463935965b16f91809e9a8d654f437d6a59eac9b77f76f"},
@@ -4112,8 +4073,6 @@ version = "2.2.1"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
-markers = "python_version < \"3.11.0\""
files = [
{file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
{file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
@@ -4155,7 +4114,6 @@ version = "2.13.3"
description = "Run-time type checker for Python"
optional = false
python-versions = ">=3.5.3"
-groups = ["dev"]
files = [
{file = "typeguard-2.13.3-py3-none-any.whl", hash = "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1"},
{file = "typeguard-2.13.3.tar.gz", hash = "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4"},
@@ -4171,7 +4129,6 @@ version = "0.23.8"
description = "Type annotations and code completion for awscrt"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "types_awscrt-0.23.8-py3-none-any.whl", hash = "sha256:d66b3817565769f5311b7e171a3c48d3dbf8a8f9c22f02686c2f003b6559a2a5"},
{file = "types_awscrt-0.23.8.tar.gz", hash = "sha256:2141391a8f4d36cf098406c19d9060b34f13a558c22d4aadac250a0c57d12710"},
@@ -4183,7 +4140,6 @@ version = "1.16.0.20241221"
description = "Typing stubs for cffi"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "types_cffi-1.16.0.20241221-py3-none-any.whl", hash = "sha256:e5b76b4211d7a9185f6ab8d06a106d56c7eb80af7cdb8bfcb4186ade10fb112f"},
{file = "types_cffi-1.16.0.20241221.tar.gz", hash = "sha256:1c96649618f4b6145f58231acb976e0b448be6b847f7ab733dabe62dfbff6591"},
@@ -4198,7 +4154,6 @@ version = "24.1.0.20240722"
description = "Typing stubs for pyOpenSSL"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "types-pyOpenSSL-24.1.0.20240722.tar.gz", hash = "sha256:47913b4678a01d879f503a12044468221ed8576263c1540dcb0484ca21b08c39"},
{file = "types_pyOpenSSL-24.1.0.20240722-py3-none-any.whl", hash = "sha256:6a7a5d2ec042537934cfb4c9d4deb0e16c4c6250b09358df1f083682fe6fda54"},
@@ -4214,7 +4169,6 @@ version = "2.9.0.20241206"
description = "Typing stubs for python-dateutil"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53"},
{file = "types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb"},
@@ -4226,7 +4180,6 @@ version = "4.6.0.20241004"
description = "Typing stubs for redis"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "types-redis-4.6.0.20241004.tar.gz", hash = "sha256:5f17d2b3f9091ab75384153bfa276619ffa1cf6a38da60e10d5e6749cc5b902e"},
{file = "types_redis-4.6.0.20241004-py3-none-any.whl", hash = "sha256:ef5da68cb827e5f606c8f9c0b49eeee4c2669d6d97122f301d3a55dc6a63f6ed"},
@@ -4242,7 +4195,6 @@ version = "2.31.0.6"
description = "Typing stubs for requests"
optional = false
python-versions = ">=3.7"
-groups = ["dev"]
files = [
{file = "types-requests-2.31.0.6.tar.gz", hash = "sha256:cd74ce3b53c461f1228a9b783929ac73a666658f223e28ed29753771477b3bd0"},
{file = "types_requests-2.31.0.6-py3-none-any.whl", hash = "sha256:a2db9cb228a81da8348b49ad6db3f5519452dd20a9c1e1a868c83c5fe88fd1a9"},
@@ -4257,7 +4209,6 @@ version = "0.11.2"
description = "Type annotations and code completion for s3transfer"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "types_s3transfer-0.11.2-py3-none-any.whl", hash = "sha256:09c31cff8c79a433fcf703b840b66d1f694a6c70c410ef52015dd4fe07ee0ae2"},
{file = "types_s3transfer-0.11.2.tar.gz", hash = "sha256:3ccb8b90b14434af2fb0d6c08500596d93f3a83fb804a2bb843d9bf4f7c2ca60"},
@@ -4269,7 +4220,6 @@ version = "75.8.0.20250110"
description = "Typing stubs for setuptools"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "types_setuptools-75.8.0.20250110-py3-none-any.whl", hash = "sha256:a9f12980bbf9bcdc23ecd80755789085bad6bfce4060c2275bc2b4ca9f2bc480"},
{file = "types_setuptools-75.8.0.20250110.tar.gz", hash = "sha256:96f7ec8bbd6e0a54ea180d66ad68ad7a1d7954e7281a710ea2de75e355545271"},
@@ -4281,7 +4231,6 @@ version = "1.26.25.14"
description = "Typing stubs for urllib3"
optional = false
python-versions = "*"
-groups = ["dev"]
files = [
{file = "types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f"},
{file = "types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e"},
@@ -4293,7 +4242,6 @@ version = "4.12.2"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
@@ -4305,8 +4253,6 @@ version = "5.10.0"
description = "Ultra fast JSON encoder and decoder for Python"
optional = true
python-versions = ">=3.8"
-groups = ["main"]
-markers = "extra == \"datadog\""
files = [
{file = "ujson-5.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2601aa9ecdbee1118a1c2065323bda35e2c5a2cf0797ef4522d485f9d3ef65bd"},
{file = "ujson-5.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:348898dd702fc1c4f1051bc3aacbf894caa0927fe2c53e68679c073375f732cf"},
@@ -4388,13 +4334,26 @@ files = [
{file = "ujson-5.10.0.tar.gz", hash = "sha256:b3cd8f3c5d8c7738257f1018880444f7b7d9b66232c64649f562d7ba86ad4bc1"},
]
+[[package]]
+name = "url-normalize"
+version = "1.4.3"
+description = "URL normalization for Python"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
+files = [
+ {file = "url-normalize-1.4.3.tar.gz", hash = "sha256:d23d3a070ac52a67b83a1c59a0e68f8608d1cd538783b401bc9de2c0fac999b2"},
+ {file = "url_normalize-1.4.3-py2.py3-none-any.whl", hash = "sha256:ec3c301f04e5bb676d333a7fa162fa977ad2ca04b7e652bfc9fac4e405728eed"},
+]
+
+[package.dependencies]
+six = "*"
+
[[package]]
name = "urllib3"
version = "1.26.20"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
-groups = ["main", "dev"]
files = [
{file = "urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e"},
{file = "urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32"},
@@ -4405,13 +4364,39 @@ brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotl
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
+[[package]]
+name = "uv"
+version = "0.5.27"
+description = "An extremely fast Python package and project manager, written in Rust."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "uv-0.5.27-py3-none-linux_armv6l.whl", hash = "sha256:57ba7b4e9f5cc25c0a003f18b9a37a881a60e161cd081cfe3f540dd4c4dfa270"},
+ {file = "uv-0.5.27-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5f6042fb5d29b09408a0f17016cce1b9ddc6298fbf712b15b01862078e1a4fc5"},
+ {file = "uv-0.5.27-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5e8ce099c129e48c88c1bfa92f3b439c0dbd314e6ea29609ebe9f281c051e8ac"},
+ {file = "uv-0.5.27-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:5ca212d3c8141e3f25b1aaed124f34c782af93d94ca03638f295fde6bb15f8a6"},
+ {file = "uv-0.5.27-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7bd021410bcaf64c197916c33d2bbca08b8ff3ced7e17936fa037dc96146dcca"},
+ {file = "uv-0.5.27-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fef326056b5551f0ef9d2c0ddacfe69940bdc01b30d39a78fac13fe24c23bfe9"},
+ {file = "uv-0.5.27-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:dc40d3912edde1a504dba31f034e88bc178c5ba8771c13aab8ca7781711be6bf"},
+ {file = "uv-0.5.27-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ebfa9bbcf82db56cd65aca91b08839c247806a7c2cb6c7ddf8c762ece083e7bd"},
+ {file = "uv-0.5.27-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:751e64d543a965a44a02aa1de9d83c861a2721cc57ee7f6aa7f1c6c6018b3511"},
+ {file = "uv-0.5.27-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f78e0753dd24b0f1adb5cc99a733848ef59d070a3e2dba88810e7bf78512971b"},
+ {file = "uv-0.5.27-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:e7eab779aa2cbdfb768c420d51f4275d60f9d68d54ee41e2db34966a16d1318b"},
+ {file = "uv-0.5.27-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:4d9159eb1c1b4f762cba924ea879470752f17de48dc07516d22dea9887db6fd7"},
+ {file = "uv-0.5.27-py3-none-musllinux_1_1_i686.whl", hash = "sha256:c31e440fc479da7385158393ab5f25a00dbb8c993f83deaaf3d4d3db3a706694"},
+ {file = "uv-0.5.27-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:fb9e7f9ab760aa21dfaac5ff876f43683a7eab1619c8fe063438abf4dd3bddef"},
+ {file = "uv-0.5.27-py3-none-win32.whl", hash = "sha256:9dfb3adaee9bd9574c7743ff9a3a108cb8f95ffef4fe85f177e435a996aa6428"},
+ {file = "uv-0.5.27-py3-none-win_amd64.whl", hash = "sha256:3046562b314513c69f93f33f5d933d470413355257a5c67c8ea34022fa53fd3b"},
+ {file = "uv-0.5.27-py3-none-win_arm64.whl", hash = "sha256:e0d265294b565f7b136d4dc65a7cb90aa98e0a9ff824edf33644537a231a45ab"},
+ {file = "uv-0.5.27.tar.gz", hash = "sha256:5d8174d71c2d884181a79c96b35a0ef1e4b4a57356c53d781399da015f393b24"},
+]
+
[[package]]
name = "verspec"
version = "0.1.0"
description = "Flexible version handling"
optional = false
python-versions = "*"
-groups = ["dev"]
files = [
{file = "verspec-0.1.0-py3-none-any.whl", hash = "sha256:741877d5633cc9464c45a469ae2a31e801e6dbbaa85b9675d481cda100f11c31"},
{file = "verspec-0.1.0.tar.gz", hash = "sha256:c4504ca697b2056cdb4bfa7121461f5a0e81809255b41c03dda4ba823637c01e"},
@@ -4426,7 +4411,6 @@ version = "20.29.1"
description = "Virtual Python Environment builder"
optional = false
python-versions = ">=3.8"
-groups = ["dev"]
files = [
{file = "virtualenv-20.29.1-py3-none-any.whl", hash = "sha256:4e4cb403c0b0da39e13b46b1b2476e505cb0046b25f242bee80f62bf990b2779"},
{file = "virtualenv-20.29.1.tar.gz", hash = "sha256:b8b8970138d32fb606192cb97f6cd4bb644fa486be9308fb9b63f81091b5dc35"},
@@ -4447,7 +4431,6 @@ version = "6.0.0"
description = "Filesystem events monitoring"
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"},
{file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"},
@@ -4484,13 +4467,26 @@ files = [
[package.extras]
watchmedo = ["PyYAML (>=3.10)"]
+[[package]]
+name = "win32-setctime"
+version = "1.2.0"
+description = "A small Python utility to set file creation time on Windows"
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390"},
+ {file = "win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0"},
+]
+
+[package.extras]
+dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"]
+
[[package]]
name = "wrapt"
version = "1.17.2"
description = "Module for decorators, wrappers and monkey patching."
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
files = [
{file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984"},
{file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22"},
@@ -4572,7 +4568,6 @@ files = [
{file = "wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8"},
{file = "wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3"},
]
-markers = {main = "extra == \"tracer\" or extra == \"all\" or extra == \"datadog\" or extra == \"datamasking\""}
[[package]]
name = "xenon"
@@ -4580,7 +4575,6 @@ version = "0.9.3"
description = "Monitor code metrics for Python on your CI server"
optional = false
python-versions = "*"
-groups = ["dev"]
files = [
{file = "xenon-0.9.3-py2.py3-none-any.whl", hash = "sha256:6e2c2c251cc5e9d01fe984e623499b13b2140fcbf74d6c03a613fa43a9347097"},
{file = "xenon-0.9.3.tar.gz", hash = "sha256:4a7538d8ba08aa5d79055fb3e0b2393c0bd6d7d16a4ab0fcdef02ef1f10a43fa"},
@@ -4597,8 +4591,6 @@ version = "0.14.2"
description = "Makes working with XML feel like you are working with JSON"
optional = true
python-versions = ">=3.6"
-groups = ["main"]
-markers = "extra == \"datadog\""
files = [
{file = "xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac"},
{file = "xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553"},
@@ -4610,7 +4602,6 @@ version = "3.21.0"
description = "Backport of pathlib-compatible object wrapper for zip files"
optional = false
python-versions = ">=3.9"
-groups = ["dev"]
files = [
{file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"},
{file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"},
@@ -4635,6 +4626,6 @@ tracer = ["aws-xray-sdk"]
validation = ["fastjsonschema"]
[metadata]
-lock-version = "2.1"
+lock-version = "2.0"
python-versions = ">=3.9,<4.0.0"
-content-hash = "d9f1328c56d8cbad3242d4f5f5f7ca04482270605a7505994dfc2872847dff05"
+content-hash = "9f429270dfd274c938e728842aa9412fe3f71a8be4daa282e52eeff1be881079"
diff --git a/provenance/3.5.1a0/multiple.intoto.jsonl b/provenance/3.5.1a0/multiple.intoto.jsonl
new file mode 100644
index 00000000000..a9997a0d56c
--- /dev/null
+++ b/provenance/3.5.1a0/multiple.intoto.jsonl
@@ -0,0 +1 @@
+{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMiIsInN1YmplY3QiOlt7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWEwLXB5My1ub25lLWFueS53aGwiLCJkaWdlc3QiOnsic2hhMjU2IjoiNTFmNGRlNmI4MmIxMTc1ZTEyYTQzZTk2MzkxMTQ5NTNiN2U3OTg2NDc0YTVhZjA0ODVmNjBlZTU5NzU2NzVhNyJ9fSx7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWEwLnRhci5neiIsImRpZ2VzdCI6eyJzaGEyNTYiOiJiMmFmM2Q1MzNlNDgwYTk2MTg3YjYxMzBlZjczMDc0Nzc1MjAwMTlmYzc2ODdiZDY4YjdjNDYxMWY3MTZkMjA3In19XSwicHJlZGljYXRlIjp7ImJ1aWxkZXIiOnsiaWQiOiJodHRwczovL2dpdGh1Yi5jb20vc2xzYS1mcmFtZXdvcmsvc2xzYS1naXRodWItZ2VuZXJhdG9yLy5naXRodWIvd29ya2Zsb3dzL2dlbmVyYXRvcl9nZW5lcmljX3Nsc2EzLnltbEByZWZzL3RhZ3MvdjIuMC4wIn0sImJ1aWxkVHlwZSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvZ2VuZXJpY0B2MSIsImludm9jYXRpb24iOnsiY29uZmlnU291cmNlIjp7InVyaSI6ImdpdCtodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uQHJlZnMvaGVhZHMvZGV2ZWxvcCIsImRpZ2VzdCI6eyJzaGExIjoiYjZlYzZmMTkzZTRkZDMwZmIyY2NmMTEyOTU4MjM0Yzk2NTdlZDJiOSJ9LCJlbnRyeVBvaW50IjoiLmdpdGh1Yi93b3JrZmxvd3MvcHJlLXJlbGVhc2UueW1sIn0sInBhcmFtZXRlcnMiOnt9LCJlbnZpcm9ubWVudCI6eyJnaXRodWJfYWN0b3IiOiJsZWFuZHJvZGFtYXNjZW5hIiwiZ2l0aHViX2FjdG9yX2lkIjoiNDI5NTE3MyIsImdpdGh1Yl9iYXNlX3JlZiI6IiIsImdpdGh1Yl9ldmVudF9uYW1lIjoic2NoZWR1bGUiLCJnaXRodWJfZXZlbnRfcGF5bG9hZCI6eyJlbnRlcnByaXNlIjp7ImF2YXRhcl91cmwiOiJodHRwczovL2F2YXRhcnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2IvMTI5MD92PTQiLCJjcmVhdGVkX2F0IjoiMjAxOS0xMS0xM1QxODowNTo0MVoiLCJkZXNjcmlwdGlvbiI6IiIsImh0bWxfdXJsIjoiaHR0cHM6Ly9naXRodWIuY29tL2VudGVycHJpc2VzL2FtYXpvbiIsImlkIjoxMjkwLCJuYW1lIjoiQW1hem9uIiwibm9kZV9pZCI6Ik1ERXdPa1Z1ZEdWeWNISnBjMlV4TWprdyIsInNsdWciOiJhbWF6b24iLCJ1cGRhdGVkX2F0IjoiMjAyNC0wOS0zMFQyMTowMjozMFoiLCJ3ZWJzaXRlX3VybCI6Imh0dHBzOi8vd3d3LmFtYXpvbi5jb20vIn0sIm9yZ2FuaXphdGlvbiI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJkZXNjcmlwdGlvbiI6IiIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvZXZlbnRzIiwiaG9va3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9vcmdzL2F3cy1wb3dlcnRvb2xzL2hvb2tzIiwiaWQiOjEyOTEyNzYzOCwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vb3Jncy9hd3MtcG93ZXJ0b29scy9pc3N1ZXMiLCJsb2dpbiI6ImF3cy1wb3dlcnRvb2xzIiwibWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvbWVtYmVyc3svbWVtYmVyfSIsIm5vZGVfaWQiOiJPX2tnRE9CN0pVMWciLCJwdWJsaWNfbWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcHVibGljX21lbWJlcnN7L21lbWJlcn0iLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcmVwb3MiLCJ1cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMifSwicmVwb3NpdG9yeSI6eyJhbGxvd19mb3JraW5nIjp0cnVlLCJhcmNoaXZlX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3thcmNoaXZlX2Zvcm1hdH17L3JlZn0iLCJhcmNoaXZlZCI6ZmFsc2UsImFzc2lnbmVlc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hc3NpZ25lZXN7L3VzZXJ9IiwiYmxvYnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L2Jsb2Jzey9zaGF9IiwiYnJhbmNoZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vYnJhbmNoZXN7L2JyYW5jaH0iLCJjbG9uZV91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsImNvbGxhYm9yYXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29sbGFib3JhdG9yc3svY29sbGFib3JhdG9yfSIsImNvbW1lbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbW1lbnRzey9udW1iZXJ9IiwiY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21taXRzey9zaGF9IiwiY29tcGFyZV91cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21wYXJlL3tiYXNlfS4uLntoZWFkfSIsImNvbnRlbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbnRlbnRzL3srcGF0aH0iLCJjb250cmlidXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29udHJpYnV0b3JzIiwiY3JlYXRlZF9hdCI6IjIwMTktMTEtMTVUMTI6MjY6MTJaIiwiY3VzdG9tX3Byb3BlcnRpZXMiOnt9LCJkZWZhdWx0X2JyYW5jaCI6ImRldmVsb3AiLCJkZXBsb3ltZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9kZXBsb3ltZW50cyIsImRlc2NyaXB0aW9uIjoiQSBkZXZlbG9wZXIgdG9vbGtpdCB0byBpbXBsZW1lbnQgU2VydmVybGVzcyBiZXN0IHByYWN0aWNlcyBhbmQgaW5jcmVhc2UgZGV2ZWxvcGVyIHZlbG9jaXR5LiIsImRpc2FibGVkIjpmYWxzZSwiZG93bmxvYWRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2Rvd25sb2FkcyIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9ldmVudHMiLCJmb3JrIjpmYWxzZSwiZm9ya3MiOjQwNiwiZm9ya3NfY291bnQiOjQwNiwiZm9ya3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZm9ya3MiLCJmdWxsX25hbWUiOiJhd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJnaXRfY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9naXQvY29tbWl0c3svc2hhfSIsImdpdF9yZWZzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2dpdC9yZWZzey9zaGF9IiwiZ2l0X3RhZ3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RhZ3N7L3NoYX0iLCJnaXRfdXJsIjoiZ2l0Oi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24uZ2l0IiwiaGFzX2Rpc2N1c3Npb25zIjp0cnVlLCJoYXNfZG93bmxvYWRzIjp0cnVlLCJoYXNfaXNzdWVzIjp0cnVlLCJoYXNfcGFnZXMiOmZhbHNlLCJoYXNfcHJvamVjdHMiOnRydWUsImhhc193aWtpIjpmYWxzZSwiaG9tZXBhZ2UiOiJodHRwczovL2RvY3MucG93ZXJ0b29scy5hd3MuZGV2L2xhbWJkYS9weXRob24vbGF0ZXN0LyIsImhvb2tzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2hvb2tzIiwiaHRtbF91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uIiwiaWQiOjIyMTkxOTM3OSwiaXNfdGVtcGxhdGUiOmZhbHNlLCJpc3N1ZV9jb21tZW50X3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlcy9jb21tZW50c3svbnVtYmVyfSIsImlzc3VlX2V2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9pc3N1ZXMvZXZlbnRzey9udW1iZXJ9IiwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlc3svbnVtYmVyfSIsImtleXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24va2V5c3sva2V5X2lkfSIsImxhYmVsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9sYWJlbHN7L25hbWV9IiwibGFuZ3VhZ2UiOiJQeXRob24iLCJsYW5ndWFnZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbGFuZ3VhZ2VzIiwibGljZW5zZSI6eyJrZXkiOiJtaXQtMCIsIm5hbWUiOiJNSVQgTm8gQXR0cmlidXRpb24iLCJub2RlX2lkIjoiTURjNlRHbGpaVzV6WlRReCIsInNwZHhfaWQiOiJNSVQtMCIsInVybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vbGljZW5zZXMvbWl0LTAifSwibWVyZ2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL21lcmdlcyIsIm1pbGVzdG9uZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbWlsZXN0b25lc3svbnVtYmVyfSIsIm1pcnJvcl91cmwiOm51bGwsIm5hbWUiOiJwb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJub2RlX2lkIjoiTURFd09sSmxjRzl6YVhSdmNua3lNakU1TVRrek56az0iLCJub3RpZmljYXRpb25zX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL25vdGlmaWNhdGlvbnN7P3NpbmNlLGFsbCxwYXJ0aWNpcGF0aW5nfSIsIm9wZW5faXNzdWVzIjo2Nywib3Blbl9pc3N1ZXNfY291bnQiOjY3LCJvd25lciI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9ldmVudHN7L3ByaXZhY3l9IiwiZm9sbG93ZXJzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93ZXJzIiwiZm9sbG93aW5nX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93aW5ney9vdGhlcl91c2VyfSIsImdpc3RzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZ2lzdHN7L2dpc3RfaWR9IiwiZ3JhdmF0YXJfaWQiOiIiLCJodG1sX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scyIsImlkIjoxMjkxMjc2MzgsImxvZ2luIjoiYXdzLXBvd2VydG9vbHMiLCJub2RlX2lkIjoiT19rZ0RPQjdKVTFnIiwib3JnYW5pemF0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL29yZ3MiLCJyZWNlaXZlZF9ldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9yZWNlaXZlZF9ldmVudHMiLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3JlcG9zIiwic2l0ZV9hZG1pbiI6ZmFsc2UsInN0YXJyZWRfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9zdGFycmVkey9vd25lcn17L3JlcG99Iiwic3Vic2NyaXB0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3N1YnNjcmlwdGlvbnMiLCJ0eXBlIjoiT3JnYW5pemF0aW9uIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scyIsInVzZXJfdmlld190eXBlIjoicHVibGljIn0sInByaXZhdGUiOmZhbHNlLCJwdWxsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9wdWxsc3svbnVtYmVyfSIsInB1c2hlZF9hdCI6IjIwMjUtMDEtMjhUMjI6MTY6NDVaIiwicmVsZWFzZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vcmVsZWFzZXN7L2lkfSIsInNpemUiOjY2MzQ0LCJzc2hfdXJsIjoiZ2l0QGdpdGh1Yi5jb206YXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsInN0YXJnYXplcnNfY291bnQiOjI5NzQsInN0YXJnYXplcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3RhcmdhemVycyIsInN0YXR1c2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3N0YXR1c2VzL3tzaGF9Iiwic3Vic2NyaWJlcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaWJlcnMiLCJzdWJzY3JpcHRpb25fdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaXB0aW9uIiwic3ZuX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ0YWdzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3RhZ3MiLCJ0ZWFtc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi90ZWFtcyIsInRvcGljcyI6WyJhd3MiLCJhd3MtbGFtYmRhIiwiaGFja3RvYmVyZmVzdCIsImxhbWJkYSIsInB5dGhvbiIsInNlcnZlcmxlc3MiXSwidHJlZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RyZWVzey9zaGF9IiwidXBkYXRlZF9hdCI6IjIwMjUtMDEtMjhUMjI6NTU6NTlaIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ2aXNpYmlsaXR5IjoicHVibGljIiwid2F0Y2hlcnMiOjI5NzQsIndhdGNoZXJzX2NvdW50IjoyOTc0LCJ3ZWJfY29tbWl0X3NpZ25vZmZfcmVxdWlyZWQiOnRydWV9LCJzY2hlZHVsZSI6IjAgOCAqICogMS01Iiwid29ya2Zsb3ciOiIuZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVsZWFzZS55bWwifSwiZ2l0aHViX2hlYWRfcmVmIjoiIiwiZ2l0aHViX3JlZiI6InJlZnMvaGVhZHMvZGV2ZWxvcCIsImdpdGh1Yl9yZWZfdHlwZSI6ImJyYW5jaCIsImdpdGh1Yl9yZXBvc2l0b3J5X2lkIjoiMjIxOTE5Mzc5IiwiZ2l0aHViX3JlcG9zaXRvcnlfb3duZXIiOiJhd3MtcG93ZXJ0b29scyIsImdpdGh1Yl9yZXBvc2l0b3J5X293bmVyX2lkIjoiMTI5MTI3NjM4IiwiZ2l0aHViX3J1bl9hdHRlbXB0IjoiMSIsImdpdGh1Yl9ydW5faWQiOiIxMzAyNjkyODE3MyIsImdpdGh1Yl9ydW5fbnVtYmVyIjoiMTY0IiwiZ2l0aHViX3NoYTEiOiJiNmVjNmYxOTNlNGRkMzBmYjJjY2YxMTI5NTgyMzRjOTY1N2VkMmI5In19LCJtZXRhZGF0YSI6eyJidWlsZEludm9jYXRpb25JRCI6IjEzMDI2OTI4MTczLTEiLCJjb21wbGV0ZW5lc3MiOnsicGFyYW1ldGVycyI6dHJ1ZSwiZW52aXJvbm1lbnQiOmZhbHNlLCJtYXRlcmlhbHMiOmZhbHNlfSwicmVwcm9kdWNpYmxlIjpmYWxzZX0sIm1hdGVyaWFscyI6W3sidXJpIjoiZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob25AcmVmcy9oZWFkcy9kZXZlbG9wIiwiZGlnZXN0Ijp7InNoYTEiOiJiNmVjNmYxOTNlNGRkMzBmYjJjY2YxMTI5NTgyMzRjOTY1N2VkMmI5In19XX19","signatures":[{"keyid":"","sig":"MEUCIQCMg0LGVf4Zu1O5LjZ7Q1/+szZ1YccUjjnRZDx2nQVb/wIgSZh14aPbRN0zMaYNDMk4ZdCXd9E1CtHXCfLgw/6qnFo=","cert":"-----BEGIN CERTIFICATE-----\nMIIHZzCCBuygAwIBAgIUEKZOdzPXWqg4MsQ87g7UXfoC2/gwCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjUwMTI5MDgwNzM1WhcNMjUwMTI5MDgxNzM1WjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAE+9PjDmRC4JqsGtX/4V2yxIWCCpmZYvyOcpxU\n2wJNwXY1ZRdNxJ7OHnnWvs5N26sT60hBOsFxvGdWcw1CfpQhraOCBgswggYHMA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQULCxP\nvubmcuugMkxmyfldf6HtME4wHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wgYQGA1UdEQEB/wR6MHiGdmh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1l\nd29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvLmdpdGh1Yi93b3JrZmxvd3MvZ2Vu\nZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJlZnMvdGFncy92Mi4wLjAwOQYKKwYB\nBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50\nLmNvbTAWBgorBgEEAYO/MAECBAhzY2hlZHVsZTA2BgorBgEEAYO/MAEDBChiNmVj\nNmYxOTNlNGRkMzBmYjJjY2YxMTI5NTgyMzRjOTY1N2VkMmI5MBkGCisGAQQBg78w\nAQQEC1ByZS1SZWxlYXNlMDUGCisGAQQBg78wAQUEJ2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbjAgBgorBgEEAYO/MAEGBBJyZWZzL2hlYWRz\nL2RldmVsb3AwOwYKKwYBBAGDvzABCAQtDCtodHRwczovL3Rva2VuLmFjdGlvbnMu\nZ2l0aHVidXNlcmNvbnRlbnQuY29tMIGGBgorBgEEAYO/MAEJBHgMdmh0dHBzOi8v\nZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3Iv\nLmdpdGh1Yi93b3JrZmxvd3MvZ2VuZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJl\nZnMvdGFncy92Mi4wLjAwOAYKKwYBBAGDvzABCgQqDCg1YTc3NWIzNjdhNTZkNWJk\nMTE4YTIyNGE4MTFiYmEyODgxNTBhNTYzMB0GCisGAQQBg78wAQsEDwwNZ2l0aHVi\nLWhvc3RlZDBKBgorBgEEAYO/MAEMBDwMOmh0dHBzOi8vZ2l0aHViLmNvbS9hd3Mt\ncG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24wOAYKKwYBBAGDvzAB\nDQQqDChiNmVjNmYxOTNlNGRkMzBmYjJjY2YxMTI5NTgyMzRjOTY1N2VkMmI5MCIG\nCisGAQQBg78wAQ4EFAwScmVmcy9oZWFkcy9kZXZlbG9wMBkGCisGAQQBg78wAQ8E\nCwwJMjIxOTE5Mzc5MDEGCisGAQQBg78wARAEIwwhaHR0cHM6Ly9naXRodWIuY29t\nL2F3cy1wb3dlcnRvb2xzMBkGCisGAQQBg78wAREECwwJMTI5MTI3NjM4MH8GCisG\nAQQBg78wARIEcQxvaHR0cHM6Ly9naXRodWIuY29tL2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbi8uZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVs\nZWFzZS55bWxAcmVmcy9oZWFkcy9kZXZlbG9wMDgGCisGAQQBg78wARMEKgwoYjZl\nYzZmMTkzZTRkZDMwZmIyY2NmMTEyOTU4MjM0Yzk2NTdlZDJiOTAYBgorBgEEAYO/\nMAEUBAoMCHNjaGVkdWxlMG4GCisGAQQBg78wARUEYAxeaHR0cHM6Ly9naXRodWIu\nY29tL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hY3Rp\nb25zL3J1bnMvMTMwMjY5MjgxNzMvYXR0ZW1wdHMvMTAWBgorBgEEAYO/MAEWBAgM\nBnB1YmxpYzCBigYKKwYBBAHWeQIEAgR8BHoAeAB2AN09MGrGxxEyYxkeHJlnNwKi\nSl643jyt/4eKcoAvKe6OAAABlLEZ9LAAAAQDAEcwRQIgJThr5prui9R+c3JmaIJN\nec0+525TvxZSRAiobcMJV9cCIQCW44ih+9wJwWz3Wid5lw+adewOC1MUBknLm37r\nVuZBYDAKBggqhkjOPQQDAwNpADBmAjEA7ogxP6H1wMLvnVr1ZXe+UMvWat95VJ1m\nQUqtX3uGLjCHZCb7HZliaXKLiTDhjf0jAjEAgLeaXm9ewmBqFJ6BOJmjvRCU7aMn\nv65stm8v4QxjA8PVQUpmTvloVdUBQKTqndLr\n-----END CERTIFICATE-----\n"}]}
\ No newline at end of file
diff --git a/provenance/3.5.1a1/multiple.intoto.jsonl b/provenance/3.5.1a1/multiple.intoto.jsonl
new file mode 100644
index 00000000000..2dd26095fa9
--- /dev/null
+++ b/provenance/3.5.1a1/multiple.intoto.jsonl
@@ -0,0 +1 @@
+{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMiIsInN1YmplY3QiOlt7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWExLXB5My1ub25lLWFueS53aGwiLCJkaWdlc3QiOnsic2hhMjU2IjoiMDk2OGEyMzI2YjIxYTVhZWFhZWIwMGRlNjc3MzBkMmVhNTZiYjc3NWQxYjMxMDNiYjEwYTc0NTM1MjY0OTg5NiJ9fSx7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWExLnRhci5neiIsImRpZ2VzdCI6eyJzaGEyNTYiOiI2NWQ0NGY4NmVhMGQ2YWM4YTI5OGU2NmMzYWM2MTBmNDljZmViOWI1MDk4MDQ2MDk1OGMzYTVjNDgwNTg2MDA2In19XSwicHJlZGljYXRlIjp7ImJ1aWxkZXIiOnsiaWQiOiJodHRwczovL2dpdGh1Yi5jb20vc2xzYS1mcmFtZXdvcmsvc2xzYS1naXRodWItZ2VuZXJhdG9yLy5naXRodWIvd29ya2Zsb3dzL2dlbmVyYXRvcl9nZW5lcmljX3Nsc2EzLnltbEByZWZzL3RhZ3MvdjIuMC4wIn0sImJ1aWxkVHlwZSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvZ2VuZXJpY0B2MSIsImludm9jYXRpb24iOnsiY29uZmlnU291cmNlIjp7InVyaSI6ImdpdCtodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uQHJlZnMvaGVhZHMvZGV2ZWxvcCIsImRpZ2VzdCI6eyJzaGExIjoiZTA5Njg5YTdhMjg4NjZhZDNkNDBjZTBhYjJlYzRjNTQyNzA1ZTE5ZSJ9LCJlbnRyeVBvaW50IjoiLmdpdGh1Yi93b3JrZmxvd3MvcHJlLXJlbGVhc2UueW1sIn0sInBhcmFtZXRlcnMiOnt9LCJlbnZpcm9ubWVudCI6eyJnaXRodWJfYWN0b3IiOiJsZWFuZHJvZGFtYXNjZW5hIiwiZ2l0aHViX2FjdG9yX2lkIjoiNDI5NTE3MyIsImdpdGh1Yl9iYXNlX3JlZiI6IiIsImdpdGh1Yl9ldmVudF9uYW1lIjoic2NoZWR1bGUiLCJnaXRodWJfZXZlbnRfcGF5bG9hZCI6eyJlbnRlcnByaXNlIjp7ImF2YXRhcl91cmwiOiJodHRwczovL2F2YXRhcnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2IvMTI5MD92PTQiLCJjcmVhdGVkX2F0IjoiMjAxOS0xMS0xM1QxODowNTo0MVoiLCJkZXNjcmlwdGlvbiI6IiIsImh0bWxfdXJsIjoiaHR0cHM6Ly9naXRodWIuY29tL2VudGVycHJpc2VzL2FtYXpvbiIsImlkIjoxMjkwLCJuYW1lIjoiQW1hem9uIiwibm9kZV9pZCI6Ik1ERXdPa1Z1ZEdWeWNISnBjMlV4TWprdyIsInNsdWciOiJhbWF6b24iLCJ1cGRhdGVkX2F0IjoiMjAyNC0wOS0zMFQyMTowMjozMFoiLCJ3ZWJzaXRlX3VybCI6Imh0dHBzOi8vd3d3LmFtYXpvbi5jb20vIn0sIm9yZ2FuaXphdGlvbiI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJkZXNjcmlwdGlvbiI6IiIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvZXZlbnRzIiwiaG9va3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9vcmdzL2F3cy1wb3dlcnRvb2xzL2hvb2tzIiwiaWQiOjEyOTEyNzYzOCwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vb3Jncy9hd3MtcG93ZXJ0b29scy9pc3N1ZXMiLCJsb2dpbiI6ImF3cy1wb3dlcnRvb2xzIiwibWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvbWVtYmVyc3svbWVtYmVyfSIsIm5vZGVfaWQiOiJPX2tnRE9CN0pVMWciLCJwdWJsaWNfbWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcHVibGljX21lbWJlcnN7L21lbWJlcn0iLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcmVwb3MiLCJ1cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMifSwicmVwb3NpdG9yeSI6eyJhbGxvd19mb3JraW5nIjp0cnVlLCJhcmNoaXZlX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3thcmNoaXZlX2Zvcm1hdH17L3JlZn0iLCJhcmNoaXZlZCI6ZmFsc2UsImFzc2lnbmVlc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hc3NpZ25lZXN7L3VzZXJ9IiwiYmxvYnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L2Jsb2Jzey9zaGF9IiwiYnJhbmNoZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vYnJhbmNoZXN7L2JyYW5jaH0iLCJjbG9uZV91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsImNvbGxhYm9yYXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29sbGFib3JhdG9yc3svY29sbGFib3JhdG9yfSIsImNvbW1lbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbW1lbnRzey9udW1iZXJ9IiwiY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21taXRzey9zaGF9IiwiY29tcGFyZV91cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21wYXJlL3tiYXNlfS4uLntoZWFkfSIsImNvbnRlbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbnRlbnRzL3srcGF0aH0iLCJjb250cmlidXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29udHJpYnV0b3JzIiwiY3JlYXRlZF9hdCI6IjIwMTktMTEtMTVUMTI6MjY6MTJaIiwiY3VzdG9tX3Byb3BlcnRpZXMiOnt9LCJkZWZhdWx0X2JyYW5jaCI6ImRldmVsb3AiLCJkZXBsb3ltZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9kZXBsb3ltZW50cyIsImRlc2NyaXB0aW9uIjoiQSBkZXZlbG9wZXIgdG9vbGtpdCB0byBpbXBsZW1lbnQgU2VydmVybGVzcyBiZXN0IHByYWN0aWNlcyBhbmQgaW5jcmVhc2UgZGV2ZWxvcGVyIHZlbG9jaXR5LiIsImRpc2FibGVkIjpmYWxzZSwiZG93bmxvYWRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2Rvd25sb2FkcyIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9ldmVudHMiLCJmb3JrIjpmYWxzZSwiZm9ya3MiOjQwNiwiZm9ya3NfY291bnQiOjQwNiwiZm9ya3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZm9ya3MiLCJmdWxsX25hbWUiOiJhd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJnaXRfY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9naXQvY29tbWl0c3svc2hhfSIsImdpdF9yZWZzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2dpdC9yZWZzey9zaGF9IiwiZ2l0X3RhZ3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RhZ3N7L3NoYX0iLCJnaXRfdXJsIjoiZ2l0Oi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24uZ2l0IiwiaGFzX2Rpc2N1c3Npb25zIjp0cnVlLCJoYXNfZG93bmxvYWRzIjp0cnVlLCJoYXNfaXNzdWVzIjp0cnVlLCJoYXNfcGFnZXMiOmZhbHNlLCJoYXNfcHJvamVjdHMiOnRydWUsImhhc193aWtpIjpmYWxzZSwiaG9tZXBhZ2UiOiJodHRwczovL2RvY3MucG93ZXJ0b29scy5hd3MuZGV2L2xhbWJkYS9weXRob24vbGF0ZXN0LyIsImhvb2tzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2hvb2tzIiwiaHRtbF91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uIiwiaWQiOjIyMTkxOTM3OSwiaXNfdGVtcGxhdGUiOmZhbHNlLCJpc3N1ZV9jb21tZW50X3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlcy9jb21tZW50c3svbnVtYmVyfSIsImlzc3VlX2V2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9pc3N1ZXMvZXZlbnRzey9udW1iZXJ9IiwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlc3svbnVtYmVyfSIsImtleXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24va2V5c3sva2V5X2lkfSIsImxhYmVsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9sYWJlbHN7L25hbWV9IiwibGFuZ3VhZ2UiOiJQeXRob24iLCJsYW5ndWFnZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbGFuZ3VhZ2VzIiwibGljZW5zZSI6eyJrZXkiOiJtaXQtMCIsIm5hbWUiOiJNSVQgTm8gQXR0cmlidXRpb24iLCJub2RlX2lkIjoiTURjNlRHbGpaVzV6WlRReCIsInNwZHhfaWQiOiJNSVQtMCIsInVybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vbGljZW5zZXMvbWl0LTAifSwibWVyZ2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL21lcmdlcyIsIm1pbGVzdG9uZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbWlsZXN0b25lc3svbnVtYmVyfSIsIm1pcnJvcl91cmwiOm51bGwsIm5hbWUiOiJwb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJub2RlX2lkIjoiTURFd09sSmxjRzl6YVhSdmNua3lNakU1TVRrek56az0iLCJub3RpZmljYXRpb25zX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL25vdGlmaWNhdGlvbnN7P3NpbmNlLGFsbCxwYXJ0aWNpcGF0aW5nfSIsIm9wZW5faXNzdWVzIjo2NCwib3Blbl9pc3N1ZXNfY291bnQiOjY0LCJvd25lciI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9ldmVudHN7L3ByaXZhY3l9IiwiZm9sbG93ZXJzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93ZXJzIiwiZm9sbG93aW5nX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93aW5ney9vdGhlcl91c2VyfSIsImdpc3RzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZ2lzdHN7L2dpc3RfaWR9IiwiZ3JhdmF0YXJfaWQiOiIiLCJodG1sX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scyIsImlkIjoxMjkxMjc2MzgsImxvZ2luIjoiYXdzLXBvd2VydG9vbHMiLCJub2RlX2lkIjoiT19rZ0RPQjdKVTFnIiwib3JnYW5pemF0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL29yZ3MiLCJyZWNlaXZlZF9ldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9yZWNlaXZlZF9ldmVudHMiLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3JlcG9zIiwic2l0ZV9hZG1pbiI6ZmFsc2UsInN0YXJyZWRfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9zdGFycmVkey9vd25lcn17L3JlcG99Iiwic3Vic2NyaXB0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3N1YnNjcmlwdGlvbnMiLCJ0eXBlIjoiT3JnYW5pemF0aW9uIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scyIsInVzZXJfdmlld190eXBlIjoicHVibGljIn0sInByaXZhdGUiOmZhbHNlLCJwdWxsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9wdWxsc3svbnVtYmVyfSIsInB1c2hlZF9hdCI6IjIwMjUtMDEtMjlUMjI6NDk6MDdaIiwicmVsZWFzZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vcmVsZWFzZXN7L2lkfSIsInNpemUiOjY3MTQ1LCJzc2hfdXJsIjoiZ2l0QGdpdGh1Yi5jb206YXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsInN0YXJnYXplcnNfY291bnQiOjI5NzYsInN0YXJnYXplcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3RhcmdhemVycyIsInN0YXR1c2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3N0YXR1c2VzL3tzaGF9Iiwic3Vic2NyaWJlcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaWJlcnMiLCJzdWJzY3JpcHRpb25fdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaXB0aW9uIiwic3ZuX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ0YWdzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3RhZ3MiLCJ0ZWFtc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi90ZWFtcyIsInRvcGljcyI6WyJhd3MiLCJhd3MtbGFtYmRhIiwiaGFja3RvYmVyZmVzdCIsImxhbWJkYSIsInB5dGhvbiIsInNlcnZlcmxlc3MiXSwidHJlZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RyZWVzey9zaGF9IiwidXBkYXRlZF9hdCI6IjIwMjUtMDEtMzBUMDM6NDQ6MTRaIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ2aXNpYmlsaXR5IjoicHVibGljIiwid2F0Y2hlcnMiOjI5NzYsIndhdGNoZXJzX2NvdW50IjoyOTc2LCJ3ZWJfY29tbWl0X3NpZ25vZmZfcmVxdWlyZWQiOnRydWV9LCJzY2hlZHVsZSI6IjAgOCAqICogMS01Iiwid29ya2Zsb3ciOiIuZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVsZWFzZS55bWwifSwiZ2l0aHViX2hlYWRfcmVmIjoiIiwiZ2l0aHViX3JlZiI6InJlZnMvaGVhZHMvZGV2ZWxvcCIsImdpdGh1Yl9yZWZfdHlwZSI6ImJyYW5jaCIsImdpdGh1Yl9yZXBvc2l0b3J5X2lkIjoiMjIxOTE5Mzc5IiwiZ2l0aHViX3JlcG9zaXRvcnlfb3duZXIiOiJhd3MtcG93ZXJ0b29scyIsImdpdGh1Yl9yZXBvc2l0b3J5X293bmVyX2lkIjoiMTI5MTI3NjM4IiwiZ2l0aHViX3J1bl9hdHRlbXB0IjoiMSIsImdpdGh1Yl9ydW5faWQiOiIxMzA0Nzk3MzQwNiIsImdpdGh1Yl9ydW5fbnVtYmVyIjoiMTY1IiwiZ2l0aHViX3NoYTEiOiJlMDk2ODlhN2EyODg2NmFkM2Q0MGNlMGFiMmVjNGM1NDI3MDVlMTllIn19LCJtZXRhZGF0YSI6eyJidWlsZEludm9jYXRpb25JRCI6IjEzMDQ3OTczNDA2LTEiLCJjb21wbGV0ZW5lc3MiOnsicGFyYW1ldGVycyI6dHJ1ZSwiZW52aXJvbm1lbnQiOmZhbHNlLCJtYXRlcmlhbHMiOmZhbHNlfSwicmVwcm9kdWNpYmxlIjpmYWxzZX0sIm1hdGVyaWFscyI6W3sidXJpIjoiZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob25AcmVmcy9oZWFkcy9kZXZlbG9wIiwiZGlnZXN0Ijp7InNoYTEiOiJlMDk2ODlhN2EyODg2NmFkM2Q0MGNlMGFiMmVjNGM1NDI3MDVlMTllIn19XX19","signatures":[{"keyid":"","sig":"MEUCIQCBLSLpjdAzjXEI+uUgOIp9lbNSkIQ8i1GOph5wRlqbXgIgH+6TV2YFPMwtVweRyEDsEXTun6W+gSGlcCdiu9MAo5c=","cert":"-----BEGIN CERTIFICATE-----\nMIIHZjCCBuygAwIBAgIUSkDUoXdBfe9Fo1Q9YVMCzbnVY6AwCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjUwMTMwMDgwNzM0WhcNMjUwMTMwMDgxNzM0WjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAE8P9Tc0P81VhGJ3zVYsBLxMS8R1Tm0Qe60x+D\nrERliHnUYwLNgr+QxSC9lbuWo6aBFiz4lw+M/6rLfYU4TslH/KOCBgswggYHMA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUqoDE\nBFKyCsxPAk91/WVJCwYNrOIwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wgYQGA1UdEQEB/wR6MHiGdmh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1l\nd29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvLmdpdGh1Yi93b3JrZmxvd3MvZ2Vu\nZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJlZnMvdGFncy92Mi4wLjAwOQYKKwYB\nBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50\nLmNvbTAWBgorBgEEAYO/MAECBAhzY2hlZHVsZTA2BgorBgEEAYO/MAEDBChlMDk2\nODlhN2EyODg2NmFkM2Q0MGNlMGFiMmVjNGM1NDI3MDVlMTllMBkGCisGAQQBg78w\nAQQEC1ByZS1SZWxlYXNlMDUGCisGAQQBg78wAQUEJ2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbjAgBgorBgEEAYO/MAEGBBJyZWZzL2hlYWRz\nL2RldmVsb3AwOwYKKwYBBAGDvzABCAQtDCtodHRwczovL3Rva2VuLmFjdGlvbnMu\nZ2l0aHVidXNlcmNvbnRlbnQuY29tMIGGBgorBgEEAYO/MAEJBHgMdmh0dHBzOi8v\nZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3Iv\nLmdpdGh1Yi93b3JrZmxvd3MvZ2VuZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJl\nZnMvdGFncy92Mi4wLjAwOAYKKwYBBAGDvzABCgQqDCg1YTc3NWIzNjdhNTZkNWJk\nMTE4YTIyNGE4MTFiYmEyODgxNTBhNTYzMB0GCisGAQQBg78wAQsEDwwNZ2l0aHVi\nLWhvc3RlZDBKBgorBgEEAYO/MAEMBDwMOmh0dHBzOi8vZ2l0aHViLmNvbS9hd3Mt\ncG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24wOAYKKwYBBAGDvzAB\nDQQqDChlMDk2ODlhN2EyODg2NmFkM2Q0MGNlMGFiMmVjNGM1NDI3MDVlMTllMCIG\nCisGAQQBg78wAQ4EFAwScmVmcy9oZWFkcy9kZXZlbG9wMBkGCisGAQQBg78wAQ8E\nCwwJMjIxOTE5Mzc5MDEGCisGAQQBg78wARAEIwwhaHR0cHM6Ly9naXRodWIuY29t\nL2F3cy1wb3dlcnRvb2xzMBkGCisGAQQBg78wAREECwwJMTI5MTI3NjM4MH8GCisG\nAQQBg78wARIEcQxvaHR0cHM6Ly9naXRodWIuY29tL2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbi8uZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVs\nZWFzZS55bWxAcmVmcy9oZWFkcy9kZXZlbG9wMDgGCisGAQQBg78wARMEKgwoZTA5\nNjg5YTdhMjg4NjZhZDNkNDBjZTBhYjJlYzRjNTQyNzA1ZTE5ZTAYBgorBgEEAYO/\nMAEUBAoMCHNjaGVkdWxlMG4GCisGAQQBg78wARUEYAxeaHR0cHM6Ly9naXRodWIu\nY29tL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hY3Rp\nb25zL3J1bnMvMTMwNDc5NzM0MDYvYXR0ZW1wdHMvMTAWBgorBgEEAYO/MAEWBAgM\nBnB1YmxpYzCBigYKKwYBBAHWeQIEAgR8BHoAeAB2AN09MGrGxxEyYxkeHJlnNwKi\nSl643jyt/4eKcoAvKe6OAAABlLZASbsAAAQDAEcwRQIhALUOltioB1w4BsfPgRoe\nbuezMxCNMMyLfECBf76WunxlAiBwbmWEbl4s7Hd17l57epIvU2A29SVcWjnANMzl\nhWZJTjAKBggqhkjOPQQDAwNoADBlAjAK89ZnZ5nK7PX7kVJx4hQbSlTcPWmiDnMP\nPsfUK6B5cAfM9sA6Luxz9DpfYrJDSoMCMQC5hsRLnU1niiiw6b/ht9nWOBjLP+FD\nM4NmAGcpjxs+t5AUXyJR+YpOCYgnubmqOCA=\n-----END CERTIFICATE-----\n"}]}
\ No newline at end of file
diff --git a/provenance/3.5.1a2/multiple.intoto.jsonl b/provenance/3.5.1a2/multiple.intoto.jsonl
new file mode 100644
index 00000000000..a9c94a8335a
--- /dev/null
+++ b/provenance/3.5.1a2/multiple.intoto.jsonl
@@ -0,0 +1 @@
+{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMiIsInN1YmplY3QiOlt7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWEyLXB5My1ub25lLWFueS53aGwiLCJkaWdlc3QiOnsic2hhMjU2IjoiYTAzMzNlZjFlNGQ2Y2M1ZTRjZjVjZTc1ZGQ4MTRmNTNmNDk2MjdlNDMwNzVjMTkyZTIzOGRhYTJkMzY1MDZjZSJ9fSx7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWEyLnRhci5neiIsImRpZ2VzdCI6eyJzaGEyNTYiOiI3NWY4MzZkOGZiY2VkZmQzNzBkZDI3NDljZDc5YmZhNzYxM2YzY2E4MmFiZDc5MzI4ZGIyOTE1ZjkyMTg1MGViIn19XSwicHJlZGljYXRlIjp7ImJ1aWxkZXIiOnsiaWQiOiJodHRwczovL2dpdGh1Yi5jb20vc2xzYS1mcmFtZXdvcmsvc2xzYS1naXRodWItZ2VuZXJhdG9yLy5naXRodWIvd29ya2Zsb3dzL2dlbmVyYXRvcl9nZW5lcmljX3Nsc2EzLnltbEByZWZzL3RhZ3MvdjIuMC4wIn0sImJ1aWxkVHlwZSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvZ2VuZXJpY0B2MSIsImludm9jYXRpb24iOnsiY29uZmlnU291cmNlIjp7InVyaSI6ImdpdCtodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uQHJlZnMvaGVhZHMvZGV2ZWxvcCIsImRpZ2VzdCI6eyJzaGExIjoiMjRmY2MwZjdiYmZiM2Y1YjViNmU5Yjc0NWU4NjBmMDFjNjg0NDg3MyJ9LCJlbnRyeVBvaW50IjoiLmdpdGh1Yi93b3JrZmxvd3MvcHJlLXJlbGVhc2UueW1sIn0sInBhcmFtZXRlcnMiOnt9LCJlbnZpcm9ubWVudCI6eyJnaXRodWJfYWN0b3IiOiJsZWFuZHJvZGFtYXNjZW5hIiwiZ2l0aHViX2FjdG9yX2lkIjoiNDI5NTE3MyIsImdpdGh1Yl9iYXNlX3JlZiI6IiIsImdpdGh1Yl9ldmVudF9uYW1lIjoic2NoZWR1bGUiLCJnaXRodWJfZXZlbnRfcGF5bG9hZCI6eyJlbnRlcnByaXNlIjp7ImF2YXRhcl91cmwiOiJodHRwczovL2F2YXRhcnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2IvMTI5MD92PTQiLCJjcmVhdGVkX2F0IjoiMjAxOS0xMS0xM1QxODowNTo0MVoiLCJkZXNjcmlwdGlvbiI6IiIsImh0bWxfdXJsIjoiaHR0cHM6Ly9naXRodWIuY29tL2VudGVycHJpc2VzL2FtYXpvbiIsImlkIjoxMjkwLCJuYW1lIjoiQW1hem9uIiwibm9kZV9pZCI6Ik1ERXdPa1Z1ZEdWeWNISnBjMlV4TWprdyIsInNsdWciOiJhbWF6b24iLCJ1cGRhdGVkX2F0IjoiMjAyNC0wOS0zMFQyMTowMjozMFoiLCJ3ZWJzaXRlX3VybCI6Imh0dHBzOi8vd3d3LmFtYXpvbi5jb20vIn0sIm9yZ2FuaXphdGlvbiI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJkZXNjcmlwdGlvbiI6IiIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvZXZlbnRzIiwiaG9va3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9vcmdzL2F3cy1wb3dlcnRvb2xzL2hvb2tzIiwiaWQiOjEyOTEyNzYzOCwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vb3Jncy9hd3MtcG93ZXJ0b29scy9pc3N1ZXMiLCJsb2dpbiI6ImF3cy1wb3dlcnRvb2xzIiwibWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvbWVtYmVyc3svbWVtYmVyfSIsIm5vZGVfaWQiOiJPX2tnRE9CN0pVMWciLCJwdWJsaWNfbWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcHVibGljX21lbWJlcnN7L21lbWJlcn0iLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcmVwb3MiLCJ1cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMifSwicmVwb3NpdG9yeSI6eyJhbGxvd19mb3JraW5nIjp0cnVlLCJhcmNoaXZlX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3thcmNoaXZlX2Zvcm1hdH17L3JlZn0iLCJhcmNoaXZlZCI6ZmFsc2UsImFzc2lnbmVlc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hc3NpZ25lZXN7L3VzZXJ9IiwiYmxvYnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L2Jsb2Jzey9zaGF9IiwiYnJhbmNoZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vYnJhbmNoZXN7L2JyYW5jaH0iLCJjbG9uZV91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsImNvbGxhYm9yYXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29sbGFib3JhdG9yc3svY29sbGFib3JhdG9yfSIsImNvbW1lbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbW1lbnRzey9udW1iZXJ9IiwiY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21taXRzey9zaGF9IiwiY29tcGFyZV91cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21wYXJlL3tiYXNlfS4uLntoZWFkfSIsImNvbnRlbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbnRlbnRzL3srcGF0aH0iLCJjb250cmlidXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29udHJpYnV0b3JzIiwiY3JlYXRlZF9hdCI6IjIwMTktMTEtMTVUMTI6MjY6MTJaIiwiY3VzdG9tX3Byb3BlcnRpZXMiOnt9LCJkZWZhdWx0X2JyYW5jaCI6ImRldmVsb3AiLCJkZXBsb3ltZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9kZXBsb3ltZW50cyIsImRlc2NyaXB0aW9uIjoiQSBkZXZlbG9wZXIgdG9vbGtpdCB0byBpbXBsZW1lbnQgU2VydmVybGVzcyBiZXN0IHByYWN0aWNlcyBhbmQgaW5jcmVhc2UgZGV2ZWxvcGVyIHZlbG9jaXR5LiIsImRpc2FibGVkIjpmYWxzZSwiZG93bmxvYWRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2Rvd25sb2FkcyIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9ldmVudHMiLCJmb3JrIjpmYWxzZSwiZm9ya3MiOjQwNiwiZm9ya3NfY291bnQiOjQwNiwiZm9ya3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZm9ya3MiLCJmdWxsX25hbWUiOiJhd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJnaXRfY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9naXQvY29tbWl0c3svc2hhfSIsImdpdF9yZWZzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2dpdC9yZWZzey9zaGF9IiwiZ2l0X3RhZ3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RhZ3N7L3NoYX0iLCJnaXRfdXJsIjoiZ2l0Oi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24uZ2l0IiwiaGFzX2Rpc2N1c3Npb25zIjp0cnVlLCJoYXNfZG93bmxvYWRzIjp0cnVlLCJoYXNfaXNzdWVzIjp0cnVlLCJoYXNfcGFnZXMiOmZhbHNlLCJoYXNfcHJvamVjdHMiOnRydWUsImhhc193aWtpIjpmYWxzZSwiaG9tZXBhZ2UiOiJodHRwczovL2RvY3MucG93ZXJ0b29scy5hd3MuZGV2L2xhbWJkYS9weXRob24vbGF0ZXN0LyIsImhvb2tzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2hvb2tzIiwiaHRtbF91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uIiwiaWQiOjIyMTkxOTM3OSwiaXNfdGVtcGxhdGUiOmZhbHNlLCJpc3N1ZV9jb21tZW50X3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlcy9jb21tZW50c3svbnVtYmVyfSIsImlzc3VlX2V2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9pc3N1ZXMvZXZlbnRzey9udW1iZXJ9IiwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlc3svbnVtYmVyfSIsImtleXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24va2V5c3sva2V5X2lkfSIsImxhYmVsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9sYWJlbHN7L25hbWV9IiwibGFuZ3VhZ2UiOiJQeXRob24iLCJsYW5ndWFnZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbGFuZ3VhZ2VzIiwibGljZW5zZSI6eyJrZXkiOiJtaXQtMCIsIm5hbWUiOiJNSVQgTm8gQXR0cmlidXRpb24iLCJub2RlX2lkIjoiTURjNlRHbGpaVzV6WlRReCIsInNwZHhfaWQiOiJNSVQtMCIsInVybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vbGljZW5zZXMvbWl0LTAifSwibWVyZ2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL21lcmdlcyIsIm1pbGVzdG9uZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbWlsZXN0b25lc3svbnVtYmVyfSIsIm1pcnJvcl91cmwiOm51bGwsIm5hbWUiOiJwb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJub2RlX2lkIjoiTURFd09sSmxjRzl6YVhSdmNua3lNakU1TVRrek56az0iLCJub3RpZmljYXRpb25zX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL25vdGlmaWNhdGlvbnN7P3NpbmNlLGFsbCxwYXJ0aWNpcGF0aW5nfSIsIm9wZW5faXNzdWVzIjo3NCwib3Blbl9pc3N1ZXNfY291bnQiOjc0LCJvd25lciI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9ldmVudHN7L3ByaXZhY3l9IiwiZm9sbG93ZXJzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93ZXJzIiwiZm9sbG93aW5nX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93aW5ney9vdGhlcl91c2VyfSIsImdpc3RzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZ2lzdHN7L2dpc3RfaWR9IiwiZ3JhdmF0YXJfaWQiOiIiLCJodG1sX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scyIsImlkIjoxMjkxMjc2MzgsImxvZ2luIjoiYXdzLXBvd2VydG9vbHMiLCJub2RlX2lkIjoiT19rZ0RPQjdKVTFnIiwib3JnYW5pemF0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL29yZ3MiLCJyZWNlaXZlZF9ldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9yZWNlaXZlZF9ldmVudHMiLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3JlcG9zIiwic2l0ZV9hZG1pbiI6ZmFsc2UsInN0YXJyZWRfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9zdGFycmVkey9vd25lcn17L3JlcG99Iiwic3Vic2NyaXB0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3N1YnNjcmlwdGlvbnMiLCJ0eXBlIjoiT3JnYW5pemF0aW9uIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scyIsInVzZXJfdmlld190eXBlIjoicHVibGljIn0sInByaXZhdGUiOmZhbHNlLCJwdWxsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9wdWxsc3svbnVtYmVyfSIsInB1c2hlZF9hdCI6IjIwMjUtMDEtMzFUMDc6MjY6MjFaIiwicmVsZWFzZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vcmVsZWFzZXN7L2lkfSIsInNpemUiOjY3NDgzLCJzc2hfdXJsIjoiZ2l0QGdpdGh1Yi5jb206YXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsInN0YXJnYXplcnNfY291bnQiOjI5NzYsInN0YXJnYXplcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3RhcmdhemVycyIsInN0YXR1c2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3N0YXR1c2VzL3tzaGF9Iiwic3Vic2NyaWJlcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaWJlcnMiLCJzdWJzY3JpcHRpb25fdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaXB0aW9uIiwic3ZuX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ0YWdzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3RhZ3MiLCJ0ZWFtc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi90ZWFtcyIsInRvcGljcyI6WyJhd3MiLCJhd3MtbGFtYmRhIiwiaGFja3RvYmVyZmVzdCIsImxhbWJkYSIsInB5dGhvbiIsInNlcnZlcmxlc3MiXSwidHJlZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RyZWVzey9zaGF9IiwidXBkYXRlZF9hdCI6IjIwMjUtMDEtMzBUMjM6MDQ6MjBaIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ2aXNpYmlsaXR5IjoicHVibGljIiwid2F0Y2hlcnMiOjI5NzYsIndhdGNoZXJzX2NvdW50IjoyOTc2LCJ3ZWJfY29tbWl0X3NpZ25vZmZfcmVxdWlyZWQiOnRydWV9LCJzY2hlZHVsZSI6IjAgOCAqICogMS01Iiwid29ya2Zsb3ciOiIuZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVsZWFzZS55bWwifSwiZ2l0aHViX2hlYWRfcmVmIjoiIiwiZ2l0aHViX3JlZiI6InJlZnMvaGVhZHMvZGV2ZWxvcCIsImdpdGh1Yl9yZWZfdHlwZSI6ImJyYW5jaCIsImdpdGh1Yl9yZXBvc2l0b3J5X2lkIjoiMjIxOTE5Mzc5IiwiZ2l0aHViX3JlcG9zaXRvcnlfb3duZXIiOiJhd3MtcG93ZXJ0b29scyIsImdpdGh1Yl9yZXBvc2l0b3J5X293bmVyX2lkIjoiMTI5MTI3NjM4IiwiZ2l0aHViX3J1bl9hdHRlbXB0IjoiMSIsImdpdGh1Yl9ydW5faWQiOiIxMzA2ODY5MjkzMCIsImdpdGh1Yl9ydW5fbnVtYmVyIjoiMTY2IiwiZ2l0aHViX3NoYTEiOiIyNGZjYzBmN2JiZmIzZjViNWI2ZTliNzQ1ZTg2MGYwMWM2ODQ0ODczIn19LCJtZXRhZGF0YSI6eyJidWlsZEludm9jYXRpb25JRCI6IjEzMDY4NjkyOTMwLTEiLCJjb21wbGV0ZW5lc3MiOnsicGFyYW1ldGVycyI6dHJ1ZSwiZW52aXJvbm1lbnQiOmZhbHNlLCJtYXRlcmlhbHMiOmZhbHNlfSwicmVwcm9kdWNpYmxlIjpmYWxzZX0sIm1hdGVyaWFscyI6W3sidXJpIjoiZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob25AcmVmcy9oZWFkcy9kZXZlbG9wIiwiZGlnZXN0Ijp7InNoYTEiOiIyNGZjYzBmN2JiZmIzZjViNWI2ZTliNzQ1ZTg2MGYwMWM2ODQ0ODczIn19XX19","signatures":[{"keyid":"","sig":"MEUCICOsN/kVZ8uRbwIJvo3fC+zDTfsldiUFlciZ6UF/thLvAiEAnTh2k/YoeZIjT3wvMEkU4iYUn53nAWBcRMaaiV/qqm4=","cert":"-----BEGIN CERTIFICATE-----\nMIIHZTCCBuygAwIBAgIUNICEhsMtBmFplKkqsNlDS5L8n20wCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjUwMTMxMDgwNzQyWhcNMjUwMTMxMDgxNzQyWjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAE6+S+ocOH0WG6f7jUV88EwQZEaQ0Aj/6Y5Z5Q\nmvzSbAEzioGA0M9jQLZXhZQMyyShKZPE14WKl63PNikJ0E7b5aOCBgswggYHMA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUPdEo\nzJ7twK1pwiJx+aDS1xAyRA0wHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wgYQGA1UdEQEB/wR6MHiGdmh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1l\nd29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvLmdpdGh1Yi93b3JrZmxvd3MvZ2Vu\nZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJlZnMvdGFncy92Mi4wLjAwOQYKKwYB\nBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50\nLmNvbTAWBgorBgEEAYO/MAECBAhzY2hlZHVsZTA2BgorBgEEAYO/MAEDBCgyNGZj\nYzBmN2JiZmIzZjViNWI2ZTliNzQ1ZTg2MGYwMWM2ODQ0ODczMBkGCisGAQQBg78w\nAQQEC1ByZS1SZWxlYXNlMDUGCisGAQQBg78wAQUEJ2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbjAgBgorBgEEAYO/MAEGBBJyZWZzL2hlYWRz\nL2RldmVsb3AwOwYKKwYBBAGDvzABCAQtDCtodHRwczovL3Rva2VuLmFjdGlvbnMu\nZ2l0aHVidXNlcmNvbnRlbnQuY29tMIGGBgorBgEEAYO/MAEJBHgMdmh0dHBzOi8v\nZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3Iv\nLmdpdGh1Yi93b3JrZmxvd3MvZ2VuZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJl\nZnMvdGFncy92Mi4wLjAwOAYKKwYBBAGDvzABCgQqDCg1YTc3NWIzNjdhNTZkNWJk\nMTE4YTIyNGE4MTFiYmEyODgxNTBhNTYzMB0GCisGAQQBg78wAQsEDwwNZ2l0aHVi\nLWhvc3RlZDBKBgorBgEEAYO/MAEMBDwMOmh0dHBzOi8vZ2l0aHViLmNvbS9hd3Mt\ncG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24wOAYKKwYBBAGDvzAB\nDQQqDCgyNGZjYzBmN2JiZmIzZjViNWI2ZTliNzQ1ZTg2MGYwMWM2ODQ0ODczMCIG\nCisGAQQBg78wAQ4EFAwScmVmcy9oZWFkcy9kZXZlbG9wMBkGCisGAQQBg78wAQ8E\nCwwJMjIxOTE5Mzc5MDEGCisGAQQBg78wARAEIwwhaHR0cHM6Ly9naXRodWIuY29t\nL2F3cy1wb3dlcnRvb2xzMBkGCisGAQQBg78wAREECwwJMTI5MTI3NjM4MH8GCisG\nAQQBg78wARIEcQxvaHR0cHM6Ly9naXRodWIuY29tL2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbi8uZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVs\nZWFzZS55bWxAcmVmcy9oZWFkcy9kZXZlbG9wMDgGCisGAQQBg78wARMEKgwoMjRm\nY2MwZjdiYmZiM2Y1YjViNmU5Yjc0NWU4NjBmMDFjNjg0NDg3MzAYBgorBgEEAYO/\nMAEUBAoMCHNjaGVkdWxlMG4GCisGAQQBg78wARUEYAxeaHR0cHM6Ly9naXRodWIu\nY29tL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hY3Rp\nb25zL3J1bnMvMTMwNjg2OTI5MzAvYXR0ZW1wdHMvMTAWBgorBgEEAYO/MAEWBAgM\nBnB1YmxpYzCBigYKKwYBBAHWeQIEAgR8BHoAeAB2AN09MGrGxxEyYxkeHJlnNwKi\nSl643jyt/4eKcoAvKe6OAAABlLtmxsAAAAQDAEcwRQIhAJrsBTJRGfQkCLoLWeZW\n7jL97W5XrSQl0uFmwyuPUX/QAiBDvxpcEOvcV0yLvKROmmUs326BqP+5onQ5QcwC\noXGPTTAKBggqhkjOPQQDAwNnADBkAjA2x+VEUt2Bx4DuBauS5rCGLlCfNJh2eVF8\nBdbkr1fGeIJfdwvahYYZlCIKB4D3XyUCMHVjawhBRkYeDxetlReCjSrrqTzGYPer\nfREw5GychT7sBBZScjfb/tIzdvc3Jyvxig==\n-----END CERTIFICATE-----\n"}]}
\ No newline at end of file
diff --git a/provenance/3.5.1a3/multiple.intoto.jsonl b/provenance/3.5.1a3/multiple.intoto.jsonl
new file mode 100644
index 00000000000..3262822bd16
--- /dev/null
+++ b/provenance/3.5.1a3/multiple.intoto.jsonl
@@ -0,0 +1 @@
+{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMiIsInN1YmplY3QiOlt7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWEzLXB5My1ub25lLWFueS53aGwiLCJkaWdlc3QiOnsic2hhMjU2IjoiMDhhYzlmYzY5Yjg1MzU0OGI0YWMwMTFmYmZiMDFhMDMzNzk4M2I5ZDRkNTM4M2VmYjkyNjZlZDZhODAzZGQ3OCJ9fSx7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWEzLnRhci5neiIsImRpZ2VzdCI6eyJzaGEyNTYiOiIxMjM4MzY3NGM4YzM1OTMwM2M2ZDkyYzJkNjI5YzYyMTg3MGY1YmZiZDQ5NTNmN2U5Mjg1MmY4NWJlYWVmZjUyIn19XSwicHJlZGljYXRlIjp7ImJ1aWxkZXIiOnsiaWQiOiJodHRwczovL2dpdGh1Yi5jb20vc2xzYS1mcmFtZXdvcmsvc2xzYS1naXRodWItZ2VuZXJhdG9yLy5naXRodWIvd29ya2Zsb3dzL2dlbmVyYXRvcl9nZW5lcmljX3Nsc2EzLnltbEByZWZzL3RhZ3MvdjIuMC4wIn0sImJ1aWxkVHlwZSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvZ2VuZXJpY0B2MSIsImludm9jYXRpb24iOnsiY29uZmlnU291cmNlIjp7InVyaSI6ImdpdCtodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uQHJlZnMvaGVhZHMvZGV2ZWxvcCIsImRpZ2VzdCI6eyJzaGExIjoiNGIyYTIzOTQ2ZWQwN2Y5ZGRhZWYyNTQzYWMwMWUyZWZiYjdlMGZhMiJ9LCJlbnRyeVBvaW50IjoiLmdpdGh1Yi93b3JrZmxvd3MvcHJlLXJlbGVhc2UueW1sIn0sInBhcmFtZXRlcnMiOnt9LCJlbnZpcm9ubWVudCI6eyJnaXRodWJfYWN0b3IiOiJsZWFuZHJvZGFtYXNjZW5hIiwiZ2l0aHViX2FjdG9yX2lkIjoiNDI5NTE3MyIsImdpdGh1Yl9iYXNlX3JlZiI6IiIsImdpdGh1Yl9ldmVudF9uYW1lIjoic2NoZWR1bGUiLCJnaXRodWJfZXZlbnRfcGF5bG9hZCI6eyJlbnRlcnByaXNlIjp7ImF2YXRhcl91cmwiOiJodHRwczovL2F2YXRhcnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2IvMTI5MD92PTQiLCJjcmVhdGVkX2F0IjoiMjAxOS0xMS0xM1QxODowNTo0MVoiLCJkZXNjcmlwdGlvbiI6IiIsImh0bWxfdXJsIjoiaHR0cHM6Ly9naXRodWIuY29tL2VudGVycHJpc2VzL2FtYXpvbiIsImlkIjoxMjkwLCJuYW1lIjoiQW1hem9uIiwibm9kZV9pZCI6Ik1ERXdPa1Z1ZEdWeWNISnBjMlV4TWprdyIsInNsdWciOiJhbWF6b24iLCJ1cGRhdGVkX2F0IjoiMjAyNC0wOS0zMFQyMTowMjozMFoiLCJ3ZWJzaXRlX3VybCI6Imh0dHBzOi8vd3d3LmFtYXpvbi5jb20vIn0sIm9yZ2FuaXphdGlvbiI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJkZXNjcmlwdGlvbiI6IiIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvZXZlbnRzIiwiaG9va3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9vcmdzL2F3cy1wb3dlcnRvb2xzL2hvb2tzIiwiaWQiOjEyOTEyNzYzOCwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vb3Jncy9hd3MtcG93ZXJ0b29scy9pc3N1ZXMiLCJsb2dpbiI6ImF3cy1wb3dlcnRvb2xzIiwibWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvbWVtYmVyc3svbWVtYmVyfSIsIm5vZGVfaWQiOiJPX2tnRE9CN0pVMWciLCJwdWJsaWNfbWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcHVibGljX21lbWJlcnN7L21lbWJlcn0iLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcmVwb3MiLCJ1cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMifSwicmVwb3NpdG9yeSI6eyJhbGxvd19mb3JraW5nIjp0cnVlLCJhcmNoaXZlX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3thcmNoaXZlX2Zvcm1hdH17L3JlZn0iLCJhcmNoaXZlZCI6ZmFsc2UsImFzc2lnbmVlc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hc3NpZ25lZXN7L3VzZXJ9IiwiYmxvYnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L2Jsb2Jzey9zaGF9IiwiYnJhbmNoZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vYnJhbmNoZXN7L2JyYW5jaH0iLCJjbG9uZV91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsImNvbGxhYm9yYXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29sbGFib3JhdG9yc3svY29sbGFib3JhdG9yfSIsImNvbW1lbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbW1lbnRzey9udW1iZXJ9IiwiY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21taXRzey9zaGF9IiwiY29tcGFyZV91cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21wYXJlL3tiYXNlfS4uLntoZWFkfSIsImNvbnRlbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbnRlbnRzL3srcGF0aH0iLCJjb250cmlidXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29udHJpYnV0b3JzIiwiY3JlYXRlZF9hdCI6IjIwMTktMTEtMTVUMTI6MjY6MTJaIiwiY3VzdG9tX3Byb3BlcnRpZXMiOnt9LCJkZWZhdWx0X2JyYW5jaCI6ImRldmVsb3AiLCJkZXBsb3ltZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9kZXBsb3ltZW50cyIsImRlc2NyaXB0aW9uIjoiQSBkZXZlbG9wZXIgdG9vbGtpdCB0byBpbXBsZW1lbnQgU2VydmVybGVzcyBiZXN0IHByYWN0aWNlcyBhbmQgaW5jcmVhc2UgZGV2ZWxvcGVyIHZlbG9jaXR5LiIsImRpc2FibGVkIjpmYWxzZSwiZG93bmxvYWRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2Rvd25sb2FkcyIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9ldmVudHMiLCJmb3JrIjpmYWxzZSwiZm9ya3MiOjQwNywiZm9ya3NfY291bnQiOjQwNywiZm9ya3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZm9ya3MiLCJmdWxsX25hbWUiOiJhd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJnaXRfY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9naXQvY29tbWl0c3svc2hhfSIsImdpdF9yZWZzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2dpdC9yZWZzey9zaGF9IiwiZ2l0X3RhZ3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RhZ3N7L3NoYX0iLCJnaXRfdXJsIjoiZ2l0Oi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24uZ2l0IiwiaGFzX2Rpc2N1c3Npb25zIjp0cnVlLCJoYXNfZG93bmxvYWRzIjp0cnVlLCJoYXNfaXNzdWVzIjp0cnVlLCJoYXNfcGFnZXMiOmZhbHNlLCJoYXNfcHJvamVjdHMiOnRydWUsImhhc193aWtpIjpmYWxzZSwiaG9tZXBhZ2UiOiJodHRwczovL2RvY3MucG93ZXJ0b29scy5hd3MuZGV2L2xhbWJkYS9weXRob24vbGF0ZXN0LyIsImhvb2tzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2hvb2tzIiwiaHRtbF91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uIiwiaWQiOjIyMTkxOTM3OSwiaXNfdGVtcGxhdGUiOmZhbHNlLCJpc3N1ZV9jb21tZW50X3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlcy9jb21tZW50c3svbnVtYmVyfSIsImlzc3VlX2V2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9pc3N1ZXMvZXZlbnRzey9udW1iZXJ9IiwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlc3svbnVtYmVyfSIsImtleXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24va2V5c3sva2V5X2lkfSIsImxhYmVsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9sYWJlbHN7L25hbWV9IiwibGFuZ3VhZ2UiOiJQeXRob24iLCJsYW5ndWFnZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbGFuZ3VhZ2VzIiwibGljZW5zZSI6eyJrZXkiOiJtaXQtMCIsIm5hbWUiOiJNSVQgTm8gQXR0cmlidXRpb24iLCJub2RlX2lkIjoiTURjNlRHbGpaVzV6WlRReCIsInNwZHhfaWQiOiJNSVQtMCIsInVybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vbGljZW5zZXMvbWl0LTAifSwibWVyZ2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL21lcmdlcyIsIm1pbGVzdG9uZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbWlsZXN0b25lc3svbnVtYmVyfSIsIm1pcnJvcl91cmwiOm51bGwsIm5hbWUiOiJwb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJub2RlX2lkIjoiTURFd09sSmxjRzl6YVhSdmNua3lNakU1TVRrek56az0iLCJub3RpZmljYXRpb25zX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL25vdGlmaWNhdGlvbnN7P3NpbmNlLGFsbCxwYXJ0aWNpcGF0aW5nfSIsIm9wZW5faXNzdWVzIjo3OSwib3Blbl9pc3N1ZXNfY291bnQiOjc5LCJvd25lciI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9ldmVudHN7L3ByaXZhY3l9IiwiZm9sbG93ZXJzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93ZXJzIiwiZm9sbG93aW5nX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93aW5ney9vdGhlcl91c2VyfSIsImdpc3RzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZ2lzdHN7L2dpc3RfaWR9IiwiZ3JhdmF0YXJfaWQiOiIiLCJodG1sX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scyIsImlkIjoxMjkxMjc2MzgsImxvZ2luIjoiYXdzLXBvd2VydG9vbHMiLCJub2RlX2lkIjoiT19rZ0RPQjdKVTFnIiwib3JnYW5pemF0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL29yZ3MiLCJyZWNlaXZlZF9ldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9yZWNlaXZlZF9ldmVudHMiLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3JlcG9zIiwic2l0ZV9hZG1pbiI6ZmFsc2UsInN0YXJyZWRfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9zdGFycmVkey9vd25lcn17L3JlcG99Iiwic3Vic2NyaXB0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3N1YnNjcmlwdGlvbnMiLCJ0eXBlIjoiT3JnYW5pemF0aW9uIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scyIsInVzZXJfdmlld190eXBlIjoicHVibGljIn0sInByaXZhdGUiOmZhbHNlLCJwdWxsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9wdWxsc3svbnVtYmVyfSIsInB1c2hlZF9hdCI6IjIwMjUtMDItMDJUMTc6MTA6MjlaIiwicmVsZWFzZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vcmVsZWFzZXN7L2lkfSIsInNpemUiOjY3OTE5LCJzc2hfdXJsIjoiZ2l0QGdpdGh1Yi5jb206YXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsInN0YXJnYXplcnNfY291bnQiOjI5NzcsInN0YXJnYXplcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3RhcmdhemVycyIsInN0YXR1c2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3N0YXR1c2VzL3tzaGF9Iiwic3Vic2NyaWJlcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaWJlcnMiLCJzdWJzY3JpcHRpb25fdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaXB0aW9uIiwic3ZuX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ0YWdzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3RhZ3MiLCJ0ZWFtc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi90ZWFtcyIsInRvcGljcyI6WyJhd3MiLCJhd3MtbGFtYmRhIiwiaGFja3RvYmVyZmVzdCIsImxhbWJkYSIsInB5dGhvbiIsInNlcnZlcmxlc3MiXSwidHJlZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RyZWVzey9zaGF9IiwidXBkYXRlZF9hdCI6IjIwMjUtMDItMDJUMTc6MDk6MzVaIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ2aXNpYmlsaXR5IjoicHVibGljIiwid2F0Y2hlcnMiOjI5NzcsIndhdGNoZXJzX2NvdW50IjoyOTc3LCJ3ZWJfY29tbWl0X3NpZ25vZmZfcmVxdWlyZWQiOnRydWV9LCJzY2hlZHVsZSI6IjAgOCAqICogMS01Iiwid29ya2Zsb3ciOiIuZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVsZWFzZS55bWwifSwiZ2l0aHViX2hlYWRfcmVmIjoiIiwiZ2l0aHViX3JlZiI6InJlZnMvaGVhZHMvZGV2ZWxvcCIsImdpdGh1Yl9yZWZfdHlwZSI6ImJyYW5jaCIsImdpdGh1Yl9yZXBvc2l0b3J5X2lkIjoiMjIxOTE5Mzc5IiwiZ2l0aHViX3JlcG9zaXRvcnlfb3duZXIiOiJhd3MtcG93ZXJ0b29scyIsImdpdGh1Yl9yZXBvc2l0b3J5X293bmVyX2lkIjoiMTI5MTI3NjM4IiwiZ2l0aHViX3J1bl9hdHRlbXB0IjoiMSIsImdpdGh1Yl9ydW5faWQiOiIxMzEwODg4OTY0OSIsImdpdGh1Yl9ydW5fbnVtYmVyIjoiMTY3IiwiZ2l0aHViX3NoYTEiOiI0YjJhMjM5NDZlZDA3ZjlkZGFlZjI1NDNhYzAxZTJlZmJiN2UwZmEyIn19LCJtZXRhZGF0YSI6eyJidWlsZEludm9jYXRpb25JRCI6IjEzMTA4ODg5NjQ5LTEiLCJjb21wbGV0ZW5lc3MiOnsicGFyYW1ldGVycyI6dHJ1ZSwiZW52aXJvbm1lbnQiOmZhbHNlLCJtYXRlcmlhbHMiOmZhbHNlfSwicmVwcm9kdWNpYmxlIjpmYWxzZX0sIm1hdGVyaWFscyI6W3sidXJpIjoiZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob25AcmVmcy9oZWFkcy9kZXZlbG9wIiwiZGlnZXN0Ijp7InNoYTEiOiI0YjJhMjM5NDZlZDA3ZjlkZGFlZjI1NDNhYzAxZTJlZmJiN2UwZmEyIn19XX19","signatures":[{"keyid":"","sig":"MEUCIAY8F9UVAIKvxA5SUDtARIJ1n7uQg/cJEQgUfhD8yxMbAiEA2zYGziYQ/AVgbL+e6kuVfw0dIypytRbOIxypG4Nln50=","cert":"-----BEGIN CERTIFICATE-----\nMIIHZjCCBuygAwIBAgIUMgv75r7USXHZjYaaxwGP9CXinZ0wCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjUwMjAzMDgwNzE5WhcNMjUwMjAzMDgxNzE5WjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAEghbdmSXb1gYKC4kPt/foD5zmlG2kXubjL6sP\nEiw0d9VBfpL+war90gxbXY/qeI/op9G0wt/S//9hSSbuS/Wd2qOCBgswggYHMA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUoivo\nOFD7qb9ashMakrrnfa8nTdYwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wgYQGA1UdEQEB/wR6MHiGdmh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1l\nd29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvLmdpdGh1Yi93b3JrZmxvd3MvZ2Vu\nZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJlZnMvdGFncy92Mi4wLjAwOQYKKwYB\nBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50\nLmNvbTAWBgorBgEEAYO/MAECBAhzY2hlZHVsZTA2BgorBgEEAYO/MAEDBCg0YjJh\nMjM5NDZlZDA3ZjlkZGFlZjI1NDNhYzAxZTJlZmJiN2UwZmEyMBkGCisGAQQBg78w\nAQQEC1ByZS1SZWxlYXNlMDUGCisGAQQBg78wAQUEJ2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbjAgBgorBgEEAYO/MAEGBBJyZWZzL2hlYWRz\nL2RldmVsb3AwOwYKKwYBBAGDvzABCAQtDCtodHRwczovL3Rva2VuLmFjdGlvbnMu\nZ2l0aHVidXNlcmNvbnRlbnQuY29tMIGGBgorBgEEAYO/MAEJBHgMdmh0dHBzOi8v\nZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3Iv\nLmdpdGh1Yi93b3JrZmxvd3MvZ2VuZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJl\nZnMvdGFncy92Mi4wLjAwOAYKKwYBBAGDvzABCgQqDCg1YTc3NWIzNjdhNTZkNWJk\nMTE4YTIyNGE4MTFiYmEyODgxNTBhNTYzMB0GCisGAQQBg78wAQsEDwwNZ2l0aHVi\nLWhvc3RlZDBKBgorBgEEAYO/MAEMBDwMOmh0dHBzOi8vZ2l0aHViLmNvbS9hd3Mt\ncG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24wOAYKKwYBBAGDvzAB\nDQQqDCg0YjJhMjM5NDZlZDA3ZjlkZGFlZjI1NDNhYzAxZTJlZmJiN2UwZmEyMCIG\nCisGAQQBg78wAQ4EFAwScmVmcy9oZWFkcy9kZXZlbG9wMBkGCisGAQQBg78wAQ8E\nCwwJMjIxOTE5Mzc5MDEGCisGAQQBg78wARAEIwwhaHR0cHM6Ly9naXRodWIuY29t\nL2F3cy1wb3dlcnRvb2xzMBkGCisGAQQBg78wAREECwwJMTI5MTI3NjM4MH8GCisG\nAQQBg78wARIEcQxvaHR0cHM6Ly9naXRodWIuY29tL2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbi8uZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVs\nZWFzZS55bWxAcmVmcy9oZWFkcy9kZXZlbG9wMDgGCisGAQQBg78wARMEKgwoNGIy\nYTIzOTQ2ZWQwN2Y5ZGRhZWYyNTQzYWMwMWUyZWZiYjdlMGZhMjAYBgorBgEEAYO/\nMAEUBAoMCHNjaGVkdWxlMG4GCisGAQQBg78wARUEYAxeaHR0cHM6Ly9naXRodWIu\nY29tL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hY3Rp\nb25zL3J1bnMvMTMxMDg4ODk2NDkvYXR0ZW1wdHMvMTAWBgorBgEEAYO/MAEWBAgM\nBnB1YmxpYzCBigYKKwYBBAHWeQIEAgR8BHoAeAB2AN09MGrGxxEyYxkeHJlnNwKi\nSl643jyt/4eKcoAvKe6OAAABlMrZgDsAAAQDAEcwRQIgUQ80N03lqon6YKWNPZbF\nfp1tz3DMF8su1FPKseDeMIUCIQCtg7BM2hQp/+CbYk8NjcU0ELzWIOjwpSE9zeAp\nGWuQPjAKBggqhkjOPQQDAwNoADBlAjAcOLDXZ6C+t0vMHKsOcszN+nMxzNgT6M0x\nusjTmYPrmqNRllIHgE6zJObKF8DtL1kCMQDMUfBsKDcs05QMY/J6/a4u9Ua1SRsX\nnGl9zx5abz5y37BmdSJoe/23w9nOuyZc0qA=\n-----END CERTIFICATE-----\n"}]}
\ No newline at end of file
diff --git a/provenance/3.5.1a4/multiple.intoto.jsonl b/provenance/3.5.1a4/multiple.intoto.jsonl
new file mode 100644
index 00000000000..9e18c3fddf6
--- /dev/null
+++ b/provenance/3.5.1a4/multiple.intoto.jsonl
@@ -0,0 +1 @@
+{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMiIsInN1YmplY3QiOlt7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWE0LXB5My1ub25lLWFueS53aGwiLCJkaWdlc3QiOnsic2hhMjU2IjoiNjg3ZDA3MTlmZGJlZTQ2Zjg0ZjA0ODAwNGUxOGFkMDg2YzE1YTMyNDZlYTA1MWNhMjRhYTRlMzA5NDA0YjM4OSJ9fSx7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWE0LnRhci5neiIsImRpZ2VzdCI6eyJzaGEyNTYiOiIwMThkNWU1ZTJhNzVjY2RlZTEwNmNlYTNmMDMzNjA0MjZiOGI0Y2U1YzIyNDdiZDc3OGFkNDg2ZWNiNWYwNTNkIn19XSwicHJlZGljYXRlIjp7ImJ1aWxkZXIiOnsiaWQiOiJodHRwczovL2dpdGh1Yi5jb20vc2xzYS1mcmFtZXdvcmsvc2xzYS1naXRodWItZ2VuZXJhdG9yLy5naXRodWIvd29ya2Zsb3dzL2dlbmVyYXRvcl9nZW5lcmljX3Nsc2EzLnltbEByZWZzL3RhZ3MvdjIuMC4wIn0sImJ1aWxkVHlwZSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvZ2VuZXJpY0B2MSIsImludm9jYXRpb24iOnsiY29uZmlnU291cmNlIjp7InVyaSI6ImdpdCtodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uQHJlZnMvaGVhZHMvZGV2ZWxvcCIsImRpZ2VzdCI6eyJzaGExIjoiZDExZGI5YjUxODgyYzAyZmUwNmZkMDcxMDdjNmYxMDJiNmE4NmExOSJ9LCJlbnRyeVBvaW50IjoiLmdpdGh1Yi93b3JrZmxvd3MvcHJlLXJlbGVhc2UueW1sIn0sInBhcmFtZXRlcnMiOnt9LCJlbnZpcm9ubWVudCI6eyJnaXRodWJfYWN0b3IiOiJsZWFuZHJvZGFtYXNjZW5hIiwiZ2l0aHViX2FjdG9yX2lkIjoiNDI5NTE3MyIsImdpdGh1Yl9iYXNlX3JlZiI6IiIsImdpdGh1Yl9ldmVudF9uYW1lIjoic2NoZWR1bGUiLCJnaXRodWJfZXZlbnRfcGF5bG9hZCI6eyJlbnRlcnByaXNlIjp7ImF2YXRhcl91cmwiOiJodHRwczovL2F2YXRhcnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2IvMTI5MD92PTQiLCJjcmVhdGVkX2F0IjoiMjAxOS0xMS0xM1QxODowNTo0MVoiLCJkZXNjcmlwdGlvbiI6IiIsImh0bWxfdXJsIjoiaHR0cHM6Ly9naXRodWIuY29tL2VudGVycHJpc2VzL2FtYXpvbiIsImlkIjoxMjkwLCJuYW1lIjoiQW1hem9uIiwibm9kZV9pZCI6Ik1ERXdPa1Z1ZEdWeWNISnBjMlV4TWprdyIsInNsdWciOiJhbWF6b24iLCJ1cGRhdGVkX2F0IjoiMjAyNC0wOS0zMFQyMTowMjozMFoiLCJ3ZWJzaXRlX3VybCI6Imh0dHBzOi8vd3d3LmFtYXpvbi5jb20vIn0sIm9yZ2FuaXphdGlvbiI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJkZXNjcmlwdGlvbiI6IiIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvZXZlbnRzIiwiaG9va3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9vcmdzL2F3cy1wb3dlcnRvb2xzL2hvb2tzIiwiaWQiOjEyOTEyNzYzOCwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vb3Jncy9hd3MtcG93ZXJ0b29scy9pc3N1ZXMiLCJsb2dpbiI6ImF3cy1wb3dlcnRvb2xzIiwibWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvbWVtYmVyc3svbWVtYmVyfSIsIm5vZGVfaWQiOiJPX2tnRE9CN0pVMWciLCJwdWJsaWNfbWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcHVibGljX21lbWJlcnN7L21lbWJlcn0iLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcmVwb3MiLCJ1cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMifSwicmVwb3NpdG9yeSI6eyJhbGxvd19mb3JraW5nIjp0cnVlLCJhcmNoaXZlX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3thcmNoaXZlX2Zvcm1hdH17L3JlZn0iLCJhcmNoaXZlZCI6ZmFsc2UsImFzc2lnbmVlc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hc3NpZ25lZXN7L3VzZXJ9IiwiYmxvYnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L2Jsb2Jzey9zaGF9IiwiYnJhbmNoZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vYnJhbmNoZXN7L2JyYW5jaH0iLCJjbG9uZV91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsImNvbGxhYm9yYXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29sbGFib3JhdG9yc3svY29sbGFib3JhdG9yfSIsImNvbW1lbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbW1lbnRzey9udW1iZXJ9IiwiY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21taXRzey9zaGF9IiwiY29tcGFyZV91cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21wYXJlL3tiYXNlfS4uLntoZWFkfSIsImNvbnRlbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbnRlbnRzL3srcGF0aH0iLCJjb250cmlidXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29udHJpYnV0b3JzIiwiY3JlYXRlZF9hdCI6IjIwMTktMTEtMTVUMTI6MjY6MTJaIiwiY3VzdG9tX3Byb3BlcnRpZXMiOnt9LCJkZWZhdWx0X2JyYW5jaCI6ImRldmVsb3AiLCJkZXBsb3ltZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9kZXBsb3ltZW50cyIsImRlc2NyaXB0aW9uIjoiQSBkZXZlbG9wZXIgdG9vbGtpdCB0byBpbXBsZW1lbnQgU2VydmVybGVzcyBiZXN0IHByYWN0aWNlcyBhbmQgaW5jcmVhc2UgZGV2ZWxvcGVyIHZlbG9jaXR5LiIsImRpc2FibGVkIjpmYWxzZSwiZG93bmxvYWRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2Rvd25sb2FkcyIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9ldmVudHMiLCJmb3JrIjpmYWxzZSwiZm9ya3MiOjQwNywiZm9ya3NfY291bnQiOjQwNywiZm9ya3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZm9ya3MiLCJmdWxsX25hbWUiOiJhd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJnaXRfY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9naXQvY29tbWl0c3svc2hhfSIsImdpdF9yZWZzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2dpdC9yZWZzey9zaGF9IiwiZ2l0X3RhZ3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RhZ3N7L3NoYX0iLCJnaXRfdXJsIjoiZ2l0Oi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24uZ2l0IiwiaGFzX2Rpc2N1c3Npb25zIjp0cnVlLCJoYXNfZG93bmxvYWRzIjp0cnVlLCJoYXNfaXNzdWVzIjp0cnVlLCJoYXNfcGFnZXMiOmZhbHNlLCJoYXNfcHJvamVjdHMiOnRydWUsImhhc193aWtpIjpmYWxzZSwiaG9tZXBhZ2UiOiJodHRwczovL2RvY3MucG93ZXJ0b29scy5hd3MuZGV2L2xhbWJkYS9weXRob24vbGF0ZXN0LyIsImhvb2tzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2hvb2tzIiwiaHRtbF91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uIiwiaWQiOjIyMTkxOTM3OSwiaXNfdGVtcGxhdGUiOmZhbHNlLCJpc3N1ZV9jb21tZW50X3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlcy9jb21tZW50c3svbnVtYmVyfSIsImlzc3VlX2V2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9pc3N1ZXMvZXZlbnRzey9udW1iZXJ9IiwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlc3svbnVtYmVyfSIsImtleXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24va2V5c3sva2V5X2lkfSIsImxhYmVsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9sYWJlbHN7L25hbWV9IiwibGFuZ3VhZ2UiOiJQeXRob24iLCJsYW5ndWFnZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbGFuZ3VhZ2VzIiwibGljZW5zZSI6eyJrZXkiOiJtaXQtMCIsIm5hbWUiOiJNSVQgTm8gQXR0cmlidXRpb24iLCJub2RlX2lkIjoiTURjNlRHbGpaVzV6WlRReCIsInNwZHhfaWQiOiJNSVQtMCIsInVybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vbGljZW5zZXMvbWl0LTAifSwibWVyZ2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL21lcmdlcyIsIm1pbGVzdG9uZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbWlsZXN0b25lc3svbnVtYmVyfSIsIm1pcnJvcl91cmwiOm51bGwsIm5hbWUiOiJwb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJub2RlX2lkIjoiTURFd09sSmxjRzl6YVhSdmNua3lNakU1TVRrek56az0iLCJub3RpZmljYXRpb25zX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL25vdGlmaWNhdGlvbnN7P3NpbmNlLGFsbCxwYXJ0aWNpcGF0aW5nfSIsIm9wZW5faXNzdWVzIjo2Nywib3Blbl9pc3N1ZXNfY291bnQiOjY3LCJvd25lciI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9ldmVudHN7L3ByaXZhY3l9IiwiZm9sbG93ZXJzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93ZXJzIiwiZm9sbG93aW5nX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93aW5ney9vdGhlcl91c2VyfSIsImdpc3RzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZ2lzdHN7L2dpc3RfaWR9IiwiZ3JhdmF0YXJfaWQiOiIiLCJodG1sX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scyIsImlkIjoxMjkxMjc2MzgsImxvZ2luIjoiYXdzLXBvd2VydG9vbHMiLCJub2RlX2lkIjoiT19rZ0RPQjdKVTFnIiwib3JnYW5pemF0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL29yZ3MiLCJyZWNlaXZlZF9ldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9yZWNlaXZlZF9ldmVudHMiLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3JlcG9zIiwic2l0ZV9hZG1pbiI6ZmFsc2UsInN0YXJyZWRfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9zdGFycmVkey9vd25lcn17L3JlcG99Iiwic3Vic2NyaXB0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3N1YnNjcmlwdGlvbnMiLCJ0eXBlIjoiT3JnYW5pemF0aW9uIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scyIsInVzZXJfdmlld190eXBlIjoicHVibGljIn0sInByaXZhdGUiOmZhbHNlLCJwdWxsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9wdWxsc3svbnVtYmVyfSIsInB1c2hlZF9hdCI6IjIwMjUtMDItMDNUMjI6MzE6MzlaIiwicmVsZWFzZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vcmVsZWFzZXN7L2lkfSIsInNpemUiOjc2OTA1LCJzc2hfdXJsIjoiZ2l0QGdpdGh1Yi5jb206YXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsInN0YXJnYXplcnNfY291bnQiOjI5NzksInN0YXJnYXplcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3RhcmdhemVycyIsInN0YXR1c2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3N0YXR1c2VzL3tzaGF9Iiwic3Vic2NyaWJlcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaWJlcnMiLCJzdWJzY3JpcHRpb25fdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaXB0aW9uIiwic3ZuX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ0YWdzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3RhZ3MiLCJ0ZWFtc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi90ZWFtcyIsInRvcGljcyI6WyJhd3MiLCJhd3MtbGFtYmRhIiwiaGFja3RvYmVyZmVzdCIsImxhbWJkYSIsInB5dGhvbiIsInNlcnZlcmxlc3MiXSwidHJlZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RyZWVzey9zaGF9IiwidXBkYXRlZF9hdCI6IjIwMjUtMDItMDNUMjI6MTU6MDNaIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ2aXNpYmlsaXR5IjoicHVibGljIiwid2F0Y2hlcnMiOjI5NzksIndhdGNoZXJzX2NvdW50IjoyOTc5LCJ3ZWJfY29tbWl0X3NpZ25vZmZfcmVxdWlyZWQiOnRydWV9LCJzY2hlZHVsZSI6IjAgOCAqICogMS01Iiwid29ya2Zsb3ciOiIuZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVsZWFzZS55bWwifSwiZ2l0aHViX2hlYWRfcmVmIjoiIiwiZ2l0aHViX3JlZiI6InJlZnMvaGVhZHMvZGV2ZWxvcCIsImdpdGh1Yl9yZWZfdHlwZSI6ImJyYW5jaCIsImdpdGh1Yl9yZXBvc2l0b3J5X2lkIjoiMjIxOTE5Mzc5IiwiZ2l0aHViX3JlcG9zaXRvcnlfb3duZXIiOiJhd3MtcG93ZXJ0b29scyIsImdpdGh1Yl9yZXBvc2l0b3J5X293bmVyX2lkIjoiMTI5MTI3NjM4IiwiZ2l0aHViX3J1bl9hdHRlbXB0IjoiMSIsImdpdGh1Yl9ydW5faWQiOiIxMzEzMDg1MzI4NCIsImdpdGh1Yl9ydW5fbnVtYmVyIjoiMTY4IiwiZ2l0aHViX3NoYTEiOiJkMTFkYjliNTE4ODJjMDJmZTA2ZmQwNzEwN2M2ZjEwMmI2YTg2YTE5In19LCJtZXRhZGF0YSI6eyJidWlsZEludm9jYXRpb25JRCI6IjEzMTMwODUzMjg0LTEiLCJjb21wbGV0ZW5lc3MiOnsicGFyYW1ldGVycyI6dHJ1ZSwiZW52aXJvbm1lbnQiOmZhbHNlLCJtYXRlcmlhbHMiOmZhbHNlfSwicmVwcm9kdWNpYmxlIjpmYWxzZX0sIm1hdGVyaWFscyI6W3sidXJpIjoiZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob25AcmVmcy9oZWFkcy9kZXZlbG9wIiwiZGlnZXN0Ijp7InNoYTEiOiJkMTFkYjliNTE4ODJjMDJmZTA2ZmQwNzEwN2M2ZjEwMmI2YTg2YTE5In19XX19","signatures":[{"keyid":"","sig":"MEUCIQCQUl1Por3aaNsjPx6gNoVca4oAr1BTIaIDrRRSiIEOzAIgZ+yme/chkZC8drmsIrcjmzZqjfPX0z5vsQbkRpGuu9M=","cert":"-----BEGIN CERTIFICATE-----\nMIIHZjCCBuugAwIBAgIUaquS/ddblTy91v44Vj6cV4RH4W4wCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjUwMjA0MDgwNzMzWhcNMjUwMjA0MDgxNzMzWjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAE0yWlBAISq7ijiENWn6xk8T0foNdS2C1+65Fk\nVBwdkHnUGwpn54flO7/AYp771xiu7ecDeyCcBzrKvedua1f/8KOCBgowggYGMA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUewW4\nn2EPIdaZD2pXsMO2dmAXbCwwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wgYQGA1UdEQEB/wR6MHiGdmh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1l\nd29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvLmdpdGh1Yi93b3JrZmxvd3MvZ2Vu\nZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJlZnMvdGFncy92Mi4wLjAwOQYKKwYB\nBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50\nLmNvbTAWBgorBgEEAYO/MAECBAhzY2hlZHVsZTA2BgorBgEEAYO/MAEDBChkMTFk\nYjliNTE4ODJjMDJmZTA2ZmQwNzEwN2M2ZjEwMmI2YTg2YTE5MBkGCisGAQQBg78w\nAQQEC1ByZS1SZWxlYXNlMDUGCisGAQQBg78wAQUEJ2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbjAgBgorBgEEAYO/MAEGBBJyZWZzL2hlYWRz\nL2RldmVsb3AwOwYKKwYBBAGDvzABCAQtDCtodHRwczovL3Rva2VuLmFjdGlvbnMu\nZ2l0aHVidXNlcmNvbnRlbnQuY29tMIGGBgorBgEEAYO/MAEJBHgMdmh0dHBzOi8v\nZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3Iv\nLmdpdGh1Yi93b3JrZmxvd3MvZ2VuZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJl\nZnMvdGFncy92Mi4wLjAwOAYKKwYBBAGDvzABCgQqDCg1YTc3NWIzNjdhNTZkNWJk\nMTE4YTIyNGE4MTFiYmEyODgxNTBhNTYzMB0GCisGAQQBg78wAQsEDwwNZ2l0aHVi\nLWhvc3RlZDBKBgorBgEEAYO/MAEMBDwMOmh0dHBzOi8vZ2l0aHViLmNvbS9hd3Mt\ncG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24wOAYKKwYBBAGDvzAB\nDQQqDChkMTFkYjliNTE4ODJjMDJmZTA2ZmQwNzEwN2M2ZjEwMmI2YTg2YTE5MCIG\nCisGAQQBg78wAQ4EFAwScmVmcy9oZWFkcy9kZXZlbG9wMBkGCisGAQQBg78wAQ8E\nCwwJMjIxOTE5Mzc5MDEGCisGAQQBg78wARAEIwwhaHR0cHM6Ly9naXRodWIuY29t\nL2F3cy1wb3dlcnRvb2xzMBkGCisGAQQBg78wAREECwwJMTI5MTI3NjM4MH8GCisG\nAQQBg78wARIEcQxvaHR0cHM6Ly9naXRodWIuY29tL2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbi8uZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVs\nZWFzZS55bWxAcmVmcy9oZWFkcy9kZXZlbG9wMDgGCisGAQQBg78wARMEKgwoZDEx\nZGI5YjUxODgyYzAyZmUwNmZkMDcxMDdjNmYxMDJiNmE4NmExOTAYBgorBgEEAYO/\nMAEUBAoMCHNjaGVkdWxlMG4GCisGAQQBg78wARUEYAxeaHR0cHM6Ly9naXRodWIu\nY29tL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hY3Rp\nb25zL3J1bnMvMTMxMzA4NTMyODQvYXR0ZW1wdHMvMTAWBgorBgEEAYO/MAEWBAgM\nBnB1YmxpYzCBiQYKKwYBBAHWeQIEAgR7BHkAdwB1AN09MGrGxxEyYxkeHJlnNwKi\nSl643jyt/4eKcoAvKe6OAAABlNAAFHsAAAQDAEYwRAIgKLRo1Y7uG4ehy24OFfMj\n5gSvay8J8nFOllLYW/SOdt8CIBOW7uup/GSW5/VaFujKE7rTns7v5DnRur6IgoZj\nSJUyMAoGCCqGSM49BAMDA2kAMGYCMQCYy7JWNmpPBZmNdDbHgsnLOLXovFRJKldG\nX+3lVRUaB3uzR2ERXJSXzxF+bLhpQ3YCMQCOxK0jMU9M0QzZNsnbnxny9b/1Q1nk\nG7e0HlkvY4yOUrwRroRT6upsEwJfAjO9QmY=\n-----END CERTIFICATE-----\n"}]}
\ No newline at end of file
diff --git a/provenance/3.5.1a5/multiple.intoto.jsonl b/provenance/3.5.1a5/multiple.intoto.jsonl
new file mode 100644
index 00000000000..d3f09af5c75
--- /dev/null
+++ b/provenance/3.5.1a5/multiple.intoto.jsonl
@@ -0,0 +1 @@
+{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMiIsInN1YmplY3QiOlt7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWE1LXB5My1ub25lLWFueS53aGwiLCJkaWdlc3QiOnsic2hhMjU2IjoiODcxNTQ0MDJjNGQ5ZDMyYTljZWZmY2ZlNDA1ZDAxN2U5M2M0ZDc1NGNlY2E1ZjdlYjczZGQ0MzM4NDM4YTFjZCJ9fSx7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWE1LnRhci5neiIsImRpZ2VzdCI6eyJzaGEyNTYiOiJlMzU4NTU2Y2ZjZDdhOTc0NTE5OTY1MDE4YWE2ODUyOTA0NGM2NGY3YTMyZjFhNTVmYmNjNTA4YTg2MGQ2Nzc0In19XSwicHJlZGljYXRlIjp7ImJ1aWxkZXIiOnsiaWQiOiJodHRwczovL2dpdGh1Yi5jb20vc2xzYS1mcmFtZXdvcmsvc2xzYS1naXRodWItZ2VuZXJhdG9yLy5naXRodWIvd29ya2Zsb3dzL2dlbmVyYXRvcl9nZW5lcmljX3Nsc2EzLnltbEByZWZzL3RhZ3MvdjIuMC4wIn0sImJ1aWxkVHlwZSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvZ2VuZXJpY0B2MSIsImludm9jYXRpb24iOnsiY29uZmlnU291cmNlIjp7InVyaSI6ImdpdCtodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uQHJlZnMvaGVhZHMvZGV2ZWxvcCIsImRpZ2VzdCI6eyJzaGExIjoiZjRlNzdmMWFjNTA0NjE4NzU2YTMyNDY0YjUyNDRhMTA4YmQwYzA4MiJ9LCJlbnRyeVBvaW50IjoiLmdpdGh1Yi93b3JrZmxvd3MvcHJlLXJlbGVhc2UueW1sIn0sInBhcmFtZXRlcnMiOnt9LCJlbnZpcm9ubWVudCI6eyJnaXRodWJfYWN0b3IiOiJsZWFuZHJvZGFtYXNjZW5hIiwiZ2l0aHViX2FjdG9yX2lkIjoiNDI5NTE3MyIsImdpdGh1Yl9iYXNlX3JlZiI6IiIsImdpdGh1Yl9ldmVudF9uYW1lIjoic2NoZWR1bGUiLCJnaXRodWJfZXZlbnRfcGF5bG9hZCI6eyJlbnRlcnByaXNlIjp7ImF2YXRhcl91cmwiOiJodHRwczovL2F2YXRhcnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2IvMTI5MD92PTQiLCJjcmVhdGVkX2F0IjoiMjAxOS0xMS0xM1QxODowNTo0MVoiLCJkZXNjcmlwdGlvbiI6IiIsImh0bWxfdXJsIjoiaHR0cHM6Ly9naXRodWIuY29tL2VudGVycHJpc2VzL2FtYXpvbiIsImlkIjoxMjkwLCJuYW1lIjoiQW1hem9uIiwibm9kZV9pZCI6Ik1ERXdPa1Z1ZEdWeWNISnBjMlV4TWprdyIsInNsdWciOiJhbWF6b24iLCJ1cGRhdGVkX2F0IjoiMjAyNC0wOS0zMFQyMTowMjozMFoiLCJ3ZWJzaXRlX3VybCI6Imh0dHBzOi8vd3d3LmFtYXpvbi5jb20vIn0sIm9yZ2FuaXphdGlvbiI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJkZXNjcmlwdGlvbiI6IiIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvZXZlbnRzIiwiaG9va3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9vcmdzL2F3cy1wb3dlcnRvb2xzL2hvb2tzIiwiaWQiOjEyOTEyNzYzOCwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vb3Jncy9hd3MtcG93ZXJ0b29scy9pc3N1ZXMiLCJsb2dpbiI6ImF3cy1wb3dlcnRvb2xzIiwibWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvbWVtYmVyc3svbWVtYmVyfSIsIm5vZGVfaWQiOiJPX2tnRE9CN0pVMWciLCJwdWJsaWNfbWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcHVibGljX21lbWJlcnN7L21lbWJlcn0iLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcmVwb3MiLCJ1cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMifSwicmVwb3NpdG9yeSI6eyJhbGxvd19mb3JraW5nIjp0cnVlLCJhcmNoaXZlX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3thcmNoaXZlX2Zvcm1hdH17L3JlZn0iLCJhcmNoaXZlZCI6ZmFsc2UsImFzc2lnbmVlc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hc3NpZ25lZXN7L3VzZXJ9IiwiYmxvYnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L2Jsb2Jzey9zaGF9IiwiYnJhbmNoZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vYnJhbmNoZXN7L2JyYW5jaH0iLCJjbG9uZV91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsImNvbGxhYm9yYXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29sbGFib3JhdG9yc3svY29sbGFib3JhdG9yfSIsImNvbW1lbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbW1lbnRzey9udW1iZXJ9IiwiY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21taXRzey9zaGF9IiwiY29tcGFyZV91cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21wYXJlL3tiYXNlfS4uLntoZWFkfSIsImNvbnRlbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbnRlbnRzL3srcGF0aH0iLCJjb250cmlidXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29udHJpYnV0b3JzIiwiY3JlYXRlZF9hdCI6IjIwMTktMTEtMTVUMTI6MjY6MTJaIiwiY3VzdG9tX3Byb3BlcnRpZXMiOnt9LCJkZWZhdWx0X2JyYW5jaCI6ImRldmVsb3AiLCJkZXBsb3ltZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9kZXBsb3ltZW50cyIsImRlc2NyaXB0aW9uIjoiQSBkZXZlbG9wZXIgdG9vbGtpdCB0byBpbXBsZW1lbnQgU2VydmVybGVzcyBiZXN0IHByYWN0aWNlcyBhbmQgaW5jcmVhc2UgZGV2ZWxvcGVyIHZlbG9jaXR5LiIsImRpc2FibGVkIjpmYWxzZSwiZG93bmxvYWRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2Rvd25sb2FkcyIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9ldmVudHMiLCJmb3JrIjpmYWxzZSwiZm9ya3MiOjQwOCwiZm9ya3NfY291bnQiOjQwOCwiZm9ya3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZm9ya3MiLCJmdWxsX25hbWUiOiJhd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJnaXRfY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9naXQvY29tbWl0c3svc2hhfSIsImdpdF9yZWZzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2dpdC9yZWZzey9zaGF9IiwiZ2l0X3RhZ3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RhZ3N7L3NoYX0iLCJnaXRfdXJsIjoiZ2l0Oi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24uZ2l0IiwiaGFzX2Rpc2N1c3Npb25zIjp0cnVlLCJoYXNfZG93bmxvYWRzIjp0cnVlLCJoYXNfaXNzdWVzIjp0cnVlLCJoYXNfcGFnZXMiOmZhbHNlLCJoYXNfcHJvamVjdHMiOnRydWUsImhhc193aWtpIjpmYWxzZSwiaG9tZXBhZ2UiOiJodHRwczovL2RvY3MucG93ZXJ0b29scy5hd3MuZGV2L2xhbWJkYS9weXRob24vbGF0ZXN0LyIsImhvb2tzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2hvb2tzIiwiaHRtbF91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uIiwiaWQiOjIyMTkxOTM3OSwiaXNfdGVtcGxhdGUiOmZhbHNlLCJpc3N1ZV9jb21tZW50X3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlcy9jb21tZW50c3svbnVtYmVyfSIsImlzc3VlX2V2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9pc3N1ZXMvZXZlbnRzey9udW1iZXJ9IiwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlc3svbnVtYmVyfSIsImtleXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24va2V5c3sva2V5X2lkfSIsImxhYmVsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9sYWJlbHN7L25hbWV9IiwibGFuZ3VhZ2UiOiJQeXRob24iLCJsYW5ndWFnZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbGFuZ3VhZ2VzIiwibGljZW5zZSI6eyJrZXkiOiJtaXQtMCIsIm5hbWUiOiJNSVQgTm8gQXR0cmlidXRpb24iLCJub2RlX2lkIjoiTURjNlRHbGpaVzV6WlRReCIsInNwZHhfaWQiOiJNSVQtMCIsInVybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vbGljZW5zZXMvbWl0LTAifSwibWVyZ2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL21lcmdlcyIsIm1pbGVzdG9uZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbWlsZXN0b25lc3svbnVtYmVyfSIsIm1pcnJvcl91cmwiOm51bGwsIm5hbWUiOiJwb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJub2RlX2lkIjoiTURFd09sSmxjRzl6YVhSdmNua3lNakU1TVRrek56az0iLCJub3RpZmljYXRpb25zX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL25vdGlmaWNhdGlvbnN7P3NpbmNlLGFsbCxwYXJ0aWNpcGF0aW5nfSIsIm9wZW5faXNzdWVzIjo1OSwib3Blbl9pc3N1ZXNfY291bnQiOjU5LCJvd25lciI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9ldmVudHN7L3ByaXZhY3l9IiwiZm9sbG93ZXJzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93ZXJzIiwiZm9sbG93aW5nX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93aW5ney9vdGhlcl91c2VyfSIsImdpc3RzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZ2lzdHN7L2dpc3RfaWR9IiwiZ3JhdmF0YXJfaWQiOiIiLCJodG1sX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scyIsImlkIjoxMjkxMjc2MzgsImxvZ2luIjoiYXdzLXBvd2VydG9vbHMiLCJub2RlX2lkIjoiT19rZ0RPQjdKVTFnIiwib3JnYW5pemF0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL29yZ3MiLCJyZWNlaXZlZF9ldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9yZWNlaXZlZF9ldmVudHMiLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3JlcG9zIiwic2l0ZV9hZG1pbiI6ZmFsc2UsInN0YXJyZWRfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9zdGFycmVkey9vd25lcn17L3JlcG99Iiwic3Vic2NyaXB0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3N1YnNjcmlwdGlvbnMiLCJ0eXBlIjoiT3JnYW5pemF0aW9uIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scyIsInVzZXJfdmlld190eXBlIjoicHVibGljIn0sInByaXZhdGUiOmZhbHNlLCJwdWxsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9wdWxsc3svbnVtYmVyfSIsInB1c2hlZF9hdCI6IjIwMjUtMDItMDRUMjI6NDM6NDBaIiwicmVsZWFzZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vcmVsZWFzZXN7L2lkfSIsInNpemUiOjgxOTc5LCJzc2hfdXJsIjoiZ2l0QGdpdGh1Yi5jb206YXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsInN0YXJnYXplcnNfY291bnQiOjI5ODAsInN0YXJnYXplcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3RhcmdhemVycyIsInN0YXR1c2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3N0YXR1c2VzL3tzaGF9Iiwic3Vic2NyaWJlcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaWJlcnMiLCJzdWJzY3JpcHRpb25fdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaXB0aW9uIiwic3ZuX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ0YWdzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3RhZ3MiLCJ0ZWFtc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi90ZWFtcyIsInRvcGljcyI6WyJhd3MiLCJhd3MtbGFtYmRhIiwiaGFja3RvYmVyZmVzdCIsImxhbWJkYSIsInB5dGhvbiIsInNlcnZlcmxlc3MiXSwidHJlZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RyZWVzey9zaGF9IiwidXBkYXRlZF9hdCI6IjIwMjUtMDItMDRUMjI6MDQ6MzlaIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ2aXNpYmlsaXR5IjoicHVibGljIiwid2F0Y2hlcnMiOjI5ODAsIndhdGNoZXJzX2NvdW50IjoyOTgwLCJ3ZWJfY29tbWl0X3NpZ25vZmZfcmVxdWlyZWQiOnRydWV9LCJzY2hlZHVsZSI6IjAgOCAqICogMS01Iiwid29ya2Zsb3ciOiIuZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVsZWFzZS55bWwifSwiZ2l0aHViX2hlYWRfcmVmIjoiIiwiZ2l0aHViX3JlZiI6InJlZnMvaGVhZHMvZGV2ZWxvcCIsImdpdGh1Yl9yZWZfdHlwZSI6ImJyYW5jaCIsImdpdGh1Yl9yZXBvc2l0b3J5X2lkIjoiMjIxOTE5Mzc5IiwiZ2l0aHViX3JlcG9zaXRvcnlfb3duZXIiOiJhd3MtcG93ZXJ0b29scyIsImdpdGh1Yl9yZXBvc2l0b3J5X293bmVyX2lkIjoiMTI5MTI3NjM4IiwiZ2l0aHViX3J1bl9hdHRlbXB0IjoiMSIsImdpdGh1Yl9ydW5faWQiOiIxMzE1Mjc2MjI0OCIsImdpdGh1Yl9ydW5fbnVtYmVyIjoiMTY5IiwiZ2l0aHViX3NoYTEiOiJmNGU3N2YxYWM1MDQ2MTg3NTZhMzI0NjRiNTI0NGExMDhiZDBjMDgyIn19LCJtZXRhZGF0YSI6eyJidWlsZEludm9jYXRpb25JRCI6IjEzMTUyNzYyMjQ4LTEiLCJjb21wbGV0ZW5lc3MiOnsicGFyYW1ldGVycyI6dHJ1ZSwiZW52aXJvbm1lbnQiOmZhbHNlLCJtYXRlcmlhbHMiOmZhbHNlfSwicmVwcm9kdWNpYmxlIjpmYWxzZX0sIm1hdGVyaWFscyI6W3sidXJpIjoiZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob25AcmVmcy9oZWFkcy9kZXZlbG9wIiwiZGlnZXN0Ijp7InNoYTEiOiJmNGU3N2YxYWM1MDQ2MTg3NTZhMzI0NjRiNTI0NGExMDhiZDBjMDgyIn19XX19","signatures":[{"keyid":"","sig":"MEUCIH4KwjQeCn+3fJ5egn05L90+0OfDPZIRYY796Xd+gcuuAiEA87rSe1H5bafn+6u6WaAounjyurR20CzrZHSeg0Ld2xo=","cert":"-----BEGIN CERTIFICATE-----\nMIIHZDCCBuugAwIBAgIUFzoVNI6JCYXoDh2wH2I512V2Fr8wCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjUwMjA1MDgwNzE0WhcNMjUwMjA1MDgxNzE0WjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAEdopnPAltBNLILBka8XFH0mrp7DKzNo95TpKv\n8F6t2vee6tSP3UHILcBB77zs9qHFciNK80tipHfz2NXuPloZxaOCBgowggYGMA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUCDEr\naa5iyGHk4FhPUndgAGzmQzwwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wgYQGA1UdEQEB/wR6MHiGdmh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1l\nd29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvLmdpdGh1Yi93b3JrZmxvd3MvZ2Vu\nZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJlZnMvdGFncy92Mi4wLjAwOQYKKwYB\nBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50\nLmNvbTAWBgorBgEEAYO/MAECBAhzY2hlZHVsZTA2BgorBgEEAYO/MAEDBChmNGU3\nN2YxYWM1MDQ2MTg3NTZhMzI0NjRiNTI0NGExMDhiZDBjMDgyMBkGCisGAQQBg78w\nAQQEC1ByZS1SZWxlYXNlMDUGCisGAQQBg78wAQUEJ2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbjAgBgorBgEEAYO/MAEGBBJyZWZzL2hlYWRz\nL2RldmVsb3AwOwYKKwYBBAGDvzABCAQtDCtodHRwczovL3Rva2VuLmFjdGlvbnMu\nZ2l0aHVidXNlcmNvbnRlbnQuY29tMIGGBgorBgEEAYO/MAEJBHgMdmh0dHBzOi8v\nZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3Iv\nLmdpdGh1Yi93b3JrZmxvd3MvZ2VuZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJl\nZnMvdGFncy92Mi4wLjAwOAYKKwYBBAGDvzABCgQqDCg1YTc3NWIzNjdhNTZkNWJk\nMTE4YTIyNGE4MTFiYmEyODgxNTBhNTYzMB0GCisGAQQBg78wAQsEDwwNZ2l0aHVi\nLWhvc3RlZDBKBgorBgEEAYO/MAEMBDwMOmh0dHBzOi8vZ2l0aHViLmNvbS9hd3Mt\ncG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24wOAYKKwYBBAGDvzAB\nDQQqDChmNGU3N2YxYWM1MDQ2MTg3NTZhMzI0NjRiNTI0NGExMDhiZDBjMDgyMCIG\nCisGAQQBg78wAQ4EFAwScmVmcy9oZWFkcy9kZXZlbG9wMBkGCisGAQQBg78wAQ8E\nCwwJMjIxOTE5Mzc5MDEGCisGAQQBg78wARAEIwwhaHR0cHM6Ly9naXRodWIuY29t\nL2F3cy1wb3dlcnRvb2xzMBkGCisGAQQBg78wAREECwwJMTI5MTI3NjM4MH8GCisG\nAQQBg78wARIEcQxvaHR0cHM6Ly9naXRodWIuY29tL2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbi8uZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVs\nZWFzZS55bWxAcmVmcy9oZWFkcy9kZXZlbG9wMDgGCisGAQQBg78wARMEKgwoZjRl\nNzdmMWFjNTA0NjE4NzU2YTMyNDY0YjUyNDRhMTA4YmQwYzA4MjAYBgorBgEEAYO/\nMAEUBAoMCHNjaGVkdWxlMG4GCisGAQQBg78wARUEYAxeaHR0cHM6Ly9naXRodWIu\nY29tL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hY3Rp\nb25zL3J1bnMvMTMxNTI3NjIyNDgvYXR0ZW1wdHMvMTAWBgorBgEEAYO/MAEWBAgM\nBnB1YmxpYzCBiQYKKwYBBAHWeQIEAgR7BHkAdwB1AN09MGrGxxEyYxkeHJlnNwKi\nSl643jyt/4eKcoAvKe6OAAABlNUmJCIAAAQDAEYwRAIgZp+mTTlfZ5YfR0cBZpqz\nokbL+XRZOuPpY55Hri1ZJ2gCIFaE3lZXC12+xRX8QacXfJ2CXekwU6k3sMLXx89B\nsZZtMAoGCCqGSM49BAMDA2cAMGQCMFHYm/nNYeckfp3tkVmwHB75s4Hgufpg6sNz\nYzltv9gkHjxc1LO0RTnFgEC+iQxbFgIwFNwYhVu1SI9rqb/HlHtYQeR/u9jpi02f\nxln4ylYjS4iIxNQtnUwA4+M5gDe0zpDj\n-----END CERTIFICATE-----\n"}]}
\ No newline at end of file
diff --git a/provenance/3.5.1a6/multiple.intoto.jsonl b/provenance/3.5.1a6/multiple.intoto.jsonl
new file mode 100644
index 00000000000..fc474e1dbf5
--- /dev/null
+++ b/provenance/3.5.1a6/multiple.intoto.jsonl
@@ -0,0 +1 @@
+{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMiIsInN1YmplY3QiOlt7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWE2LXB5My1ub25lLWFueS53aGwiLCJkaWdlc3QiOnsic2hhMjU2IjoiMDUwZWE3OWZiMDEyOTlkZDY0NGRjMTlhZDkwODRmNTk0NWE3NmVhNDVmMzAxZTVlY2M0MWE0NGVlMWNmYWFmOCJ9fSx7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWE2LnRhci5neiIsImRpZ2VzdCI6eyJzaGEyNTYiOiI2M2Y1NTU1ZDE1NTczMGExZGJmNThiZGU0ODUwZDNmYTQwOWNkNjkxODllZjA0ZWEyZGJlNDYyMmZiNTFkYzBkIn19XSwicHJlZGljYXRlIjp7ImJ1aWxkZXIiOnsiaWQiOiJodHRwczovL2dpdGh1Yi5jb20vc2xzYS1mcmFtZXdvcmsvc2xzYS1naXRodWItZ2VuZXJhdG9yLy5naXRodWIvd29ya2Zsb3dzL2dlbmVyYXRvcl9nZW5lcmljX3Nsc2EzLnltbEByZWZzL3RhZ3MvdjIuMC4wIn0sImJ1aWxkVHlwZSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvZ2VuZXJpY0B2MSIsImludm9jYXRpb24iOnsiY29uZmlnU291cmNlIjp7InVyaSI6ImdpdCtodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uQHJlZnMvaGVhZHMvZGV2ZWxvcCIsImRpZ2VzdCI6eyJzaGExIjoiM2E0YmQ5OTNmZjMxMjg5NzhkN2EwZDRiYTI3MzAzZTM2M2IwZDYzMSJ9LCJlbnRyeVBvaW50IjoiLmdpdGh1Yi93b3JrZmxvd3MvcHJlLXJlbGVhc2UueW1sIn0sInBhcmFtZXRlcnMiOnt9LCJlbnZpcm9ubWVudCI6eyJnaXRodWJfYWN0b3IiOiJsZWFuZHJvZGFtYXNjZW5hIiwiZ2l0aHViX2FjdG9yX2lkIjoiNDI5NTE3MyIsImdpdGh1Yl9iYXNlX3JlZiI6IiIsImdpdGh1Yl9ldmVudF9uYW1lIjoic2NoZWR1bGUiLCJnaXRodWJfZXZlbnRfcGF5bG9hZCI6eyJlbnRlcnByaXNlIjp7ImF2YXRhcl91cmwiOiJodHRwczovL2F2YXRhcnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2IvMTI5MD92PTQiLCJjcmVhdGVkX2F0IjoiMjAxOS0xMS0xM1QxODowNTo0MVoiLCJkZXNjcmlwdGlvbiI6IiIsImh0bWxfdXJsIjoiaHR0cHM6Ly9naXRodWIuY29tL2VudGVycHJpc2VzL2FtYXpvbiIsImlkIjoxMjkwLCJuYW1lIjoiQW1hem9uIiwibm9kZV9pZCI6Ik1ERXdPa1Z1ZEdWeWNISnBjMlV4TWprdyIsInNsdWciOiJhbWF6b24iLCJ1cGRhdGVkX2F0IjoiMjAyNC0wOS0zMFQyMTowMjozMFoiLCJ3ZWJzaXRlX3VybCI6Imh0dHBzOi8vd3d3LmFtYXpvbi5jb20vIn0sIm9yZ2FuaXphdGlvbiI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJkZXNjcmlwdGlvbiI6IiIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvZXZlbnRzIiwiaG9va3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9vcmdzL2F3cy1wb3dlcnRvb2xzL2hvb2tzIiwiaWQiOjEyOTEyNzYzOCwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vb3Jncy9hd3MtcG93ZXJ0b29scy9pc3N1ZXMiLCJsb2dpbiI6ImF3cy1wb3dlcnRvb2xzIiwibWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvbWVtYmVyc3svbWVtYmVyfSIsIm5vZGVfaWQiOiJPX2tnRE9CN0pVMWciLCJwdWJsaWNfbWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcHVibGljX21lbWJlcnN7L21lbWJlcn0iLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcmVwb3MiLCJ1cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMifSwicmVwb3NpdG9yeSI6eyJhbGxvd19mb3JraW5nIjp0cnVlLCJhcmNoaXZlX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3thcmNoaXZlX2Zvcm1hdH17L3JlZn0iLCJhcmNoaXZlZCI6ZmFsc2UsImFzc2lnbmVlc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hc3NpZ25lZXN7L3VzZXJ9IiwiYmxvYnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L2Jsb2Jzey9zaGF9IiwiYnJhbmNoZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vYnJhbmNoZXN7L2JyYW5jaH0iLCJjbG9uZV91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsImNvbGxhYm9yYXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29sbGFib3JhdG9yc3svY29sbGFib3JhdG9yfSIsImNvbW1lbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbW1lbnRzey9udW1iZXJ9IiwiY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21taXRzey9zaGF9IiwiY29tcGFyZV91cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21wYXJlL3tiYXNlfS4uLntoZWFkfSIsImNvbnRlbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbnRlbnRzL3srcGF0aH0iLCJjb250cmlidXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29udHJpYnV0b3JzIiwiY3JlYXRlZF9hdCI6IjIwMTktMTEtMTVUMTI6MjY6MTJaIiwiY3VzdG9tX3Byb3BlcnRpZXMiOnt9LCJkZWZhdWx0X2JyYW5jaCI6ImRldmVsb3AiLCJkZXBsb3ltZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9kZXBsb3ltZW50cyIsImRlc2NyaXB0aW9uIjoiQSBkZXZlbG9wZXIgdG9vbGtpdCB0byBpbXBsZW1lbnQgU2VydmVybGVzcyBiZXN0IHByYWN0aWNlcyBhbmQgaW5jcmVhc2UgZGV2ZWxvcGVyIHZlbG9jaXR5LiIsImRpc2FibGVkIjpmYWxzZSwiZG93bmxvYWRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2Rvd25sb2FkcyIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9ldmVudHMiLCJmb3JrIjpmYWxzZSwiZm9ya3MiOjQwOCwiZm9ya3NfY291bnQiOjQwOCwiZm9ya3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZm9ya3MiLCJmdWxsX25hbWUiOiJhd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJnaXRfY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9naXQvY29tbWl0c3svc2hhfSIsImdpdF9yZWZzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2dpdC9yZWZzey9zaGF9IiwiZ2l0X3RhZ3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RhZ3N7L3NoYX0iLCJnaXRfdXJsIjoiZ2l0Oi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24uZ2l0IiwiaGFzX2Rpc2N1c3Npb25zIjp0cnVlLCJoYXNfZG93bmxvYWRzIjp0cnVlLCJoYXNfaXNzdWVzIjp0cnVlLCJoYXNfcGFnZXMiOmZhbHNlLCJoYXNfcHJvamVjdHMiOnRydWUsImhhc193aWtpIjpmYWxzZSwiaG9tZXBhZ2UiOiJodHRwczovL2RvY3MucG93ZXJ0b29scy5hd3MuZGV2L2xhbWJkYS9weXRob24vbGF0ZXN0LyIsImhvb2tzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2hvb2tzIiwiaHRtbF91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uIiwiaWQiOjIyMTkxOTM3OSwiaXNfdGVtcGxhdGUiOmZhbHNlLCJpc3N1ZV9jb21tZW50X3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlcy9jb21tZW50c3svbnVtYmVyfSIsImlzc3VlX2V2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9pc3N1ZXMvZXZlbnRzey9udW1iZXJ9IiwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlc3svbnVtYmVyfSIsImtleXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24va2V5c3sva2V5X2lkfSIsImxhYmVsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9sYWJlbHN7L25hbWV9IiwibGFuZ3VhZ2UiOiJQeXRob24iLCJsYW5ndWFnZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbGFuZ3VhZ2VzIiwibGljZW5zZSI6eyJrZXkiOiJtaXQtMCIsIm5hbWUiOiJNSVQgTm8gQXR0cmlidXRpb24iLCJub2RlX2lkIjoiTURjNlRHbGpaVzV6WlRReCIsInNwZHhfaWQiOiJNSVQtMCIsInVybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vbGljZW5zZXMvbWl0LTAifSwibWVyZ2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL21lcmdlcyIsIm1pbGVzdG9uZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbWlsZXN0b25lc3svbnVtYmVyfSIsIm1pcnJvcl91cmwiOm51bGwsIm5hbWUiOiJwb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJub2RlX2lkIjoiTURFd09sSmxjRzl6YVhSdmNua3lNakU1TVRrek56az0iLCJub3RpZmljYXRpb25zX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL25vdGlmaWNhdGlvbnN7P3NpbmNlLGFsbCxwYXJ0aWNpcGF0aW5nfSIsIm9wZW5faXNzdWVzIjo2Miwib3Blbl9pc3N1ZXNfY291bnQiOjYyLCJvd25lciI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9ldmVudHN7L3ByaXZhY3l9IiwiZm9sbG93ZXJzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93ZXJzIiwiZm9sbG93aW5nX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93aW5ney9vdGhlcl91c2VyfSIsImdpc3RzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZ2lzdHN7L2dpc3RfaWR9IiwiZ3JhdmF0YXJfaWQiOiIiLCJodG1sX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scyIsImlkIjoxMjkxMjc2MzgsImxvZ2luIjoiYXdzLXBvd2VydG9vbHMiLCJub2RlX2lkIjoiT19rZ0RPQjdKVTFnIiwib3JnYW5pemF0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL29yZ3MiLCJyZWNlaXZlZF9ldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9yZWNlaXZlZF9ldmVudHMiLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3JlcG9zIiwic2l0ZV9hZG1pbiI6ZmFsc2UsInN0YXJyZWRfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9zdGFycmVkey9vd25lcn17L3JlcG99Iiwic3Vic2NyaXB0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3N1YnNjcmlwdGlvbnMiLCJ0eXBlIjoiT3JnYW5pemF0aW9uIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scyIsInVzZXJfdmlld190eXBlIjoicHVibGljIn0sInByaXZhdGUiOmZhbHNlLCJwdWxsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9wdWxsc3svbnVtYmVyfSIsInB1c2hlZF9hdCI6IjIwMjUtMDItMDVUMjA6NDQ6MTRaIiwicmVsZWFzZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vcmVsZWFzZXN7L2lkfSIsInNpemUiOjgxOTkwLCJzc2hfdXJsIjoiZ2l0QGdpdGh1Yi5jb206YXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsInN0YXJnYXplcnNfY291bnQiOjI5ODAsInN0YXJnYXplcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3RhcmdhemVycyIsInN0YXR1c2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3N0YXR1c2VzL3tzaGF9Iiwic3Vic2NyaWJlcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaWJlcnMiLCJzdWJzY3JpcHRpb25fdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaXB0aW9uIiwic3ZuX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ0YWdzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3RhZ3MiLCJ0ZWFtc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi90ZWFtcyIsInRvcGljcyI6WyJhd3MiLCJhd3MtbGFtYmRhIiwiaGFja3RvYmVyZmVzdCIsImxhbWJkYSIsInB5dGhvbiIsInNlcnZlcmxlc3MiXSwidHJlZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RyZWVzey9zaGF9IiwidXBkYXRlZF9hdCI6IjIwMjUtMDItMDVUMTA6MDU6MjRaIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ2aXNpYmlsaXR5IjoicHVibGljIiwid2F0Y2hlcnMiOjI5ODAsIndhdGNoZXJzX2NvdW50IjoyOTgwLCJ3ZWJfY29tbWl0X3NpZ25vZmZfcmVxdWlyZWQiOnRydWV9LCJzY2hlZHVsZSI6IjAgOCAqICogMS01Iiwid29ya2Zsb3ciOiIuZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVsZWFzZS55bWwifSwiZ2l0aHViX2hlYWRfcmVmIjoiIiwiZ2l0aHViX3JlZiI6InJlZnMvaGVhZHMvZGV2ZWxvcCIsImdpdGh1Yl9yZWZfdHlwZSI6ImJyYW5jaCIsImdpdGh1Yl9yZXBvc2l0b3J5X2lkIjoiMjIxOTE5Mzc5IiwiZ2l0aHViX3JlcG9zaXRvcnlfb3duZXIiOiJhd3MtcG93ZXJ0b29scyIsImdpdGh1Yl9yZXBvc2l0b3J5X293bmVyX2lkIjoiMTI5MTI3NjM4IiwiZ2l0aHViX3J1bl9hdHRlbXB0IjoiMSIsImdpdGh1Yl9ydW5faWQiOiIxMzE3NDMwOTA0MSIsImdpdGh1Yl9ydW5fbnVtYmVyIjoiMTcwIiwiZ2l0aHViX3NoYTEiOiIzYTRiZDk5M2ZmMzEyODk3OGQ3YTBkNGJhMjczMDNlMzYzYjBkNjMxIn19LCJtZXRhZGF0YSI6eyJidWlsZEludm9jYXRpb25JRCI6IjEzMTc0MzA5MDQxLTEiLCJjb21wbGV0ZW5lc3MiOnsicGFyYW1ldGVycyI6dHJ1ZSwiZW52aXJvbm1lbnQiOmZhbHNlLCJtYXRlcmlhbHMiOmZhbHNlfSwicmVwcm9kdWNpYmxlIjpmYWxzZX0sIm1hdGVyaWFscyI6W3sidXJpIjoiZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob25AcmVmcy9oZWFkcy9kZXZlbG9wIiwiZGlnZXN0Ijp7InNoYTEiOiIzYTRiZDk5M2ZmMzEyODk3OGQ3YTBkNGJhMjczMDNlMzYzYjBkNjMxIn19XX19","signatures":[{"keyid":"","sig":"MEUCIHPxyD7Fbff073k7EFJdk1Zkns57QhDflaN70793XaYhAiEA7B6YZtK/Q0XsMdYVHknlZESbAUQZdB1B9pvFfiSK1zI=","cert":"-----BEGIN CERTIFICATE-----\nMIIHZzCCBuygAwIBAgIUIX/kIuxLppks3pOivByIKk2hDXEwCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjUwMjA2MDgwNzIyWhcNMjUwMjA2MDgxNzIyWjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAE5I0xqKopebdG458MrVOiFrImIyqsbqen9B1f\nUQYjxOGpk6cjqtVTk3jG44ehCnJiw+Ed/p1s6MYqSiF0yA1+WKOCBgswggYHMA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQU39cC\nPvNgMzmQQzGR6uGb/BxKzCEwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wgYQGA1UdEQEB/wR6MHiGdmh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1l\nd29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvLmdpdGh1Yi93b3JrZmxvd3MvZ2Vu\nZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJlZnMvdGFncy92Mi4wLjAwOQYKKwYB\nBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50\nLmNvbTAWBgorBgEEAYO/MAECBAhzY2hlZHVsZTA2BgorBgEEAYO/MAEDBCgzYTRi\nZDk5M2ZmMzEyODk3OGQ3YTBkNGJhMjczMDNlMzYzYjBkNjMxMBkGCisGAQQBg78w\nAQQEC1ByZS1SZWxlYXNlMDUGCisGAQQBg78wAQUEJ2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbjAgBgorBgEEAYO/MAEGBBJyZWZzL2hlYWRz\nL2RldmVsb3AwOwYKKwYBBAGDvzABCAQtDCtodHRwczovL3Rva2VuLmFjdGlvbnMu\nZ2l0aHVidXNlcmNvbnRlbnQuY29tMIGGBgorBgEEAYO/MAEJBHgMdmh0dHBzOi8v\nZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3Iv\nLmdpdGh1Yi93b3JrZmxvd3MvZ2VuZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJl\nZnMvdGFncy92Mi4wLjAwOAYKKwYBBAGDvzABCgQqDCg1YTc3NWIzNjdhNTZkNWJk\nMTE4YTIyNGE4MTFiYmEyODgxNTBhNTYzMB0GCisGAQQBg78wAQsEDwwNZ2l0aHVi\nLWhvc3RlZDBKBgorBgEEAYO/MAEMBDwMOmh0dHBzOi8vZ2l0aHViLmNvbS9hd3Mt\ncG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24wOAYKKwYBBAGDvzAB\nDQQqDCgzYTRiZDk5M2ZmMzEyODk3OGQ3YTBkNGJhMjczMDNlMzYzYjBkNjMxMCIG\nCisGAQQBg78wAQ4EFAwScmVmcy9oZWFkcy9kZXZlbG9wMBkGCisGAQQBg78wAQ8E\nCwwJMjIxOTE5Mzc5MDEGCisGAQQBg78wARAEIwwhaHR0cHM6Ly9naXRodWIuY29t\nL2F3cy1wb3dlcnRvb2xzMBkGCisGAQQBg78wAREECwwJMTI5MTI3NjM4MH8GCisG\nAQQBg78wARIEcQxvaHR0cHM6Ly9naXRodWIuY29tL2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbi8uZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVs\nZWFzZS55bWxAcmVmcy9oZWFkcy9kZXZlbG9wMDgGCisGAQQBg78wARMEKgwoM2E0\nYmQ5OTNmZjMxMjg5NzhkN2EwZDRiYTI3MzAzZTM2M2IwZDYzMTAYBgorBgEEAYO/\nMAEUBAoMCHNjaGVkdWxlMG4GCisGAQQBg78wARUEYAxeaHR0cHM6Ly9naXRodWIu\nY29tL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hY3Rp\nb25zL3J1bnMvMTMxNzQzMDkwNDEvYXR0ZW1wdHMvMTAWBgorBgEEAYO/MAEWBAgM\nBnB1YmxpYzCBigYKKwYBBAHWeQIEAgR8BHoAeAB2AN09MGrGxxEyYxkeHJlnNwKi\nSl643jyt/4eKcoAvKe6OAAABlNpMn3EAAAQDAEcwRQIgT2T+w+zYCr5M/26jXK8f\ngC5r28a8ZVRhkl3DYcWTZ8UCIQD/qSoSaXzFBoQQqajRGiZmKdiepNN2gtoqNXhL\ndiZ33DAKBggqhkjOPQQDAwNpADBmAjEA1sJgCeUJxNUCKqGjNNBNejObX9FPBO8b\nSgQ2hOjxIS/Jf36d95Fwe5DRXoUMrOBjAjEAjjsRjpC6Ug3oOCgEzWAw/sbS3aMC\nolYU6FmCmb7bLY/ERPgH+DbITJo19olLq8Hc\n-----END CERTIFICATE-----\n"}]}
\ No newline at end of file
diff --git a/provenance/3.5.1a7/multiple.intoto.jsonl b/provenance/3.5.1a7/multiple.intoto.jsonl
new file mode 100644
index 00000000000..474657fe965
--- /dev/null
+++ b/provenance/3.5.1a7/multiple.intoto.jsonl
@@ -0,0 +1 @@
+{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMiIsInN1YmplY3QiOlt7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWE3LXB5My1ub25lLWFueS53aGwiLCJkaWdlc3QiOnsic2hhMjU2IjoiNmQ4ZDJkMzZhZWU1OWI4NDhjMDFmYTQ4ZGY5N2Q4ZjBmYWJkYTc5NTY3MjBlZjJjMDhiZDFhMWRlMWE3YTFjYiJ9fSx7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWE3LnRhci5neiIsImRpZ2VzdCI6eyJzaGEyNTYiOiIwZjcxOWY4MDkxMTgyMDFmYjgxYTcwNDI3MjExZmMxZTQwNDYxNThmYTFlYTQwMjMyYzdiMTA4MGMzOGM1OGRiIn19XSwicHJlZGljYXRlIjp7ImJ1aWxkZXIiOnsiaWQiOiJodHRwczovL2dpdGh1Yi5jb20vc2xzYS1mcmFtZXdvcmsvc2xzYS1naXRodWItZ2VuZXJhdG9yLy5naXRodWIvd29ya2Zsb3dzL2dlbmVyYXRvcl9nZW5lcmljX3Nsc2EzLnltbEByZWZzL3RhZ3MvdjIuMC4wIn0sImJ1aWxkVHlwZSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvZ2VuZXJpY0B2MSIsImludm9jYXRpb24iOnsiY29uZmlnU291cmNlIjp7InVyaSI6ImdpdCtodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uQHJlZnMvaGVhZHMvZGV2ZWxvcCIsImRpZ2VzdCI6eyJzaGExIjoiZmI4YjRmZjM1MzI0Y2Q1MmM3ZjEzODdiOTAxNDgyYjczMzM1YmNkYSJ9LCJlbnRyeVBvaW50IjoiLmdpdGh1Yi93b3JrZmxvd3MvcHJlLXJlbGVhc2UueW1sIn0sInBhcmFtZXRlcnMiOnt9LCJlbnZpcm9ubWVudCI6eyJnaXRodWJfYWN0b3IiOiJsZWFuZHJvZGFtYXNjZW5hIiwiZ2l0aHViX2FjdG9yX2lkIjoiNDI5NTE3MyIsImdpdGh1Yl9iYXNlX3JlZiI6IiIsImdpdGh1Yl9ldmVudF9uYW1lIjoic2NoZWR1bGUiLCJnaXRodWJfZXZlbnRfcGF5bG9hZCI6eyJlbnRlcnByaXNlIjp7ImF2YXRhcl91cmwiOiJodHRwczovL2F2YXRhcnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2IvMTI5MD92PTQiLCJjcmVhdGVkX2F0IjoiMjAxOS0xMS0xM1QxODowNTo0MVoiLCJkZXNjcmlwdGlvbiI6IiIsImh0bWxfdXJsIjoiaHR0cHM6Ly9naXRodWIuY29tL2VudGVycHJpc2VzL2FtYXpvbiIsImlkIjoxMjkwLCJuYW1lIjoiQW1hem9uIiwibm9kZV9pZCI6Ik1ERXdPa1Z1ZEdWeWNISnBjMlV4TWprdyIsInNsdWciOiJhbWF6b24iLCJ1cGRhdGVkX2F0IjoiMjAyNC0wOS0zMFQyMTowMjozMFoiLCJ3ZWJzaXRlX3VybCI6Imh0dHBzOi8vd3d3LmFtYXpvbi5jb20vIn0sIm9yZ2FuaXphdGlvbiI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJkZXNjcmlwdGlvbiI6IiIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvZXZlbnRzIiwiaG9va3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9vcmdzL2F3cy1wb3dlcnRvb2xzL2hvb2tzIiwiaWQiOjEyOTEyNzYzOCwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vb3Jncy9hd3MtcG93ZXJ0b29scy9pc3N1ZXMiLCJsb2dpbiI6ImF3cy1wb3dlcnRvb2xzIiwibWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvbWVtYmVyc3svbWVtYmVyfSIsIm5vZGVfaWQiOiJPX2tnRE9CN0pVMWciLCJwdWJsaWNfbWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcHVibGljX21lbWJlcnN7L21lbWJlcn0iLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcmVwb3MiLCJ1cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMifSwicmVwb3NpdG9yeSI6eyJhbGxvd19mb3JraW5nIjp0cnVlLCJhcmNoaXZlX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3thcmNoaXZlX2Zvcm1hdH17L3JlZn0iLCJhcmNoaXZlZCI6ZmFsc2UsImFzc2lnbmVlc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hc3NpZ25lZXN7L3VzZXJ9IiwiYmxvYnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L2Jsb2Jzey9zaGF9IiwiYnJhbmNoZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vYnJhbmNoZXN7L2JyYW5jaH0iLCJjbG9uZV91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsImNvbGxhYm9yYXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29sbGFib3JhdG9yc3svY29sbGFib3JhdG9yfSIsImNvbW1lbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbW1lbnRzey9udW1iZXJ9IiwiY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21taXRzey9zaGF9IiwiY29tcGFyZV91cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21wYXJlL3tiYXNlfS4uLntoZWFkfSIsImNvbnRlbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbnRlbnRzL3srcGF0aH0iLCJjb250cmlidXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29udHJpYnV0b3JzIiwiY3JlYXRlZF9hdCI6IjIwMTktMTEtMTVUMTI6MjY6MTJaIiwiY3VzdG9tX3Byb3BlcnRpZXMiOnt9LCJkZWZhdWx0X2JyYW5jaCI6ImRldmVsb3AiLCJkZXBsb3ltZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9kZXBsb3ltZW50cyIsImRlc2NyaXB0aW9uIjoiQSBkZXZlbG9wZXIgdG9vbGtpdCB0byBpbXBsZW1lbnQgU2VydmVybGVzcyBiZXN0IHByYWN0aWNlcyBhbmQgaW5jcmVhc2UgZGV2ZWxvcGVyIHZlbG9jaXR5LiIsImRpc2FibGVkIjpmYWxzZSwiZG93bmxvYWRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2Rvd25sb2FkcyIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9ldmVudHMiLCJmb3JrIjpmYWxzZSwiZm9ya3MiOjQwOCwiZm9ya3NfY291bnQiOjQwOCwiZm9ya3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZm9ya3MiLCJmdWxsX25hbWUiOiJhd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJnaXRfY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9naXQvY29tbWl0c3svc2hhfSIsImdpdF9yZWZzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2dpdC9yZWZzey9zaGF9IiwiZ2l0X3RhZ3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RhZ3N7L3NoYX0iLCJnaXRfdXJsIjoiZ2l0Oi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24uZ2l0IiwiaGFzX2Rpc2N1c3Npb25zIjp0cnVlLCJoYXNfZG93bmxvYWRzIjp0cnVlLCJoYXNfaXNzdWVzIjp0cnVlLCJoYXNfcGFnZXMiOmZhbHNlLCJoYXNfcHJvamVjdHMiOnRydWUsImhhc193aWtpIjpmYWxzZSwiaG9tZXBhZ2UiOiJodHRwczovL2RvY3MucG93ZXJ0b29scy5hd3MuZGV2L2xhbWJkYS9weXRob24vbGF0ZXN0LyIsImhvb2tzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2hvb2tzIiwiaHRtbF91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uIiwiaWQiOjIyMTkxOTM3OSwiaXNfdGVtcGxhdGUiOmZhbHNlLCJpc3N1ZV9jb21tZW50X3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlcy9jb21tZW50c3svbnVtYmVyfSIsImlzc3VlX2V2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9pc3N1ZXMvZXZlbnRzey9udW1iZXJ9IiwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlc3svbnVtYmVyfSIsImtleXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24va2V5c3sva2V5X2lkfSIsImxhYmVsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9sYWJlbHN7L25hbWV9IiwibGFuZ3VhZ2UiOiJQeXRob24iLCJsYW5ndWFnZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbGFuZ3VhZ2VzIiwibGljZW5zZSI6eyJrZXkiOiJtaXQtMCIsIm5hbWUiOiJNSVQgTm8gQXR0cmlidXRpb24iLCJub2RlX2lkIjoiTURjNlRHbGpaVzV6WlRReCIsInNwZHhfaWQiOiJNSVQtMCIsInVybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vbGljZW5zZXMvbWl0LTAifSwibWVyZ2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL21lcmdlcyIsIm1pbGVzdG9uZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbWlsZXN0b25lc3svbnVtYmVyfSIsIm1pcnJvcl91cmwiOm51bGwsIm5hbWUiOiJwb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJub2RlX2lkIjoiTURFd09sSmxjRzl6YVhSdmNua3lNakU1TVRrek56az0iLCJub3RpZmljYXRpb25zX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL25vdGlmaWNhdGlvbnN7P3NpbmNlLGFsbCxwYXJ0aWNpcGF0aW5nfSIsIm9wZW5faXNzdWVzIjo1Nywib3Blbl9pc3N1ZXNfY291bnQiOjU3LCJvd25lciI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9ldmVudHN7L3ByaXZhY3l9IiwiZm9sbG93ZXJzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93ZXJzIiwiZm9sbG93aW5nX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93aW5ney9vdGhlcl91c2VyfSIsImdpc3RzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZ2lzdHN7L2dpc3RfaWR9IiwiZ3JhdmF0YXJfaWQiOiIiLCJodG1sX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scyIsImlkIjoxMjkxMjc2MzgsImxvZ2luIjoiYXdzLXBvd2VydG9vbHMiLCJub2RlX2lkIjoiT19rZ0RPQjdKVTFnIiwib3JnYW5pemF0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL29yZ3MiLCJyZWNlaXZlZF9ldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9yZWNlaXZlZF9ldmVudHMiLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3JlcG9zIiwic2l0ZV9hZG1pbiI6ZmFsc2UsInN0YXJyZWRfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9zdGFycmVkey9vd25lcn17L3JlcG99Iiwic3Vic2NyaXB0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3N1YnNjcmlwdGlvbnMiLCJ0eXBlIjoiT3JnYW5pemF0aW9uIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scyIsInVzZXJfdmlld190eXBlIjoicHVibGljIn0sInByaXZhdGUiOmZhbHNlLCJwdWxsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9wdWxsc3svbnVtYmVyfSIsInB1c2hlZF9hdCI6IjIwMjUtMDItMDZUMjM6MjE6MzlaIiwicmVsZWFzZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vcmVsZWFzZXN7L2lkfSIsInNpemUiOjg2NjAzLCJzc2hfdXJsIjoiZ2l0QGdpdGh1Yi5jb206YXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsInN0YXJnYXplcnNfY291bnQiOjI5ODEsInN0YXJnYXplcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3RhcmdhemVycyIsInN0YXR1c2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3N0YXR1c2VzL3tzaGF9Iiwic3Vic2NyaWJlcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaWJlcnMiLCJzdWJzY3JpcHRpb25fdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaXB0aW9uIiwic3ZuX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ0YWdzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3RhZ3MiLCJ0ZWFtc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi90ZWFtcyIsInRvcGljcyI6WyJhd3MiLCJhd3MtbGFtYmRhIiwiaGFja3RvYmVyZmVzdCIsImxhbWJkYSIsInB5dGhvbiIsInNlcnZlcmxlc3MiXSwidHJlZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RyZWVzey9zaGF9IiwidXBkYXRlZF9hdCI6IjIwMjUtMDItMDZUMjM6MjE6NDJaIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ2aXNpYmlsaXR5IjoicHVibGljIiwid2F0Y2hlcnMiOjI5ODEsIndhdGNoZXJzX2NvdW50IjoyOTgxLCJ3ZWJfY29tbWl0X3NpZ25vZmZfcmVxdWlyZWQiOnRydWV9LCJzY2hlZHVsZSI6IjAgOCAqICogMS01Iiwid29ya2Zsb3ciOiIuZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVsZWFzZS55bWwifSwiZ2l0aHViX2hlYWRfcmVmIjoiIiwiZ2l0aHViX3JlZiI6InJlZnMvaGVhZHMvZGV2ZWxvcCIsImdpdGh1Yl9yZWZfdHlwZSI6ImJyYW5jaCIsImdpdGh1Yl9yZXBvc2l0b3J5X2lkIjoiMjIxOTE5Mzc5IiwiZ2l0aHViX3JlcG9zaXRvcnlfb3duZXIiOiJhd3MtcG93ZXJ0b29scyIsImdpdGh1Yl9yZXBvc2l0b3J5X293bmVyX2lkIjoiMTI5MTI3NjM4IiwiZ2l0aHViX3J1bl9hdHRlbXB0IjoiMSIsImdpdGh1Yl9ydW5faWQiOiIxMzE5NTYzMDI5NCIsImdpdGh1Yl9ydW5fbnVtYmVyIjoiMTcxIiwiZ2l0aHViX3NoYTEiOiJmYjhiNGZmMzUzMjRjZDUyYzdmMTM4N2I5MDE0ODJiNzMzMzViY2RhIn19LCJtZXRhZGF0YSI6eyJidWlsZEludm9jYXRpb25JRCI6IjEzMTk1NjMwMjk0LTEiLCJjb21wbGV0ZW5lc3MiOnsicGFyYW1ldGVycyI6dHJ1ZSwiZW52aXJvbm1lbnQiOmZhbHNlLCJtYXRlcmlhbHMiOmZhbHNlfSwicmVwcm9kdWNpYmxlIjpmYWxzZX0sIm1hdGVyaWFscyI6W3sidXJpIjoiZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob25AcmVmcy9oZWFkcy9kZXZlbG9wIiwiZGlnZXN0Ijp7InNoYTEiOiJmYjhiNGZmMzUzMjRjZDUyYzdmMTM4N2I5MDE0ODJiNzMzMzViY2RhIn19XX19","signatures":[{"keyid":"","sig":"MEUCIQC+/7Jm3AHMweRNOFceVlF7kAI4uP98rIQN0Tf7kkUUHwIgdO5abiSLBtgjcYyIqTZizfwvQZJvXgY4AkR47cfWuq4=","cert":"-----BEGIN CERTIFICATE-----\nMIIHZjCCBuygAwIBAgIUUCoHrtEnWdz6AQloHbOKJb4ZHY4wCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjUwMjA3MDgwNjU5WhcNMjUwMjA3MDgxNjU5WjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAEQVAZ+TbuoCDFYybGoZkDtWEFR4AUcyH6BaW5\nPickzMTWwUgvpOwSAN+XKu3PUUZso/QAp18htVsA0LAzl/vte6OCBgswggYHMA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUcxZr\n7poyiAbU4BpiWP4fQLJjFH4wHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wgYQGA1UdEQEB/wR6MHiGdmh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1l\nd29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvLmdpdGh1Yi93b3JrZmxvd3MvZ2Vu\nZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJlZnMvdGFncy92Mi4wLjAwOQYKKwYB\nBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50\nLmNvbTAWBgorBgEEAYO/MAECBAhzY2hlZHVsZTA2BgorBgEEAYO/MAEDBChmYjhi\nNGZmMzUzMjRjZDUyYzdmMTM4N2I5MDE0ODJiNzMzMzViY2RhMBkGCisGAQQBg78w\nAQQEC1ByZS1SZWxlYXNlMDUGCisGAQQBg78wAQUEJ2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbjAgBgorBgEEAYO/MAEGBBJyZWZzL2hlYWRz\nL2RldmVsb3AwOwYKKwYBBAGDvzABCAQtDCtodHRwczovL3Rva2VuLmFjdGlvbnMu\nZ2l0aHVidXNlcmNvbnRlbnQuY29tMIGGBgorBgEEAYO/MAEJBHgMdmh0dHBzOi8v\nZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3Iv\nLmdpdGh1Yi93b3JrZmxvd3MvZ2VuZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJl\nZnMvdGFncy92Mi4wLjAwOAYKKwYBBAGDvzABCgQqDCg1YTc3NWIzNjdhNTZkNWJk\nMTE4YTIyNGE4MTFiYmEyODgxNTBhNTYzMB0GCisGAQQBg78wAQsEDwwNZ2l0aHVi\nLWhvc3RlZDBKBgorBgEEAYO/MAEMBDwMOmh0dHBzOi8vZ2l0aHViLmNvbS9hd3Mt\ncG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24wOAYKKwYBBAGDvzAB\nDQQqDChmYjhiNGZmMzUzMjRjZDUyYzdmMTM4N2I5MDE0ODJiNzMzMzViY2RhMCIG\nCisGAQQBg78wAQ4EFAwScmVmcy9oZWFkcy9kZXZlbG9wMBkGCisGAQQBg78wAQ8E\nCwwJMjIxOTE5Mzc5MDEGCisGAQQBg78wARAEIwwhaHR0cHM6Ly9naXRodWIuY29t\nL2F3cy1wb3dlcnRvb2xzMBkGCisGAQQBg78wAREECwwJMTI5MTI3NjM4MH8GCisG\nAQQBg78wARIEcQxvaHR0cHM6Ly9naXRodWIuY29tL2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbi8uZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVs\nZWFzZS55bWxAcmVmcy9oZWFkcy9kZXZlbG9wMDgGCisGAQQBg78wARMEKgwoZmI4\nYjRmZjM1MzI0Y2Q1MmM3ZjEzODdiOTAxNDgyYjczMzM1YmNkYTAYBgorBgEEAYO/\nMAEUBAoMCHNjaGVkdWxlMG4GCisGAQQBg78wARUEYAxeaHR0cHM6Ly9naXRodWIu\nY29tL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hY3Rp\nb25zL3J1bnMvMTMxOTU2MzAyOTQvYXR0ZW1wdHMvMTAWBgorBgEEAYO/MAEWBAgM\nBnB1YmxpYzCBigYKKwYBBAHWeQIEAgR8BHoAeAB2AN09MGrGxxEyYxkeHJlnNwKi\nSl643jyt/4eKcoAvKe6OAAABlN9yoVMAAAQDAEcwRQIgeO9AHCCR2kHL2ROqzGs3\nTD1gg+R1G1r8dd65VehMMPACIQCNGNDCfQ3ZnC1rO91ShqUpF0AfZ8G6RCsBCOc2\nrFjR4jAKBggqhkjOPQQDAwNoADBlAjEAq/h2LQABoTkQHKcNkv9ZOF93B7jtBezU\nt0zNtlRPV5LVOjjgQ9LldlGjToRotbFHAjADVhvJj+XBVjdOhyyy+EX+TLl0x02q\nPrAaL+0g5uEOvfj4vO5BRYohdSvZlPIJeaA=\n-----END CERTIFICATE-----\n"}]}
\ No newline at end of file
diff --git a/provenance/3.5.1a8/multiple.intoto.jsonl b/provenance/3.5.1a8/multiple.intoto.jsonl
new file mode 100644
index 00000000000..9583eeea6b0
--- /dev/null
+++ b/provenance/3.5.1a8/multiple.intoto.jsonl
@@ -0,0 +1 @@
+{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMiIsInN1YmplY3QiOlt7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWE4LXB5My1ub25lLWFueS53aGwiLCJkaWdlc3QiOnsic2hhMjU2IjoiOTQ2MDExMzFkYzA0YzcxMWM3M2I1MzE5YzVkODBlMDU2NmUwYzJjYjEwYjcyNTQxNzI2NGI0YmYwNTE2MTg0NCJ9fSx7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWE4LnRhci5neiIsImRpZ2VzdCI6eyJzaGEyNTYiOiJkZTNjZTVjYmU5OTczNTZhM2Q2NzAyMmZiOTMyNTY0ZThkMGE5MTRmYmI0OGM3YTk3NjQ3Y2Q5NjhjZjVmYjA3In19XSwicHJlZGljYXRlIjp7ImJ1aWxkZXIiOnsiaWQiOiJodHRwczovL2dpdGh1Yi5jb20vc2xzYS1mcmFtZXdvcmsvc2xzYS1naXRodWItZ2VuZXJhdG9yLy5naXRodWIvd29ya2Zsb3dzL2dlbmVyYXRvcl9nZW5lcmljX3Nsc2EzLnltbEByZWZzL3RhZ3MvdjIuMC4wIn0sImJ1aWxkVHlwZSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvZ2VuZXJpY0B2MSIsImludm9jYXRpb24iOnsiY29uZmlnU291cmNlIjp7InVyaSI6ImdpdCtodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uQHJlZnMvaGVhZHMvZGV2ZWxvcCIsImRpZ2VzdCI6eyJzaGExIjoiODEyNzI2OTY4ODk4ZGM1MTE2MThhZGU3YTIyYTE0MWIxYzQ0NjllYSJ9LCJlbnRyeVBvaW50IjoiLmdpdGh1Yi93b3JrZmxvd3MvcHJlLXJlbGVhc2UueW1sIn0sInBhcmFtZXRlcnMiOnt9LCJlbnZpcm9ubWVudCI6eyJnaXRodWJfYWN0b3IiOiJsZWFuZHJvZGFtYXNjZW5hIiwiZ2l0aHViX2FjdG9yX2lkIjoiNDI5NTE3MyIsImdpdGh1Yl9iYXNlX3JlZiI6IiIsImdpdGh1Yl9ldmVudF9uYW1lIjoic2NoZWR1bGUiLCJnaXRodWJfZXZlbnRfcGF5bG9hZCI6eyJlbnRlcnByaXNlIjp7ImF2YXRhcl91cmwiOiJodHRwczovL2F2YXRhcnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2IvMTI5MD92PTQiLCJjcmVhdGVkX2F0IjoiMjAxOS0xMS0xM1QxODowNTo0MVoiLCJkZXNjcmlwdGlvbiI6IiIsImh0bWxfdXJsIjoiaHR0cHM6Ly9naXRodWIuY29tL2VudGVycHJpc2VzL2FtYXpvbiIsImlkIjoxMjkwLCJuYW1lIjoiQW1hem9uIiwibm9kZV9pZCI6Ik1ERXdPa1Z1ZEdWeWNISnBjMlV4TWprdyIsInNsdWciOiJhbWF6b24iLCJ1cGRhdGVkX2F0IjoiMjAyNC0wOS0zMFQyMTowMjozMFoiLCJ3ZWJzaXRlX3VybCI6Imh0dHBzOi8vd3d3LmFtYXpvbi5jb20vIn0sIm9yZ2FuaXphdGlvbiI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJkZXNjcmlwdGlvbiI6IiIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvZXZlbnRzIiwiaG9va3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9vcmdzL2F3cy1wb3dlcnRvb2xzL2hvb2tzIiwiaWQiOjEyOTEyNzYzOCwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vb3Jncy9hd3MtcG93ZXJ0b29scy9pc3N1ZXMiLCJsb2dpbiI6ImF3cy1wb3dlcnRvb2xzIiwibWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvbWVtYmVyc3svbWVtYmVyfSIsIm5vZGVfaWQiOiJPX2tnRE9CN0pVMWciLCJwdWJsaWNfbWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcHVibGljX21lbWJlcnN7L21lbWJlcn0iLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcmVwb3MiLCJ1cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMifSwicmVwb3NpdG9yeSI6eyJhbGxvd19mb3JraW5nIjp0cnVlLCJhcmNoaXZlX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3thcmNoaXZlX2Zvcm1hdH17L3JlZn0iLCJhcmNoaXZlZCI6ZmFsc2UsImFzc2lnbmVlc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hc3NpZ25lZXN7L3VzZXJ9IiwiYmxvYnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L2Jsb2Jzey9zaGF9IiwiYnJhbmNoZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vYnJhbmNoZXN7L2JyYW5jaH0iLCJjbG9uZV91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsImNvbGxhYm9yYXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29sbGFib3JhdG9yc3svY29sbGFib3JhdG9yfSIsImNvbW1lbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbW1lbnRzey9udW1iZXJ9IiwiY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21taXRzey9zaGF9IiwiY29tcGFyZV91cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21wYXJlL3tiYXNlfS4uLntoZWFkfSIsImNvbnRlbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbnRlbnRzL3srcGF0aH0iLCJjb250cmlidXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29udHJpYnV0b3JzIiwiY3JlYXRlZF9hdCI6IjIwMTktMTEtMTVUMTI6MjY6MTJaIiwiY3VzdG9tX3Byb3BlcnRpZXMiOnt9LCJkZWZhdWx0X2JyYW5jaCI6ImRldmVsb3AiLCJkZXBsb3ltZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9kZXBsb3ltZW50cyIsImRlc2NyaXB0aW9uIjoiQSBkZXZlbG9wZXIgdG9vbGtpdCB0byBpbXBsZW1lbnQgU2VydmVybGVzcyBiZXN0IHByYWN0aWNlcyBhbmQgaW5jcmVhc2UgZGV2ZWxvcGVyIHZlbG9jaXR5LiIsImRpc2FibGVkIjpmYWxzZSwiZG93bmxvYWRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2Rvd25sb2FkcyIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9ldmVudHMiLCJmb3JrIjpmYWxzZSwiZm9ya3MiOjQwOCwiZm9ya3NfY291bnQiOjQwOCwiZm9ya3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZm9ya3MiLCJmdWxsX25hbWUiOiJhd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJnaXRfY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9naXQvY29tbWl0c3svc2hhfSIsImdpdF9yZWZzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2dpdC9yZWZzey9zaGF9IiwiZ2l0X3RhZ3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RhZ3N7L3NoYX0iLCJnaXRfdXJsIjoiZ2l0Oi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24uZ2l0IiwiaGFzX2Rpc2N1c3Npb25zIjp0cnVlLCJoYXNfZG93bmxvYWRzIjp0cnVlLCJoYXNfaXNzdWVzIjp0cnVlLCJoYXNfcGFnZXMiOmZhbHNlLCJoYXNfcHJvamVjdHMiOnRydWUsImhhc193aWtpIjpmYWxzZSwiaG9tZXBhZ2UiOiJodHRwczovL2RvY3MucG93ZXJ0b29scy5hd3MuZGV2L2xhbWJkYS9weXRob24vbGF0ZXN0LyIsImhvb2tzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2hvb2tzIiwiaHRtbF91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uIiwiaWQiOjIyMTkxOTM3OSwiaXNfdGVtcGxhdGUiOmZhbHNlLCJpc3N1ZV9jb21tZW50X3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlcy9jb21tZW50c3svbnVtYmVyfSIsImlzc3VlX2V2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9pc3N1ZXMvZXZlbnRzey9udW1iZXJ9IiwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlc3svbnVtYmVyfSIsImtleXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24va2V5c3sva2V5X2lkfSIsImxhYmVsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9sYWJlbHN7L25hbWV9IiwibGFuZ3VhZ2UiOiJQeXRob24iLCJsYW5ndWFnZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbGFuZ3VhZ2VzIiwibGljZW5zZSI6eyJrZXkiOiJtaXQtMCIsIm5hbWUiOiJNSVQgTm8gQXR0cmlidXRpb24iLCJub2RlX2lkIjoiTURjNlRHbGpaVzV6WlRReCIsInNwZHhfaWQiOiJNSVQtMCIsInVybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vbGljZW5zZXMvbWl0LTAifSwibWVyZ2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL21lcmdlcyIsIm1pbGVzdG9uZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbWlsZXN0b25lc3svbnVtYmVyfSIsIm1pcnJvcl91cmwiOm51bGwsIm5hbWUiOiJwb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJub2RlX2lkIjoiTURFd09sSmxjRzl6YVhSdmNua3lNakU1TVRrek56az0iLCJub3RpZmljYXRpb25zX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL25vdGlmaWNhdGlvbnN7P3NpbmNlLGFsbCxwYXJ0aWNpcGF0aW5nfSIsIm9wZW5faXNzdWVzIjo2MSwib3Blbl9pc3N1ZXNfY291bnQiOjYxLCJvd25lciI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9ldmVudHN7L3ByaXZhY3l9IiwiZm9sbG93ZXJzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93ZXJzIiwiZm9sbG93aW5nX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93aW5ney9vdGhlcl91c2VyfSIsImdpc3RzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZ2lzdHN7L2dpc3RfaWR9IiwiZ3JhdmF0YXJfaWQiOiIiLCJodG1sX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scyIsImlkIjoxMjkxMjc2MzgsImxvZ2luIjoiYXdzLXBvd2VydG9vbHMiLCJub2RlX2lkIjoiT19rZ0RPQjdKVTFnIiwib3JnYW5pemF0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL29yZ3MiLCJyZWNlaXZlZF9ldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9yZWNlaXZlZF9ldmVudHMiLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3JlcG9zIiwic2l0ZV9hZG1pbiI6ZmFsc2UsInN0YXJyZWRfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9zdGFycmVkey9vd25lcn17L3JlcG99Iiwic3Vic2NyaXB0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3N1YnNjcmlwdGlvbnMiLCJ0eXBlIjoiT3JnYW5pemF0aW9uIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scyIsInVzZXJfdmlld190eXBlIjoicHVibGljIn0sInByaXZhdGUiOmZhbHNlLCJwdWxsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9wdWxsc3svbnVtYmVyfSIsInB1c2hlZF9hdCI6IjIwMjUtMDItMDlUMjM6Mzc6NDhaIiwicmVsZWFzZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vcmVsZWFzZXN7L2lkfSIsInNpemUiOjg2ODIwLCJzc2hfdXJsIjoiZ2l0QGdpdGh1Yi5jb206YXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsInN0YXJnYXplcnNfY291bnQiOjI5ODEsInN0YXJnYXplcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3RhcmdhemVycyIsInN0YXR1c2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3N0YXR1c2VzL3tzaGF9Iiwic3Vic2NyaWJlcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaWJlcnMiLCJzdWJzY3JpcHRpb25fdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaXB0aW9uIiwic3ZuX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ0YWdzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3RhZ3MiLCJ0ZWFtc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi90ZWFtcyIsInRvcGljcyI6WyJhd3MiLCJhd3MtbGFtYmRhIiwiaGFja3RvYmVyZmVzdCIsImxhbWJkYSIsInB5dGhvbiIsInNlcnZlcmxlc3MiXSwidHJlZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RyZWVzey9zaGF9IiwidXBkYXRlZF9hdCI6IjIwMjUtMDItMDlUMjI6NTY6NDFaIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ2aXNpYmlsaXR5IjoicHVibGljIiwid2F0Y2hlcnMiOjI5ODEsIndhdGNoZXJzX2NvdW50IjoyOTgxLCJ3ZWJfY29tbWl0X3NpZ25vZmZfcmVxdWlyZWQiOnRydWV9LCJzY2hlZHVsZSI6IjAgOCAqICogMS01Iiwid29ya2Zsb3ciOiIuZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVsZWFzZS55bWwifSwiZ2l0aHViX2hlYWRfcmVmIjoiIiwiZ2l0aHViX3JlZiI6InJlZnMvaGVhZHMvZGV2ZWxvcCIsImdpdGh1Yl9yZWZfdHlwZSI6ImJyYW5jaCIsImdpdGh1Yl9yZXBvc2l0b3J5X2lkIjoiMjIxOTE5Mzc5IiwiZ2l0aHViX3JlcG9zaXRvcnlfb3duZXIiOiJhd3MtcG93ZXJ0b29scyIsImdpdGh1Yl9yZXBvc2l0b3J5X293bmVyX2lkIjoiMTI5MTI3NjM4IiwiZ2l0aHViX3J1bl9hdHRlbXB0IjoiMSIsImdpdGh1Yl9ydW5faWQiOiIxMzIzNjEyMzUxNyIsImdpdGh1Yl9ydW5fbnVtYmVyIjoiMTcyIiwiZ2l0aHViX3NoYTEiOiI4MTI3MjY5Njg4OThkYzUxMTYxOGFkZTdhMjJhMTQxYjFjNDQ2OWVhIn19LCJtZXRhZGF0YSI6eyJidWlsZEludm9jYXRpb25JRCI6IjEzMjM2MTIzNTE3LTEiLCJjb21wbGV0ZW5lc3MiOnsicGFyYW1ldGVycyI6dHJ1ZSwiZW52aXJvbm1lbnQiOmZhbHNlLCJtYXRlcmlhbHMiOmZhbHNlfSwicmVwcm9kdWNpYmxlIjpmYWxzZX0sIm1hdGVyaWFscyI6W3sidXJpIjoiZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob25AcmVmcy9oZWFkcy9kZXZlbG9wIiwiZGlnZXN0Ijp7InNoYTEiOiI4MTI3MjY5Njg4OThkYzUxMTYxOGFkZTdhMjJhMTQxYjFjNDQ2OWVhIn19XX19","signatures":[{"keyid":"","sig":"MEYCIQCtAtpk8DQUQb3bSjV042C52ry4uTvrbZihI3iha/PO9gIhAKGsX8AXs2uxa/kzQHB+4ybu+jJb9ov6h2nwdr6dOR1l","cert":"-----BEGIN CERTIFICATE-----\nMIIHZjCCBuygAwIBAgIUJ70rjz5cUUmAijLQ4hv96S1iLq8wCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjUwMjEwMDgwNzI0WhcNMjUwMjEwMDgxNzI0WjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAEtXsac6HHaZLvzrBLSKG1h1gNaeaLsF2tvCrK\nnothzGcHYW0zHl52ZOJFxbr/bvGsGb/p5Qhnj6MWM0W0xVmYVqOCBgswggYHMA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUCh0Q\nZuM5lzdClUcKBy4skzvR54gwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wgYQGA1UdEQEB/wR6MHiGdmh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1l\nd29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvLmdpdGh1Yi93b3JrZmxvd3MvZ2Vu\nZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJlZnMvdGFncy92Mi4wLjAwOQYKKwYB\nBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50\nLmNvbTAWBgorBgEEAYO/MAECBAhzY2hlZHVsZTA2BgorBgEEAYO/MAEDBCg4MTI3\nMjY5Njg4OThkYzUxMTYxOGFkZTdhMjJhMTQxYjFjNDQ2OWVhMBkGCisGAQQBg78w\nAQQEC1ByZS1SZWxlYXNlMDUGCisGAQQBg78wAQUEJ2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbjAgBgorBgEEAYO/MAEGBBJyZWZzL2hlYWRz\nL2RldmVsb3AwOwYKKwYBBAGDvzABCAQtDCtodHRwczovL3Rva2VuLmFjdGlvbnMu\nZ2l0aHVidXNlcmNvbnRlbnQuY29tMIGGBgorBgEEAYO/MAEJBHgMdmh0dHBzOi8v\nZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3Iv\nLmdpdGh1Yi93b3JrZmxvd3MvZ2VuZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJl\nZnMvdGFncy92Mi4wLjAwOAYKKwYBBAGDvzABCgQqDCg1YTc3NWIzNjdhNTZkNWJk\nMTE4YTIyNGE4MTFiYmEyODgxNTBhNTYzMB0GCisGAQQBg78wAQsEDwwNZ2l0aHVi\nLWhvc3RlZDBKBgorBgEEAYO/MAEMBDwMOmh0dHBzOi8vZ2l0aHViLmNvbS9hd3Mt\ncG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24wOAYKKwYBBAGDvzAB\nDQQqDCg4MTI3MjY5Njg4OThkYzUxMTYxOGFkZTdhMjJhMTQxYjFjNDQ2OWVhMCIG\nCisGAQQBg78wAQ4EFAwScmVmcy9oZWFkcy9kZXZlbG9wMBkGCisGAQQBg78wAQ8E\nCwwJMjIxOTE5Mzc5MDEGCisGAQQBg78wARAEIwwhaHR0cHM6Ly9naXRodWIuY29t\nL2F3cy1wb3dlcnRvb2xzMBkGCisGAQQBg78wAREECwwJMTI5MTI3NjM4MH8GCisG\nAQQBg78wARIEcQxvaHR0cHM6Ly9naXRodWIuY29tL2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbi8uZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVs\nZWFzZS55bWxAcmVmcy9oZWFkcy9kZXZlbG9wMDgGCisGAQQBg78wARMEKgwoODEy\nNzI2OTY4ODk4ZGM1MTE2MThhZGU3YTIyYTE0MWIxYzQ0NjllYTAYBgorBgEEAYO/\nMAEUBAoMCHNjaGVkdWxlMG4GCisGAQQBg78wARUEYAxeaHR0cHM6Ly9naXRodWIu\nY29tL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hY3Rp\nb25zL3J1bnMvMTMyMzYxMjM1MTcvYXR0ZW1wdHMvMTAWBgorBgEEAYO/MAEWBAgM\nBnB1YmxpYzCBigYKKwYBBAHWeQIEAgR8BHoAeAB2AN09MGrGxxEyYxkeHJlnNwKi\nSl643jyt/4eKcoAvKe6OAAABlO7mGJUAAAQDAEcwRQIgOEVcMYJSCheF5WqCMtwt\n43xL2LsjVRJktrWzG9gorG0CIQD30xFlhK5fmM6mSTIUyAiI2Rmy0ELntb4JBXYz\n9PV+ejAKBggqhkjOPQQDAwNoADBlAjEA5juUAMHWw6yRWcv0vokmVyWKdFG5bZbM\n3P/IjMsMkR9mHkzz7xCNGaPoATVFXTpDAjA+5+/qcLCGRIMVBOuyfrtcIUGCFgVt\n/J1S+OOWg8YwJBmJgxXBRkc2Nd+YFltzxHY=\n-----END CERTIFICATE-----\n"}]}
\ No newline at end of file
diff --git a/provenance/3.5.1a9/multiple.intoto.jsonl b/provenance/3.5.1a9/multiple.intoto.jsonl
new file mode 100644
index 00000000000..89d9a02ad58
--- /dev/null
+++ b/provenance/3.5.1a9/multiple.intoto.jsonl
@@ -0,0 +1 @@
+{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMiIsInN1YmplY3QiOlt7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWE5LXB5My1ub25lLWFueS53aGwiLCJkaWdlc3QiOnsic2hhMjU2IjoiYmMxZjAwZGY3ZmUzYjdmYjQ1ZjBkY2IxNTFiNGJiMmEwYTNmY2ZkNDIyNjg0ZTE0MzBkZTE1ZGI2NjY5MWFmZCJ9fSx7Im5hbWUiOiIuL2F3c19sYW1iZGFfcG93ZXJ0b29scy0zLjUuMWE5LnRhci5neiIsImRpZ2VzdCI6eyJzaGEyNTYiOiI2NmQ3MmFmMDMxOTE1MDRhOTE2NjYzZGFmYjUyNTFlZDEyNzZkZWNmNTRmMDVkZmU5ZThjM2Q0NmZkYmJiMDE2In19XSwicHJlZGljYXRlIjp7ImJ1aWxkZXIiOnsiaWQiOiJodHRwczovL2dpdGh1Yi5jb20vc2xzYS1mcmFtZXdvcmsvc2xzYS1naXRodWItZ2VuZXJhdG9yLy5naXRodWIvd29ya2Zsb3dzL2dlbmVyYXRvcl9nZW5lcmljX3Nsc2EzLnltbEByZWZzL3RhZ3MvdjIuMC4wIn0sImJ1aWxkVHlwZSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvZ2VuZXJpY0B2MSIsImludm9jYXRpb24iOnsiY29uZmlnU291cmNlIjp7InVyaSI6ImdpdCtodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uQHJlZnMvaGVhZHMvZGV2ZWxvcCIsImRpZ2VzdCI6eyJzaGExIjoiMWNhMDVhMjcyYzhjMjQ1ZDVkYjFlMDNkNmNkZGNiYjZkM2QxODRmNyJ9LCJlbnRyeVBvaW50IjoiLmdpdGh1Yi93b3JrZmxvd3MvcHJlLXJlbGVhc2UueW1sIn0sInBhcmFtZXRlcnMiOnt9LCJlbnZpcm9ubWVudCI6eyJnaXRodWJfYWN0b3IiOiJsZWFuZHJvZGFtYXNjZW5hIiwiZ2l0aHViX2FjdG9yX2lkIjoiNDI5NTE3MyIsImdpdGh1Yl9iYXNlX3JlZiI6IiIsImdpdGh1Yl9ldmVudF9uYW1lIjoic2NoZWR1bGUiLCJnaXRodWJfZXZlbnRfcGF5bG9hZCI6eyJlbnRlcnByaXNlIjp7ImF2YXRhcl91cmwiOiJodHRwczovL2F2YXRhcnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2IvMTI5MD92PTQiLCJjcmVhdGVkX2F0IjoiMjAxOS0xMS0xM1QxODowNTo0MVoiLCJkZXNjcmlwdGlvbiI6IiIsImh0bWxfdXJsIjoiaHR0cHM6Ly9naXRodWIuY29tL2VudGVycHJpc2VzL2FtYXpvbiIsImlkIjoxMjkwLCJuYW1lIjoiQW1hem9uIiwibm9kZV9pZCI6Ik1ERXdPa1Z1ZEdWeWNISnBjMlV4TWprdyIsInNsdWciOiJhbWF6b24iLCJ1cGRhdGVkX2F0IjoiMjAyNC0wOS0zMFQyMTowMjozMFoiLCJ3ZWJzaXRlX3VybCI6Imh0dHBzOi8vd3d3LmFtYXpvbi5jb20vIn0sIm9yZ2FuaXphdGlvbiI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJkZXNjcmlwdGlvbiI6IiIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvZXZlbnRzIiwiaG9va3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9vcmdzL2F3cy1wb3dlcnRvb2xzL2hvb2tzIiwiaWQiOjEyOTEyNzYzOCwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vb3Jncy9hd3MtcG93ZXJ0b29scy9pc3N1ZXMiLCJsb2dpbiI6ImF3cy1wb3dlcnRvb2xzIiwibWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvbWVtYmVyc3svbWVtYmVyfSIsIm5vZGVfaWQiOiJPX2tnRE9CN0pVMWciLCJwdWJsaWNfbWVtYmVyc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcHVibGljX21lbWJlcnN7L21lbWJlcn0iLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMvcmVwb3MiLCJ1cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL29yZ3MvYXdzLXBvd2VydG9vbHMifSwicmVwb3NpdG9yeSI6eyJhbGxvd19mb3JraW5nIjp0cnVlLCJhcmNoaXZlX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3thcmNoaXZlX2Zvcm1hdH17L3JlZn0iLCJhcmNoaXZlZCI6ZmFsc2UsImFzc2lnbmVlc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hc3NpZ25lZXN7L3VzZXJ9IiwiYmxvYnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L2Jsb2Jzey9zaGF9IiwiYnJhbmNoZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vYnJhbmNoZXN7L2JyYW5jaH0iLCJjbG9uZV91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsImNvbGxhYm9yYXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29sbGFib3JhdG9yc3svY29sbGFib3JhdG9yfSIsImNvbW1lbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbW1lbnRzey9udW1iZXJ9IiwiY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21taXRzey9zaGF9IiwiY29tcGFyZV91cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9jb21wYXJlL3tiYXNlfS4uLntoZWFkfSIsImNvbnRlbnRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2NvbnRlbnRzL3srcGF0aH0iLCJjb250cmlidXRvcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vY29udHJpYnV0b3JzIiwiY3JlYXRlZF9hdCI6IjIwMTktMTEtMTVUMTI6MjY6MTJaIiwiY3VzdG9tX3Byb3BlcnRpZXMiOnt9LCJkZWZhdWx0X2JyYW5jaCI6ImRldmVsb3AiLCJkZXBsb3ltZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9kZXBsb3ltZW50cyIsImRlc2NyaXB0aW9uIjoiQSBkZXZlbG9wZXIgdG9vbGtpdCB0byBpbXBsZW1lbnQgU2VydmVybGVzcyBiZXN0IHByYWN0aWNlcyBhbmQgaW5jcmVhc2UgZGV2ZWxvcGVyIHZlbG9jaXR5LiIsImRpc2FibGVkIjpmYWxzZSwiZG93bmxvYWRzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2Rvd25sb2FkcyIsImV2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9ldmVudHMiLCJmb3JrIjpmYWxzZSwiZm9ya3MiOjQwOCwiZm9ya3NfY291bnQiOjQwOCwiZm9ya3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZm9ya3MiLCJmdWxsX25hbWUiOiJhd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJnaXRfY29tbWl0c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9naXQvY29tbWl0c3svc2hhfSIsImdpdF9yZWZzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2dpdC9yZWZzey9zaGF9IiwiZ2l0X3RhZ3NfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RhZ3N7L3NoYX0iLCJnaXRfdXJsIjoiZ2l0Oi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24uZ2l0IiwiaGFzX2Rpc2N1c3Npb25zIjp0cnVlLCJoYXNfZG93bmxvYWRzIjp0cnVlLCJoYXNfaXNzdWVzIjp0cnVlLCJoYXNfcGFnZXMiOmZhbHNlLCJoYXNfcHJvamVjdHMiOnRydWUsImhhc193aWtpIjpmYWxzZSwiaG9tZXBhZ2UiOiJodHRwczovL2RvY3MucG93ZXJ0b29scy5hd3MuZGV2L2xhbWJkYS9weXRob24vbGF0ZXN0LyIsImhvb2tzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2hvb2tzIiwiaHRtbF91cmwiOiJodHRwczovL2dpdGh1Yi5jb20vYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uIiwiaWQiOjIyMTkxOTM3OSwiaXNfdGVtcGxhdGUiOmZhbHNlLCJpc3N1ZV9jb21tZW50X3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlcy9jb21tZW50c3svbnVtYmVyfSIsImlzc3VlX2V2ZW50c191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9pc3N1ZXMvZXZlbnRzey9udW1iZXJ9IiwiaXNzdWVzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL2lzc3Vlc3svbnVtYmVyfSIsImtleXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24va2V5c3sva2V5X2lkfSIsImxhYmVsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9sYWJlbHN7L25hbWV9IiwibGFuZ3VhZ2UiOiJQeXRob24iLCJsYW5ndWFnZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbGFuZ3VhZ2VzIiwibGljZW5zZSI6eyJrZXkiOiJtaXQtMCIsIm5hbWUiOiJNSVQgTm8gQXR0cmlidXRpb24iLCJub2RlX2lkIjoiTURjNlRHbGpaVzV6WlRReCIsInNwZHhfaWQiOiJNSVQtMCIsInVybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vbGljZW5zZXMvbWl0LTAifSwibWVyZ2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL21lcmdlcyIsIm1pbGVzdG9uZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vbWlsZXN0b25lc3svbnVtYmVyfSIsIm1pcnJvcl91cmwiOm51bGwsIm5hbWUiOiJwb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJub2RlX2lkIjoiTURFd09sSmxjRzl6YVhSdmNua3lNakU1TVRrek56az0iLCJub3RpZmljYXRpb25zX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL25vdGlmaWNhdGlvbnN7P3NpbmNlLGFsbCxwYXJ0aWNpcGF0aW5nfSIsIm9wZW5faXNzdWVzIjo1OSwib3Blbl9pc3N1ZXNfY291bnQiOjU5LCJvd25lciI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzEyOTEyNzYzOD92PTQiLCJldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9ldmVudHN7L3ByaXZhY3l9IiwiZm9sbG93ZXJzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93ZXJzIiwiZm9sbG93aW5nX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZm9sbG93aW5ney9vdGhlcl91c2VyfSIsImdpc3RzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvYXdzLXBvd2VydG9vbHMvZ2lzdHN7L2dpc3RfaWR9IiwiZ3JhdmF0YXJfaWQiOiIiLCJodG1sX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scyIsImlkIjoxMjkxMjc2MzgsImxvZ2luIjoiYXdzLXBvd2VydG9vbHMiLCJub2RlX2lkIjoiT19rZ0RPQjdKVTFnIiwib3JnYW5pemF0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL29yZ3MiLCJyZWNlaXZlZF9ldmVudHNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9yZWNlaXZlZF9ldmVudHMiLCJyZXBvc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3JlcG9zIiwic2l0ZV9hZG1pbiI6ZmFsc2UsInN0YXJyZWRfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scy9zdGFycmVkey9vd25lcn17L3JlcG99Iiwic3Vic2NyaXB0aW9uc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3VzZXJzL2F3cy1wb3dlcnRvb2xzL3N1YnNjcmlwdGlvbnMiLCJ0eXBlIjoiT3JnYW5pemF0aW9uIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy9hd3MtcG93ZXJ0b29scyIsInVzZXJfdmlld190eXBlIjoicHVibGljIn0sInByaXZhdGUiOmZhbHNlLCJwdWxsc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9wdWxsc3svbnVtYmVyfSIsInB1c2hlZF9hdCI6IjIwMjUtMDItMTBUMjE6NTY6MTdaIiwicmVsZWFzZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vcmVsZWFzZXN7L2lkfSIsInNpemUiOjg2MjIwLCJzc2hfdXJsIjoiZ2l0QGdpdGh1Yi5jb206YXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uLmdpdCIsInN0YXJnYXplcnNfY291bnQiOjI5ODMsInN0YXJnYXplcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3RhcmdhemVycyIsInN0YXR1c2VzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3N0YXR1c2VzL3tzaGF9Iiwic3Vic2NyaWJlcnNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaWJlcnMiLCJzdWJzY3JpcHRpb25fdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vc3Vic2NyaXB0aW9uIiwic3ZuX3VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ0YWdzX3VybCI6Imh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvYXdzLXBvd2VydG9vbHMvcG93ZXJ0b29scy1sYW1iZGEtcHl0aG9uL3RhZ3MiLCJ0ZWFtc191cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi90ZWFtcyIsInRvcGljcyI6WyJhd3MiLCJhd3MtbGFtYmRhIiwiaGFja3RvYmVyZmVzdCIsImxhbWJkYSIsInB5dGhvbiIsInNlcnZlcmxlc3MiXSwidHJlZXNfdXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24vZ2l0L3RyZWVzey9zaGF9IiwidXBkYXRlZF9hdCI6IjIwMjUtMDItMTFUMDU6MDE6MjlaIiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24iLCJ2aXNpYmlsaXR5IjoicHVibGljIiwid2F0Y2hlcnMiOjI5ODMsIndhdGNoZXJzX2NvdW50IjoyOTgzLCJ3ZWJfY29tbWl0X3NpZ25vZmZfcmVxdWlyZWQiOnRydWV9LCJzY2hlZHVsZSI6IjAgOCAqICogMS01Iiwid29ya2Zsb3ciOiIuZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVsZWFzZS55bWwifSwiZ2l0aHViX2hlYWRfcmVmIjoiIiwiZ2l0aHViX3JlZiI6InJlZnMvaGVhZHMvZGV2ZWxvcCIsImdpdGh1Yl9yZWZfdHlwZSI6ImJyYW5jaCIsImdpdGh1Yl9yZXBvc2l0b3J5X2lkIjoiMjIxOTE5Mzc5IiwiZ2l0aHViX3JlcG9zaXRvcnlfb3duZXIiOiJhd3MtcG93ZXJ0b29scyIsImdpdGh1Yl9yZXBvc2l0b3J5X293bmVyX2lkIjoiMTI5MTI3NjM4IiwiZ2l0aHViX3J1bl9hdHRlbXB0IjoiMSIsImdpdGh1Yl9ydW5faWQiOiIxMzI1ODI4OTY4NyIsImdpdGh1Yl9ydW5fbnVtYmVyIjoiMTczIiwiZ2l0aHViX3NoYTEiOiIxY2EwNWEyNzJjOGMyNDVkNWRiMWUwM2Q2Y2RkY2JiNmQzZDE4NGY3In19LCJtZXRhZGF0YSI6eyJidWlsZEludm9jYXRpb25JRCI6IjEzMjU4Mjg5Njg3LTEiLCJjb21wbGV0ZW5lc3MiOnsicGFyYW1ldGVycyI6dHJ1ZSwiZW52aXJvbm1lbnQiOmZhbHNlLCJtYXRlcmlhbHMiOmZhbHNlfSwicmVwcm9kdWNpYmxlIjpmYWxzZX0sIm1hdGVyaWFscyI6W3sidXJpIjoiZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9hd3MtcG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob25AcmVmcy9oZWFkcy9kZXZlbG9wIiwiZGlnZXN0Ijp7InNoYTEiOiIxY2EwNWEyNzJjOGMyNDVkNWRiMWUwM2Q2Y2RkY2JiNmQzZDE4NGY3In19XX19","signatures":[{"keyid":"","sig":"MEUCIDwSCOre8yWH8osNcZVE0hK1WhO4Lj5TXcdMz+KGOC0BAiEApZ4fHP7B/XCoONpQH+a9gOWvJDF6lRiYMG/pirEqijM=","cert":"-----BEGIN CERTIFICATE-----\nMIIHZjCCBuygAwIBAgIUEP2vbsn3CmsfmG8GY3NnxxVghPswCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjUwMjExMDgwNjU3WhcNMjUwMjExMDgxNjU3WjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAENnEUvPH6AZwA86iBNosXWKfBlGCHSVmV2SPa\nRQ7m2jePc1y2BaNU1kh9XXChn0NJAifZdSbdN5cSO/sKChMpaqOCBgswggYHMA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUFfeZ\nRNn73KaC3Rn/HjxdU/oGpkQwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wgYQGA1UdEQEB/wR6MHiGdmh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1l\nd29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvLmdpdGh1Yi93b3JrZmxvd3MvZ2Vu\nZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJlZnMvdGFncy92Mi4wLjAwOQYKKwYB\nBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50\nLmNvbTAWBgorBgEEAYO/MAECBAhzY2hlZHVsZTA2BgorBgEEAYO/MAEDBCgxY2Ew\nNWEyNzJjOGMyNDVkNWRiMWUwM2Q2Y2RkY2JiNmQzZDE4NGY3MBkGCisGAQQBg78w\nAQQEC1ByZS1SZWxlYXNlMDUGCisGAQQBg78wAQUEJ2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbjAgBgorBgEEAYO/MAEGBBJyZWZzL2hlYWRz\nL2RldmVsb3AwOwYKKwYBBAGDvzABCAQtDCtodHRwczovL3Rva2VuLmFjdGlvbnMu\nZ2l0aHVidXNlcmNvbnRlbnQuY29tMIGGBgorBgEEAYO/MAEJBHgMdmh0dHBzOi8v\nZ2l0aHViLmNvbS9zbHNhLWZyYW1ld29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3Iv\nLmdpdGh1Yi93b3JrZmxvd3MvZ2VuZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJl\nZnMvdGFncy92Mi4wLjAwOAYKKwYBBAGDvzABCgQqDCg1YTc3NWIzNjdhNTZkNWJk\nMTE4YTIyNGE4MTFiYmEyODgxNTBhNTYzMB0GCisGAQQBg78wAQsEDwwNZ2l0aHVi\nLWhvc3RlZDBKBgorBgEEAYO/MAEMBDwMOmh0dHBzOi8vZ2l0aHViLmNvbS9hd3Mt\ncG93ZXJ0b29scy9wb3dlcnRvb2xzLWxhbWJkYS1weXRob24wOAYKKwYBBAGDvzAB\nDQQqDCgxY2EwNWEyNzJjOGMyNDVkNWRiMWUwM2Q2Y2RkY2JiNmQzZDE4NGY3MCIG\nCisGAQQBg78wAQ4EFAwScmVmcy9oZWFkcy9kZXZlbG9wMBkGCisGAQQBg78wAQ8E\nCwwJMjIxOTE5Mzc5MDEGCisGAQQBg78wARAEIwwhaHR0cHM6Ly9naXRodWIuY29t\nL2F3cy1wb3dlcnRvb2xzMBkGCisGAQQBg78wAREECwwJMTI5MTI3NjM4MH8GCisG\nAQQBg78wARIEcQxvaHR0cHM6Ly9naXRodWIuY29tL2F3cy1wb3dlcnRvb2xzL3Bv\nd2VydG9vbHMtbGFtYmRhLXB5dGhvbi8uZ2l0aHViL3dvcmtmbG93cy9wcmUtcmVs\nZWFzZS55bWxAcmVmcy9oZWFkcy9kZXZlbG9wMDgGCisGAQQBg78wARMEKgwoMWNh\nMDVhMjcyYzhjMjQ1ZDVkYjFlMDNkNmNkZGNiYjZkM2QxODRmNzAYBgorBgEEAYO/\nMAEUBAoMCHNjaGVkdWxlMG4GCisGAQQBg78wARUEYAxeaHR0cHM6Ly9naXRodWIu\nY29tL2F3cy1wb3dlcnRvb2xzL3Bvd2VydG9vbHMtbGFtYmRhLXB5dGhvbi9hY3Rp\nb25zL3J1bnMvMTMyNTgyODk2ODcvYXR0ZW1wdHMvMTAWBgorBgEEAYO/MAEWBAgM\nBnB1YmxpYzCBigYKKwYBBAHWeQIEAgR8BHoAeAB2AN09MGrGxxEyYxkeHJlnNwKi\nSl643jyt/4eKcoAvKe6OAAABlPQMC5oAAAQDAEcwRQIhAK1GC+Gju7udOGYM9m7v\nN6fhUpQAVjpVaN5FBpLfTBoNAiBFwSFuc/0pJOBn44GS/7ZAYsrg3ik3jvSnRAIH\nj9iO5TAKBggqhkjOPQQDAwNoADBlAjEAwETKGts8i/12J2NFkMSpQhu/NO6nZKB7\ngNw3dTLn4ztiNMvYeiGFWwjbhmfRO0HBAjAtFeen+4kMdBFkX9o/Y81lpHiARemU\nVeuQr/10Q767/s6jw4Fwp6M+Y4xzKFsSMfM=\n-----END CERTIFICATE-----\n"}]}
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 26fa05c9273..5549221f886 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "aws_lambda_powertools"
-version = "3.4.2a0"
+version = "3.6.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"]
@@ -77,12 +77,11 @@ datamasking = ["aws-encryption-sdk", "jsonpath-ng"]
[tool.poetry.group.dev.dependencies]
coverage = { extras = ["toml"], version = "^7.6" }
pytest = "^8.3.4"
-black = "^24.8"
+black = ">=24.8,<26.0"
boto3 = "^1.26.164"
-isort = "^5.13.2"
+isort = ">=5.13.2,<7.0.0"
pytest-cov = ">=5,<7"
pytest-mock = "^3.14.0"
-pdoc3 = "^0.11.0"
pytest-asyncio = ">=0.24,<0.26"
bandit = "^1.7.10"
radon = "^6.0.1"
@@ -108,13 +107,13 @@ hvac = "^2.3.0"
aws-requests-auth = "^0.4.3"
urllib3 = "<2"
requests = ">=2.32.0"
-cfn-lint = "1.22.7"
+cfn-lint = "1.24.0"
mypy = "^1.1.1"
types-python-dateutil = "^2.8.19.6"
aws-cdk-aws-appsync-alpha = "^2.59.0a0"
httpx = ">=0.23.3,<0.29.0"
sentry-sdk = ">=1.22.2,<3.0.0"
-ruff = ">=0.5.1,<0.9.4"
+ruff = ">=0.5.1,<0.9.7"
retry2 = "^0.9.5"
pytest-socket = ">=0.6,<0.8"
types-redis = "^4.6.0.7"
@@ -122,6 +121,8 @@ testcontainers = { extras = ["redis"], version = ">=3.7.1,<5.0.0" }
multiprocess = "^0.70.16"
boto3-stubs = {extras = ["appconfig", "appconfigdata", "cloudformation", "cloudwatch", "dynamodb", "lambda", "logs", "s3", "secretsmanager", "ssm", "xray"], version = "^1.34.139"}
nox = "^2024.4.15"
+mkdocstrings-python = "^1.13.0"
+licensecheck = "^2024.3"
[tool.coverage.run]
source = ["aws_lambda_powertools"]
@@ -134,9 +135,6 @@ omit = [
]
branch = true
-[tool.poetry.requires-plugins]
-poetry-plugin-export = "^1.9.0"
-
[tool.coverage.html]
directory = "test_report"
title = "Powertools for AWS Lambda (Python) Test Coverage"
diff --git a/tests/events/apiGatewayAuthorizerWebSocketEvent.json b/tests/events/apiGatewayAuthorizerWebSocketEvent.json
new file mode 100644
index 00000000000..f89b7449e1e
--- /dev/null
+++ b/tests/events/apiGatewayAuthorizerWebSocketEvent.json
@@ -0,0 +1,81 @@
+{
+ "type":"REQUEST",
+ "methodArn":"arn:aws:execute-api:us-east-1:533568316194:c5jwxq709g/production/$connect",
+ "headers":{
+ "Authorization":"Leo",
+ "Connection":"upgrade",
+ "content-length":"0",
+ "Host":"c5jwxq709g.execute-api.us-east-1.amazonaws.com",
+ "Sec-WebSocket-Extensions":"permessage-deflate; client_max_window_bits",
+ "Sec-WebSocket-Version":"13",
+ "Upgrade":"websocket",
+ "X-Amzn-Trace-Id":"Root=1-6797b6d3-64f9c928577f3ac56f5368ce",
+ "X-Forwarded-For":"93.108.161.96",
+ "X-Forwarded-Port":"443",
+ "X-Forwarded-Proto":"https"
+ },
+ "multiValueHeaders":{
+ "Authorization":[
+ "Leo"
+ ],
+ "Connection":[
+ "upgrade"
+ ],
+ "content-length":[
+ "0"
+ ],
+ "Host":[
+ "c5jwxq709g.execute-api.us-east-1.amazonaws.com"
+ ],
+ "Sec-WebSocket-Extensions":[
+ "permessage-deflate; client_max_window_bits"
+ ],
+ "Sec-WebSocket-Key":[
+ "CYZZrfNgEcgzzzwL44qytQ=="
+ ],
+ "Sec-WebSocket-Version":[
+ "13"
+ ],
+ "Upgrade":[
+ "websocket"
+ ],
+ "X-Amzn-Trace-Id":[
+ "Root=1-6797b6d3-64f9c928577f3ac56f5368ce"
+ ],
+ "X-Forwarded-For":[
+ "93.108.161.96"
+ ],
+ "X-Forwarded-Port":[
+ "443"
+ ],
+ "X-Forwarded-Proto":[
+ "https"
+ ]
+ },
+ "queryStringParameters":{
+
+ },
+ "multiValueQueryStringParameters":{
+
+ },
+ "stageVariables":{
+
+ },
+ "requestContext":{
+ "routeKey":"$connect",
+ "eventType":"CONNECT",
+ "extendedRequestId":"FDmBIG3EoAMEqYA=",
+ "requestTime":"27/Jan/2025:16:39:47 +0000",
+ "messageDirection":"IN",
+ "stage":"production",
+ "connectedAt":1737995987617,
+ "requestTimeEpoch":1737995987617,
+ "identity":{
+ "sourceIp":"93.108.161.96"
+ },
+ "requestId":"FDmBIG3EoAMEqYA=",
+ "domainName":"c5jwxq709g.execute-api.us-east-1.amazonaws.com",
+ "connectionId":"FDmBIeapIAMCIQg=",
+ "apiId":"c5jwxq709g"
+ }
+}
diff --git a/tests/functional/data_masking/required_dependencies/test_erase_data_masking.py b/tests/functional/data_masking/required_dependencies/test_erase_data_masking.py
new file mode 100644
index 00000000000..12ffd054376
--- /dev/null
+++ b/tests/functional/data_masking/required_dependencies/test_erase_data_masking.py
@@ -0,0 +1,488 @@
+import json
+
+import pytest
+
+from aws_lambda_powertools.utilities.data_masking.base import DataMasking
+from aws_lambda_powertools.utilities.data_masking.constants import DATA_MASKING_STRING
+from aws_lambda_powertools.utilities.data_masking.exceptions import (
+ DataMaskingFieldNotFoundError,
+ DataMaskingUnsupportedTypeError,
+)
+from aws_lambda_powertools.warnings import PowertoolsUserWarning
+
+
+@pytest.fixture
+def data_masker() -> DataMasking:
+ return DataMasking()
+
+
+def test_erase_int(data_masker):
+ # GIVEN an int data type
+
+ # WHEN erase is called with no fields argument
+ erased_string = data_masker.erase(42)
+
+ # THEN the result is the data masked
+ assert erased_string == DATA_MASKING_STRING
+
+
+def test_erase_int_custom_mask(data_masker):
+ # GIVEN an int data type
+
+ # WHEN erase is called with no fields argument
+ erased_string = data_masker.erase(42, custom_mask="XX")
+
+ # THEN the result is the data masked
+ assert erased_string == "XX"
+
+
+def test_erase_float(data_masker):
+ # GIVEN a float data type
+
+ # WHEN erase is called with no fields argument
+ erased_string = data_masker.erase(4.2)
+
+ # THEN the result is the data masked
+ assert erased_string == DATA_MASKING_STRING
+
+
+def test_erase_bool(data_masker):
+ # GIVEN a bool data type
+
+ # WHEN erase is called with no fields argument
+ erased_string = data_masker.erase(True)
+
+ # THEN the result is the data masked
+ assert erased_string == DATA_MASKING_STRING
+
+
+def test_erase_none(data_masker):
+ # GIVEN a None data type
+
+ # WHEN erase is called with no fields argument
+ erased_string = data_masker.erase(None)
+
+ # THEN the result is the data masked
+ assert erased_string == DATA_MASKING_STRING
+
+
+def test_erase_str(data_masker):
+ # GIVEN a str data type
+
+ # WHEN erase is called with no fields argument
+ erased_string = data_masker.erase("this is a string")
+
+ # THEN the result is the data masked
+ assert erased_string == DATA_MASKING_STRING
+
+
+def test_erase_list(data_masker):
+ # GIVEN a list data type
+
+ # WHEN erase is called with no fields argument
+ erased_string = data_masker.erase([1, 2, "string", 3])
+
+ # THEN the result is the data masked, while maintaining type list
+ assert erased_string == [DATA_MASKING_STRING, DATA_MASKING_STRING, DATA_MASKING_STRING, DATA_MASKING_STRING]
+
+
+def test_erase_dict(data_masker):
+ # GIVEN a dict data type
+ data = {
+ "a": {
+ "1": {"None": "hello", "four": "world"},
+ "b": {"3": {"4": "goodbye", "e": "world"}},
+ },
+ }
+
+ # WHEN erase is called with no fields argument
+ erased_string = data_masker.erase(data)
+
+ # THEN the result is the data masked
+ assert erased_string == DATA_MASKING_STRING
+
+
+def test_erase_dict_with_fields(data_masker):
+ # GIVEN a dict data type
+ data = {
+ "a": {
+ "1": {"None": "hello", "four": "world"},
+ "b": {"3": {"4": "goodbye", "e": "world"}},
+ },
+ }
+
+ # WHEN erase is called with a list of fields specified
+ erased_string = data_masker.erase(data, fields=["a.'1'.None", "a..'4'"])
+
+ # THEN the result is only the specified fields are erased
+ assert erased_string == {
+ "a": {
+ "1": {"None": DATA_MASKING_STRING, "four": "world"},
+ "b": {"3": {"4": DATA_MASKING_STRING, "e": "world"}},
+ },
+ }
+
+
+def test_erase_json_dict_with_fields(data_masker):
+ # GIVEN the data type is a json representation of a dictionary
+ data = json.dumps(
+ {
+ "a": {
+ "1": {"None": "hello", "four": "world"},
+ "b": {"3": {"4": "goodbye", "e": "world"}},
+ },
+ },
+ )
+
+ # WHEN erase is called with a list of fields specified
+ masked_json_string = data_masker.erase(data, fields=["a.'1'.None", "a..'4'"])
+
+ # THEN the result is only the specified fields are erased
+ assert masked_json_string == {
+ "a": {
+ "1": {"None": DATA_MASKING_STRING, "four": "world"},
+ "b": {"3": {"4": DATA_MASKING_STRING, "e": "world"}},
+ },
+ }
+
+
+def test_encrypt_not_implemented(data_masker):
+ # GIVEN DataMasking is not initialized with a Provider
+
+ # WHEN attempting to call the encrypt method on the data
+ with pytest.raises(NotImplementedError):
+ # THEN the result is a NotImplementedError
+ data_masker.encrypt("hello world")
+
+
+def test_decrypt_not_implemented(data_masker):
+ # GIVEN DataMasking is not initialized with a Provider
+
+ # WHEN attempting to call the decrypt method on the data
+ with pytest.raises(NotImplementedError):
+ # THEN the result is a NotImplementedError
+ data_masker.decrypt("hello world")
+
+
+def test_parsing_unsupported_data_type(data_masker):
+ # GIVEN an initialization of the DataMasking class
+
+ # WHEN attempting to pass in a list of fields with input data that is not a dict
+ with pytest.raises(DataMaskingUnsupportedTypeError):
+ # THEN the result is a TypeError
+ data_masker.erase(42, ["this.field"])
+
+
+def test_parsing_with_empty_field(data_masker):
+ # GIVEN an initialization of the DataMasking class
+
+ # WHEN attempting to pass in a list of fields with input data that is not a dict
+ with pytest.raises(ValueError):
+ # THEN the result is a TypeError
+ data_masker.erase(42, [])
+
+
+def test_parsing_nonexistent_fields_with_raise_on_missing_field():
+ # GIVEN a dict data type
+
+ data_masker = DataMasking(raise_on_missing_field=True)
+ data = {
+ "3": {
+ "1": {"None": "hello", "four": "world"},
+ "4": {"33": {"5": "goodbye", "e": "world"}},
+ },
+ }
+
+ # WHEN attempting to pass in fields that do not exist in the input data
+ with pytest.raises(DataMaskingFieldNotFoundError):
+ # THEN the result is a KeyError
+ data_masker.erase(data, ["'3'..True"])
+
+
+def test_parsing_nonexistent_fields_warning_on_missing_field():
+ # GIVEN a dict data type
+
+ data_masker = DataMasking(raise_on_missing_field=False)
+ data = {
+ "3": {
+ "1": {"None": "hello", "four": "world"},
+ "4": {"33": {"5": "goodbye", "e": "world"}},
+ },
+ }
+
+ # WHEN erase is called with a non-existing field
+ with pytest.warns(UserWarning, match="Field or expression*"):
+ masked_json_string = data_masker.erase(data, fields=["non-existing"])
+
+ # THEN the "erased" payload is the same of the original
+ assert masked_json_string == data
+
+
+def test_regex_mask(data_masker):
+ # GIVEN a str data type
+ data = "Hello! My name is John Doe"
+
+ # WHEN erase is called with regex pattern and mask format
+ regex_pattern = r"\b[A-Z][a-z]+ [A-Z][a-z]+\b"
+ mask_format = "XXXX XXXX"
+
+ result = data_masker.erase(data, regex_pattern=regex_pattern, mask_format=mask_format)
+
+ # THEN the result is the regex part masked by the masked format
+ assert result == "Hello! My name is XXXX XXXX"
+
+
+def test_regex_mask_with_cache(data_masker):
+ # GIVEN a str data type
+ data = "Hello! My name is John Doe"
+ data1 = "Hello! My name is John Xix"
+
+ # WHEN erase is called with regex pattern and mask format
+ regex_pattern = r"\b[A-Z][a-z]+ [A-Z][a-z]+\b"
+ mask_format = "XXXX XXXX"
+
+ # WHEN erasing twice to check the regex compiled and stored in the cache
+ result = data_masker.erase(data, regex_pattern=regex_pattern, mask_format=mask_format)
+ result1 = data_masker.erase(data1, regex_pattern=regex_pattern, mask_format=mask_format)
+
+ # THEN the result is the regex part masked by the masked format
+ assert result == "Hello! My name is XXXX XXXX"
+ assert result1 == "Hello! My name is XXXX XXXX"
+
+
+def test_erase_json_dict_with_fields_and_masks(data_masker):
+ # GIVEN the data type is a json representation of a dictionary
+ data = json.dumps(
+ {
+ "a": {
+ "1": {"None": "hello", "four": "world"},
+ "b": {"3": {"4": "goodbye", "e": "world"}},
+ },
+ },
+ )
+
+ # WHEN erase is called with a list of fields specified
+ masked_json_string = data_masker.erase(data, fields=["a.'1'.None", "a..'4'"], dynamic_mask=True)
+
+ # THEN the result is only the specified fields are erased
+ assert masked_json_string == {
+ "a": {
+ "1": {"None": "*****", "four": "world"},
+ "b": {"3": {"4": "*******", "e": "world"}},
+ },
+ }
+
+
+def test_erase_json_dict_with_complex_masking_rules(data_masker):
+ # GIVEN the data type is a json representation of a dictionary with nested and filtered paths
+ data = {
+ "email": "johndoe@example.com",
+ "age": 30,
+ "address": {"zip": 13000, "street": "123 Main St", "details": {"name": "Home", "type": "Primary"}},
+ }
+
+ # WHEN erase is called with complex masking rules
+ masking_rules = {
+ "email": {"regex_pattern": "(.)(.*)(@.*)", "mask_format": r"\1****\3"},
+ "age": {"dynamic_mask": True},
+ "address.zip": {"custom_mask": "xxx"},
+ }
+
+ masked_json_string = data_masker.erase(data=data, masking_rules=masking_rules)
+
+ # THEN the result should have all specified fields masked according to their rules
+ assert masked_json_string == {
+ "email": "j****@example.com",
+ "age": "**",
+ "address": {"zip": "xxx", "street": "123 Main St", "details": {"name": "Home", "type": "Primary"}},
+ }
+
+
+def test_dynamic_mask_with_string(data_masker):
+ # GIVEN the data type is a json representation of a dictionary with nested and filtered paths
+ data = "XYZEKDEDE"
+
+ masked_json_string = data_masker.erase(data=data, dynamic_mask=True)
+
+ # THEN the result should have all specified fields masked according to their rules
+ assert masked_json_string == "*********"
+
+
+def test_no_matches_for_masking_rule(data_masker):
+ # GIVEN a dictionary without the expected field
+ data = {"name": "Ana"}
+ masking_rules = {"$.missing_field": {"dynamic_mask": True}}
+
+ # WHEN applying the masking rule
+ with pytest.warns(UserWarning, match=r"No matches found *"):
+ result = data_masker.erase(data=data, masking_rules=masking_rules)
+
+ # THEN the original data remains unchanged
+ assert result == data
+
+
+def test_warning_during_masking_value(data_masker):
+ # GIVEN data and a masking rule
+ data = {"value": "test"}
+
+ # Mock provider that raises an error
+ class MockProvider:
+ def erase(self, value, **kwargs):
+ raise ValueError("Mock error")
+
+ data_masker.provider = MockProvider()
+
+ # WHEN erase is called
+ with pytest.warns(expected_warning=PowertoolsUserWarning, match="Error masking value for path value: Mock error"):
+ masked_data = data_masker.erase(data, masking_rules={"value": {"rule": "value"}})
+
+ # THEN the original data should remain unchanged
+ assert masked_data["value"] == "test"
+
+
+def test_mask_nested_field_success(data_masker):
+ # GIVEN nested data with a field to mask
+ data = {"user": {"contact": {"details": {"address": {"street": "123 Main St", "zip": "12345"}}}}}
+
+ # WHEN masking a nested field with a masking rule
+ data_masked = data_masker.erase(data=data, fields=["user.contact.details.address.zip"], custom_mask="xxx")
+
+ # THEN the nested field should be masked while other data remains unchanged
+ assert data_masked == {"user": {"contact": {"details": {"address": {"street": "123 Main St", "zip": "xxx"}}}}}
+
+
+def test_erase_dictionary_with_masking_rules(data_masker):
+ # GIVEN a dictionary with nested sensitive data
+ data = {"user": {"name": "John Doe", "ssn": "123-45-6789", "address": {"street": "123 Main St", "zip": "12345"}}}
+
+ # AND masking rules for specific fields
+ masking_rules = {"user.ssn": {"custom_mask": "XXX-XX-XXXX"}, "user.address.zip": {"custom_mask": "00000"}}
+
+ # WHEN erase is called with masking rules
+ result = data_masker.erase(data, masking_rules=masking_rules)
+
+ # THEN only the specified fields should be masked
+ assert result == {
+ "user": {
+ "name": "John Doe", # unchanged
+ "ssn": "XXX-XX-XXXX", # masked
+ "address": {"street": "123 Main St", "zip": "00000"}, # unchanged # masked
+ },
+ }
+
+
+def test_erase_dictionary_with_masking_rules_with_list(data_masker):
+ # GIVEN a dictionary with nested sensitive data
+ data = {"user": {"name": ["leandro", "powertools"]}}
+
+ # AND masking rules for specific fields
+ masking_rules = {"user.name": {"custom_mask": "NO-NAME"}}
+
+ # WHEN erase is called with masking rules
+ result = data_masker.erase(data, masking_rules=masking_rules)
+
+ # THEN only the specified fields should be masked
+ assert result == {
+ "user": {
+ "name": "NO-NAME",
+ },
+ }
+
+
+def test_erase_list_with_custom_mask(data_masker):
+ # GIVEN a dictionary with nested sensitive data
+ data = {"user": {"name": ["leandro", "powertools"]}}
+
+ # WHEN erase is called with masking rules
+ result = data_masker.erase(data, fields=["user.name"], dynamic_mask=True)
+
+ # THEN only the specified fields should be masked
+ assert result == {
+ "user": {
+ "name": ["*******", "**********"],
+ },
+ }
+
+
+def test_erase_dictionary_with_global_mask(data_masker):
+ # GIVEN a dictionary with sensitive data
+ data = {"user": {"name": "John Doe", "ssn": "123-45-6789"}}
+
+ # WHEN erase is called with a custom mask for all fields
+ result = data_masker.erase(data, custom_mask="REDACTED")
+
+ # THEN all fields should use the custom mask
+ assert result == {"user": {"name": "REDACTED", "ssn": "REDACTED"}}
+
+
+def test_erase_empty_dictionary(data_masker):
+ # GIVEN an empty dictionary
+ data = {}
+
+ # WHEN erase is called
+ result = data_masker.erase(data, custom_mask="MASKED")
+
+ # THEN an empty dictionary should be returned
+ assert result == {}
+
+
+def test_erase_different_iterables_with_masking(data_masker):
+ # GIVEN different types of iterables
+ list_data = ["name", "phone", "email"]
+ tuple_data = ("name", "phone", "email")
+ set_data = {"name", "phone", "email"}
+
+ # WHEN erase is called with a custom mask
+ masked_list = data_masker.erase(list_data, custom_mask="XXX")
+ masked_tuple = data_masker.erase(tuple_data, custom_mask="XXX")
+ masked_set = data_masker.erase(set_data, custom_mask="XXX")
+
+ # THEN the masked data should maintain its original type
+ assert isinstance(masked_list, list)
+ assert isinstance(masked_tuple, tuple)
+ assert isinstance(masked_set, set)
+
+ # AND all values should be masked
+ expected_values = {"XXX"}
+ assert set(masked_list) == expected_values
+ assert set(masked_tuple) == expected_values
+ assert masked_set == expected_values
+
+
+def test_erase_handles_invalid_regex_pattern(data_masker):
+ # GIVEN a string and an invalid regex pattern
+ data = "test123"
+
+ # WHEN masking with invalid regex
+ result = data_masker.erase(
+ data,
+ regex_pattern="[",
+ mask_format="X", # Invalid regex pattern that will raise re.error
+ )
+
+ # THEN original data should be returned
+ assert result == "test123"
+
+
+def test_erase_handles_empty_string_with_dynamic_mask(data_masker):
+ # GIVEN an empty string
+ data = ""
+
+ # WHEN erase is called with dynamic_mask
+ result = data_masker.erase(data, dynamic_mask=True)
+
+ # THEN empty string should be returned
+ assert result == ""
+
+
+def test_erase_dictionary_with_masking_rules_wrong_field(data_masker):
+ # GIVEN a dictionary with nested sensitive data
+ data = {"user": {"name": "John Doe", "ssn": "123-45-6789", "address": {"street": "123 Main St", "zip": "12345"}}}
+
+ # AND masking rules for specific fields
+ masking_rules = {"user.ssn...": {"custom_mask": "XXX-XX-XXXX"}, "user.address.zip": {"custom_mask": "00000"}}
+
+ # WHEN erase is called with wrong masking rules
+ # We must have a warning
+ with pytest.warns(expected_warning=PowertoolsUserWarning, match="Error processing path*"):
+ data_masker.erase(data, masking_rules=masking_rules)
diff --git a/tests/functional/event_handler/_pydantic/test_openapi_params.py b/tests/functional/event_handler/_pydantic/test_openapi_params.py
index a57156db130..0273c4b5712 100644
--- a/tests/functional/event_handler/_pydantic/test_openapi_params.py
+++ b/tests/functional/event_handler/_pydantic/test_openapi_params.py
@@ -1,6 +1,6 @@
from dataclasses import dataclass
from datetime import datetime
-from typing import List
+from typing import List, Tuple
from pydantic import BaseModel, Field
from typing_extensions import Annotated
@@ -172,6 +172,42 @@ def handler() -> Response[Annotated[str, Body(title="Response title")]]:
assert response.schema_.type == "string"
+def test_openapi_with_tuple_returns():
+ app = APIGatewayRestResolver()
+
+ @app.get("/")
+ def handler() -> Tuple[str, int]:
+ return "Hello, world", 200
+
+ schema = app.get_openapi_schema()
+ assert len(schema.paths.keys()) == 1
+
+ get = schema.paths["/"].get
+ assert get.parameters is None
+
+ response = get.responses[200].content[JSON_CONTENT_TYPE]
+ assert response.schema_.title == "Return"
+ assert response.schema_.type == "string"
+
+
+def test_openapi_with_tuple_annotated_returns():
+ app = APIGatewayRestResolver()
+
+ @app.get("/")
+ def handler() -> Tuple[Annotated[str, Body(title="Response title")], int]:
+ return "Hello, world", 200
+
+ schema = app.get_openapi_schema()
+ assert len(schema.paths.keys()) == 1
+
+ get = schema.paths["/"].get
+ assert get.parameters is None
+
+ response = get.responses[200].content[JSON_CONTENT_TYPE]
+ assert response.schema_.title == "Response title"
+ assert response.schema_.type == "string"
+
+
def test_openapi_with_omitted_param():
app = APIGatewayRestResolver()
diff --git a/tests/functional/logger/required_dependencies/test_logger.py b/tests/functional/logger/required_dependencies/test_logger.py
index 70f08f1bbdd..92c8e27ff4b 100644
--- a/tests/functional/logger/required_dependencies/test_logger.py
+++ b/tests/functional/logger/required_dependencies/test_logger.py
@@ -1217,3 +1217,72 @@ def remove_keys(self, keys: Iterable[str]) -> None:
# THEN the context keys should not persist
current_keys = logger.get_current_keys()
assert current_keys == {}
+
+
+def test_logger_change_level_child_logger(stdout, service_name):
+ # GIVEN a new Logger and child Logger
+ logger = Logger(service=service_name, stream=stdout)
+ child_logger = Logger(service=service_name, child=True, stream=stdout, level="DEBUG")
+
+ # WHEN we emit logs for both in DEBUG level
+ logger.debug("PARENT")
+ child_logger.debug("CHILD")
+
+ # THEN only child log must emit log due to level
+ logs = list(stdout.getvalue().strip().split("\n"))
+ assert len(logs) == 1
+ assert "service" in logs[0]
+
+
+def test_clear_state_with_append_keys():
+ # GIVEN a Logger is initialized
+ logger = Logger(service="service_name", stream=stdout)
+
+ # WHEN append keys are added
+ logger.append_keys(custom_key="custom_key")
+ logger.info("message with appended keys")
+ logger.clear_state()
+
+ # THEN context keys should be cleared
+ assert "custom_key" not in logger.get_current_keys()
+
+
+def test_clear_state(stdout, service_name):
+ # GIVEN a Logger is initialized
+ logger = Logger(service=service_name, stream=stdout)
+ logger.info("message for the user")
+
+ # WHEN the clear_state method is called
+ logger.clear_state()
+
+ # THEN the logger's current keys should be reset to their default values
+ expected_keys = {
+ "level": "%(levelname)s",
+ "location": "%(funcName)s:%(lineno)d",
+ "message": None,
+ "timestamp": "%(asctime)s",
+ "service": service_name,
+ "sampling_rate": None,
+ }
+ assert logger.get_current_keys() == expected_keys
+
+
+def test_clear_state_log_output(stdout, service_name):
+ # GIVEN a Logger is initialized
+ logger = Logger(service=service_name, stream=stdout)
+
+ # WHEN we append a custom key and log
+ logger.append_keys(custom_key="test_value")
+ logger.info("first message")
+
+ # AND we clear the state and log again
+ logger.clear_state()
+ logger.info("second message")
+
+ # THEN the first log should contain the custom key
+ # AND the second log should not contain the custom key
+ first_log, second_log = capture_multiple_logging_statements_output(stdout)
+
+ assert "custom_key" in first_log
+ assert first_log["custom_key"] == "test_value"
+ assert "custom_key" not in second_log
diff --git a/tests/functional/metrics/datadog/test_metrics_datadog.py b/tests/functional/metrics/datadog/test_metrics_datadog.py
index 2626b8755c6..631518287a0 100644
--- a/tests/functional/metrics/datadog/test_metrics_datadog.py
+++ b/tests/functional/metrics/datadog/test_metrics_datadog.py
@@ -334,3 +334,163 @@ def test_namespace_env_var(monkeypatch):
# THEN namespace should match the explicitly passed variable and not the env var
assert output[0]["m"] == f"{env_namespace}.item_sold"
+
+
+def test_metrics_disabled_with_env_var(monkeypatch, capsys):
+ # GIVEN environment variable is set to disable metrics
+ monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "true")
+
+ # WHEN metrics is initialized and adding metrics
+ metrics = DatadogMetrics()
+ metrics.add_metric(name="test_metric", value=1)
+ metrics.flush_metrics()
+
+ # THEN no metrics should have been recorded
+ captured = capsys.readouterr()
+ assert not captured.out
+
+
+def test_metrics_disabled_persists_after_flush(monkeypatch, capsys):
+ # GIVEN environment variable is set to disable metrics
+ monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "true")
+ metrics = DatadogMetrics()
+
+ # WHEN multiple operations are performed with flush in between
+ metrics.add_metric(name="metric1", value=1)
+ metrics.flush_metrics()
+
+ # THEN first flush should not emit any metrics
+ captured = capsys.readouterr()
+ assert not captured.out
+
+ # WHEN adding and flushing more metrics
+ metrics.add_metric(name="metric2", value=2)
+ metrics.flush_metrics()
+
+ # THEN second flush should also not emit any metrics
+ captured = capsys.readouterr()
+ assert not captured.out
+
+
+def test_metrics_disabled_with_namespace(monkeypatch, capsys):
+ # GIVEN environment variable is set to disable metrics
+ monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "true")
+
+ # WHEN metrics is initialized with namespace and service
+ metrics = DatadogMetrics(namespace="test_namespace")
+ metrics.add_metric(name="test_metric", value=1)
+ metrics.flush_metrics()
+
+ # THEN no metrics should have been recorded
+ captured = capsys.readouterr()
+ assert not captured.out
+
+
+def test_metrics_disabled_with_dev_mode_true(monkeypatch, capsys):
+ # GIVEN dev mode is enabled
+ monkeypatch.setenv("POWERTOOLS_DEV", "true")
+
+ # WHEN metrics is initialized
+ metrics = DatadogMetrics(namespace="test")
+ metrics.add_metric(name="test_metric", value=1)
+ metrics.flush_metrics()
+
+ # THEN no metrics should have been recorded
+ captured = capsys.readouterr()
+ assert not captured.out
+
+
+def test_metrics_enabled_with_env_var_false(monkeypatch, capsys):
+ # GIVEN environment variable is set to enable metrics
+ monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "false")
+
+ # WHEN metrics is initialized with namespace and metrics added
+ metrics = DatadogMetrics(namespace="test")
+ metrics.add_metric(name="test_metric", value=1)
+ metrics.flush_metrics()
+
+ # THEN Datadog metrics should be written to stdout
+ output = capsys.readouterr().out
+ metrics_output = json.loads(output)
+
+ assert metrics_output
+
+
+def test_metrics_enabled_with_env_var_not_set(monkeypatch, capsys):
+ # GIVEN environment variable is not set
+ monkeypatch.delenv("POWERTOOLS_METRICS_DISABLED", raising=False)
+
+ # WHEN metrics is initialized with namespace and metrics added
+ metrics = DatadogMetrics(namespace="test")
+ metrics.add_metric(name="test_metric", value=1)
+ metrics.flush_metrics()
+
+ # THEN metrics should be written to stdout
+ output = capsys.readouterr().out
+ metrics_output = json.loads(output)
+
+ assert "test.test_metric" in metrics_output["m"]
+
+
+def test_metrics_enabled_with_dev_mode_false(monkeypatch, capsys):
+ # GIVEN dev mode is disabled
+ monkeypatch.setenv("POWERTOOLS_DEV", "false")
+
+ # WHEN metrics is initialized
+ metrics = DatadogMetrics(namespace="test")
+ metrics.add_metric(name="test_metric", value=1)
+ metrics.flush_metrics()
+
+ # THEN metrics should be written to stdout
+ output = capsys.readouterr().out
+ metrics_output = json.loads(output)
+ assert metrics_output
+
+
+def test_metrics_disabled_dev_mode_overrides_metrics_disabled(monkeypatch, capsys):
+ # GIVEN dev mode is enabled but metrics disabled is false
+ monkeypatch.setenv("POWERTOOLS_DEV", "true")
+ monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "false")
+
+ # WHEN metrics is initialized
+ metrics = DatadogMetrics(namespace="test")
+ metrics.add_metric(name="test_metric", value=1)
+ metrics.flush_metrics()
+
+ # THEN metrics should be written to stdout since POWERTOOLS_METRICS_DISABLED is false
+ output = capsys.readouterr().out
+ assert output # First verify we have output
+ metrics_output = json.loads(output)
+ assert metrics_output # Then verify it's valid JSON
+ assert "test.test_metric" in metrics_output["m"] # Verify the metric is present
+
+
+def test_metrics_enabled_with_both_false(monkeypatch, capsys):
+ # GIVEN both dev mode and metrics disabled are false
+ monkeypatch.setenv("POWERTOOLS_DEV", "false")
+ monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "false")
+
+ # WHEN metrics is initialized
+ metrics = DatadogMetrics(namespace="test")
+ metrics.add_metric(name="test_metric", value=1)
+ metrics.flush_metrics()
+
+ # THEN metrics should be written to stdout
+ output = capsys.readouterr().out
+ metrics_output = json.loads(output)
+ assert metrics_output
+
+
+def test_metrics_disabled_with_dev_mode_false_and_metrics_disabled_true(monkeypatch, capsys):
+ # GIVEN dev mode is false but metrics disabled is true
+ monkeypatch.setenv("POWERTOOLS_DEV", "false")
+ monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "true")
+
+ # WHEN metrics is initialized
+ metrics = DatadogMetrics(namespace="test")
+ metrics.add_metric(name="test_metric", value=1)
+ metrics.flush_metrics()
+
+ # THEN no metrics should have been recorded
+ captured = capsys.readouterr()
+ assert not captured.out
diff --git a/tests/functional/metrics/required_dependencies/test_metrics_cloudwatch_emf.py b/tests/functional/metrics/required_dependencies/test_metrics_cloudwatch_emf.py
index 5633d573a54..29418c42bcf 100644
--- a/tests/functional/metrics/required_dependencies/test_metrics_cloudwatch_emf.py
+++ b/tests/functional/metrics/required_dependencies/test_metrics_cloudwatch_emf.py
@@ -1329,3 +1329,160 @@ def lambda_handler(evt, ctx):
"This metric doesn't meet the requirements and will be skipped by Amazon CloudWatch. "
"Ensure the timestamp is within 14 days past or 2 hours future."
)
+
+
+def test_metrics_disabled_with_env_var(monkeypatch, namespace, capsys):
+ # GIVEN environment variable is set to disable metrics
+ monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "true")
+
+ # WHEN metrics is initialized and adding metrics
+ metrics = Metrics(namespace=namespace)
+ metrics.add_metric(name="test_metric", unit="Count", value=1)
+ metrics.flush_metrics()
+
+ # THEN no Powertools metrics should be sent to CloudWatch
+ output = capsys.readouterr()
+ assert not output.out
+
+
+def test_metrics_disabled_persists_after_flush(monkeypatch, capsys, namespace):
+ # GIVEN environment variable is set to disable metrics
+ monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "true")
+ metrics = Metrics(namespace=namespace)
+
+ # WHEN multiple operations are performed with flush in between
+ metrics.add_metric(name="metric1", unit="Count", value=1)
+ metrics.flush_metrics()
+
+ # THEN first flush should not emit any metrics
+ captured = capsys.readouterr()
+ assert not captured.out
+
+ # WHEN adding and flushing more metrics
+ metrics.add_metric(name="metric2", unit="Count", value=2)
+ metrics.flush_metrics()
+
+ # THEN second flush should also not emit any metrics
+ captured = capsys.readouterr()
+ assert not captured.out
+
+
+def test_metrics_disabled_with_namespace_and_service(monkeypatch, capsys):
+ # GIVEN environment variable is set to disable metrics
+ monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "true")
+
+ # WHEN metrics is initialized with namespace and service
+ metrics = Metrics(namespace="test_namespace", service="test_service")
+ metrics.add_metric(name="test_metric", unit="Count", value=1)
+ metrics.flush_metrics()
+
+ # THEN no metrics should have been recorded
+ captured = capsys.readouterr()
+ assert not captured.out
+
+
+def test_metrics_enabled_with_env_var_false(monkeypatch, capsys):
+ # GIVEN environment variable is set to enable metrics
+ monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "false")
+
+ # WHEN metrics is initialized with namespace and metrics added
+ metrics = Metrics(namespace="test")
+ metrics.add_metric(name="test_metric", unit="Count", value=1)
+ metrics.flush_metrics()
+
+ # THEN metrics should be written to stdout
+ output = capsys.readouterr().out
+ metrics_output = json.loads(output)
+
+ assert "test_metric" in metrics_output
+ assert metrics_output["test_metric"] == [1.0]
+ assert metrics_output["_aws"]["CloudWatchMetrics"][0]["Namespace"] == "test"
+ assert metrics_output["_aws"]["CloudWatchMetrics"][0]["Metrics"][0]["Name"] == "test_metric"
+
+
+def test_metrics_enabled_with_env_var_not_set(monkeypatch, capsys):
+ # GIVEN environment variable is not set
+ monkeypatch.delenv("POWERTOOLS_METRICS_DISABLED", raising=False)
+
+ # WHEN metrics is initialized with namespace and metrics added
+ metrics = Metrics(namespace="test")
+ metrics.add_metric(name="test_metric", unit="Count", value=1)
+ metrics.flush_metrics()
+
+ # THEN metrics should be written to stdout
+ output = capsys.readouterr().out
+ metrics_output = json.loads(output)
+
+ assert "test_metric" in metrics_output
+ assert metrics_output["test_metric"] == [1.0]
+ assert metrics_output["_aws"]["CloudWatchMetrics"][0]["Namespace"] == "test"
+ assert metrics_output["_aws"]["CloudWatchMetrics"][0]["Metrics"][0]["Name"] == "test_metric"
+
+
+def test_metrics_disabled_with_dev_mode(monkeypatch, namespace, capsys):
+ # GIVEN environment variable is set to disable metrics
+ monkeypatch.setenv("POWERTOOLS_DEV", "true")
+
+ # WHEN metrics is initialized and adding metrics
+ metrics = Metrics(namespace=namespace)
+ metrics.add_metric(name="test_metric", unit="Count", value=1)
+
+ # AND flushing metrics
+ metrics.flush_metrics()
+
+ # THEN no metrics should have been recorded
+ captured = capsys.readouterr()
+ assert not captured.out
+
+
+def test_metrics_enabled_with_dev_mode_false(monkeypatch, capsys):
+ # GIVEN environment variable is set to enable metrics
+ monkeypatch.setenv("POWERTOOLS_DEV", "false")
+
+ # WHEN metrics is initialized with namespace and metrics added
+ metrics = Metrics(namespace="test")
+ metrics.add_metric(name="test_metric", unit="Count", value=1)
+ metrics.flush_metrics()
+
+ # THEN metrics should be written to stdout
+ output = capsys.readouterr().out
+ metrics_output = json.loads(output)
+
+ assert "test_metric" in metrics_output
+ assert metrics_output["test_metric"] == [1.0]
+ assert metrics_output["_aws"]["CloudWatchMetrics"][0]["Namespace"] == "test"
+ assert metrics_output["_aws"]["CloudWatchMetrics"][0]["Metrics"][0]["Name"] == "test_metric"
+
+
+def test_metrics_dev_mode_does_not_override_metrics_disabled(monkeypatch, capsys):
+ # GIVEN dev mode is enabled but metrics disabled is explicitly false
+ monkeypatch.setenv("POWERTOOLS_DEV", "true")
+ monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "false")
+
+ # WHEN metrics is initialized
+ metrics = Metrics(namespace="test")
+ metrics.add_metric(name="test_metric", value=1, unit="Count")
+ metrics.flush_metrics()
+
+ # THEN metrics should be written to stdout since POWERTOOLS_METRICS_DISABLED is false
+ output = capsys.readouterr().out
+ assert output # First verify we have output
+ metrics_output = json.loads(output)
+ assert metrics_output
+ assert "_aws" in metrics_output
+ assert any(metric["Name"] == "test_metric" for metric in metrics_output["_aws"]["CloudWatchMetrics"][0]["Metrics"])
+
+
+def test_metrics_disabled_with_dev_mode_false_and_metrics_disabled_true(monkeypatch, capsys):
+ # GIVEN dev mode is false but metrics disabled is true
+ monkeypatch.setenv("POWERTOOLS_DEV", "false")
+ monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "true")
+
+ # WHEN metrics is initialized
+ metrics = Metrics(namespace="test")
+ metrics.add_metric(name="test_metric", value=1, unit="Count")
+ metrics.flush_metrics()
+
+ # THEN no metrics should have been recorded
+ captured = capsys.readouterr()
+ assert not captured.out
diff --git a/tests/unit/data_classes/required_dependencies/test_api_gateway_authorizer_websocket_event.py b/tests/unit/data_classes/required_dependencies/test_api_gateway_authorizer_websocket_event.py
new file mode 100644
index 00000000000..d1f0d10735b
--- /dev/null
+++ b/tests/unit/data_classes/required_dependencies/test_api_gateway_authorizer_websocket_event.py
@@ -0,0 +1,181 @@
+import pytest
+
+from aws_lambda_powertools.utilities.data_classes.api_gateway_authorizer_event import (
+ DENY_ALL_RESPONSE,
+ APIGatewayAuthorizerResponseWebSocket,
+)
+
+
+@pytest.fixture
+def builder():
+ return APIGatewayAuthorizerResponseWebSocket("foo", "us-west-1", "123456789", "fantom", "dev")
+
+
+def test_authorizer_response_no_statement(builder: APIGatewayAuthorizerResponseWebSocket):
+ # GIVEN a builder with no statements
+ with pytest.raises(ValueError) as ex:
+ # WHEN calling build
+ builder.asdict()
+
+ # THEN raise a name error for not statements
+ assert str(ex.value) == "No statements defined for the policy"
+
+
+def test_authorizer_response_allow_all_routes_with_context():
+ arn = "arn:aws:execute-api:us-west-1:123456789:fantom/dev/$connect"
+ builder = APIGatewayAuthorizerResponseWebSocket.from_route_arn(arn, principal_id="foo", context={"name": "Foo"})
+ builder.allow_all_routes()
+ assert builder.asdict() == {
+ "principalId": "foo",
+ "policyDocument": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Action": "execute-api:Invoke",
+ "Effect": "Allow",
+ "Resource": ["arn:aws:execute-api:us-west-1:123456789:fantom/dev/*"],
+ },
+ ],
+ },
+ "context": {"name": "Foo"},
+ }
+
+
+def test_authorizer_response_allow_all_routes_with_usage_identifier_key():
+ arn = "arn:aws:execute-api:us-east-1:1111111111:api/dev/y"
+ builder = APIGatewayAuthorizerResponseWebSocket.from_route_arn(arn, principal_id="cow", usage_identifier_key="key")
+ builder.allow_all_routes()
+ assert builder.asdict() == {
+ "principalId": "cow",
+ "policyDocument": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Action": "execute-api:Invoke",
+ "Effect": "Allow",
+ "Resource": ["arn:aws:execute-api:us-east-1:1111111111:api/dev/*"],
+ },
+ ],
+ },
+ "usageIdentifierKey": "key",
+ }
+
+
+def test_authorizer_response_deny_all_routes(builder: APIGatewayAuthorizerResponseWebSocket):
+ builder.deny_all_routes()
+ assert builder.asdict() == {
+ "principalId": "foo",
+ "policyDocument": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Action": "execute-api:Invoke",
+ "Effect": "Deny",
+ "Resource": ["arn:aws:execute-api:us-west-1:123456789:fantom/dev/*"],
+ },
+ ],
+ },
+ }
+
+
+def test_authorizer_response_allow_route(builder: APIGatewayAuthorizerResponseWebSocket):
+ builder.allow_route(resource="/foo")
+ assert builder.asdict() == {
+ "policyDocument": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Action": "execute-api:Invoke",
+ "Effect": "Allow",
+ "Resource": ["arn:aws:execute-api:us-west-1:123456789:fantom/dev/foo"],
+ },
+ ],
+ },
+ "principalId": "foo",
+ }
+
+
+def test_authorizer_response_deny_route(builder: APIGatewayAuthorizerResponseWebSocket):
+ builder.deny_route(resource="foo")
+ assert builder.asdict() == {
+ "principalId": "foo",
+ "policyDocument": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Action": "execute-api:Invoke",
+ "Effect": "Deny",
+ "Resource": ["arn:aws:execute-api:us-west-1:123456789:fantom/dev/foo"],
+ },
+ ],
+ },
+ }
+
+
+def test_authorizer_response_allow_route_with_conditions(builder: APIGatewayAuthorizerResponseWebSocket):
+ condition = {"StringEquals": {"method.request.header.Content-Type": "text/html"}}
+ builder.allow_route(
+ resource="/foo",
+ conditions=[condition],
+ )
+ assert builder.asdict() == {
+ "principalId": "foo",
+ "policyDocument": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Action": "execute-api:Invoke",
+ "Effect": "Allow",
+ "Resource": ["arn:aws:execute-api:us-west-1:123456789:fantom/dev/foo"],
+ "Condition": [{"StringEquals": {"method.request.header.Content-Type": "text/html"}}],
+ },
+ ],
+ },
+ }
+
+
+def test_authorizer_response_deny_route_with_conditions(builder: APIGatewayAuthorizerResponseWebSocket):
+ condition = {"StringEquals": {"method.request.header.Content-Type": "application/json"}}
+ builder.deny_route(resource="/foo", conditions=[condition])
+ assert builder.asdict() == {
+ "principalId": "foo",
+ "policyDocument": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Action": "execute-api:Invoke",
+ "Effect": "Deny",
+ "Resource": ["arn:aws:execute-api:us-west-1:123456789:fantom/dev/foo"],
+ "Condition": [{"StringEquals": {"method.request.header.Content-Type": "application/json"}}],
+ },
+ ],
+ },
+ }
+
+
+def test_deny_all():
+ # CHECK we always explicitly deny all
+ statements = DENY_ALL_RESPONSE["policyDocument"]["Statement"]
+ assert len(statements) == 1
+ assert statements[0] == {
+ "Action": "execute-api:Invoke",
+ "Effect": "Deny",
+ "Resource": ["*"],
+ }
+
+
+def test_authorizer_response_allow_route_with_underscore(builder: APIGatewayAuthorizerResponseWebSocket):
+ builder.allow_route(resource="/has_underscore")
+ assert builder.asdict() == {
+ "principalId": "foo",
+ "policyDocument": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Action": "execute-api:Invoke",
+ "Effect": "Allow",
+ "Resource": ["arn:aws:execute-api:us-west-1:123456789:fantom/dev/has_underscore"],
+ },
+ ],
+ },
+ }
diff --git a/tests/unit/data_masking/_aws_encryption_sdk/test_unit_data_masking.py b/tests/unit/data_masking/_aws_encryption_sdk/test_unit_data_masking.py
deleted file mode 100644
index 4fbbc188ceb..00000000000
--- a/tests/unit/data_masking/_aws_encryption_sdk/test_unit_data_masking.py
+++ /dev/null
@@ -1,207 +0,0 @@
-import json
-
-import pytest
-
-from aws_lambda_powertools.utilities.data_masking.base import DataMasking
-from aws_lambda_powertools.utilities.data_masking.constants import DATA_MASKING_STRING
-from aws_lambda_powertools.utilities.data_masking.exceptions import (
- DataMaskingFieldNotFoundError,
- DataMaskingUnsupportedTypeError,
-)
-
-
-@pytest.fixture
-def data_masker() -> DataMasking:
- return DataMasking()
-
-
-def test_erase_int(data_masker):
- # GIVEN an int data type
-
- # WHEN erase is called with no fields argument
- erased_string = data_masker.erase(42)
-
- # THEN the result is the data masked
- assert erased_string == DATA_MASKING_STRING
-
-
-def test_erase_float(data_masker):
- # GIVEN a float data type
-
- # WHEN erase is called with no fields argument
- erased_string = data_masker.erase(4.2)
-
- # THEN the result is the data masked
- assert erased_string == DATA_MASKING_STRING
-
-
-def test_erase_bool(data_masker):
- # GIVEN a bool data type
-
- # WHEN erase is called with no fields argument
- erased_string = data_masker.erase(True)
-
- # THEN the result is the data masked
- assert erased_string == DATA_MASKING_STRING
-
-
-def test_erase_none(data_masker):
- # GIVEN a None data type
-
- # WHEN erase is called with no fields argument
- erased_string = data_masker.erase(None)
-
- # THEN the result is the data masked
- assert erased_string == DATA_MASKING_STRING
-
-
-def test_erase_str(data_masker):
- # GIVEN a str data type
-
- # WHEN erase is called with no fields argument
- erased_string = data_masker.erase("this is a string")
-
- # THEN the result is the data masked
- assert erased_string == DATA_MASKING_STRING
-
-
-def test_erase_list(data_masker):
- # GIVEN a list data type
-
- # WHEN erase is called with no fields argument
- erased_string = data_masker.erase([1, 2, "string", 3])
-
- # THEN the result is the data masked, while maintaining type list
- assert erased_string == [DATA_MASKING_STRING, DATA_MASKING_STRING, DATA_MASKING_STRING, DATA_MASKING_STRING]
-
-
-def test_erase_dict(data_masker):
- # GIVEN a dict data type
- data = {
- "a": {
- "1": {"None": "hello", "four": "world"},
- "b": {"3": {"4": "goodbye", "e": "world"}},
- },
- }
-
- # WHEN erase is called with no fields argument
- erased_string = data_masker.erase(data)
-
- # THEN the result is the data masked
- assert erased_string == DATA_MASKING_STRING
-
-
-def test_erase_dict_with_fields(data_masker):
- # GIVEN a dict data type
- data = {
- "a": {
- "1": {"None": "hello", "four": "world"},
- "b": {"3": {"4": "goodbye", "e": "world"}},
- },
- }
-
- # WHEN erase is called with a list of fields specified
- erased_string = data_masker.erase(data, fields=["a.'1'.None", "a..'4'"])
-
- # THEN the result is only the specified fields are erased
- assert erased_string == {
- "a": {
- "1": {"None": DATA_MASKING_STRING, "four": "world"},
- "b": {"3": {"4": DATA_MASKING_STRING, "e": "world"}},
- },
- }
-
-
-def test_erase_json_dict_with_fields(data_masker):
- # GIVEN the data type is a json representation of a dictionary
- data = json.dumps(
- {
- "a": {
- "1": {"None": "hello", "four": "world"},
- "b": {"3": {"4": "goodbye", "e": "world"}},
- },
- },
- )
-
- # WHEN erase is called with a list of fields specified
- masked_json_string = data_masker.erase(data, fields=["a.'1'.None", "a..'4'"])
-
- # THEN the result is only the specified fields are erased
- assert masked_json_string == {
- "a": {
- "1": {"None": DATA_MASKING_STRING, "four": "world"},
- "b": {"3": {"4": DATA_MASKING_STRING, "e": "world"}},
- },
- }
-
-
-def test_encrypt_not_implemented(data_masker):
- # GIVEN DataMasking is not initialized with a Provider
-
- # WHEN attempting to call the encrypt method on the data
- with pytest.raises(NotImplementedError):
- # THEN the result is a NotImplementedError
- data_masker.encrypt("hello world")
-
-
-def test_decrypt_not_implemented(data_masker):
- # GIVEN DataMasking is not initialized with a Provider
-
- # WHEN attempting to call the decrypt method on the data
- with pytest.raises(NotImplementedError):
- # THEN the result is a NotImplementedError
- data_masker.decrypt("hello world")
-
-
-def test_parsing_unsupported_data_type(data_masker):
- # GIVEN an initialization of the DataMasking class
-
- # WHEN attempting to pass in a list of fields with input data that is not a dict
- with pytest.raises(DataMaskingUnsupportedTypeError):
- # THEN the result is a TypeError
- data_masker.erase(42, ["this.field"])
-
-
-def test_parsing_with_empty_field(data_masker):
- # GIVEN an initialization of the DataMasking class
-
- # WHEN attempting to pass in a list of fields with input data that is not a dict
- with pytest.raises(ValueError):
- # THEN the result is a TypeError
- data_masker.erase(42, [])
-
-
-def test_parsing_nonexistent_fields_with_raise_on_missing_field():
- # GIVEN a dict data type
-
- data_masker = DataMasking(raise_on_missing_field=True)
- data = {
- "3": {
- "1": {"None": "hello", "four": "world"},
- "4": {"33": {"5": "goodbye", "e": "world"}},
- },
- }
-
- # WHEN attempting to pass in fields that do not exist in the input data
- with pytest.raises(DataMaskingFieldNotFoundError):
- # THEN the result is a KeyError
- data_masker.erase(data, ["'3'..True"])
-
-
-def test_parsing_nonexistent_fields_warning_on_missing_field():
- # GIVEN a dict data type
-
- data_masker = DataMasking(raise_on_missing_field=False)
- data = {
- "3": {
- "1": {"None": "hello", "four": "world"},
- "4": {"33": {"5": "goodbye", "e": "world"}},
- },
- }
-
- # WHEN erase is called with a non-existing field
- with pytest.warns(UserWarning, match="Field or expression*"):
- masked_json_string = data_masker.erase(data, fields=["non-existing"])
-
- # THEN the "erased" payload is the same of the original
- assert masked_json_string == data
diff --git a/tests/unit/data_masking/required_dependencies/test_base_functions.py b/tests/unit/data_masking/required_dependencies/test_base_functions.py
new file mode 100644
index 00000000000..1af532967c7
--- /dev/null
+++ b/tests/unit/data_masking/required_dependencies/test_base_functions.py
@@ -0,0 +1,30 @@
+import pytest
+
+from aws_lambda_powertools.utilities.data_masking.base import DataMasking
+
+
+@pytest.fixture
+def data_masker() -> DataMasking:
+ return DataMasking()
+
+
+def test_mask_nested_field_with_non_dict_value(data_masker):
+ # GIVEN nested data where a middle path component is not a dictionary
+ data = {"user": {"contact": "not_a_dict", "details": {"ssn": "123-45-6789"}}} # This will stop the traversal
+
+ # WHEN attempting to mask a field through a path containing a non-dict value
+ data_masker._mask_nested_field(data, "user.contact.details.ssn", lambda x: "MASKED")
+
+ # THEN the data should remain unchanged since traversal stopped at non-dict value
+ assert data == {"user": {"contact": "not_a_dict", "details": {"ssn": "123-45-6789"}}}
+
+
+def test_mask_nested_field_success(data_masker):
+ # GIVEN nested data with a field to mask
+ data = {"user": {"contact": {"details": {"address": {"street": "123 Main St", "zip": "12345"}}}}}
+
+ # WHEN masking a nested field with a masking rule
+ data_masker._mask_nested_field(data, "user.contact.details.address.zip", {"custom_mask": "xxx"})
+
+ # THEN the nested field should be masked while other data remains unchanged
+ assert data == {"user": {"contact": {"details": {"address": {"street": "123 Main St", "zip": "xxx"}}}}}