From da567138fab58e6eb9d39d845e7691ea8c6a22d7 Mon Sep 17 00:00:00 2001 From: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Date: Thu, 8 Jan 2026 10:19:16 +0100 Subject: [PATCH 001/337] docs(developer-guide): add missing compliance framework link (#9736) --- docs/developer-guide/introduction.mdx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/developer-guide/introduction.mdx b/docs/developer-guide/introduction.mdx index 9d1ea742b1..5377991fac 100644 --- a/docs/developer-guide/introduction.mdx +++ b/docs/developer-guide/introduction.mdx @@ -32,6 +32,9 @@ Prowler is constantly evolving. Contributions to checks, services, or integratio If you would like to extend Prowler to work with a new cloud provider, this typically involves setting up new services and checks to ensure compatibility. + + Need to ensure Prowler supports a specific compliance framework? Add new security compliance frameworks to map checks against regulatory or industry standards. + Want to tailor how results are displayed or exported? You can add custom output formats. @@ -213,4 +216,4 @@ pipx install "git+https://github.com/prowler-cloud/prowler.git@branch-name" Replace `branch-name` with the name of the branch you want to test. This will install Prowler in an isolated environment, allowing you to try out the changes safely. -For more details on testing go to the [Testing section](/developer-guide/unit-testing) of this documentation. \ No newline at end of file +For more details on testing go to the [Testing section](/developer-guide/unit-testing) of this documentation. From 8b2dea52fa4089a083c20a8e403268328f382d3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:52:42 +0100 Subject: [PATCH 002/337] build(deps): bump docker/setup-buildx-action from 3.11.1 to 3.12.0 (#9709) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-container-build-push.yml | 4 ++-- .github/workflows/api-container-checks.yml | 2 +- .github/workflows/mcp-container-build-push.yml | 4 ++-- .github/workflows/mcp-container-checks.yml | 2 +- .github/workflows/sdk-container-build-push.yml | 4 ++-- .github/workflows/sdk-container-checks.yml | 2 +- .github/workflows/ui-container-build-push.yml | 4 ++-- .github/workflows/ui-container-checks.yml | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/api-container-build-push.yml b/.github/workflows/api-container-build-push.yml index c6952c42a2..f91ad251b9 100644 --- a/.github/workflows/api-container-build-push.yml +++ b/.github/workflows/api-container-build-push.yml @@ -102,7 +102,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Build and push API container for ${{ matrix.arch }} id: container-push @@ -131,7 +131,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Create and push manifests for push event if: github.event_name == 'push' diff --git a/.github/workflows/api-container-checks.yml b/.github/workflows/api-container-checks.yml index b5905e5311..335555975b 100644 --- a/.github/workflows/api-container-checks.yml +++ b/.github/workflows/api-container-checks.yml @@ -77,7 +77,7 @@ jobs: - name: Set up Docker Buildx if: steps.check-changes.outputs.any_changed == 'true' - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Build container for ${{ matrix.arch }} if: steps.check-changes.outputs.any_changed == 'true' diff --git a/.github/workflows/mcp-container-build-push.yml b/.github/workflows/mcp-container-build-push.yml index 3821f226aa..30c9e2775c 100644 --- a/.github/workflows/mcp-container-build-push.yml +++ b/.github/workflows/mcp-container-build-push.yml @@ -100,7 +100,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Build and push MCP container for ${{ matrix.arch }} id: container-push @@ -137,7 +137,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Create and push manifests for push event if: github.event_name == 'push' diff --git a/.github/workflows/mcp-container-checks.yml b/.github/workflows/mcp-container-checks.yml index 35c4cc6ced..f15e63d401 100644 --- a/.github/workflows/mcp-container-checks.yml +++ b/.github/workflows/mcp-container-checks.yml @@ -75,7 +75,7 @@ jobs: - name: Set up Docker Buildx if: steps.check-changes.outputs.any_changed == 'true' - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Build MCP container for ${{ matrix.arch }} if: steps.check-changes.outputs.any_changed == 'true' diff --git a/.github/workflows/sdk-container-build-push.yml b/.github/workflows/sdk-container-build-push.yml index 22cca521b3..9f2f19bb8e 100644 --- a/.github/workflows/sdk-container-build-push.yml +++ b/.github/workflows/sdk-container-build-push.yml @@ -169,7 +169,7 @@ jobs: AWS_REGION: ${{ env.AWS_REGION }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Build and push SDK container for ${{ matrix.arch }} id: container-push @@ -208,7 +208,7 @@ jobs: AWS_REGION: ${{ env.AWS_REGION }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Create and push manifests for push event if: github.event_name == 'push' diff --git a/.github/workflows/sdk-container-checks.yml b/.github/workflows/sdk-container-checks.yml index 7b729ab148..e4f95a7836 100644 --- a/.github/workflows/sdk-container-checks.yml +++ b/.github/workflows/sdk-container-checks.yml @@ -89,7 +89,7 @@ jobs: - name: Set up Docker Buildx if: steps.check-changes.outputs.any_changed == 'true' - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Build SDK container for ${{ matrix.arch }} if: steps.check-changes.outputs.any_changed == 'true' diff --git a/.github/workflows/ui-container-build-push.yml b/.github/workflows/ui-container-build-push.yml index cfec354e89..c039418de7 100644 --- a/.github/workflows/ui-container-build-push.yml +++ b/.github/workflows/ui-container-build-push.yml @@ -104,7 +104,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Build and push UI container for ${{ matrix.arch }} id: container-push @@ -136,7 +136,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Create and push manifests for push event if: github.event_name == 'push' diff --git a/.github/workflows/ui-container-checks.yml b/.github/workflows/ui-container-checks.yml index ac41eaab81..2f19f89899 100644 --- a/.github/workflows/ui-container-checks.yml +++ b/.github/workflows/ui-container-checks.yml @@ -76,7 +76,7 @@ jobs: - name: Set up Docker Buildx if: steps.check-changes.outputs.any_changed == 'true' - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Build UI container for ${{ matrix.arch }} if: steps.check-changes.outputs.any_changed == 'true' From 64c9dd4947739a825386315566304da9ffca0c05 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:54:03 +0100 Subject: [PATCH 003/337] build(deps): bump docker/login-action from 3.4.0 to 3.6.0 (#9396) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-container-build-push.yml | 2 +- .github/workflows/mcp-container-build-push.yml | 2 +- .github/workflows/sdk-container-build-push.yml | 4 ++-- .github/workflows/ui-container-build-push.yml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/api-container-build-push.yml b/.github/workflows/api-container-build-push.yml index f91ad251b9..17693785f7 100644 --- a/.github/workflows/api-container-build-push.yml +++ b/.github/workflows/api-container-build-push.yml @@ -125,7 +125,7 @@ jobs: steps: - name: Login to DockerHub - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/mcp-container-build-push.yml b/.github/workflows/mcp-container-build-push.yml index 30c9e2775c..130ef90129 100644 --- a/.github/workflows/mcp-container-build-push.yml +++ b/.github/workflows/mcp-container-build-push.yml @@ -131,7 +131,7 @@ jobs: steps: - name: Login to DockerHub - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/sdk-container-build-push.yml b/.github/workflows/sdk-container-build-push.yml index 9f2f19bb8e..d510ec8568 100644 --- a/.github/workflows/sdk-container-build-push.yml +++ b/.github/workflows/sdk-container-build-push.yml @@ -193,13 +193,13 @@ jobs: steps: - name: Login to DockerHub - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to Public ECR - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 with: registry: public.ecr.aws username: ${{ secrets.PUBLIC_ECR_AWS_ACCESS_KEY_ID }} diff --git a/.github/workflows/ui-container-build-push.yml b/.github/workflows/ui-container-build-push.yml index c039418de7..6f8c232185 100644 --- a/.github/workflows/ui-container-build-push.yml +++ b/.github/workflows/ui-container-build-push.yml @@ -130,7 +130,7 @@ jobs: steps: - name: Login to DockerHub - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} From 319f5b6c3860bc24ab689bfddcf24a23b3951ad9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:54:40 +0100 Subject: [PATCH 004/337] build(deps): bump actions/cache from 4.3.0 to 5.0.1 (#9706) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ui-e2e-tests.yml | 4 ++-- .github/workflows/ui-tests.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ui-e2e-tests.yml b/.github/workflows/ui-e2e-tests.yml index db35056879..196f30891b 100644 --- a/.github/workflows/ui-e2e-tests.yml +++ b/.github/workflows/ui-e2e-tests.yml @@ -126,7 +126,7 @@ jobs: shell: bash run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - name: Setup pnpm cache - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 with: path: ${{ env.STORE_PATH }} key: ${{ runner.os }}-pnpm-store-${{ hashFiles('ui/pnpm-lock.yaml') }} @@ -139,7 +139,7 @@ jobs: working-directory: ./ui run: pnpm run build - name: Cache Playwright browsers - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 id: playwright-cache with: path: ~/.cache/ms-playwright diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 530b3e1212..b4ac0e88ce 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -63,7 +63,7 @@ jobs: - name: Setup pnpm cache if: steps.check-changes.outputs.any_changed == 'true' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 with: path: ${{ env.STORE_PATH }} key: ${{ runner.os }}-pnpm-store-${{ hashFiles('ui/pnpm-lock.yaml') }} From 5cd446c446ea16345e149a64da40548e8019e4e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:56:04 +0100 Subject: [PATCH 005/337] build(deps): bump codecov/codecov-action from 5.5.1 to 5.5.2 (#9708) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-tests.yml | 2 +- .github/workflows/sdk-tests.yml | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/api-tests.yml b/.github/workflows/api-tests.yml index e9b2cef4c5..dcf97fa18b 100644 --- a/.github/workflows/api-tests.yml +++ b/.github/workflows/api-tests.yml @@ -100,7 +100,7 @@ jobs: - name: Upload coverage reports to Codecov if: steps.check-changes.outputs.any_changed == 'true' - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: diff --git a/.github/workflows/sdk-tests.yml b/.github/workflows/sdk-tests.yml index bcc407d3bf..c86885214b 100644 --- a/.github/workflows/sdk-tests.yml +++ b/.github/workflows/sdk-tests.yml @@ -189,7 +189,7 @@ jobs: - name: Upload AWS coverage to Codecov if: steps.changed-aws.outputs.any_changed == 'true' - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: @@ -213,7 +213,7 @@ jobs: - name: Upload Azure coverage to Codecov if: steps.changed-azure.outputs.any_changed == 'true' - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: @@ -237,7 +237,7 @@ jobs: - name: Upload GCP coverage to Codecov if: steps.changed-gcp.outputs.any_changed == 'true' - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: @@ -261,7 +261,7 @@ jobs: - name: Upload Kubernetes coverage to Codecov if: steps.changed-kubernetes.outputs.any_changed == 'true' - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: @@ -285,7 +285,7 @@ jobs: - name: Upload GitHub coverage to Codecov if: steps.changed-github.outputs.any_changed == 'true' - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: @@ -309,7 +309,7 @@ jobs: - name: Upload NHN coverage to Codecov if: steps.changed-nhn.outputs.any_changed == 'true' - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: @@ -333,7 +333,7 @@ jobs: - name: Upload M365 coverage to Codecov if: steps.changed-m365.outputs.any_changed == 'true' - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: @@ -357,7 +357,7 @@ jobs: - name: Upload IaC coverage to Codecov if: steps.changed-iac.outputs.any_changed == 'true' - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: @@ -381,7 +381,7 @@ jobs: - name: Upload MongoDB Atlas coverage to Codecov if: steps.changed-mongodbatlas.outputs.any_changed == 'true' - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: @@ -405,7 +405,7 @@ jobs: - name: Upload OCI coverage to Codecov if: steps.changed-oraclecloud.outputs.any_changed == 'true' - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: @@ -429,7 +429,7 @@ jobs: - name: Upload Lib coverage to Codecov if: steps.changed-lib.outputs.any_changed == 'true' - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: @@ -453,7 +453,7 @@ jobs: - name: Upload Config coverage to Codecov if: steps.changed-config.outputs.any_changed == 'true' - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: From e9ca8bfda67f27aad3a78d569ed98b3fee502899 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:56:15 +0100 Subject: [PATCH 006/337] build(deps): bump trufflesecurity/trufflehog from 3.91.1 to 3.92.4 (#9710) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Pepe Fagoaga --- .github/workflows/find-secrets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/find-secrets.yml b/.github/workflows/find-secrets.yml index 4796630e11..c525d8faa4 100644 --- a/.github/workflows/find-secrets.yml +++ b/.github/workflows/find-secrets.yml @@ -28,6 +28,6 @@ jobs: fetch-depth: 0 - name: Scan for secrets with TruffleHog - uses: trufflesecurity/trufflehog@aade3bff5594fe8808578dd4db3dfeae9bf2abdc # v3.91.1 + uses: trufflesecurity/trufflehog@ef6e76c3c4023279497fab4721ffa071a722fd05 # v3.92.4 with: extra_args: '--results=verified,unknown' From 858446c740e72289e88e49ad98dbc0e7f2a5ac03 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 13:00:44 +0100 Subject: [PATCH 007/337] build(deps): bump actions/setup-node from 6.0.0 to 6.1.0 (#9707) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ui-e2e-tests.yml | 2 +- .github/workflows/ui-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ui-e2e-tests.yml b/.github/workflows/ui-e2e-tests.yml index 196f30891b..aa269af1ce 100644 --- a/.github/workflows/ui-e2e-tests.yml +++ b/.github/workflows/ui-e2e-tests.yml @@ -114,7 +114,7 @@ jobs: echo "All database fixtures loaded successfully!" ' - name: Setup Node.js environment - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version: '20.x' - name: Setup pnpm diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index b4ac0e88ce..0d2b55fbd3 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -45,7 +45,7 @@ jobs: - name: Setup Node.js ${{ env.NODE_VERSION }} if: steps.check-changes.outputs.any_changed == 'true' - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version: ${{ env.NODE_VERSION }} From 8d78831d2966165174a1530e9cd7404a97c15baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20De=20la=20Torre=20Vico?= Date: Thu, 8 Jan 2026 13:13:32 +0100 Subject: [PATCH 008/337] chore(aws): enhance metadata for `s3` service (#9552) Co-authored-by: Daniel Barranquero --- prowler/CHANGELOG.md | 1 + ...ss_point_public_access_block.metadata.json | 34 +++++++++------ ...t_level_public_access_blocks.metadata.json | 32 +++++++++------ .../s3_bucket_acl_prohibited.metadata.json | 32 +++++++++------ ..._bucket_cross_account_access.metadata.json | 34 +++++++++------ ...ket_cross_region_replication.metadata.json | 29 +++++++------ ...s3_bucket_default_encryption.metadata.json | 30 +++++++++----- ..._event_notifications_enabled.metadata.json | 34 +++++++++------ .../s3_bucket_kms_encryption.metadata.json | 32 +++++++++------ ...et_level_public_access_block.metadata.json | 41 +++++++++++-------- .../s3_bucket_lifecycle_enabled.metadata.json | 31 ++++++++------ .../s3_bucket_no_mfa_delete.metadata.json | 31 +++++++++----- .../s3_bucket_object_lock.metadata.json | 33 +++++++++------ .../s3_bucket_object_versioning.metadata.json | 32 +++++++++------ ...t_policy_public_write_access.metadata.json | 29 ++++++++----- .../s3_bucket_public_access.metadata.json | 29 ++++++++----- .../s3_bucket_public_list_acl.metadata.json | 29 ++++++++----- .../s3_bucket_public_write_acl.metadata.json | 28 ++++++++----- ...cket_secure_transport_policy.metadata.json | 28 ++++++++----- ...erver_access_logging_enabled.metadata.json | 29 ++++++++----- ...hadow_resource_vulnerability.metadata.json | 29 ++++++++----- ...ss_point_public_access_block.metadata.json | 33 +++++++++------ 22 files changed, 411 insertions(+), 249 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index c42eb0728e..711a17b046 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -37,6 +37,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Update AWS OpenSearch service metadata to new format [(#9383)](https://github.com/prowler-cloud/prowler/pull/9383) - Update AWS VPC service metadata to new format [(#9479)](https://github.com/prowler-cloud/prowler/pull/9479) - Update AWS Transfer service metadata to new format [(#9434)](https://github.com/prowler-cloud/prowler/pull/9434) +- Update AWS S3 service metadata to new format [(#9552)](https://github.com/prowler-cloud/prowler/pull/9552) --- diff --git a/prowler/providers/aws/services/s3/s3_access_point_public_access_block/s3_access_point_public_access_block.metadata.json b/prowler/providers/aws/services/s3/s3_access_point_public_access_block/s3_access_point_public_access_block.metadata.json index 4863f43409..f22c40c8f1 100644 --- a/prowler/providers/aws/services/s3/s3_access_point_public_access_block/s3_access_point_public_access_block.metadata.json +++ b/prowler/providers/aws/services/s3/s3_access_point_public_access_block/s3_access_point_public_access_block.metadata.json @@ -1,32 +1,42 @@ { "Provider": "aws", "CheckID": "s3_access_point_public_access_block", - "CheckTitle": "Block Public Access Settings enabled on Access Points.", + "CheckTitle": "S3 access point has all Block Public Access settings enabled", "CheckType": [ - "Data Protection" + "Software and Configuration Checks/AWS Security Best Practices/Network Reachability", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark", + "Effects/Data Exposure" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "critical", "ResourceType": "AwsS3AccessPoint", "ResourceGroup": "storage", - "Description": "Ensures that public access is blocked on S3 Access Points.", - "Risk": "Leaving S3 access points open to the public in AWS can lead to data exposure, breaches, compliance violations, unauthorized access, and data integrity issues.", - "RelatedUrl": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-points.html#access-points-policies", + "Description": "**Amazon S3 access points** have **Block Public Access** configured with all settings enabled: `block_public_acls`, `ignore_public_acls`, `block_public_policy`, and `restrict_public_buckets`.\n\nThe evaluation inspects each access point's public access block configuration.", + "Risk": "Without block public access on an access point, ACLs or policies can expose objects publicly despite intended restrictions. This enables unauthorized reads (**confidentiality** loss), writes or deletions (**integrity/availability** impact), and supports bulk data exfiltration or destructive actions.", + "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/config/latest/developerguide/s3-access-point-public-access-blocks.html", + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-points.html#access-points-policies", + "https://docs.aws.amazon.com/securityhub/latest/userguide/s3-controls.html#s3-19" + ], "Remediation": { "Code": { "CLI": "", - "NativeIaC": "", - "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/s3-controls.html#s3-19", - "Terraform": "" + "NativeIaC": "```yaml\n# CloudFormation: S3 Access Point with all Block Public Access settings enabled\nResources:\n :\n Type: AWS::S3::AccessPoint\n Properties:\n Bucket: \n PublicAccessBlockConfiguration:\n BlockPublicAcls: true # Critical: block public ACLs\n IgnorePublicAcls: true # Critical: ignore any public ACLs\n BlockPublicPolicy: true # Critical: block public policies\n RestrictPublicBuckets: true # Critical: restrict public buckets\n```", + "Other": "1. In the AWS console, go to S3 > Access points\n2. Select the noncompliant access point and click Delete access point\n3. Click Create access point, select the same bucket\n4. Ensure Block public access is enabled (all options On by default)\n5. Click Create access point", + "Terraform": "```hcl\n# Terraform: S3 Access Point with all Block Public Access settings enabled\nresource \"aws_s3_access_point\" \"\" {\n name = \"\"\n bucket = \"\"\n\n public_access_block_configuration {\n block_public_acls = true # Critical: block public ACLs\n ignore_public_acls = true # Critical: ignore any public ACLs\n block_public_policy = true # Critical: block public policies\n restrict_public_buckets = true # Critical: restrict public buckets\n }\n}\n```" }, "Recommendation": { - "Text": "Ensure S3 access points are private by default, applying strict access controls, and regularly auditing permissions to prevent unauthorized public access.", - "Url": "https://docs.aws.amazon.com/config/latest/developerguide/s3-access-point-public-access-blocks.html" + "Text": "Enable all access-point Block Public Access settings (`block_public_acls`, `ignore_public_acls`, `block_public_policy`, `restrict_public_buckets`).\n\nApply **least privilege**, prefer **VPC-only** access points, and layer account and bucket blocks for **defense in depth**. Regularly audit for public principals like `Principal: *`.", + "Url": "https://hub.prowler.com/check/s3_access_point_public_access_block" } }, - "Categories": [], + "Categories": [ + "internet-exposed" + ], "DependsOn": [], "RelatedTo": [], "Notes": "" diff --git a/prowler/providers/aws/services/s3/s3_account_level_public_access_blocks/s3_account_level_public_access_blocks.metadata.json b/prowler/providers/aws/services/s3/s3_account_level_public_access_blocks/s3_account_level_public_access_blocks.metadata.json index a2caeca720..d9caa2a338 100644 --- a/prowler/providers/aws/services/s3/s3_account_level_public_access_blocks/s3_account_level_public_access_blocks.metadata.json +++ b/prowler/providers/aws/services/s3/s3_account_level_public_access_blocks/s3_account_level_public_access_blocks.metadata.json @@ -1,32 +1,40 @@ { "Provider": "aws", "CheckID": "s3_account_level_public_access_blocks", - "CheckTitle": "Check S3 Account Level Public Access Block.", + "CheckTitle": "S3 account-level Block Public Access ignores public ACLs and restricts public buckets", "CheckType": [ - "Data Protection" + "Software and Configuration Checks/AWS Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark", + "Effects/Data Exposure" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "high", "ResourceType": "AwsS3AccountPublicAccessBlock", "ResourceGroup": "storage", - "Description": "Check S3 Account Level Public Access Block.", - "Risk": "Public access policies may be applied to sensitive data buckets.", + "Description": "**Amazon S3** account-level **Block Public Access** is assessed for `ignore_public_acls` and `restrict_public_buckets` to confirm centralized blocking of ACL-based public access and limiting buckets with public policies to in-account principals.", + "Risk": "Absent these settings, **public ACLs** and broad bucket policies may grant internet or cross-account access. This risks:\n- Confidentiality: bulk data exfiltration\n- Integrity: object overwrite/tampering\n- Availability: malicious deletions or malware hosting, triggering takedowns", "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html" + ], "Remediation": { "Code": { - "CLI": "aws s3control put-public-access-block --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true --account-id ", - "NativeIaC": "https://docs.prowler.com/checks/aws/s3-policies/bc_aws_s3_21#cloudformation", - "Other": "https://github.com/cloudmatos/matos/tree/master/remediations/aws/s3/s3control/block-public-access", - "Terraform": "https://docs.prowler.com/checks/aws/s3-policies/bc_aws_s3_21#terraform" + "CLI": "aws s3control put-public-access-block --account-id --public-access-block-configuration IgnorePublicAcls=true,RestrictPublicBuckets=true", + "NativeIaC": "```yaml\n# CloudFormation: Enable required S3 Account-level Block Public Access settings\nResources:\n :\n Type: AWS::S3::AccountPublicAccessBlock\n Properties:\n AccountId: !Ref AWS::AccountId\n IgnorePublicAcls: true # Critical: Ignores any public ACLs at the account level\n RestrictPublicBuckets: true # Critical: Restricts buckets with public policies to only same-account principals\n```", + "Other": "1. In the AWS Console, go to S3\n2. Click Block public access (account settings)\n3. Click Edit\n4. Turn on: Ignore public ACLs and Restrict public buckets\n5. Click Save changes", + "Terraform": "```hcl\n# Terraform: Enable required S3 Account-level Block Public Access settings\nresource \"aws_s3_account_public_access_block\" \"\" {\n ignore_public_acls = true # Critical: Ignores any public ACLs account-wide\n restrict_public_buckets = true # Critical: Restricts buckets with public policies to same-account principals\n}\n```" }, "Recommendation": { - "Text": "You can enable Public Access Block at the account level to prevent the exposure of your data stored in S3.", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html" + "Text": "Turn on account-level **Block Public Access** (prefer enabling all four: `block_public_acls`, `ignore_public_acls`, `block_public_policy`, `restrict_public_buckets`) to enforce least privilege. For legitimate access, use private buckets with **CloudFront**, VPC endpoints, or presigned URLs. Regularly review policies with IAM Access Analyzer.", + "Url": "https://hub.prowler.com/check/s3_account_level_public_access_blocks" } }, - "Categories": [], + "Categories": [ + "internet-exposed" + ], "DependsOn": [], "RelatedTo": [], "Notes": "" diff --git a/prowler/providers/aws/services/s3/s3_bucket_acl_prohibited/s3_bucket_acl_prohibited.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_acl_prohibited/s3_bucket_acl_prohibited.metadata.json index b33e90e09e..3d20a8d11d 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_acl_prohibited/s3_bucket_acl_prohibited.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_acl_prohibited/s3_bucket_acl_prohibited.metadata.json @@ -1,32 +1,40 @@ { "Provider": "aws", "CheckID": "s3_bucket_acl_prohibited", - "CheckTitle": "Check if S3 buckets have ACLs enabled", + "CheckTitle": "S3 bucket has bucket ACLs disabled", "CheckType": [ - "Logging and Monitoring" + "Software and Configuration Checks/AWS Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "medium", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Check if S3 buckets have ACLs enabled", - "Risk": "S3 ACLs are a legacy access control mechanism that predates IAM. IAM and bucket policies are currently the preferred methods.", + "Description": "**Amazon S3 buckets** are evaluated for **Object Ownership** set to `BucketOwnerEnforced`, which disables bucket and object ACLs. Buckets using any other ownership setting indicate that ACLs remain enabled.", + "Risk": "With **ACLs enabled**, access can bypass centralized policy controls, impacting confidentiality and integrity.\n- Unintended public or cross-account reads/writes\n- Object-writer ownership blocking bucket-owner governance\n- Per-object grants hinder auditing, enabling data exfiltration or tampering", "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html", + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/ensure-object-ownership.html" + ], "Remediation": { "Code": { - "CLI": "aws s3api put-bucket-ownership-controls --bucket --ownership-controls Rules=[{ObjectOwnership=BucketOwnerEnforced}]", - "NativeIaC": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-ownershipcontrols.html", - "Other": "", - "Terraform": "" + "CLI": "aws s3api put-bucket-ownership-controls --bucket --ownership-controls \"Rules=[{ObjectOwnership=BucketOwnerEnforced}]\"", + "NativeIaC": "```yaml\n# CloudFormation: Disable ACLs by enforcing bucket owner for all objects\nResources:\n OwnershipControls:\n Type: AWS::S3::BucketOwnershipControls\n Properties:\n Bucket: \n OwnershipControls:\n Rules:\n - ObjectOwnership: BucketOwnerEnforced # Critical: Disables ACLs and makes bucket owner the object owner\n```", + "Other": "1. In the AWS Console, go to S3 > Buckets and select the target bucket\n2. Open the Permissions tab\n3. In Object Ownership, click Edit\n4. Select Bucket owner enforced (ACLs disabled)\n5. Click Save changes", + "Terraform": "```hcl\n# Disable ACLs by enforcing bucket owner for all objects\nresource \"aws_s3_bucket_ownership_controls\" \"\" {\n bucket = \"\"\n rule {\n object_ownership = \"BucketOwnerEnforced\" # Critical: Disables ACLs and enforces bucket owner\n }\n}\n```" }, "Recommendation": { - "Text": "Ensure that S3 ACLs are disabled (BucketOwnerEnforced). Use IAM policies and bucket policies to manage access.", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html" + "Text": "Disable ACLs by setting **Object Ownership** to `BucketOwnerEnforced` and manage access with **IAM** and **bucket policies** under **least privilege**. Centralize authorization, review policies regularly, and use organizational guardrails to prevent re-enabling ACLs. *Migrate ACL-based grants into policies before the change.*", + "Url": "https://hub.prowler.com/check/s3_bucket_acl_prohibited" } }, - "Categories": [], + "Categories": [ + "identity-access" + ], "DependsOn": [], "RelatedTo": [], "Notes": "" diff --git a/prowler/providers/aws/services/s3/s3_bucket_cross_account_access/s3_bucket_cross_account_access.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_cross_account_access/s3_bucket_cross_account_access.metadata.json index c71b56abdf..c92912b2cd 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_cross_account_access/s3_bucket_cross_account_access.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_cross_account_access/s3_bucket_cross_account_access.metadata.json @@ -1,32 +1,42 @@ { "Provider": "aws", "CheckID": "s3_bucket_cross_account_access", - "CheckTitle": "Ensure that general-purpose bucket policies restrict access to other AWS accounts.", + "CheckTitle": "S3 bucket policy does not allow cross-account access", "CheckType": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "TTPs/Initial Access/Unauthorized Access", "Effects/Data Exposure" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "high", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "This check verifies that S3 bucket policies are configured in a way that limits access to the intended AWS accounts only, preventing unauthorized access by external or unintended accounts.", - "Risk": "Allowing other AWS accounts to perform sensitive actions (e.g., modifying bucket policies, ACLs, or encryption settings) on your S3 buckets can lead to data exposure, unauthorized access, or misconfigurations, increasing the risk of insider threats or attacks.", - "RelatedUrl": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html", + "Description": "**Amazon S3 bucket policies** are analyzed for statements that grant **cross-account access**.\n\nAny policy that names principals outside the owning account (other account IDs or `Principal: \"*\"`) is treated as cross-account; absence of a policy implies no cross-account grants.", + "Risk": "Cross-account grants can let external principals read, write, or administer the bucket, impacting:\n- Confidentiality: unauthorized object access/exfiltration\n- Integrity: object tampering, policy or encryption changes\n- Availability: deletions, versioning changes, or lockouts causing data loss and downtime", + "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/securityhub/latest/userguide/s3-controls.html#s3-6", + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html" + ], "Remediation": { "Code": { - "CLI": "", - "NativeIaC": "", - "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/s3-controls.html#s3-6", - "Terraform": "" + "CLI": "aws s3api delete-bucket-policy --bucket ", + "NativeIaC": "```yaml\n# CloudFormation: restrict bucket policy to this AWS account only\nResources:\n BucketPolicy:\n Type: AWS::S3::BucketPolicy\n Properties:\n Bucket: \n PolicyDocument:\n Version: '2012-10-17'\n Statement:\n - Effect: Allow\n Principal:\n AWS: !Sub arn:aws:iam::${AWS::AccountId}:root # Critical: limits access to the bucket owner's account, preventing cross-account access\n Action: s3:*\n Resource:\n - !Sub arn:aws:s3:::\n - !Sub arn:aws:s3:::/*\n```", + "Other": "1. In the AWS console, go to S3 > Buckets > select the bucket\n2. Open the Permissions tab > Bucket policy\n3. Click Delete bucket policy (or remove all statements) and Save\n4. If a policy is required, ensure all statements only use your account as Principal (arn:aws:iam:::root); remove any other accounts or \"*\"", + "Terraform": "```hcl\n# Terraform: restrict bucket policy to this AWS account only\nresource \"aws_s3_bucket_policy\" \"\" {\n bucket = \"\"\n policy = jsonencode({\n Version = \"2012-10-17\"\n Statement = [{\n Effect = \"Allow\"\n Principal = { AWS = \"arn:aws:iam:::root\" } # Critical: limits access to the bucket owner's account, preventing cross-account access\n Action = \"s3:*\"\n Resource = [\n \"arn:aws:s3:::\",\n \"arn:aws:s3:::/*\"\n ]\n }]\n })\n}\n```" }, "Recommendation": { - "Text": "Review and update your S3 bucket policies to remove permissions that grant external AWS accounts access to critical actions and implement least privilege principles to ensure sensitive operations are restricted to trusted accounts only", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html" + "Text": "Enforce **least privilege**: limit bucket policy `Principal` to your account or approved org IDs with fixed values; avoid wildcards.\n\nUse **role-based cross-account access** with scoped permissions when needed. Add **defense-in-depth** conditions (private networks, TLS), and periodically review for unintended external access.", + "Url": "https://hub.prowler.com/check/s3_bucket_cross_account_access" } }, - "Categories": [], + "Categories": [ + "identity-access", + "trust-boundaries" + ], "DependsOn": [], "RelatedTo": [], "Notes": "" diff --git a/prowler/providers/aws/services/s3/s3_bucket_cross_region_replication/s3_bucket_cross_region_replication.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_cross_region_replication/s3_bucket_cross_region_replication.metadata.json index a5cf1642b8..932ba8ed9c 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_cross_region_replication/s3_bucket_cross_region_replication.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_cross_region_replication/s3_bucket_cross_region_replication.metadata.json @@ -1,33 +1,38 @@ { "Provider": "aws", "CheckID": "s3_bucket_cross_region_replication", - "CheckTitle": "Check if S3 buckets use cross region replication.", + "CheckTitle": "S3 bucket has cross-region replication configured to a bucket in a different region", "CheckType": [ - "Secure access management" + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Destruction" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "low", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Verifying whether S3 buckets have cross-region replication enabled, ensuring data redundancy and availability across multiple AWS regions", - "Risk": "Without cross-region replication in S3 buckets, data is at risk of being lost or inaccessible if an entire region goes down, leading to potential service disruptions and data unavailability.", - "RelatedUrl": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/replication.html", + "Description": "**Amazon S3 buckets** use **cross-Region replication** with `versioning` and an enabled rule that targets a destination bucket in a different AWS Region.\n\nBuckets with same-Region targets, missing destinations, or disabled `versioning` don't meet this replication posture.", + "Risk": "**Single-Region storage** creates an availability gap: a Regional outage, control-plane isolation, or denial of service can make data **unreachable**.\n\nLack of replication raises RPO/RTO, delaying recovery and disrupting multi-Region workloads. Missing replicas also weaken data **integrity** during restore from corruption or deletion.", + "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/securityhub/latest/userguide/s3-controls.html#s3-7", + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/replication.html" + ], "Remediation": { "Code": { "CLI": "", - "NativeIaC": "", - "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/s3-controls.html#s3-7", - "Terraform": "https://docs.prowler.com/checks/aws/general-policies/ensure-that-s3-bucket-has-cross-region-replication-enabled#terraform" + "NativeIaC": "```yaml\n# CloudFormation: Enable versioning and CRR to a bucket in another region\nResources:\n ExampleBucket:\n Type: AWS::S3::Bucket\n Properties:\n VersioningConfiguration:\n Status: Enabled # critical: enables versioning (required for replication)\n ReplicationConfiguration: # critical: enables cross-Region replication\n Role: !GetAtt ReplicationRole.Arn\n Rules:\n - Status: Enabled # critical: replication rule must be enabled\n Destination:\n Bucket: arn:aws:s3::: # critical: destination bucket ARN in a different region\n\n ReplicationRole:\n Type: AWS::IAM::Role\n Properties:\n AssumeRolePolicyDocument:\n Version: '2012-10-17'\n Statement:\n - Effect: Allow\n Principal:\n Service: s3.amazonaws.com\n Action: sts:AssumeRole\n Policies:\n - PolicyName: s3-replication-minimal\n PolicyDocument:\n Version: '2012-10-17'\n Statement:\n - Effect: Allow\n Action:\n - s3:ListBucket\n - s3:GetReplicationConfiguration\n Resource: !Sub arn:aws:s3:::${ExampleBucket}\n - Effect: Allow\n Action:\n - s3:GetObjectVersionForReplication\n - s3:GetObjectVersionAcl\n - s3:GetObjectVersionTagging\n Resource: !Sub arn:aws:s3:::${ExampleBucket}/*\n - Effect: Allow\n Action:\n - s3:ReplicateObject\n - s3:ReplicateDelete\n - s3:ReplicateTags\n Resource: arn:aws:s3:::/*\n```", + "Other": "1. In the S3 console, open the source bucket\n2. Go to Properties > Bucket Versioning and click Enable\n3. Go to Management > Replication rules > Create replication rule\n4. Scope: Apply to all objects in the bucket\n5. Destination: Select a bucket in a different AWS Region\n6. Status: Ensure Enabled is selected\n7. IAM role: Choose Create new role (recommended)\n8. Save the rule", + "Terraform": "```hcl\n# Enable versioning and minimal CRR to a bucket in another region\nresource \"aws_s3_bucket\" \"source\" {\n bucket = \"\"\n\n versioning { \n enabled = true # critical: required for replication\n }\n\n replication_configuration { \n role = aws_iam_role.replication.arn # critical: role used by S3 to replicate\n\n rules {\n status = \"Enabled\" # critical: replication rule must be enabled\n destination {\n bucket = \"arn:aws:s3:::\" # critical: destination bucket ARN in a different region\n }\n }\n }\n}\n\nresource \"aws_iam_role\" \"replication\" {\n name = \"-s3-replication-role\"\n assume_role_policy = jsonencode({\n Version = \"2012-10-17\"\n Statement = [{\n Effect = \"Allow\"\n Principal = { Service = \"s3.amazonaws.com\" }\n Action = \"sts:AssumeRole\"\n }]\n })\n}\n\nresource \"aws_iam_role_policy\" \"replication\" {\n name = \"-s3-replication-policy\"\n role = aws_iam_role.replication.id\n policy = jsonencode({\n Version = \"2012-10-17\",\n Statement = [\n {\n Effect = \"Allow\",\n Action = [\"s3:ListBucket\", \"s3:GetReplicationConfiguration\"],\n Resource = \"arn:aws:s3:::${aws_s3_bucket.source.bucket}\"\n },\n {\n Effect = \"Allow\",\n Action = [\n \"s3:GetObjectVersionForReplication\",\n \"s3:GetObjectVersionAcl\",\n \"s3:GetObjectVersionTagging\"\n ],\n Resource = \"arn:aws:s3:::${aws_s3_bucket.source.bucket}/*\"\n },\n {\n Effect = \"Allow\",\n Action = [\"s3:ReplicateObject\", \"s3:ReplicateDelete\", \"s3:ReplicateTags\"],\n Resource = \"arn:aws:s3:::/*\"\n }\n ]\n })\n}\n```" }, "Recommendation": { - "Text": "Ensure that S3 buckets have cross region replication.", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/replication-walkthrough1.html" + "Text": "Enable **CRR** to a different Region with `versioning` and least-privilege roles.\n\n- Replicate needed prefixes and metadata\n- Consider `S3 Replication Time Control` for tighter RPO\n- Protect deletes via `delete marker` strategy and Object Lock\n- Monitor replication metrics and test DR regularly\n\nAlign with **defense in depth** and availability by design.", + "Url": "https://hub.prowler.com/check/s3_bucket_cross_region_replication" } }, "Categories": [ - "redundancy" + "resilience" ], "DependsOn": [], "RelatedTo": [], diff --git a/prowler/providers/aws/services/s3/s3_bucket_default_encryption/s3_bucket_default_encryption.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_default_encryption/s3_bucket_default_encryption.metadata.json index 569aa01dcc..eb0c07e8af 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_default_encryption/s3_bucket_default_encryption.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_default_encryption/s3_bucket_default_encryption.metadata.json @@ -1,29 +1,37 @@ { "Provider": "aws", "CheckID": "s3_bucket_default_encryption", - "CheckTitle": "Check if S3 buckets have default encryption (SSE) enabled or use a bucket policy to enforce it.", + "CheckTitle": "S3 bucket has default server-side encryption (SSE) enabled", "CheckType": [ - "Data Protection" + "Software and Configuration Checks/AWS Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark", + "Effects/Data Exposure" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "medium", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Check if S3 buckets have default encryption (SSE) enabled or use a bucket policy to enforce it.", - "Risk": "Amazon S3 default encryption provides a way to set the default encryption behavior for an S3 bucket. This will ensure data-at-rest is encrypted.", + "Description": "**Amazon S3 buckets** have a default **server-side encryption** setting that automatically encrypts new objects using `SSE-S3` or `SSE-KMS`. This evaluates whether a bucket has a default encryption configuration defined.", + "Risk": "Without default encryption, older objects may remain unencrypted and new uploads won't be forced to use `SSE-KMS`. This reduces confidentiality and governance by limiting key audit logs, rotation, and cross-account controls, and increases exposure if data is copied, replicated, or accessed outside intended paths.", "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.amazonaws.cn/en_us/AmazonS3/latest/userguide/bucket-encryption.html", + "https://aws.amazon.com/blogs/security/how-to-prevent-uploads-of-unencrypted-objects-to-amazon-s3/", + "https://docs.aws.amazon.com/us_en/AmazonS3/latest/userguide/default-encryption-faq.html" + ], "Remediation": { "Code": { - "CLI": "aws s3api put-bucket-encryption --bucket --server-side-encryption-configuration '{'Rules': [{'ApplyServerSideEncryptionByDefault': {'SSEAlgorithm': 'AES256'}}]}'", - "NativeIaC": "https://docs.prowler.com/checks/aws/s3-policies/s3_14-data-encrypted-at-rest#cloudformation", - "Other": "", - "Terraform": "https://docs.prowler.com/checks/aws/s3-policies/s3_14-data-encrypted-at-rest#terraform" + "CLI": "aws s3api put-bucket-encryption --bucket --server-side-encryption-configuration '{\"Rules\":[{\"ApplyServerSideEncryptionByDefault\":{\"SSEAlgorithm\":\"AES256\"}}]}'", + "NativeIaC": "```yaml\nResources:\n :\n Type: AWS::S3::Bucket\n Properties:\n BucketEncryption:\n ServerSideEncryptionConfiguration:\n - ServerSideEncryptionByDefault:\n SSEAlgorithm: AES256 # Critical: enables default SSE-S3 so new objects are encrypted\n```", + "Other": "1. Open the AWS S3 console and select the bucket\n2. Go to the Properties tab\n3. In Default encryption, click Edit\n4. Enable default encryption and select SSE-S3 (AES-256)\n5. Click Save changes", + "Terraform": "```hcl\nresource \"aws_s3_bucket\" \"\" {\n bucket = \"\"\n}\n\nresource \"aws_s3_bucket_server_side_encryption_configuration\" \"\" {\n bucket = aws_s3_bucket..id\n\n rule {\n apply_server_side_encryption_by_default {\n sse_algorithm = \"AES256\" # Critical: enables default SSE-S3 for the bucket\n }\n }\n}\n```" }, "Recommendation": { - "Text": "Ensure that S3 buckets have encryption at rest enabled.", - "Url": "https://aws.amazon.com/blogs/security/how-to-prevent-uploads-of-unencrypted-objects-to-amazon-s3/" + "Text": "Enable default encryption on all buckets, preferring `SSE-KMS` for sensitive data to retain key control and auditing. Enforce encryption with restrictive bucket policies, apply **least privilege** to KMS keys with rotation, and re-encrypt existing objects. Use **defense in depth** monitoring to detect drift and noncompliant uploads.", + "Url": "https://hub.prowler.com/check/s3_bucket_default_encryption" } }, "Categories": [ diff --git a/prowler/providers/aws/services/s3/s3_bucket_event_notifications_enabled/s3_bucket_event_notifications_enabled.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_event_notifications_enabled/s3_bucket_event_notifications_enabled.metadata.json index 5d67f3325b..eecbe4df3e 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_event_notifications_enabled/s3_bucket_event_notifications_enabled.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_event_notifications_enabled/s3_bucket_event_notifications_enabled.metadata.json @@ -1,32 +1,40 @@ { "Provider": "aws", "CheckID": "s3_bucket_event_notifications_enabled", - "CheckTitle": "Check if S3 buckets have event notifications enabled.", + "CheckTitle": "S3 bucket has event notifications enabled", "CheckType": [ + "Software and Configuration Checks/AWS Security Best Practices", "Software and Configuration Checks/Industry and Regulatory Standards/NIST 800-53 Controls" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", - "Severity": "medium", + "ResourceIdTemplate": "", + "Severity": "low", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Ensure whether S3 buckets have event notifications enabled.", - "Risk": "Without event notifications, important actions on S3 buckets may go unnoticed, leading to missed opportunities for timely response to critical changes, such as object creation, deletion, or updates that could impact data security and availability.", - "RelatedUrl": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/notification-how-to-event-types-and-destinations.html#supported-notification-event-types", + "Description": "**Amazon S3 buckets** define a **notification configuration** that publishes bucket events (for example `s3:ObjectCreated:*`, `s3:ObjectRemoved:*`) to a destination. The evaluation identifies buckets that lack any notification setup.", + "Risk": "Missing notifications leaves object and bucket changes **unseen**, weakening **integrity** and **availability** oversight. Undetected deletions, policy drift, or replication issues can stall data pipelines (S3 to Lambda/SQS), slow incident response, and allow tampering or exfiltration to persist longer.", + "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/securityhub/latest/userguide/s3-controls.html#s3-11", + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/enable-event-notifications.html", + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/EventNotifications.html" + ], "Remediation": { "Code": { - "CLI": "", - "NativeIaC": "", - "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/s3-controls.html#s3-11", - "Terraform": "" + "CLI": "aws s3api put-bucket-notification-configuration --bucket --notification-configuration '{\"EventBridgeConfiguration\": {}}'", + "NativeIaC": "```yaml\n# CloudFormation: Enable S3 event notifications via EventBridge\nResources:\n :\n Type: AWS::S3::Bucket\n Properties:\n NotificationConfiguration:\n EventBridgeConfiguration: {} # Critical: turns on EventBridge notifications, making notifications enabled\n```", + "Other": "1. Open the S3 console and select your bucket\n2. Go to the Properties tab\n3. In Event notifications, find Amazon EventBridge and turn it On (Enable)\n4. Click Save changes", + "Terraform": "```hcl\n# Enable S3 event notifications via EventBridge\nresource \"aws_s3_bucket_notification\" \"\" {\n bucket = \"\"\n\n eventbridge {} # Critical: enables EventBridge delivery, satisfying notifications enabled\n}\n```" }, "Recommendation": { - "Text": "Enable event notifications for all S3 general-purpose buckets to monitor important events such as object creation, deletion, tagging, and lifecycle events, ensuring visibility and quick action on relevant changes.", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/EventNotifications.html" + "Text": "Enable **S3 event notifications** for relevant events (e.g., `s3:ObjectCreated:*`, `s3:ObjectRemoved:*`) and route to controlled destinations (SNS, SQS, Lambda, EventBridge).\n\nUse prefix/suffix filters, avoid recursive triggers, and enforce **least privilege** on targets. Pair with object-level logging for **defense in depth**.", + "Url": "https://hub.prowler.com/check/s3_bucket_event_notifications_enabled" } }, - "Categories": [], + "Categories": [ + "logging" + ], "DependsOn": [], "RelatedTo": [], "Notes": "" diff --git a/prowler/providers/aws/services/s3/s3_bucket_kms_encryption/s3_bucket_kms_encryption.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_kms_encryption/s3_bucket_kms_encryption.metadata.json index d8741fc837..9c593ab704 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_kms_encryption/s3_bucket_kms_encryption.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_kms_encryption/s3_bucket_kms_encryption.metadata.json @@ -1,29 +1,37 @@ { "Provider": "aws", "CheckID": "s3_bucket_kms_encryption", - "CheckTitle": "Check if S3 buckets have KMS encryption enabled.", + "CheckTitle": "S3 bucket has server-side encryption with AWS KMS", "CheckType": [ - "Data Protection" + "Software and Configuration Checks/AWS Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark", + "Effects/Data Exposure" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "medium", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Check if S3 buckets have KMS encryption enabled.", - "Risk": "Amazon S3 KMS encryption provides a way to set the encryption behavior for an S3 bucket using a managed key. This will ensure data-at-rest is encrypted.", - "RelatedUrl": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html", + "Description": "**Amazon S3 buckets** use server-side encryption with **AWS KMS** keys, including dual-layer `aws:kms:dsse`. The evaluation identifies buckets whose default encryption is `aws:kms` or `aws:kms:dsse` rather than SSE-S3.", + "Risk": "Without **KMS-based encryption**, data relies only on SSE-S3, reducing **confidentiality** controls. Missing key policies and grants weakens **least privilege**, cross-account scoping, and the ability to disable or rotate keys. Lack of **KMS audit trails** obscures key usage, hindering detection of misuse and **defense in depth**.", + "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/default-bucket-encryption.html", + "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/aws/S3/encrypted-with-kms-customer-master-keys.html", + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html" + ], "Remediation": { "Code": { - "CLI": "aws put-bucket-encryption --bucket --server-side-encryption-configuration '{\"Rules\":[{\"ApplyServerSideEncryptionByDefault\":{\"SSEAlgorithm\":\"aws:kms\",\"KMSMasterKeyID\":\"arn:aws:kms:::key/\"}}]}'", - "NativeIaC": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/aws/S3/encrypted-with-kms-customer-master-keys.html", - "Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/aws/S3/encrypted-with-kms-customer-master-keys.html", - "Terraform": "https://docs.prowler.com/checks/aws/general-policies/ensure-that-s3-buckets-are-encrypted-with-kms-by-default#terraform" + "CLI": "aws s3api put-bucket-encryption --bucket --server-side-encryption-configuration '{\"Rules\":[{\"ApplyServerSideEncryptionByDefault\":{\"SSEAlgorithm\":\"aws:kms\"}}]}'", + "NativeIaC": "```yaml\n# CloudFormation: enable default SSE-KMS on the bucket\nResources:\n :\n Type: AWS::S3::Bucket\n Properties:\n BucketEncryption:\n ServerSideEncryptionConfiguration:\n - ServerSideEncryptionByDefault:\n SSEAlgorithm: aws:kms # Critical: sets default encryption to AWS KMS (SSE-KMS)\n```", + "Other": "1. In the AWS Console, go to S3 and open the target bucket\n2. Select the Properties tab\n3. Under Default encryption, click Edit\n4. Choose Server-side encryption with AWS KMS keys (SSE-KMS)\n5. Leave AWS managed key (aws/s3) selected (or choose your CMK if required)\n6. Click Save changes", + "Terraform": "```hcl\n# Enable default SSE-KMS on an existing S3 bucket\nresource \"aws_s3_bucket_server_side_encryption_configuration\" \"\" {\n bucket = \"\"\n\n rule {\n apply_server_side_encryption_by_default {\n sse_algorithm = \"aws:kms\" # Critical: enforces SSE-KMS by default\n }\n }\n}\n```" }, "Recommendation": { - "Text": "Ensure that S3 buckets have encryption at rest enabled using KMS.", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html" + "Text": "Enable default **SSE-KMS** (or **DSSE-KMS** for highly sensitive data). Use a customer-managed key, enforce **least privilege** and separation of duties for key usage, and require KMS encryption via bucket policy (specify `aws:kms` and a designated key). Monitor key activity in **CloudTrail** and consider **S3 Bucket Keys** to control cost.", + "Url": "https://hub.prowler.com/check/s3_bucket_kms_encryption" } }, "Categories": [ diff --git a/prowler/providers/aws/services/s3/s3_bucket_level_public_access_block/s3_bucket_level_public_access_block.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_level_public_access_block/s3_bucket_level_public_access_block.metadata.json index e5f014b637..20796001ab 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_level_public_access_block/s3_bucket_level_public_access_block.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_level_public_access_block/s3_bucket_level_public_access_block.metadata.json @@ -1,36 +1,41 @@ { "Provider": "aws", "CheckID": "s3_bucket_level_public_access_block", - "CheckTitle": "Check S3 Bucket Level Public Access Block.", + "CheckTitle": "S3 bucket has Block Public Access with IgnorePublicAcls and RestrictPublicBuckets enabled at bucket or account level", "CheckType": [ - "Data Protection" + "Software and Configuration Checks/AWS Security Best Practices/Network Reachability", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark", + "Effects/Data Exposure" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", - "Severity": "medium", + "ResourceIdTemplate": "", + "Severity": "high", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Check S3 Bucket Level Public Access Block.", - "Risk": "Public access policies may be applied to sensitive data buckets.", - "RelatedUrl": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html", + "Description": "**Amazon S3 buckets** are evaluated for **Block Public Access** settings, ensuring `ignore_public_acls` and `restrict_public_buckets` are enabled at the bucket or account scope.\n\n*Account-wide protections, when present, are treated as effective for the bucket.*", + "Risk": "Absent **S3 Block Public Access**, public ACLs or broad policies can grant Internet or cross-account access.\n- Data disclosure (confidentiality)\n- Object overwrite or uploads (integrity)\n- Deletion or outages from misuse (availability)", + "RelatedUrl": "", + "AdditionalURLs": [ + "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/S3/bucket-public-access-block.html", + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html" + ], "Remediation": { "Code": { - "CLI": "aws s3api put-public-access-block --region --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true --bucket ", - "NativeIaC": "", - "Other": "https://github.com/cloudmatos/matos/tree/master/remediations/aws/s3/s3/block-public-access", - "Terraform": "https://docs.prowler.com/checks/aws/s3-policies/bc_aws_s3_20#terraform" + "CLI": "aws s3api put-public-access-block --bucket --public-access-block-configuration IgnorePublicAcls=true,RestrictPublicBuckets=true", + "NativeIaC": "```yaml\n# CloudFormation - enable required S3 Block Public Access settings on a bucket\nResources:\n :\n Type: AWS::S3::Bucket\n Properties:\n PublicAccessBlockConfiguration:\n IgnorePublicAcls: true # CRITICAL: Ignore public ACLs on the bucket/objects\n RestrictPublicBuckets: true # CRITICAL: Restrict buckets with public policies to same-account/AWS services\n```", + "Other": "1. In AWS Console, open S3 and select the target bucket\n2. Go to Permissions > Block public access (bucket settings)\n3. Enable only:\n - Ignore public ACLs\n - Restrict public buckets\n4. Click Save changes\n5. (Alternatively, to apply account-wide) S3 > Account settings > Block Public Access: enable the same two options and Save", + "Terraform": "```hcl\n# Enable required S3 Block Public Access settings on a bucket\nresource \"aws_s3_bucket_public_access_block\" \"\" {\n bucket = \"\"\n ignore_public_acls = true # CRITICAL: Ignore public ACLs\n restrict_public_buckets = true # CRITICAL: Restrict public buckets\n}\n```" }, "Recommendation": { - "Text": "You can enable Public Access Block at the bucket level to prevent the exposure of your data stored in S3.", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html" + "Text": "Enable **Block Public Access** at account and bucket levels with `block_public_acls`, `ignore_public_acls`, `block_public_policy`, and `restrict_public_buckets` set to `true`. Apply **least privilege** and **defense in depth**. *If public access is required*, narrowly scope policies to fixed principals and conditions.", + "Url": "https://hub.prowler.com/check/s3_bucket_level_public_access_block" } }, - "Categories": [], - "Tags": { - "Tag1Key": "value", - "Tag2Key": "value" - }, + "Categories": [ + "internet-exposed" + ], "DependsOn": [], "RelatedTo": [], "Notes": "" diff --git a/prowler/providers/aws/services/s3/s3_bucket_lifecycle_enabled/s3_bucket_lifecycle_enabled.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_lifecycle_enabled/s3_bucket_lifecycle_enabled.metadata.json index f7b13296e3..855aed9511 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_lifecycle_enabled/s3_bucket_lifecycle_enabled.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_lifecycle_enabled/s3_bucket_lifecycle_enabled.metadata.json @@ -1,29 +1,36 @@ { "Provider": "aws", "CheckID": "s3_bucket_lifecycle_enabled", - "CheckTitle": "Check if S3 buckets have a Lifecycle configuration enabled", + "CheckTitle": "S3 bucket has a lifecycle configuration enabled", "CheckType": [ - "AWS Foundational Security Best Practices" + "Software and Configuration Checks/AWS Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "low", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Check if S3 buckets have Lifecycle configuration enabled.", - "Risk": "The risks of not having lifecycle management enabled for S3 buckets include higher storage costs, unmanaged data retention, and potential non-compliance with data policies.", - "RelatedUrl": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html", + "Description": "**Amazon S3 buckets** use **Lifecycle configurations** with at least one rule `Status: Enabled` to automate object `Transitions` and `Expiration` based on age, prefix, or tags", + "Risk": "Without lifecycle rules, objects persist indefinitely, driving costs and retaining sensitive data beyond policy. Unchecked log/version growth strains operations and recovery. Long-lived data increases exposure if the account is compromised and can break required deletion timelines, affecting confidentiality and availability.", + "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/securityhub/latest/userguide/s3-controls.html#s3-13", + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html", + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/how-to-set-lifecycle-configuration-intro.html", + "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/S3/lifecycle-configuration.html" + ], "Remediation": { "Code": { - "CLI": "", - "NativeIaC": "", - "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/s3-controls.html#s3-13", - "Terraform": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/S3/lifecycle-configuration.html" + "CLI": "aws s3api put-bucket-lifecycle-configuration --bucket --lifecycle-configuration '{\"Rules\":[{\"Status\":\"Enabled\",\"Filter\":{\"Prefix\":\"\"},\"AbortIncompleteMultipartUpload\":{\"DaysAfterInitiation\":7}}]}'", + "NativeIaC": "```yaml\n# CloudFormation: enable a minimal S3 Lifecycle configuration\nResources:\n :\n Type: AWS::S3::Bucket\n Properties:\n LifecycleConfiguration: # CRITICAL: Adds a Lifecycle configuration to the bucket\n Rules:\n - Status: Enabled # CRITICAL: Rule must be Enabled to pass the check\n Filter:\n Prefix: \"\" # Applies to all objects\n AbortIncompleteMultipartUpload:\n DaysAfterInitiation: 7 # Minimal action to satisfy schema\n```", + "Other": "1. In the AWS Console, go to S3 and open the target bucket\n2. Select the Management tab, then click Create lifecycle rule\n3. Enter a name and choose This rule applies to all objects in the bucket\n4. Under Lifecycle rule actions, select Clean up incomplete multipart uploads and set Days after initiation to 7\n5. Ensure Status is Enabled and click Create rule", + "Terraform": "```hcl\n# Minimal lifecycle configuration to mark the bucket as having an enabled rule\nresource \"aws_s3_bucket_lifecycle_configuration\" \"\" {\n bucket = \"\"\n\n rule {\n status = \"Enabled\" # CRITICAL: Enables lifecycle rule to pass the check\n filter {} # Applies to all objects\n\n abort_incomplete_multipart_upload {\n days_after_initiation = 7 # Minimal action to satisfy schema\n }\n }\n}\n```" }, "Recommendation": { - "Text": "Enable lifecycle policies on your S3 buckets to automatically manage the transition and expiration of data.", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/how-to-set-lifecycle-configuration-intro.html" + "Text": "Define **Lifecycle policies** by data classification: set `Expiration` to enforce retention, use `Transitions` to lower-cost classes, and enable `AbortIncompleteMultipartUpload`. For critical logs, keep versioning and, *if required*, **Object Lock**. Limit who can change lifecycle using least privilege and separation of duties.", + "Url": "https://hub.prowler.com/check/s3_bucket_lifecycle_enabled" } }, "Categories": [], diff --git a/prowler/providers/aws/services/s3/s3_bucket_no_mfa_delete/s3_bucket_no_mfa_delete.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_no_mfa_delete/s3_bucket_no_mfa_delete.metadata.json index 54d40697ca..1b08dc66ae 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_no_mfa_delete/s3_bucket_no_mfa_delete.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_no_mfa_delete/s3_bucket_no_mfa_delete.metadata.json @@ -1,32 +1,41 @@ { "Provider": "aws", "CheckID": "s3_bucket_no_mfa_delete", - "CheckTitle": "Check if S3 bucket MFA Delete is not enabled.", + "CheckTitle": "S3 bucket has MFA Delete enabled", "CheckType": [ - "Logging and Monitoring" + "Software and Configuration Checks/AWS Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark", + "Effects/Data Destruction" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "medium", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Check if S3 bucket MFA Delete is not enabled.", - "Risk": "Your security credentials are compromised or unauthorized access is granted.", + "Description": "**Amazon S3 buckets** are assessed for **MFA Delete** status. MFA Delete requires a second factor to permanently delete object versions or change `Versioning` configuration. The finding highlights buckets where this protection is not enabled.", + "Risk": "Without **MFA Delete**, a compromised or over-privileged identity can irrevocably purge object history or change versioning.\n\nThis erases recovery points, degrading data **availability**, weakening **integrity**, and increasing the blast radius of account compromise or ransomware.", "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/MultiFactorAuthenticationDelete.html", + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingMFADelete.html" + ], "Remediation": { "Code": { - "CLI": "aws s3api put-bucket-versioning --profile my-root-profile --bucket my-bucket-name --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa 'arn:aws:iam::00000000:mfa/root-account-mfa-device 123456'", + "CLI": "aws s3api put-bucket-versioning --bucket --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa \" \"", "NativeIaC": "", - "Other": "", - "Terraform": "https://docs.prowler.com/checks/aws/s3-policies/bc_aws_s3_24#terraform" + "Other": "1. Sign in to the AWS Management Console as the root user\n2. Open the account menu > Security credentials > Multi-factor authentication (MFA) and assign an MFA device; copy its ARN/serial\n3. From a machine configured to use the root user credentials, run:\n\n```bash\naws s3api put-bucket-versioning --bucket --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa \" \"\n```", + "Terraform": "" }, "Recommendation": { - "Text": "Adding MFA delete to an S3 bucket, requires additional authentication when you change the version state of your bucket or you delete and object version adding another layer of security in the event your security credentials are compromised or unauthorized access is granted.", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/MultiFactorAuthenticationDelete.html" + "Text": "Enable **MFA Delete** on sensitive, versioned buckets so permanent deletions and `Versioning` changes require a second factor. Apply **least privilege** to restrict version purge actions, enforce **change control**, and combine with **Object Lock** or immutable backups for defense in depth.", + "Url": "https://hub.prowler.com/check/s3_bucket_no_mfa_delete" } }, - "Categories": [], + "Categories": [ + "identity-access" + ], "DependsOn": [], "RelatedTo": [], "Notes": "" diff --git a/prowler/providers/aws/services/s3/s3_bucket_object_lock/s3_bucket_object_lock.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_object_lock/s3_bucket_object_lock.metadata.json index 54a639a61c..018902cb4c 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_object_lock/s3_bucket_object_lock.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_object_lock/s3_bucket_object_lock.metadata.json @@ -1,32 +1,41 @@ { "Provider": "aws", "CheckID": "s3_bucket_object_lock", - "CheckTitle": "Check if S3 buckets have object lock enabled", + "CheckTitle": "S3 bucket has Object Lock enabled", "CheckType": [ - "Data Protection" + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Destruction" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "low", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Check if S3 buckets have object lock enabled", - "Risk": "Store objects using a write-once-read-many (WORM) model to help you prevent objects from being deleted or overwritten for a fixed amount of time or indefinitely. That helps to prevent ransomware attacks.", + "Description": "**Amazon S3 buckets** have **Object Lock** enabled at the bucket level, applying WORM controls to object versions", + "Risk": "Without **Object Lock**, object versions can be deleted or overwritten, undermining data **integrity** and **availability**.\n\nThreats include ransomware erasing backups, insider or mistaken deletions, and tampering that defeats recovery. Inability to enforce retention or legal holds increases exposure to data loss and compliance gaps.", "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock-overview.html", + "https://aws.amazon.com/about-aws/whats-new/2018/11/s3-object-lock/", + "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/S3/object-lock.html", + "https://docs.aws.amazon.com/de_de/cli/latest/reference/s3api/put-object-lock-configuration.html" + ], "Remediation": { "Code": { - "CLI": "aws s3 put-object-lock-configuration --bucket --object-lock-configuration '{\"ObjectLockEnabled\":\"Enabled\",\"Rule\":{\"DefaultRetention\":{\"Mode\":\"GOVERNANCE\",\"Days\":1}}}'", - "NativeIaC": "", - "Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/S3/object-lock.html", - "Terraform": "https://docs.prowler.com/checks/aws/general-policies/ensure-that-s3-bucket-has-lock-configuration-enabled-by-default#terraform" + "CLI": "aws s3api put-object-lock-configuration --bucket --object-lock-configuration '{\"ObjectLockEnabled\":\"Enabled\",\"Rule\":{\"DefaultRetention\":{\"Mode\":\"GOVERNANCE\",\"Days\":1}}}'", + "NativeIaC": "```yaml\nResources:\n :\n Type: AWS::S3::Bucket\n Properties:\n ObjectLockEnabled: true # CRITICAL: Enables Object Lock on the bucket at creation\n ObjectLockConfiguration:\n ObjectLockEnabled: Enabled # CRITICAL: Turns on Object Lock configuration\n Rule:\n DefaultRetention:\n Mode: GOVERNANCE # CRITICAL: Sets default retention mode\n Days: 1 # CRITICAL: Minimal retention to enable default lock\n```", + "Other": "1. Open the AWS S3 console and select the target bucket\n2. Go to the Properties tab\n3. Find Object Lock and click Edit\n4. Enable Object Lock\n5. Set Default retention: Mode = Governance, Days = 1\n6. Click Save changes\n\nNote: If the bucket was not created with Object Lock, create a new bucket with Object Lock enabled and migrate objects.", + "Terraform": "```hcl\nresource \"aws_s3_bucket_object_lock_configuration\" \"\" {\n bucket = \"\"\n object_lock_enabled = \"Enabled\" # CRITICAL: Enables Object Lock configuration on the bucket\n rule {\n default_retention {\n mode = \"GOVERNANCE\" # CRITICAL: Default retention mode\n days = 1 # CRITICAL: Minimal retention period\n }\n }\n}\n```" }, "Recommendation": { - "Text": "Ensure that your Amazon S3 buckets have Object Lock feature enabled in order to prevent the objects they store from being deleted.", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock-overview.html" + "Text": "Enable **Object Lock** for critical data and set appropriate default retention in `GOVERNANCE` or `COMPLIANCE` mode.\n\nApply **immutability** and **least privilege** by restricting permissions that bypass retention, and use legal holds when you need indefinite protection for investigations or regulatory requirements.", + "Url": "https://hub.prowler.com/check/s3_bucket_object_lock" } }, - "Categories": [], + "Categories": [ + "resilience" + ], "DependsOn": [], "RelatedTo": [], "Notes": "" diff --git a/prowler/providers/aws/services/s3/s3_bucket_object_versioning/s3_bucket_object_versioning.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_object_versioning/s3_bucket_object_versioning.metadata.json index 5b8d9e5d56..0b5b42e789 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_object_versioning/s3_bucket_object_versioning.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_object_versioning/s3_bucket_object_versioning.metadata.json @@ -1,32 +1,40 @@ { "Provider": "aws", "CheckID": "s3_bucket_object_versioning", - "CheckTitle": "Check if S3 buckets have object versioning enabled", + "CheckTitle": "S3 bucket has object versioning enabled", "CheckType": [ - "Data Protection" + "Software and Configuration Checks/AWS Security Best Practices", + "Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "Industry and Regulatory Standards/CIS AWS Foundations Benchmark", + "Effects/Data Destruction" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "medium", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Check if S3 buckets have object versioning enabled", - "Risk": "With versioning, you can easily recover from both unintended user actions and application failures.", + "Description": "**Amazon S3 buckets** are evaluated for **object versioning** being `Enabled`, which maintains multiple versions of the same object key for historical state retention", + "Risk": "Without **versioning**, deletions and overwrites remove the only copy, undermining **availability** and **integrity**.\n- Compromised identities or buggy apps can mass-delete/corrupt data\n- No historical versions means limited rollback and irrecoverable loss", "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/AmazonS3/latest/dev-retired/Versioning.html" + ], "Remediation": { "Code": { - "CLI": "", - "NativeIaC": "", - "Other": "https://docs.prowler.com/checks/aws/s3-policies/s3_16-enable-versioning#aws-console", - "Terraform": "https://docs.prowler.com/checks/aws/s3-policies/s3_16-enable-versioning#terraform" + "CLI": "aws s3api put-bucket-versioning --bucket --versioning-configuration Status=Enabled", + "NativeIaC": "```yaml\n# CloudFormation: enable versioning on an S3 bucket\nResources:\n :\n Type: AWS::S3::Bucket\n Properties:\n VersioningConfiguration:\n Status: Enabled # Critical: turns on object versioning to pass the check\n```", + "Other": "1. In the AWS Console, go to S3 > Buckets and select the target bucket\n2. Open the Properties tab\n3. Find Bucket Versioning and click Edit\n4. Select Enable and click Save changes", + "Terraform": "```hcl\n# Enable versioning on an existing S3 bucket\nresource \"aws_s3_bucket_versioning\" \"\" {\n bucket = \"\"\n versioning_configuration {\n status = \"Enabled\" # Critical: enables bucket versioning to remediate the finding\n }\n}\n```" }, "Recommendation": { - "Text": "Configure versioning using the Amazon console or API for buckets with sensitive information that is changing frequently, and backup may not be enough to capture all the changes.", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/Versioning.html" + "Text": "Enable **S3 versioning** for buckets holding important or shared data.\n- Enforce **least privilege** to limit delete/overwrite\n- Use **Object Lock** and/or **MFA Delete** for stronger protection\n- Apply **lifecycle rules** to manage noncurrent versions and costs\n- Layer with backups/replication for **defense in depth**", + "Url": "https://hub.prowler.com/check/s3_bucket_object_versioning" } }, - "Categories": [], + "Categories": [ + "resilience" + ], "DependsOn": [], "RelatedTo": [], "Notes": "" diff --git a/prowler/providers/aws/services/s3/s3_bucket_policy_public_write_access/s3_bucket_policy_public_write_access.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_policy_public_write_access/s3_bucket_policy_public_write_access.metadata.json index 19a823ba64..784944d2d9 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_policy_public_write_access/s3_bucket_policy_public_write_access.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_policy_public_write_access/s3_bucket_policy_public_write_access.metadata.json @@ -1,29 +1,36 @@ { "Provider": "aws", "CheckID": "s3_bucket_policy_public_write_access", - "CheckTitle": "Check if S3 buckets have policies which allow WRITE access.", + "CheckTitle": "S3 bucket policy does not allow public write access", "CheckType": [ - "IAM" + "Software and Configuration Checks/AWS Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark", + "Effects/Data Destruction", + "TTPs/Initial Access" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "critical", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Check if S3 buckets have policies which allow WRITE access.", - "Risk": "Non intended users can put objects in a given bucket.", + "Description": "**Amazon S3 bucket policies** are evaluated for **public write permissions** (e.g., `s3:PutObject`, `s3:Delete*`, or `s3:*`). Account or bucket **Public Access Block** that restricts public buckets is considered when determining exposure.", + "Risk": "Public write access lets anyone upload, overwrite, or delete objects, undermining **integrity** and **availability**. Attackers can plant malware, stage phishing content, poison data, or wipe buckets, causing outages and potential legal and cost impacts from storage abuse and content hosting.", "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_s3_rw-bucket.html" + ], "Remediation": { "Code": { - "CLI": "", - "NativeIaC": "", - "Other": "https://docs.prowler.com/checks/aws/s3-policies/s3_18-write-permissions-public#aws-console", - "Terraform": "" + "CLI": "aws s3api put-public-access-block --bucket --public-access-block-configuration RestrictPublicBuckets=true", + "NativeIaC": "```yaml\n# CloudFormation: Enable bucket-level Public Access Block to prevent public policies from granting write\nResources:\n :\n Type: AWS::S3::Bucket\n Properties:\n PublicAccessBlockConfiguration:\n RestrictPublicBuckets: true # Critical: blocks public access granted by any public bucket policy\n```", + "Other": "1. Open the AWS S3 console and select the target bucket\n2. Go to the Permissions tab\n3. Under Block public access (bucket settings), click Edit\n4. Enable \"Block public and cross-account access to buckets and objects through any public bucket or access point policies\"\n5. Click Save changes", + "Terraform": "```hcl\n# Enable bucket-level Public Access Block so public bucket policies (including write) are blocked\nresource \"aws_s3_bucket_public_access_block\" \"\" {\n bucket = \"\"\n restrict_public_buckets = true # Critical: prevents public access granted via bucket policies\n}\n```" }, "Recommendation": { - "Text": "Ensure proper bucket policy is in place with the least privilege principle applied.", - "Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_s3_rw-bucket.html" + "Text": "Restrict writes to trusted principals using **least privilege**; avoid `Principal: \"*\"`. Enable **Public Access Block** at account and bucket levels for defense in depth. Prefer IAM roles over broad bucket policies, require private access paths, and enable versioning to recover from unwanted changes.", + "Url": "https://hub.prowler.com/check/s3_bucket_policy_public_write_access" } }, "Categories": [ diff --git a/prowler/providers/aws/services/s3/s3_bucket_public_access/s3_bucket_public_access.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_public_access/s3_bucket_public_access.metadata.json index 17bc58f884..97d4332e44 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_public_access/s3_bucket_public_access.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_public_access/s3_bucket_public_access.metadata.json @@ -1,29 +1,36 @@ { "Provider": "aws", "CheckID": "s3_bucket_public_access", - "CheckTitle": "Ensure there are no S3 buckets open to Everyone or Any AWS user.", + "CheckTitle": "S3 bucket is not publicly accessible to Everyone or Authenticated Users", "CheckType": [ - "Data Protection" + "Software and Configuration Checks/AWS Security Best Practices/Network Reachability", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark", + "Effects/Data Exposure" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "critical", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Ensure there are no S3 buckets open to Everyone or Any AWS user.", - "Risk": "Even if you enable all possible bucket ACL options available in the Amazon S3 console the ACL alone does not allow everyone to download objects from your bucket. Depending on which option you select any user could perform some actions.", + "Description": "**Amazon S3 buckets** are evaluated for **public access** via ACLs and bucket policies. The check identifies account or bucket `PublicAccessBlock` protections (`IgnorePublicAcls`, `RestrictPublicBuckets`) and flags buckets granting group access to `AllUsers` or `AuthenticatedUsers`, or with a public bucket policy.", + "Risk": "Publicly accessible buckets jeopardize **confidentiality** through unauthenticated reads, **integrity** through write or ACL changes, and **availability** via object deletion or overwrite. Attackers can mass-exfiltrate data, host malware, or pivot after discovering secrets stored in objects.", "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/id_id/kitchensink/latest/testguide/access-control-block-public-access.html", + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html" + ], "Remediation": { "Code": { - "CLI": "aws s3api put-public-access-block --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true --bucket ", - "NativeIaC": "", - "Other": "https://github.com/cloudmatos/matos/tree/master/remediations/aws/s3/s3/block-public-access", - "Terraform": "https://docs.prowler.com/checks/aws/networking-policies/s3-bucket-should-have-public-access-blocks-defaults-to-false-if-the-public-access-block-is-not-attached#terraform" + "CLI": "aws s3api put-public-access-block --bucket --public-access-block-configuration IgnorePublicAcls=true,RestrictPublicBuckets=true", + "NativeIaC": "```yaml\n# CloudFormation: Enable minimal S3 Block Public Access on the bucket\nResources:\n ExampleBucket:\n Type: AWS::S3::Bucket\n Properties:\n PublicAccessBlockConfiguration:\n IgnorePublicAcls: true # Critical: ignores any public ACL grants (AllUsers/AuthenticatedUsers)\n RestrictPublicBuckets: true # Critical: restricts buckets with public policies to same-account/service principals\n```", + "Other": "1. In the AWS Console, go to S3 and open the bucket \n2. Select the Permissions tab\n3. Under Block public access (bucket settings), click Edit\n4. Check only:\n - Ignore public ACLs (true)\n - Restrict public buckets (true)\n5. Click Save changes and confirm", + "Terraform": "```hcl\n# Enable minimal S3 Block Public Access on the bucket\nresource \"aws_s3_bucket_public_access_block\" \"example\" {\n bucket = \"\"\n\n ignore_public_acls = true # Critical: ignores public ACLs\n restrict_public_buckets = true # Critical: restricts buckets with public policies\n}\n```" }, "Recommendation": { - "Text": "You can enable block public access settings only for access points, buckets and AWS accounts. Amazon S3 does not support block public access settings on a per-object basis. When you apply block public access settings to an account, the settings apply to all AWS Regions globally. The settings might not take effect in all Regions immediately or simultaneously, but they eventually propagate to all Regions.", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html" + "Text": "Enforce defense in depth: enable **S3 Block Public Access** at org/account and bucket levels (`BlockPublicAcls`, `IgnorePublicAcls`, `BlockPublicPolicy`, `RestrictPublicBuckets`). Apply **least privilege** with explicit principals; avoid ACLs via Object Ownership. Use private access patterns (e.g., CloudFront OAC or presigned URLs) and monitor with analyzers.", + "Url": "https://hub.prowler.com/check/s3_bucket_public_access" } }, "Categories": [ diff --git a/prowler/providers/aws/services/s3/s3_bucket_public_list_acl/s3_bucket_public_list_acl.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_public_list_acl/s3_bucket_public_list_acl.metadata.json index 6376694d3b..53d1bd6351 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_public_list_acl/s3_bucket_public_list_acl.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_public_list_acl/s3_bucket_public_list_acl.metadata.json @@ -1,29 +1,36 @@ { "Provider": "aws", "CheckID": "s3_bucket_public_list_acl", - "CheckTitle": "Ensure there are no S3 buckets listable by Everyone or Any AWS customer.", + "CheckTitle": "S3 bucket is not publicly listable by Everyone or any authenticated AWS user", "CheckType": [ - "Data Protection" + "Software and Configuration Checks/AWS Security Best Practices/Network Reachability", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "Effects/Data Exposure", + "TTPs/Initial Access/Unauthorized Access" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "critical", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Ensure there are no S3 buckets listable by Everyone or Any AWS customer.", - "Risk": "Even if you enable all possible bucket ACL options available in the Amazon S3 console the ACL alone does not allow everyone to download objects from your bucket. Depending on which option you select any user could perform some actions.", + "Description": "**Amazon S3 buckets** are evaluated for **public listing via ACLs**. Grants of `READ`, `READ_ACP`, or `FULL_CONTROL` to the `AllUsers` or `AuthenticatedUsers` groups are identified. Effective **Block Public Access** at account or bucket level (notably `IgnorePublicAcls` and `RestrictPublicBuckets`) is considered in the evaluation.", + "Risk": "**Public listability** reveals object names, counts, and structure, enabling reconnaissance and targeted scraping. `READ_ACP` exposes permission details for further abuse. With `FULL_CONTROL`, attackers could alter ACLs and disrupt access, undermining **confidentiality** and risking **integrity** and **availability**.", "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html", + "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/aws/S3/s3-bucket-public-read-access.html" + ], "Remediation": { "Code": { - "CLI": "aws s3api put-bucket-acl --bucket --acl private", - "NativeIaC": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/aws/S3/s3-bucket-public-read-access.html", - "Other": "", - "Terraform": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/aws/S3/s3-bucket-public-read-access.html" + "CLI": "aws s3api put-public-access-block --bucket --public-access-block-configuration IgnorePublicAcls=true,RestrictPublicBuckets=true", + "NativeIaC": "```yaml\n# CloudFormation: Block public listing via bucket-level Public Access Block\nResources:\n ExamplePublicAccessBlock:\n Type: AWS::S3::BucketPublicAccessBlock\n Properties:\n Bucket: \"\"\n PublicAccessBlockConfiguration:\n IgnorePublicAcls: true # Critical: ignore any public ACLs so they don't grant list access\n RestrictPublicBuckets: true # Critical: restrict buckets with public policies to trusted principals\n```", + "Other": "1. In the AWS Console, go to S3 and open the bucket\n2. Select the Permissions tab\n3. Click Edit under Block public access (bucket settings)\n4. Enable:\n - Ignore public ACLs (bucket and objects)\n - Restrict public buckets\n5. Click Save", + "Terraform": "```hcl\n# Block public listing by enabling bucket-level Public Access Block\nresource \"aws_s3_bucket_public_access_block\" \"\" {\n bucket = \"\"\n ignore_public_acls = true # Critical: ignore any public ACLs\n restrict_public_buckets = true # Critical: restrict buckets with public policies\n}\n```" }, "Recommendation": { - "Text": "You can enable block public access settings only for access points, buckets and AWS accounts. Amazon S3 does not support block public access settings on a per-object basis. When you apply block public access settings to an account, the settings apply to all AWS Regions globally. The settings might not take effect in all Regions immediately or simultaneously, but they eventually propagate to all Regions.", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html" + "Text": "Enable account-level **S3 Block Public Access** (`BlockPublicAcls`, `IgnorePublicAcls`, `BlockPublicPolicy`, `RestrictPublicBuckets`).\n- Remove ACL grants to `AllUsers`/`AuthenticatedUsers`; apply **least privilege** with IAM/bucket policies.\n- Favor private patterns (VPC endpoints, CloudFront OAC, presigned URLs) and disable ACLs via Object Ownership.", + "Url": "https://hub.prowler.com/check/s3_bucket_public_list_acl" } }, "Categories": [ diff --git a/prowler/providers/aws/services/s3/s3_bucket_public_write_acl/s3_bucket_public_write_acl.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_public_write_acl/s3_bucket_public_write_acl.metadata.json index d540e2bc66..7a00a61494 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_public_write_acl/s3_bucket_public_write_acl.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_public_write_acl/s3_bucket_public_write_acl.metadata.json @@ -1,29 +1,37 @@ { "Provider": "aws", "CheckID": "s3_bucket_public_write_acl", - "CheckTitle": "Ensure there are no S3 buckets writable by Everyone or Any AWS customer.", + "CheckTitle": "S3 bucket ACL does not grant write access to Everyone or any AWS customer", "CheckType": [ - "Data Protection" + "Software and Configuration Checks/AWS Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark", + "TTPs/Initial Access/Unauthorized Access", + "Effects/Data Destruction" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "critical", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Ensure there are no S3 buckets writable by Everyone or Any AWS customer.", - "Risk": "Even if you enable all possible bucket ACL options available in the Amazon S3 console the ACL alone does not allow everyone to download objects from your bucket. Depending on which option you select any user could perform some actions.", + "Description": "**Amazon S3 buckets** are assessed for ACL grants that allow **public write** access to `AllUsers` or `AuthenticatedUsers` via `WRITE`, `WRITE_ACP`, or `FULL_CONTROL`. Effective **Block Public Access** at account or bucket level (`ignore_public_acls`, `restrict_public_buckets`) is considered.", + "Risk": "Public or cross-account writes enable object tampering, **log poisoning**, and ACL changes via `WRITE_ACP`, undermining **integrity** and causing covert **data exposure**. Attackers can plant malware, deface content, and inflate **costs**, impacting **availability** through overwrites or prefix flooding.", "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html", + "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/aws/S3/s3-bucket-public-write-access.html" + ], "Remediation": { "Code": { "CLI": "aws s3api put-bucket-acl --bucket --acl private", - "NativeIaC": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/aws/S3/s3-bucket-public-write-access.html", - "Other": "", - "Terraform": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/aws/S3/s3-bucket-public-write-access.html" + "NativeIaC": "```yaml\n# CloudFormation: ensure bucket is not publicly writable via ACLs\nResources:\n :\n Type: AWS::S3::Bucket\n Properties:\n PublicAccessBlockConfiguration:\n IgnorePublicAcls: true # Critical: ignores any public ACLs (e.g., AllUsers/AuthenticatedUsers) so write grants don't apply\n RestrictPublicBuckets: true # Critical: restricts public buckets to the account, preventing public writes via policies\n```", + "Other": "1. In the AWS Console, go to S3 > Buckets and open \n2. Go to the Permissions tab > Access control list (ACL) > Edit\n3. Remove any grantee \"Everyone (public access)\" or \"Any AWS account\" with Write, Write ACL, or Full control\n4. Ensure only the bucket owner retains Full control\n5. Click Save changes", + "Terraform": "```hcl\n# Ensure the bucket is not publicly writable via ACLs\nresource \"aws_s3_bucket_public_access_block\" \"\" {\n bucket = \"\"\n ignore_public_acls = true # Critical: disables effect of public ACLs (e.g., AllUsers/AuthenticatedUsers)\n restrict_public_buckets = true # Critical: restricts public buckets to the account to prevent public writes\n}\n```" }, "Recommendation": { - "Text": "You can enable block public access settings only for access points, buckets and AWS accounts. Amazon S3 does not support block public access settings on a per-object basis. When you apply block public access settings to an account, the settings apply to all AWS Regions globally. The settings might not take effect in all Regions immediately or simultaneously, but they eventually propagate to all Regions.", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html" + "Text": "Apply **least privilege** to S3 writes. Enable account-level **Block Public Access** and use **Object Ownership** to disable ACLs. Grant write only to fixed principals via bucket policies with tight conditions (e.g., org IDs, VPC endpoints). Add **versioning** and monitoring for defense-in-depth.", + "Url": "https://hub.prowler.com/check/s3_bucket_public_write_acl" } }, "Categories": [ diff --git a/prowler/providers/aws/services/s3/s3_bucket_secure_transport_policy/s3_bucket_secure_transport_policy.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_secure_transport_policy/s3_bucket_secure_transport_policy.metadata.json index 709c136297..020e6685e0 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_secure_transport_policy/s3_bucket_secure_transport_policy.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_secure_transport_policy/s3_bucket_secure_transport_policy.metadata.json @@ -1,29 +1,35 @@ { "Provider": "aws", "CheckID": "s3_bucket_secure_transport_policy", - "CheckTitle": "Check if S3 buckets have secure transport policy.", + "CheckTitle": "S3 bucket policy denies requests over insecure transport", "CheckType": [ - "Data Protection" + "Software and Configuration Checks/AWS Security Best Practices/Network Reachability", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "medium", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Check if S3 buckets have secure transport policy.", - "Risk": "If HTTPS is not enforced on the bucket policy, communication between clients and S3 buckets can use unencrypted HTTP. As a result, sensitive information could be transmitted in clear text over the network or internet.", + "Description": "**Amazon S3 buckets** are evaluated for a bucket policy that enforces **secure transport** by denying requests when `aws:SecureTransport` is `false`.\n\nBuckets without this explicit denial, or without a policy, are treated as allowing access over insecure transport.", + "Risk": "HTTP access exposes object data and auth details to **eavesdropping** and **man-in-the-middle** attacks. Captured **pre-signed URLs** can be replayed to exfiltrate data. Traffic can be intercepted or altered, undermining **confidentiality** and **integrity** of S3 content.", "RelatedUrl": "", + "AdditionalURLs": [ + "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/S3/secure-transport.html", + "https://aws.amazon.com/premiumsupport/knowledge-center/s3-bucket-policy-for-config-rule/" + ], "Remediation": { "Code": { - "CLI": "", - "NativeIaC": "", - "Other": "https://docs.prowler.com/checks/aws/s3-policies/s3_15-secure-data-transport#aws-console", - "Terraform": "" + "CLI": "aws s3api put-bucket-policy --bucket --policy '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Deny\",\"Principal\":\"*\",\"Action\":\"s3:*\",\"Resource\":\"arn:aws:s3:::/*\",\"Condition\":{\"Bool\":{\"aws:SecureTransport\":\"false\"}}}]}'", + "NativeIaC": "```yaml\n# CloudFormation: Deny non-SSL (HTTP) requests to the S3 bucket\nResources:\n BucketPolicy:\n Type: AWS::S3::BucketPolicy\n Properties:\n Bucket: \n PolicyDocument:\n Version: '2012-10-17'\n Statement:\n - Effect: Deny\n Principal: \"*\"\n Action: s3:*\n Resource: arn:aws:s3:::/*\n Condition:\n Bool:\n aws:SecureTransport: \"false\" # Critical: deny requests not using SSL/TLS\n```", + "Other": "1. In the AWS Console, go to S3 and open the bucket \n2. Select the Permissions tab and click Edit in Bucket policy\n3. Paste this policy, replacing the bucket name:\n ```\n {\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Deny\",\n \"Principal\": \"*\",\n \"Action\": \"s3:*\",\n \"Resource\": \"arn:aws:s3:::/*\",\n \"Condition\": { \"Bool\": { \"aws:SecureTransport\": \"false\" } }\n }\n ]\n }\n ```\n4. Click Save changes\n", + "Terraform": "```hcl\n# Deny non-SSL (HTTP) requests to the S3 bucket\nresource \"aws_s3_bucket_policy\" \"policy\" {\n bucket = \"\"\n policy = jsonencode({\n Version = \"2012-10-17\"\n Statement = [{\n Effect = \"Deny\"\n Principal = \"*\"\n Action = \"s3:*\"\n Resource = \"arn:aws:s3:::/*\"\n Condition = {\n Bool = {\n \"aws:SecureTransport\" = \"false\" # Critical: deny requests not using SSL/TLS\n }\n }\n }]\n })\n}\n```" }, "Recommendation": { - "Text": "Ensure that S3 buckets have encryption in transit enabled.", - "Url": "https://aws.amazon.com/premiumsupport/knowledge-center/s3-bucket-policy-for-config-rule/" + "Text": "Enforce **HTTPS-only** access with a bucket policy that denies requests when `aws:SecureTransport=false`.\n\nPrefer **private access** (VPC endpoints or CloudFront with TLS), avoid S3 website endpoints, apply **least privilege**, use short-lived HTTPS **pre-signed URLs**, and monitor logs for insecure access attempts.", + "Url": "https://hub.prowler.com/check/s3_bucket_secure_transport_policy" } }, "Categories": [ diff --git a/prowler/providers/aws/services/s3/s3_bucket_server_access_logging_enabled/s3_bucket_server_access_logging_enabled.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_server_access_logging_enabled/s3_bucket_server_access_logging_enabled.metadata.json index 67fe62f840..3b0e811b4c 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_server_access_logging_enabled/s3_bucket_server_access_logging_enabled.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_server_access_logging_enabled/s3_bucket_server_access_logging_enabled.metadata.json @@ -1,32 +1,39 @@ { "Provider": "aws", "CheckID": "s3_bucket_server_access_logging_enabled", - "CheckTitle": "Check if S3 buckets have server access logging enabled", + "CheckTitle": "S3 bucket has server access logging enabled", "CheckType": [ - "Logging and Monitoring" + "Software and Configuration Checks/AWS Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "medium", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Check if S3 buckets have server access logging enabled", - "Risk": "Server access logs can assist you in security and access audits, help you learn about your customer base, and understand your Amazon S3 bill.", + "Description": "**Amazon S3 buckets** are evaluated for **server access logging** configured to record access requests and deliver logs to a designated destination bucket.", + "Risk": "Without access logs, object reads, writes, and deletions may go untracked, hindering detection of unauthorized access and data exfiltration. This degrades forensic visibility, delays incident response, and weakens evidence integrity, impacting confidentiality and integrity.", "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.amazonaws.cn/en_us/config/latest/developerguide/s3-bucket-logging-enabled.html", + "https://docs.aws.amazon.com/AmazonS3/latest/dev/security-best-practices.html" + ], "Remediation": { "Code": { - "CLI": "aws s3api put-bucket-logging --bucket --bucket-logging-status ", - "NativeIaC": "", - "Other": "https://docs.prowler.com/checks/aws/s3-policies/s3_13-enable-logging", - "Terraform": "https://docs.prowler.com/checks/aws/s3-policies/s3_13-enable-logging#terraform" + "CLI": "aws s3api put-bucket-logging --bucket --bucket-logging-status '{\"LoggingEnabled\":{\"TargetBucket\":\"\",\"TargetPrefix\":\"logs/\"}}'", + "NativeIaC": "```yaml\nResources:\n :\n Type: AWS::S3::Bucket\n Properties:\n LoggingConfiguration:\n DestinationBucketName: # CRITICAL: Enables server access logging by sending logs to this bucket\n```", + "Other": "1. Open the AWS Management Console and go to S3\n2. Select the bucket with the finding\n3. Go to the Properties tab\n4. In Server access logging, click Edit\n5. Toggle Enable, choose the target log bucket, and Save", + "Terraform": "```hcl\nresource \"aws_s3_bucket_logging\" \"\" {\n bucket = \"\"\n target_bucket = \"\" # CRITICAL: Enables server access logging by specifying the target bucket\n}\n```" }, "Recommendation": { - "Text": "Ensure that S3 buckets have Logging enabled. CloudTrail data events can be used in place of S3 bucket logging. If that is the case, this finding can be considered a false positive.", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/security-best-practices.html" + "Text": "Enable **server access logging** and send logs to a dedicated log bucket with least privilege, retention, and monitoring. Complement with **CloudTrail data events** for object-level visibility. Apply **defense in depth** by centralizing logs and protecting them from tampering.", + "Url": "https://hub.prowler.com/check/s3_bucket_server_access_logging_enabled" } }, "Categories": [ + "logging", "forensics-ready" ], "DependsOn": [], diff --git a/prowler/providers/aws/services/s3/s3_bucket_shadow_resource_vulnerability/s3_bucket_shadow_resource_vulnerability.metadata.json b/prowler/providers/aws/services/s3/s3_bucket_shadow_resource_vulnerability/s3_bucket_shadow_resource_vulnerability.metadata.json index eddcb674c4..c57026a426 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_shadow_resource_vulnerability/s3_bucket_shadow_resource_vulnerability.metadata.json +++ b/prowler/providers/aws/services/s3/s3_bucket_shadow_resource_vulnerability/s3_bucket_shadow_resource_vulnerability.metadata.json @@ -1,29 +1,36 @@ { "Provider": "aws", "CheckID": "s3_bucket_shadow_resource_vulnerability", - "CheckTitle": "Check for S3 buckets vulnerable to Shadow Resource Hijacking (Bucket Monopoly)", + "CheckTitle": "S3 bucket is not a known shadow resource owned by another account", "CheckType": [ - "Effects/Data Exposure" + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + "Effects/Data Exfiltration", + "TTPs/Collection" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:partition:s3:::bucket_name", + "ResourceIdTemplate": "", "Severity": "high", "ResourceType": "AwsS3Bucket", "ResourceGroup": "storage", - "Description": "Checks for S3 buckets with predictable names that could be hijacked by an attacker before legitimate use, leading to data leakage or other security breaches.", - "Risk": "An attacker can pre-create S3 buckets with predictable names used by various AWS services. When a legitimate user's service attempts to use that bucket, it may inadvertently write sensitive data to the attacker-controlled bucket, leading to information disclosure, denial of service, or even remote code execution.", - "RelatedUrl": "https://www.aquasec.com/blog/bucket-monopoly-breaching-aws-accounts-through-shadow-resources/", + "Description": "**Amazon S3 buckets** using **predictable service naming** (e.g., `aws-glue-assets--`, `sagemaker--`) are identified and their **ownership** checked.\n\nBuckets tied to your account that match these patterns but are owned by another account-across regions-are surfaced as shadow-resource candidates.", + "Risk": "**Preclaimed buckets** matching your account's patterns let outsiders intercept service artifacts, causing:\n- Loss of **confidentiality** (templates, data exfiltration)\n- Compromised **integrity** (script/config injection RCE, privilege escalation)\n- Reduced **availability** (creation failures or redirected writes)", + "RelatedUrl": "", + "AdditionalURLs": [ + "https://www.techtarget.com/searchsecurity/news/366602412/Researchers-unveil-AWS-vulnerabilities-shadow-resource-vector", + "https://www.aquasec.com/blog/bucket-monopoly-breaching-aws-accounts-through-shadow-resources/#section-10" + ], "Remediation": { "Code": { "CLI": "", - "NativeIaC": "", - "Other": "Manually verify the ownership of any flagged S3 buckets. If a bucket is not owned by your account, investigate its origin and purpose. If it is not a legitimate resource, you should avoid using services that may interact with it.", - "Terraform": "" + "NativeIaC": "```yaml\n# CloudFormation: pre-claim the predictable S3 bucket name to ensure your account owns it\nResources:\n :\n Type: AWS::S3::Bucket\n Properties:\n BucketName: # Critical: create the exact bucket name reported by the check so it is owned by this account\n```", + "Other": "1. In the Prowler finding, copy the exact bucket name flagged (e.g., aws-glue-assets--).\n2. Open the AWS S3 console and click Create bucket.\n3. Paste the exact bucket name and select the region that matches the name.\n4. Click Create bucket.\n5. Repeat for each flagged name/region so all predictable service buckets are owned by your account.", + "Terraform": "```hcl\n# Terraform: pre-claim the predictable S3 bucket name to ensure your account owns it\nresource \"aws_s3_bucket\" \"\" {\n bucket = \"\" # Critical: create the exact bucket name reported by the check so it is owned by this account\n}\n```" }, "Recommendation": { - "Text": "Ensure that all S3 buckets associated with your AWS account are owned by your account. Be cautious of services that create buckets with predictable names. Whenever possible, pre-create these buckets in all regions to prevent hijacking.", - "Url": "https://www.aquasec.com/blog/bucket-monopoly-breaching-aws-accounts-through-shadow-resources/" + "Text": "Apply **defense in depth**:\n- **Preprovision and own** required service buckets in all current and planned regions\n- Enforce **least privilege** so services write only to approved bucket names/ARNs\n- Use **non-guessable names** where you control naming\n- Monitor for look-alike buckets and separate duties for bucket creation vs. use", + "Url": "https://hub.prowler.com/check/s3_bucket_shadow_resource_vulnerability" } }, "Categories": [ diff --git a/prowler/providers/aws/services/s3/s3_multi_region_access_point_public_access_block/s3_multi_region_access_point_public_access_block.metadata.json b/prowler/providers/aws/services/s3/s3_multi_region_access_point_public_access_block/s3_multi_region_access_point_public_access_block.metadata.json index 8a8d7e1f59..6f3d07ed9c 100644 --- a/prowler/providers/aws/services/s3/s3_multi_region_access_point_public_access_block/s3_multi_region_access_point_public_access_block.metadata.json +++ b/prowler/providers/aws/services/s3/s3_multi_region_access_point_public_access_block/s3_multi_region_access_point_public_access_block.metadata.json @@ -1,32 +1,41 @@ { "Provider": "aws", "CheckID": "s3_multi_region_access_point_public_access_block", - "CheckTitle": "Block Public Access Settings enabled on Multi Region Access Points.", + "CheckTitle": "S3 Multi-Region Access Point has all Block Public Access settings enabled", "CheckType": [ - "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices" + "Software and Configuration Checks/AWS Security Best Practices/Network Reachability", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices", + "Effects/Data Exposure" ], "ServiceName": "s3", "SubServiceName": "", - "ResourceIdTemplate": "arn:aws:s3:region:account-id:accesspoint/access-point-name", + "ResourceIdTemplate": "", "Severity": "high", "ResourceType": "AwsS3AccessPoint", "ResourceGroup": "storage", - "Description": "Ensures that public access is blocked on S3 Access Points.", - "Risk": "Leaving S3 multi region access points open to the public in AWS can lead to data exposure, breaches, compliance violations, unauthorized access, and data integrity issues.", - "RelatedUrl": "https://aws.amazon.com/es/getting-started/hands-on/getting-started-with-amazon-s3-multi-region-access-points/", + "Description": "**Amazon S3 Multi-Region Access Points** are evaluated for **Block Public Access** being fully enabled (`block_public_acls`, `ignore_public_acls`, `block_public_policy`, `restrict_public_buckets`).\n\nFocus is on the MRAP's own settings, separate from bucket or account configurations.", + "Risk": "Without MRAP **Block Public Access**, the global endpoint can accept internet traffic, exposing linked buckets.\n\nThis undermines confidentiality (object listing/reads) and integrity (unauthorized writes or policy abuse), and can trigger costly egress and data tampering across Regions.", + "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/multi-region-access-point-block-public-access.html", + "https://aws.amazon.com/es/getting-started/hands-on/getting-started-with-amazon-s3-multi-region-access-points/", + "https://docs.aws.amazon.com/securityhub/latest/userguide/s3-controls.html#s3-24" + ], "Remediation": { "Code": { "CLI": "", - "NativeIaC": "", - "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/s3-controls.html#s3-24", - "Terraform": "" + "NativeIaC": "```yaml\n# CloudFormation: MRAP with Block Public Access enabled (cannot be changed after creation)\nResources:\n :\n Type: AWS::S3::MultiRegionAccessPoint\n Properties:\n Name: \n PublicAccessBlockConfiguration: # Critical: enable all Block Public Access settings\n BlockPublicAcls: true # Critical: blocks ACLs granting public access\n IgnorePublicAcls: true # Critical: ignores any public ACLs\n BlockPublicPolicy: true # Critical: blocks public bucket policies\n RestrictPublicBuckets: true # Critical: restricts public bucket policies\n Regions:\n - Bucket: \n - Bucket: \n```", + "Other": "1. In the AWS Console, go to S3 > Multi-Region Access Points\n2. Select the failing Multi-Region Access Point and choose Delete (settings cannot be edited after creation)\n3. Click Create Multi-Region Access Point\n4. Enter a name and select at least two buckets in different Regions\n5. Ensure Block public access is enabled for all four settings (default): BlockPublicAcls, IgnorePublicAcls, BlockPublicPolicy, RestrictPublicBuckets\n6. Create the Multi-Region Access Point", + "Terraform": "```hcl\n# Terraform: MRAP with Block Public Access enabled (must be set at creation)\nresource \"aws_s3control_multi_region_access_point\" \"\" {\n account_id = \"\"\n\n details {\n name = \"\"\n\n public_access_block { # Critical: enable all Block Public Access settings\n block_public_acls = true # Critical\n ignore_public_acls = true # Critical\n block_public_policy = true # Critical\n restrict_public_buckets = true # Critical\n }\n\n region { bucket = \"\" }\n region { bucket = \"\" }\n }\n}\n```" }, "Recommendation": { - "Text": "Ensure S3 multi region access points are private by default, applying strict access controls, and regularly auditing permissions to prevent unauthorized public access.", - "Url": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/multi-region-access-point-block-public-access.html" + "Text": "Adopt **deny-by-default**: keep all MRAP **Block Public Access** settings enabled; avoid public ACLs or policies.\n- Enforce **least privilege**\n- Prefer private access (VPC endpoints)\n- Periodically review permissions and logs\n\n*MRAP public access settings are immutable after creation.*", + "Url": "https://hub.prowler.com/check/s3_multi_region_access_point_public_access_block" } }, - "Categories": [], + "Categories": [ + "internet-exposed" + ], "DependsOn": [], "RelatedTo": [], "Notes": "" From 8f5c43744f6fe8c77a05b8c613dbb52039e8dbc7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 13:15:24 +0100 Subject: [PATCH 009/337] build(deps): bump softprops/action-gh-release from 2.4.1 to 2.5.0 (#9389) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/prepare-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index a0073277fb..9169ca5806 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -374,7 +374,7 @@ jobs: no-changelog - name: Create draft release - uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1 + uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 with: tag_name: ${{ env.PROWLER_VERSION }} name: Prowler ${{ env.PROWLER_VERSION }} From f407a24022709a82946df73cfe4a92286dab6a1c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 13:16:15 +0100 Subject: [PATCH 010/337] build(deps): bump actions/upload-artifact from 4.6.2 to 6.0.0 (#9712) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ui-e2e-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ui-e2e-tests.yml b/.github/workflows/ui-e2e-tests.yml index aa269af1ce..054bd69f6e 100644 --- a/.github/workflows/ui-e2e-tests.yml +++ b/.github/workflows/ui-e2e-tests.yml @@ -154,7 +154,7 @@ jobs: working-directory: ./ui run: pnpm run test:e2e - name: Upload test reports - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 if: failure() with: name: playwright-report From 7c9dd8fe895d7d480c703382c06984e43c265960 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 13:19:35 +0100 Subject: [PATCH 011/337] build(deps): bump peter-evans/create-pull-request from 7.0.8 to 8.0.0 (#9705) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-bump-version.yml | 6 +++--- .github/workflows/docs-bump-version.yml | 6 +++--- .github/workflows/prepare-release.yml | 2 +- .github/workflows/sdk-bump-version.yml | 6 +++--- .github/workflows/sdk-refresh-aws-services-regions.yml | 2 +- .github/workflows/ui-bump-version.yml | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/api-bump-version.yml b/.github/workflows/api-bump-version.yml index cc485a7030..97cdd546ff 100644 --- a/.github/workflows/api-bump-version.yml +++ b/.github/workflows/api-bump-version.yml @@ -110,7 +110,7 @@ jobs: git --no-pager diff - name: Create PR for next API minor version to master - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: author: prowler-bot <179230569+prowler-bot@users.noreply.github.com> token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} @@ -164,7 +164,7 @@ jobs: git --no-pager diff - name: Create PR for first API patch version to version branch - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: author: prowler-bot <179230569+prowler-bot@users.noreply.github.com> token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} @@ -235,7 +235,7 @@ jobs: git --no-pager diff - name: Create PR for next API patch version to version branch - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: author: prowler-bot <179230569+prowler-bot@users.noreply.github.com> token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} diff --git a/.github/workflows/docs-bump-version.yml b/.github/workflows/docs-bump-version.yml index c7bd940a82..dde21b9c1e 100644 --- a/.github/workflows/docs-bump-version.yml +++ b/.github/workflows/docs-bump-version.yml @@ -106,7 +106,7 @@ jobs: git --no-pager diff - name: Create PR for documentation update to master - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: author: prowler-bot <179230569+prowler-bot@users.noreply.github.com> token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} @@ -161,7 +161,7 @@ jobs: git --no-pager diff - name: Create PR for documentation update to version branch - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: author: prowler-bot <179230569+prowler-bot@users.noreply.github.com> token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} @@ -225,7 +225,7 @@ jobs: git --no-pager diff - name: Create PR for documentation update to version branch - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: author: prowler-bot <179230569+prowler-bot@users.noreply.github.com> token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 9169ca5806..815ade1dec 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -344,7 +344,7 @@ jobs: - name: Create PR for API dependency update if: ${{ env.PATCH_VERSION == '0' }} - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} commit-message: 'chore(api): update prowler dependency to ${{ env.BRANCH_NAME }} for release ${{ env.PROWLER_VERSION }}' diff --git a/.github/workflows/sdk-bump-version.yml b/.github/workflows/sdk-bump-version.yml index 0383837431..9f25065689 100644 --- a/.github/workflows/sdk-bump-version.yml +++ b/.github/workflows/sdk-bump-version.yml @@ -91,7 +91,7 @@ jobs: git --no-pager diff - name: Create PR for next minor version to master - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: author: prowler-bot <179230569+prowler-bot@users.noreply.github.com> token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} @@ -139,7 +139,7 @@ jobs: git --no-pager diff - name: Create PR for first patch version to version branch - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: author: prowler-bot <179230569+prowler-bot@users.noreply.github.com> token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} @@ -196,7 +196,7 @@ jobs: git --no-pager diff - name: Create PR for next patch version to version branch - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: author: prowler-bot <179230569+prowler-bot@users.noreply.github.com> token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} diff --git a/.github/workflows/sdk-refresh-aws-services-regions.yml b/.github/workflows/sdk-refresh-aws-services-regions.yml index 672242398c..25839f2631 100644 --- a/.github/workflows/sdk-refresh-aws-services-regions.yml +++ b/.github/workflows/sdk-refresh-aws-services-regions.yml @@ -50,7 +50,7 @@ jobs: - name: Create pull request id: create-pr - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} author: 'prowler-bot <179230569+prowler-bot@users.noreply.github.com>' diff --git a/.github/workflows/ui-bump-version.yml b/.github/workflows/ui-bump-version.yml index c25b2809a7..7c576eed55 100644 --- a/.github/workflows/ui-bump-version.yml +++ b/.github/workflows/ui-bump-version.yml @@ -90,7 +90,7 @@ jobs: git --no-pager diff - name: Create PR for next minor version to master - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: author: prowler-bot <179230569+prowler-bot@users.noreply.github.com> token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} @@ -140,7 +140,7 @@ jobs: git --no-pager diff - name: Create PR for first patch version to version branch - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: author: prowler-bot <179230569+prowler-bot@users.noreply.github.com> token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} @@ -199,7 +199,7 @@ jobs: git --no-pager diff - name: Create PR for next patch version to version branch - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: author: prowler-bot <179230569+prowler-bot@users.noreply.github.com> token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} From 503b56188b840e781295e0c90f1f60259443bf94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20De=20la=20Torre=20Vico?= Date: Thu, 8 Jan 2026 13:22:59 +0100 Subject: [PATCH 012/337] chore(aws): enhance metadata for `datasync` service (#8854) Co-authored-by: Daniel Barranquero --- prowler/CHANGELOG.md | 1 + ...atasync_task_logging_enabled.metadata.json | 29 +++++++++++-------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 711a17b046..5fd9ca66f4 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -38,6 +38,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Update AWS VPC service metadata to new format [(#9479)](https://github.com/prowler-cloud/prowler/pull/9479) - Update AWS Transfer service metadata to new format [(#9434)](https://github.com/prowler-cloud/prowler/pull/9434) - Update AWS S3 service metadata to new format [(#9552)](https://github.com/prowler-cloud/prowler/pull/9552) +- Update AWS DataSync service metadata to new format [(#8854)](https://github.com/prowler-cloud/prowler/pull/8854) --- diff --git a/prowler/providers/aws/services/datasync/datasync_task_logging_enabled/datasync_task_logging_enabled.metadata.json b/prowler/providers/aws/services/datasync/datasync_task_logging_enabled/datasync_task_logging_enabled.metadata.json index aea24cee9e..7c5d7cd05a 100644 --- a/prowler/providers/aws/services/datasync/datasync_task_logging_enabled/datasync_task_logging_enabled.metadata.json +++ b/prowler/providers/aws/services/datasync/datasync_task_logging_enabled/datasync_task_logging_enabled.metadata.json @@ -1,29 +1,34 @@ { "Provider": "aws", "CheckID": "datasync_task_logging_enabled", - "CheckTitle": "DataSync tasks should have logging enabled", + "CheckTitle": "DataSync task has CloudWatch Logs log group configured for logging", "CheckType": [ - "Software and Configuration Checks/AWS Security Best Practices" + "Software and Configuration Checks/AWS Security Best Practices", + "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices" ], "ServiceName": "datasync", "SubServiceName": "", - "ResourceIdTemplate": "arn:aws:datasync:{region}:{account-id}:task/{task-id}", + "ResourceIdTemplate": "", "Severity": "high", - "ResourceType": "AwsDataSyncTask", + "ResourceType": "Other", "ResourceGroup": "storage", - "Description": "This control checks if AWS DataSync tasks have logging enabled. The control fails if the task doesn't have the CloudWatchLogGroupArn property defined.", - "Risk": "Without logging enabled, important operational data may be lost, making it difficult to troubleshoot issues, monitor performance, and ensure compliance with auditing requirements.", - "RelatedUrl": "https://docs.aws.amazon.com/datasync/latest/userguide/monitor-datasync.html#enable-logging", + "Description": "**AWS DataSync tasks** are evaluated for a configured **CloudWatch Logs** destination (`CloudWatchLogGroupArn`).\n\nTasks that specify a log group are recognized as logging-enabled; those without one are identified as not publishing execution events.", + "Risk": "**Absent DataSync task logs** create blind spots, preventing timely detection of **failed or partial transfers**, unexpected deletions, or anomalies. This undermines data **integrity** verification, obscures potential **exfiltration** indicators, and slows forensics and recovery, reducing **availability** during incidents.", + "RelatedUrl": "", + "AdditionalURLs": [ + "https://support.icompaas.com/support/solutions/articles/62000233637-ensure-datasync-tasks-should-have-logging-enabled", + "https://docs.aws.amazon.com/datasync/latest/userguide/monitor-datasync.html#enable-logging" + ], "Remediation": { "Code": { "CLI": "aws datasync update-task --task-arn --cloud-watch-log-group-arn ", - "NativeIaC": "", - "Other": "https://docs.aws.amazon.com/datasync/latest/userguide/monitor-datasync.html#enable-logging", - "Terraform": "" + "NativeIaC": "```yaml\n# CloudFormation: Enable CloudWatch Logs for a DataSync task\nResources:\n :\n Type: AWS::DataSync::Task\n Properties:\n SourceLocationArn: \n DestinationLocationArn: \n CloudWatchLogGroupArn: # Critical: attaches a CloudWatch Logs group to enable task logging\n```", + "Other": "1. In the AWS Console, go to DataSync > Tasks\n2. Select the task and click Edit\n3. In the Logging section, set CloudWatch Log group to an existing log group\n4. Click Save", + "Terraform": "```hcl\n# Enable CloudWatch Logs for a DataSync task\nresource \"aws_datasync_task\" \"\" {\n source_location_arn = \"\"\n destination_location_arn = \"\"\n cloudwatch_log_group_arn = \"\" # Critical: attaches a CloudWatch Logs group to enable task logging\n}\n```" }, "Recommendation": { - "Text": "Configure logging for your DataSync tasks to ensure that operational data is captured and available for debugging, monitoring, and auditing purposes.", - "Url": "https://docs.aws.amazon.com/datasync/latest/userguide/monitor-datasync.html#enable-logging" + "Text": "Configure each task to publish logs to a dedicated CloudWatch Logs group. Select an appropriate log level (e.g., `BASIC` or `TRANSFER`), enforce **least privilege** for log access, set **retention** and immutability, and integrate alerts. Centralize and monitor logs to support **defense in depth** and incident response.", + "Url": "https://hub.prowler.com/check/datasync_task_logging_enabled" } }, "Categories": [ From 73375ee289165587f258d7751b4805c2d2dc60e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 13:30:41 +0100 Subject: [PATCH 013/337] build(deps): bump tj-actions/changed-files from 47.0.0 to 47.0.1 (#9711) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Pepe Fagoaga --- .github/workflows/api-code-quality.yml | 2 +- .github/workflows/api-container-checks.yml | 4 ++-- .github/workflows/api-security.yml | 2 +- .github/workflows/api-tests.yml | 2 +- .github/workflows/mcp-container-checks.yml | 4 ++-- .github/workflows/pr-check-changelog.yml | 2 +- .github/workflows/pr-conflict-checker.yml | 2 +- .github/workflows/sdk-code-quality.yml | 2 +- .github/workflows/sdk-container-checks.yml | 4 ++-- .github/workflows/sdk-security.yml | 2 +- .github/workflows/sdk-tests.yml | 26 +++++++++++----------- .github/workflows/ui-container-checks.yml | 4 ++-- .github/workflows/ui-tests.yml | 2 +- 13 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.github/workflows/api-code-quality.yml b/.github/workflows/api-code-quality.yml index e0a5306997..0b6131538d 100644 --- a/.github/workflows/api-code-quality.yml +++ b/.github/workflows/api-code-quality.yml @@ -37,7 +37,7 @@ jobs: - name: Check for API changes id: check-changes - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | api/** diff --git a/.github/workflows/api-container-checks.yml b/.github/workflows/api-container-checks.yml index 335555975b..d63f75894d 100644 --- a/.github/workflows/api-container-checks.yml +++ b/.github/workflows/api-container-checks.yml @@ -32,7 +32,7 @@ jobs: - name: Check if Dockerfile changed id: dockerfile-changed - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: api/Dockerfile @@ -67,7 +67,7 @@ jobs: - name: Check for API changes id: check-changes - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: api/** files_ignore: | diff --git a/.github/workflows/api-security.yml b/.github/workflows/api-security.yml index 14536a5183..c6273b9a11 100644 --- a/.github/workflows/api-security.yml +++ b/.github/workflows/api-security.yml @@ -37,7 +37,7 @@ jobs: - name: Check for API changes id: check-changes - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | api/** diff --git a/.github/workflows/api-tests.yml b/.github/workflows/api-tests.yml index dcf97fa18b..44b4141dc2 100644 --- a/.github/workflows/api-tests.yml +++ b/.github/workflows/api-tests.yml @@ -77,7 +77,7 @@ jobs: - name: Check for API changes id: check-changes - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | api/** diff --git a/.github/workflows/mcp-container-checks.yml b/.github/workflows/mcp-container-checks.yml index f15e63d401..5ea0b6c465 100644 --- a/.github/workflows/mcp-container-checks.yml +++ b/.github/workflows/mcp-container-checks.yml @@ -32,7 +32,7 @@ jobs: - name: Check if Dockerfile changed id: dockerfile-changed - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: mcp_server/Dockerfile @@ -66,7 +66,7 @@ jobs: - name: Check for MCP changes id: check-changes - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: mcp_server/** files_ignore: | diff --git a/.github/workflows/pr-check-changelog.yml b/.github/workflows/pr-check-changelog.yml index 3a8985977b..4a1f8e502a 100644 --- a/.github/workflows/pr-check-changelog.yml +++ b/.github/workflows/pr-check-changelog.yml @@ -35,7 +35,7 @@ jobs: - name: Get changed files id: changed-files - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | api/** diff --git a/.github/workflows/pr-conflict-checker.yml b/.github/workflows/pr-conflict-checker.yml index 6486355b80..c812f4ef19 100644 --- a/.github/workflows/pr-conflict-checker.yml +++ b/.github/workflows/pr-conflict-checker.yml @@ -32,7 +32,7 @@ jobs: - name: Get changed files id: changed-files - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: '**' diff --git a/.github/workflows/sdk-code-quality.yml b/.github/workflows/sdk-code-quality.yml index c52d1a6a8f..49f01f7fab 100644 --- a/.github/workflows/sdk-code-quality.yml +++ b/.github/workflows/sdk-code-quality.yml @@ -35,7 +35,7 @@ jobs: - name: Check for SDK changes id: check-changes - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: ./** files_ignore: | diff --git a/.github/workflows/sdk-container-checks.yml b/.github/workflows/sdk-container-checks.yml index e4f95a7836..b85f0a6ebe 100644 --- a/.github/workflows/sdk-container-checks.yml +++ b/.github/workflows/sdk-container-checks.yml @@ -31,7 +31,7 @@ jobs: - name: Check if Dockerfile changed id: dockerfile-changed - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: Dockerfile @@ -66,7 +66,7 @@ jobs: - name: Check for SDK changes id: check-changes - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: ./** files_ignore: | diff --git a/.github/workflows/sdk-security.yml b/.github/workflows/sdk-security.yml index cec5502bc9..e16cb9d160 100644 --- a/.github/workflows/sdk-security.yml +++ b/.github/workflows/sdk-security.yml @@ -28,7 +28,7 @@ jobs: - name: Check for SDK changes id: check-changes - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: ./** files_ignore: | diff --git a/.github/workflows/sdk-tests.yml b/.github/workflows/sdk-tests.yml index c86885214b..d55af082a8 100644 --- a/.github/workflows/sdk-tests.yml +++ b/.github/workflows/sdk-tests.yml @@ -35,7 +35,7 @@ jobs: - name: Check for SDK changes id: check-changes - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: ./** files_ignore: | @@ -75,7 +75,7 @@ jobs: - name: Check if AWS files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-aws - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | ./prowler/**/aws/** @@ -200,7 +200,7 @@ jobs: - name: Check if Azure files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-azure - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | ./prowler/**/azure/** @@ -224,7 +224,7 @@ jobs: - name: Check if GCP files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-gcp - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | ./prowler/**/gcp/** @@ -248,7 +248,7 @@ jobs: - name: Check if Kubernetes files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-kubernetes - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | ./prowler/**/kubernetes/** @@ -272,7 +272,7 @@ jobs: - name: Check if GitHub files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-github - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | ./prowler/**/github/** @@ -296,7 +296,7 @@ jobs: - name: Check if NHN files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-nhn - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | ./prowler/**/nhn/** @@ -320,7 +320,7 @@ jobs: - name: Check if M365 files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-m365 - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | ./prowler/**/m365/** @@ -344,7 +344,7 @@ jobs: - name: Check if IaC files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-iac - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | ./prowler/**/iac/** @@ -368,7 +368,7 @@ jobs: - name: Check if MongoDB Atlas files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-mongodbatlas - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | ./prowler/**/mongodbatlas/** @@ -392,7 +392,7 @@ jobs: - name: Check if OCI files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-oraclecloud - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | ./prowler/**/oraclecloud/** @@ -416,7 +416,7 @@ jobs: - name: Check if Lib files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-lib - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | ./prowler/lib/** @@ -440,7 +440,7 @@ jobs: - name: Check if Config files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-config - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | ./prowler/config/** diff --git a/.github/workflows/ui-container-checks.yml b/.github/workflows/ui-container-checks.yml index 2f19f89899..8329132450 100644 --- a/.github/workflows/ui-container-checks.yml +++ b/.github/workflows/ui-container-checks.yml @@ -32,7 +32,7 @@ jobs: - name: Check if Dockerfile changed id: dockerfile-changed - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: ui/Dockerfile @@ -67,7 +67,7 @@ jobs: - name: Check for UI changes id: check-changes - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: ui/** files_ignore: | diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 0d2b55fbd3..c8382f6711 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -34,7 +34,7 @@ jobs: - name: Check for UI changes id: check-changes - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0 + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 with: files: | ui/** From 44d791dfe9ef4fb1e52d29ed4c47ae18aba0735a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 13:37:20 +0100 Subject: [PATCH 014/337] build(deps-dev): bump marshmallow from 3.26.1 to 3.26.2 (#9652) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5e4ddb6b3f..42f00e39c7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3238,14 +3238,14 @@ files = [ [[package]] name = "marshmallow" -version = "3.26.1" +version = "3.26.2" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c"}, - {file = "marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6"}, + {file = "marshmallow-3.26.2-py3-none-any.whl", hash = "sha256:013fa8a3c4c276c24d26d84ce934dc964e2aa794345a0f8c7e5a7191482c8a73"}, + {file = "marshmallow-3.26.2.tar.gz", hash = "sha256:bbe2adb5a03e6e3571b573f42527c6fe926e17467833660bebd11593ab8dfd57"}, ] [package.dependencies] From 3332e5b891a0f773825e1fb6f6fabb13ff88e224 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 13:38:35 +0100 Subject: [PATCH 015/337] build(deps): bump aiohttp from 3.12.14 to 3.13.3 (#9722) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 210 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 122 insertions(+), 88 deletions(-) diff --git a/poetry.lock b/poetry.lock index 42f00e39c7..18bb12f01c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -38,98 +38,132 @@ files = [ [[package]] name = "aiohttp" -version = "3.12.14" +version = "3.13.3" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohttp-3.12.14-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:906d5075b5ba0dd1c66fcaaf60eb09926a9fef3ca92d912d2a0bbdbecf8b1248"}, - {file = "aiohttp-3.12.14-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c875bf6fc2fd1a572aba0e02ef4e7a63694778c5646cdbda346ee24e630d30fb"}, - {file = "aiohttp-3.12.14-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fbb284d15c6a45fab030740049d03c0ecd60edad9cd23b211d7e11d3be8d56fd"}, - {file = "aiohttp-3.12.14-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38e360381e02e1a05d36b223ecab7bc4a6e7b5ab15760022dc92589ee1d4238c"}, - {file = "aiohttp-3.12.14-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:aaf90137b5e5d84a53632ad95ebee5c9e3e7468f0aab92ba3f608adcb914fa95"}, - {file = "aiohttp-3.12.14-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e532a25e4a0a2685fa295a31acf65e027fbe2bea7a4b02cdfbbba8a064577663"}, - {file = "aiohttp-3.12.14-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eab9762c4d1b08ae04a6c77474e6136da722e34fdc0e6d6eab5ee93ac29f35d1"}, - {file = "aiohttp-3.12.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abe53c3812b2899889a7fca763cdfaeee725f5be68ea89905e4275476ffd7e61"}, - {file = "aiohttp-3.12.14-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5760909b7080aa2ec1d320baee90d03b21745573780a072b66ce633eb77a8656"}, - {file = "aiohttp-3.12.14-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:02fcd3f69051467bbaa7f84d7ec3267478c7df18d68b2e28279116e29d18d4f3"}, - {file = "aiohttp-3.12.14-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4dcd1172cd6794884c33e504d3da3c35648b8be9bfa946942d353b939d5f1288"}, - {file = "aiohttp-3.12.14-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:224d0da41355b942b43ad08101b1b41ce633a654128ee07e36d75133443adcda"}, - {file = "aiohttp-3.12.14-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e387668724f4d734e865c1776d841ed75b300ee61059aca0b05bce67061dcacc"}, - {file = "aiohttp-3.12.14-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:dec9cde5b5a24171e0b0a4ca064b1414950904053fb77c707efd876a2da525d8"}, - {file = "aiohttp-3.12.14-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bbad68a2af4877cc103cd94af9160e45676fc6f0c14abb88e6e092b945c2c8e3"}, - {file = "aiohttp-3.12.14-cp310-cp310-win32.whl", hash = "sha256:ee580cb7c00bd857b3039ebca03c4448e84700dc1322f860cf7a500a6f62630c"}, - {file = "aiohttp-3.12.14-cp310-cp310-win_amd64.whl", hash = "sha256:cf4f05b8cea571e2ccc3ca744e35ead24992d90a72ca2cf7ab7a2efbac6716db"}, - {file = "aiohttp-3.12.14-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f4552ff7b18bcec18b60a90c6982049cdb9dac1dba48cf00b97934a06ce2e597"}, - {file = "aiohttp-3.12.14-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8283f42181ff6ccbcf25acaae4e8ab2ff7e92b3ca4a4ced73b2c12d8cd971393"}, - {file = "aiohttp-3.12.14-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:040afa180ea514495aaff7ad34ec3d27826eaa5d19812730fe9e529b04bb2179"}, - {file = "aiohttp-3.12.14-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b413c12f14c1149f0ffd890f4141a7471ba4b41234fe4fd4a0ff82b1dc299dbb"}, - {file = "aiohttp-3.12.14-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1d6f607ce2e1a93315414e3d448b831238f1874b9968e1195b06efaa5c87e245"}, - {file = "aiohttp-3.12.14-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:565e70d03e924333004ed101599902bba09ebb14843c8ea39d657f037115201b"}, - {file = "aiohttp-3.12.14-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4699979560728b168d5ab63c668a093c9570af2c7a78ea24ca5212c6cdc2b641"}, - {file = "aiohttp-3.12.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad5fdf6af93ec6c99bf800eba3af9a43d8bfd66dce920ac905c817ef4a712afe"}, - {file = "aiohttp-3.12.14-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ac76627c0b7ee0e80e871bde0d376a057916cb008a8f3ffc889570a838f5cc7"}, - {file = "aiohttp-3.12.14-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:798204af1180885651b77bf03adc903743a86a39c7392c472891649610844635"}, - {file = "aiohttp-3.12.14-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4f1205f97de92c37dd71cf2d5bcfb65fdaed3c255d246172cce729a8d849b4da"}, - {file = "aiohttp-3.12.14-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:76ae6f1dd041f85065d9df77c6bc9c9703da9b5c018479d20262acc3df97d419"}, - {file = "aiohttp-3.12.14-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a194ace7bc43ce765338ca2dfb5661489317db216ea7ea700b0332878b392cab"}, - {file = "aiohttp-3.12.14-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:16260e8e03744a6fe3fcb05259eeab8e08342c4c33decf96a9dad9f1187275d0"}, - {file = "aiohttp-3.12.14-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c779e5ebbf0e2e15334ea404fcce54009dc069210164a244d2eac8352a44b28"}, - {file = "aiohttp-3.12.14-cp311-cp311-win32.whl", hash = "sha256:a289f50bf1bd5be227376c067927f78079a7bdeccf8daa6a9e65c38bae14324b"}, - {file = "aiohttp-3.12.14-cp311-cp311-win_amd64.whl", hash = "sha256:0b8a69acaf06b17e9c54151a6c956339cf46db4ff72b3ac28516d0f7068f4ced"}, - {file = "aiohttp-3.12.14-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a0ecbb32fc3e69bc25efcda7d28d38e987d007096cbbeed04f14a6662d0eee22"}, - {file = "aiohttp-3.12.14-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0400f0ca9bb3e0b02f6466421f253797f6384e9845820c8b05e976398ac1d81a"}, - {file = "aiohttp-3.12.14-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a56809fed4c8a830b5cae18454b7464e1529dbf66f71c4772e3cfa9cbec0a1ff"}, - {file = "aiohttp-3.12.14-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27f2e373276e4755691a963e5d11756d093e346119f0627c2d6518208483fb6d"}, - {file = "aiohttp-3.12.14-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ca39e433630e9a16281125ef57ece6817afd1d54c9f1bf32e901f38f16035869"}, - {file = "aiohttp-3.12.14-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c748b3f8b14c77720132b2510a7d9907a03c20ba80f469e58d5dfd90c079a1c"}, - {file = "aiohttp-3.12.14-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0a568abe1b15ce69d4cc37e23020720423f0728e3cb1f9bcd3f53420ec3bfe7"}, - {file = "aiohttp-3.12.14-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9888e60c2c54eaf56704b17feb558c7ed6b7439bca1e07d4818ab878f2083660"}, - {file = "aiohttp-3.12.14-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3006a1dc579b9156de01e7916d38c63dc1ea0679b14627a37edf6151bc530088"}, - {file = "aiohttp-3.12.14-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aa8ec5c15ab80e5501a26719eb48a55f3c567da45c6ea5bb78c52c036b2655c7"}, - {file = "aiohttp-3.12.14-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:39b94e50959aa07844c7fe2206b9f75d63cc3ad1c648aaa755aa257f6f2498a9"}, - {file = "aiohttp-3.12.14-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:04c11907492f416dad9885d503fbfc5dcb6768d90cad8639a771922d584609d3"}, - {file = "aiohttp-3.12.14-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:88167bd9ab69bb46cee91bd9761db6dfd45b6e76a0438c7e884c3f8160ff21eb"}, - {file = "aiohttp-3.12.14-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:791504763f25e8f9f251e4688195e8b455f8820274320204f7eafc467e609425"}, - {file = "aiohttp-3.12.14-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2785b112346e435dd3a1a67f67713a3fe692d288542f1347ad255683f066d8e0"}, - {file = "aiohttp-3.12.14-cp312-cp312-win32.whl", hash = "sha256:15f5f4792c9c999a31d8decf444e79fcfd98497bf98e94284bf390a7bb8c1729"}, - {file = "aiohttp-3.12.14-cp312-cp312-win_amd64.whl", hash = "sha256:3b66e1a182879f579b105a80d5c4bd448b91a57e8933564bf41665064796a338"}, - {file = "aiohttp-3.12.14-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3143a7893d94dc82bc409f7308bc10d60285a3cd831a68faf1aa0836c5c3c767"}, - {file = "aiohttp-3.12.14-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3d62ac3d506cef54b355bd34c2a7c230eb693880001dfcda0bf88b38f5d7af7e"}, - {file = "aiohttp-3.12.14-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:48e43e075c6a438937c4de48ec30fa8ad8e6dfef122a038847456bfe7b947b63"}, - {file = "aiohttp-3.12.14-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:077b4488411a9724cecc436cbc8c133e0d61e694995b8de51aaf351c7578949d"}, - {file = "aiohttp-3.12.14-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d8c35632575653f297dcbc9546305b2c1133391089ab925a6a3706dfa775ccab"}, - {file = "aiohttp-3.12.14-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b8ce87963f0035c6834b28f061df90cf525ff7c9b6283a8ac23acee6502afd4"}, - {file = "aiohttp-3.12.14-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0a2cf66e32a2563bb0766eb24eae7e9a269ac0dc48db0aae90b575dc9583026"}, - {file = "aiohttp-3.12.14-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdea089caf6d5cde975084a884c72d901e36ef9c2fd972c9f51efbbc64e96fbd"}, - {file = "aiohttp-3.12.14-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a7865f27db67d49e81d463da64a59365ebd6b826e0e4847aa111056dcb9dc88"}, - {file = "aiohttp-3.12.14-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0ab5b38a6a39781d77713ad930cb5e7feea6f253de656a5f9f281a8f5931b086"}, - {file = "aiohttp-3.12.14-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b3b15acee5c17e8848d90a4ebc27853f37077ba6aec4d8cb4dbbea56d156933"}, - {file = "aiohttp-3.12.14-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e4c972b0bdaac167c1e53e16a16101b17c6d0ed7eac178e653a07b9f7fad7151"}, - {file = "aiohttp-3.12.14-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7442488b0039257a3bdbc55f7209587911f143fca11df9869578db6c26feeeb8"}, - {file = "aiohttp-3.12.14-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f68d3067eecb64c5e9bab4a26aa11bd676f4c70eea9ef6536b0a4e490639add3"}, - {file = "aiohttp-3.12.14-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f88d3704c8b3d598a08ad17d06006cb1ca52a1182291f04979e305c8be6c9758"}, - {file = "aiohttp-3.12.14-cp313-cp313-win32.whl", hash = "sha256:a3c99ab19c7bf375c4ae3debd91ca5d394b98b6089a03231d4c580ef3c2ae4c5"}, - {file = "aiohttp-3.12.14-cp313-cp313-win_amd64.whl", hash = "sha256:3f8aad695e12edc9d571f878c62bedc91adf30c760c8632f09663e5f564f4baa"}, - {file = "aiohttp-3.12.14-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b8cc6b05e94d837bcd71c6531e2344e1ff0fb87abe4ad78a9261d67ef5d83eae"}, - {file = "aiohttp-3.12.14-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d1dcb015ac6a3b8facd3677597edd5ff39d11d937456702f0bb2b762e390a21b"}, - {file = "aiohttp-3.12.14-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3779ed96105cd70ee5e85ca4f457adbce3d9ff33ec3d0ebcdf6c5727f26b21b3"}, - {file = "aiohttp-3.12.14-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:717a0680729b4ebd7569c1dcd718c46b09b360745fd8eb12317abc74b14d14d0"}, - {file = "aiohttp-3.12.14-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b5dd3a2ef7c7e968dbbac8f5574ebeac4d2b813b247e8cec28174a2ba3627170"}, - {file = "aiohttp-3.12.14-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4710f77598c0092239bc12c1fcc278a444e16c7032d91babf5abbf7166463f7b"}, - {file = "aiohttp-3.12.14-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f3e9f75ae842a6c22a195d4a127263dbf87cbab729829e0bd7857fb1672400b2"}, - {file = "aiohttp-3.12.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f9c8d55d6802086edd188e3a7d85a77787e50d56ce3eb4757a3205fa4657922"}, - {file = "aiohttp-3.12.14-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79b29053ff3ad307880d94562cca80693c62062a098a5776ea8ef5ef4b28d140"}, - {file = "aiohttp-3.12.14-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:23e1332fff36bebd3183db0c7a547a1da9d3b4091509f6d818e098855f2f27d3"}, - {file = "aiohttp-3.12.14-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:a564188ce831fd110ea76bcc97085dd6c625b427db3f1dbb14ca4baa1447dcbc"}, - {file = "aiohttp-3.12.14-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a7a1b4302f70bb3ec40ca86de82def532c97a80db49cac6a6700af0de41af5ee"}, - {file = "aiohttp-3.12.14-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:1b07ccef62950a2519f9bfc1e5b294de5dd84329f444ca0b329605ea787a3de5"}, - {file = "aiohttp-3.12.14-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:938bd3ca6259e7e48b38d84f753d548bd863e0c222ed6ee6ace3fd6752768a84"}, - {file = "aiohttp-3.12.14-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8bc784302b6b9f163b54c4e93d7a6f09563bd01ff2b841b29ed3ac126e5040bf"}, - {file = "aiohttp-3.12.14-cp39-cp39-win32.whl", hash = "sha256:a3416f95961dd7d5393ecff99e3f41dc990fb72eda86c11f2a60308ac6dcd7a0"}, - {file = "aiohttp-3.12.14-cp39-cp39-win_amd64.whl", hash = "sha256:196858b8820d7f60578f8b47e5669b3195c21d8ab261e39b1d705346458f445f"}, - {file = "aiohttp-3.12.14.tar.gz", hash = "sha256:6e06e120e34d93100de448fd941522e11dafa78ef1a893c179901b7d66aa29f2"}, + {file = "aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7"}, + {file = "aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821"}, + {file = "aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845"}, + {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af"}, + {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940"}, + {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160"}, + {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7"}, + {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455"}, + {file = "aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279"}, + {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e"}, + {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d"}, + {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808"}, + {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40"}, + {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29"}, + {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11"}, + {file = "aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd"}, + {file = "aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c"}, + {file = "aiohttp-3.13.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b6073099fb654e0a068ae678b10feff95c5cae95bbfcbfa7af669d361a8aa6b"}, + {file = "aiohttp-3.13.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cb93e166e6c28716c8c6aeb5f99dfb6d5ccf482d29fe9bf9a794110e6d0ab64"}, + {file = "aiohttp-3.13.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e027cf2f6b641693a09f631759b4d9ce9165099d2b5d92af9bd4e197690eea"}, + {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b61b7169ababd7802f9568ed96142616a9118dd2be0d1866e920e77ec8fa92a"}, + {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:80dd4c21b0f6237676449c6baaa1039abae86b91636b6c91a7f8e61c87f89540"}, + {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65d2ccb7eabee90ce0503c17716fc77226be026dcc3e65cce859a30db715025b"}, + {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b179331a481cb5529fca8b432d8d3c7001cb217513c94cd72d668d1248688a3"}, + {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d4c940f02f49483b18b079d1c27ab948721852b281f8b015c058100e9421dd1"}, + {file = "aiohttp-3.13.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f9444f105664c4ce47a2a7171a2418bce5b7bae45fb610f4e2c36045d85911d3"}, + {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:694976222c711d1d00ba131904beb60534f93966562f64440d0c9d41b8cdb440"}, + {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f33ed1a2bf1997a36661874b017f5c4b760f41266341af36febaf271d179f6d7"}, + {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e636b3c5f61da31a92bf0d91da83e58fdfa96f178ba682f11d24f31944cdd28c"}, + {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5d2d94f1f5fcbe40838ac51a6ab5704a6f9ea42e72ceda48de5e6b898521da51"}, + {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2be0e9ccf23e8a94f6f0650ce06042cefc6ac703d0d7ab6c7a917289f2539ad4"}, + {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9af5e68ee47d6534d36791bbe9b646d2a7c7deb6fc24d7943628edfbb3581f29"}, + {file = "aiohttp-3.13.3-cp311-cp311-win32.whl", hash = "sha256:a2212ad43c0833a873d0fb3c63fa1bacedd4cf6af2fee62bf4b739ceec3ab239"}, + {file = "aiohttp-3.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:642f752c3eb117b105acbd87e2c143de710987e09860d674e068c4c2c441034f"}, + {file = "aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c"}, + {file = "aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168"}, + {file = "aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d"}, + {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29"}, + {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3"}, + {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d"}, + {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463"}, + {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc"}, + {file = "aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf"}, + {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033"}, + {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f"}, + {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679"}, + {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423"}, + {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce"}, + {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a"}, + {file = "aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046"}, + {file = "aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57"}, + {file = "aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c"}, + {file = "aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9"}, + {file = "aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3"}, + {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf"}, + {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6"}, + {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d"}, + {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261"}, + {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0"}, + {file = "aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730"}, + {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91"}, + {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3"}, + {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4"}, + {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998"}, + {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0"}, + {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591"}, + {file = "aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf"}, + {file = "aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e"}, + {file = "aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808"}, + {file = "aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415"}, + {file = "aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f"}, + {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6"}, + {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687"}, + {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26"}, + {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a"}, + {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1"}, + {file = "aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25"}, + {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603"}, + {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a"}, + {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926"}, + {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba"}, + {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c"}, + {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43"}, + {file = "aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1"}, + {file = "aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984"}, + {file = "aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c"}, + {file = "aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592"}, + {file = "aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f"}, + {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29"}, + {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc"}, + {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2"}, + {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587"}, + {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8"}, + {file = "aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632"}, + {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64"}, + {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0"}, + {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56"}, + {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72"}, + {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df"}, + {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa"}, + {file = "aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767"}, + {file = "aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344"}, + {file = "aiohttp-3.13.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31a83ea4aead760dfcb6962efb1d861db48c34379f2ff72db9ddddd4cda9ea2e"}, + {file = "aiohttp-3.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:988a8c5e317544fdf0d39871559e67b6341065b87fceac641108c2096d5506b7"}, + {file = "aiohttp-3.13.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9b174f267b5cfb9a7dba9ee6859cecd234e9a681841eb85068059bc867fb8f02"}, + {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:947c26539750deeaee933b000fb6517cc770bbd064bad6033f1cff4803881e43"}, + {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9ebf57d09e131f5323464bd347135a88622d1c0976e88ce15b670e7ad57e4bd6"}, + {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4ae5b5a0e1926e504c81c5b84353e7a5516d8778fbbff00429fe7b05bb25cbce"}, + {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2ba0eea45eb5cc3172dbfc497c066f19c41bac70963ea1a67d51fc92e4cf9a80"}, + {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bae5c2ed2eae26cc382020edad80d01f36cb8e746da40b292e68fec40421dc6a"}, + {file = "aiohttp-3.13.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8a60e60746623925eab7d25823329941aee7242d559baa119ca2b253c88a7bd6"}, + {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e50a2e1404f063427c9d027378472316201a2290959a295169bcf25992d04558"}, + {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:9a9dc347e5a3dc7dfdbc1f82da0ef29e388ddb2ed281bfce9dd8248a313e62b7"}, + {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b46020d11d23fe16551466c77823df9cc2f2c1e63cc965daf67fa5eec6ca1877"}, + {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:69c56fbc1993fa17043e24a546959c0178fe2b5782405ad4559e6c13975c15e3"}, + {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:b99281b0704c103d4e11e72a76f1b543d4946fea7dd10767e7e1b5f00d4e5704"}, + {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:40c5e40ecc29ba010656c18052b877a1c28f84344825efa106705e835c28530f"}, + {file = "aiohttp-3.13.3-cp39-cp39-win32.whl", hash = "sha256:56339a36b9f1fc708260c76c87e593e2afb30d26de9ae1eb445b5e051b98a7a1"}, + {file = "aiohttp-3.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:c6b8568a3bb5819a0ad087f16d40e5a3fb6099f39ea1d5625a3edc1e923fc538"}, + {file = "aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88"}, ] [package.dependencies] @@ -143,7 +177,7 @@ propcache = ">=0.2.0" yarl = ">=1.17.0,<2.0" [package.extras] -speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "brotlicffi ; platform_python_implementation != \"CPython\""] +speedups = ["Brotli (>=1.2) ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "backports.zstd ; platform_python_implementation == \"CPython\" and python_version < \"3.14\"", "brotlicffi (>=1.2) ; platform_python_implementation != \"CPython\""] [[package]] name = "aiosignal" From 6e2ba66a5a1df282714a649ecedfc3b1dce2e2e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 13:44:13 +0100 Subject: [PATCH 016/337] build(deps): bump pynacl from 1.5.0 to 1.6.2 in /api (#9739) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- api/poetry.lock | 213 ++++++++++++++++++++++++++++-------------------- 1 file changed, 125 insertions(+), 88 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index 7b2365dd9c..6599c7e0d3 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. [[package]] name = "about-time" @@ -1554,84 +1554,101 @@ files = [ [[package]] name = "cffi" -version = "1.17.1" +version = "2.0.0" description = "Foreign Function Interface for Python calling C code." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "dev"] +markers = "platform_python_implementation != \"PyPy\"" 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"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, - {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, - {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, - {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, - {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, - {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, - {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, - {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, - {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, - {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, - {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, - {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, - {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, - {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, - {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, + {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, + {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb"}, + {file = "cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a"}, + {file = "cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743"}, + {file = "cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5"}, + {file = "cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5"}, + {file = "cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187"}, + {file = "cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18"}, + {file = "cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5"}, + {file = "cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b"}, + {file = "cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27"}, + {file = "cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75"}, + {file = "cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1"}, + {file = "cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f"}, + {file = "cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25"}, + {file = "cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4"}, + {file = "cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e"}, + {file = "cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6"}, + {file = "cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322"}, + {file = "cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a"}, + {file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"}, + {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"}, ] -markers = {dev = "platform_python_implementation != \"PyPy\""} [package.dependencies] -pycparser = "*" +pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} [[package]] name = "charset-normalizer" @@ -5678,11 +5695,11 @@ description = "C parser in Python" optional = false python-versions = ">=3.8" groups = ["main", "dev"] +markers = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] -markers = {dev = "platform_python_implementation != \"PyPy\""} [[package]] name = "pycurl" @@ -5946,30 +5963,45 @@ testutils = ["gitpython (>3)"] [[package]] name = "pynacl" -version = "1.5.0" +version = "1.6.2" description = "Python binding to the Networking and Cryptography (NaCl) library" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" groups = ["main"] files = [ - {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858"}, - {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b"}, - {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff"}, - {file = "PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"}, - {file = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"}, - {file = "PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba"}, + {file = "pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14"}, + {file = "pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444"}, + {file = "pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b"}, + {file = "pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145"}, + {file = "pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590"}, + {file = "pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2"}, + {file = "pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6"}, + {file = "pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e"}, + {file = "pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577"}, + {file = "pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa"}, + {file = "pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0"}, + {file = "pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c"}, + {file = "pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c"}, ] [package.dependencies] -cffi = ">=1.4.1" +cffi = {version = ">=2.0.0", markers = "platform_python_implementation != \"PyPy\" and python_version >= \"3.9\""} [package.extras] -docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] -tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] +docs = ["sphinx (<7)", "sphinx_rtd_theme"] +tests = ["hypothesis (>=3.27.0)", "pytest (>=7.4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] [[package]] name = "pyopenssl" @@ -6698,6 +6730,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f66efbc1caa63c088dead1c4170d148eabc9b80d95fb75b6c92ac0aad2437d76"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22353049ba4181685023b25b5b51a574bce33e7f51c759371a7422dcae5402a6"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:932205970b9f9991b34f55136be327501903f7c66830e9760a8ffb15b07f05cd"}, + {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a52d48f4e7bf9005e8f0a89209bf9a73f7190ddf0489eee5eb51377385f59f2a"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win32.whl", hash = "sha256:3eac5a91891ceb88138c113f9db04f3cebdae277f5d44eaa3651a4f573e6a5da"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win_amd64.whl", hash = "sha256:ab007f2f5a87bd08ab1499bdf96f3d5c6ad4dcfa364884cb4549aa0154b13a28"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6"}, @@ -6706,6 +6739,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2"}, + {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1492a6051dab8d912fc2adeef0e8c72216b24d57bd896ea607cb90bb0c4981d3"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win32.whl", hash = "sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win_amd64.whl", hash = "sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632"}, @@ -6714,6 +6748,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680"}, + {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b82a7c94a498853aa0b272fd5bc67f29008da798d4f93a2f9f289feb8426a58d"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win32.whl", hash = "sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win_amd64.whl", hash = "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a"}, @@ -6722,6 +6757,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1"}, + {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f6f3eac23941b32afccc23081e1f50612bdbe4e982012ef4f5797986828cd01"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win32.whl", hash = "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win_amd64.whl", hash = "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:fc4b630cd3fa2cf7fce38afa91d7cfe844a9f75d7f0f36393fa98815e911d987"}, @@ -6730,6 +6766,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2f1c3765db32be59d18ab3953f43ab62a761327aafc1594a2a1fbe038b8b8a7"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d85252669dc32f98ebcd5d36768f5d4faeaeaa2d655ac0473be490ecdae3c285"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e143ada795c341b56de9418c58d028989093ee611aa27ffb9b7f609c00d813ed"}, + {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2c59aa6170b990d8d2719323e628aaf36f3bfbc1c26279c0eeeb24d05d2d11c7"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win32.whl", hash = "sha256:beffaed67936fbbeffd10966a4eb53c402fafd3d6833770516bf7314bc6ffa12"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win_amd64.whl", hash = "sha256:040ae85536960525ea62868b642bdb0c2cc6021c9f9d507810c0c604e66f5a7b"}, {file = "ruamel.yaml.clib-0.2.12.tar.gz", hash = "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f"}, From bbdb230bb21c45f86a75ea62b3a6a5c954892ed2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 13:45:14 +0100 Subject: [PATCH 017/337] build(deps): bump filelock from 3.12.4 to 3.20.1 in /api (#9594) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 25c90f9f63668faa6fa760e330af915110b5b9dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 13:45:58 +0100 Subject: [PATCH 018/337] build(deps): bump urllib3 from 2.5.0 to 2.6.3 in /api (#9735) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- api/poetry.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index 6599c7e0d3..331f5fbf58 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -7257,21 +7257,21 @@ files = [ [[package]] name = "urllib3" -version = "2.5.0" +version = "2.6.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, - {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, + {file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"}, + {file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"}, ] [package.extras] -brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] +brotli = ["brotli (>=1.2.0) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=1.2.0.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] +zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] [[package]] name = "uuid6" From 211639d849f07191a8f789834058def3b570ab9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 13:52:58 +0100 Subject: [PATCH 019/337] build(deps-dev): bump marshmallow from 3.26.1 to 3.26.2 in /api (#9651) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- api/poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index 331f5fbf58..d6c777e025 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -4233,14 +4233,14 @@ files = [ [[package]] name = "marshmallow" -version = "3.26.1" +version = "3.26.2" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c"}, - {file = "marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6"}, + {file = "marshmallow-3.26.2-py3-none-any.whl", hash = "sha256:013fa8a3c4c276c24d26d84ce934dc964e2aa794345a0f8c7e5a7191482c8a73"}, + {file = "marshmallow-3.26.2.tar.gz", hash = "sha256:bbe2adb5a03e6e3571b573f42527c6fe926e17467833660bebd11593ab8dfd57"}, ] [package.dependencies] From fa2deef2417f0c7d5b0de554afcbbe240e3d78e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 14:12:54 +0100 Subject: [PATCH 020/337] build(deps): bump aiohttp from 3.12.15 to 3.13.3 in /api (#9723) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Pepe Fagoaga --- api/poetry.lock | 210 ++++++++++++++++++++++++++++-------------------- 1 file changed, 122 insertions(+), 88 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index d6c777e025..b12a734dc9 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -38,98 +38,132 @@ files = [ [[package]] name = "aiohttp" -version = "3.12.15" +version = "3.13.3" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohttp-3.12.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b6fc902bff74d9b1879ad55f5404153e2b33a82e72a95c89cec5eb6cc9e92fbc"}, - {file = "aiohttp-3.12.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:098e92835b8119b54c693f2f88a1dec690e20798ca5f5fe5f0520245253ee0af"}, - {file = "aiohttp-3.12.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:40b3fee496a47c3b4a39a731954c06f0bd9bd3e8258c059a4beb76ac23f8e421"}, - {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ce13fcfb0bb2f259fb42106cdc63fa5515fb85b7e87177267d89a771a660b79"}, - {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3beb14f053222b391bf9cf92ae82e0171067cc9c8f52453a0f1ec7c37df12a77"}, - {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c39e87afe48aa3e814cac5f535bc6199180a53e38d3f51c5e2530f5aa4ec58c"}, - {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5f1b4ce5bc528a6ee38dbf5f39bbf11dd127048726323b72b8e85769319ffc4"}, - {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1004e67962efabbaf3f03b11b4c43b834081c9e3f9b32b16a7d97d4708a9abe6"}, - {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8faa08fcc2e411f7ab91d1541d9d597d3a90e9004180edb2072238c085eac8c2"}, - {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fe086edf38b2222328cdf89af0dde2439ee173b8ad7cb659b4e4c6f385b2be3d"}, - {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:79b26fe467219add81d5e47b4a4ba0f2394e8b7c7c3198ed36609f9ba161aecb"}, - {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b761bac1192ef24e16706d761aefcb581438b34b13a2f069a6d343ec8fb693a5"}, - {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e153e8adacfe2af562861b72f8bc47f8a5c08e010ac94eebbe33dc21d677cd5b"}, - {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:fc49c4de44977aa8601a00edbf157e9a421f227aa7eb477d9e3df48343311065"}, - {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2776c7ec89c54a47029940177e75c8c07c29c66f73464784971d6a81904ce9d1"}, - {file = "aiohttp-3.12.15-cp310-cp310-win32.whl", hash = "sha256:2c7d81a277fa78b2203ab626ced1487420e8c11a8e373707ab72d189fcdad20a"}, - {file = "aiohttp-3.12.15-cp310-cp310-win_amd64.whl", hash = "sha256:83603f881e11f0f710f8e2327817c82e79431ec976448839f3cd05d7afe8f830"}, - {file = "aiohttp-3.12.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d3ce17ce0220383a0f9ea07175eeaa6aa13ae5a41f30bc61d84df17f0e9b1117"}, - {file = "aiohttp-3.12.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:010cc9bbd06db80fe234d9003f67e97a10fe003bfbedb40da7d71c1008eda0fe"}, - {file = "aiohttp-3.12.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f9d7c55b41ed687b9d7165b17672340187f87a773c98236c987f08c858145a9"}, - {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc4fbc61bb3548d3b482f9ac7ddd0f18c67e4225aaa4e8552b9f1ac7e6bda9e5"}, - {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7fbc8a7c410bb3ad5d595bb7118147dfbb6449d862cc1125cf8867cb337e8728"}, - {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74dad41b3458dbb0511e760fb355bb0b6689e0630de8a22b1b62a98777136e16"}, - {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b6f0af863cf17e6222b1735a756d664159e58855da99cfe965134a3ff63b0b0"}, - {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5b7fe4972d48a4da367043b8e023fb70a04d1490aa7d68800e465d1b97e493b"}, - {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6443cca89553b7a5485331bc9bedb2342b08d073fa10b8c7d1c60579c4a7b9bd"}, - {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c5f40ec615e5264f44b4282ee27628cea221fcad52f27405b80abb346d9f3f8"}, - {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2abbb216a1d3a2fe86dbd2edce20cdc5e9ad0be6378455b05ec7f77361b3ab50"}, - {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:db71ce547012a5420a39c1b744d485cfb823564d01d5d20805977f5ea1345676"}, - {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ced339d7c9b5030abad5854aa5413a77565e5b6e6248ff927d3e174baf3badf7"}, - {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7c7dd29c7b5bda137464dc9bfc738d7ceea46ff70309859ffde8c022e9b08ba7"}, - {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:421da6fd326460517873274875c6c5a18ff225b40da2616083c5a34a7570b685"}, - {file = "aiohttp-3.12.15-cp311-cp311-win32.whl", hash = "sha256:4420cf9d179ec8dfe4be10e7d0fe47d6d606485512ea2265b0d8c5113372771b"}, - {file = "aiohttp-3.12.15-cp311-cp311-win_amd64.whl", hash = "sha256:edd533a07da85baa4b423ee8839e3e91681c7bfa19b04260a469ee94b778bf6d"}, - {file = "aiohttp-3.12.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:802d3868f5776e28f7bf69d349c26fc0efadb81676d0afa88ed00d98a26340b7"}, - {file = "aiohttp-3.12.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2800614cd560287be05e33a679638e586a2d7401f4ddf99e304d98878c29444"}, - {file = "aiohttp-3.12.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8466151554b593909d30a0a125d638b4e5f3836e5aecde85b66b80ded1cb5b0d"}, - {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e5a495cb1be69dae4b08f35a6c4579c539e9b5706f606632102c0f855bcba7c"}, - {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6404dfc8cdde35c69aaa489bb3542fb86ef215fc70277c892be8af540e5e21c0"}, - {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ead1c00f8521a5c9070fcb88f02967b1d8a0544e6d85c253f6968b785e1a2ab"}, - {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6990ef617f14450bc6b34941dba4f12d5613cbf4e33805932f853fbd1cf18bfb"}, - {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd736ed420f4db2b8148b52b46b88ed038d0354255f9a73196b7bbce3ea97545"}, - {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c5092ce14361a73086b90c6efb3948ffa5be2f5b6fbcf52e8d8c8b8848bb97c"}, - {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aaa2234bb60c4dbf82893e934d8ee8dea30446f0647e024074237a56a08c01bd"}, - {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6d86a2fbdd14192e2f234a92d3b494dd4457e683ba07e5905a0b3ee25389ac9f"}, - {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a041e7e2612041a6ddf1c6a33b883be6a421247c7afd47e885969ee4cc58bd8d"}, - {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5015082477abeafad7203757ae44299a610e89ee82a1503e3d4184e6bafdd519"}, - {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56822ff5ddfd1b745534e658faba944012346184fbfe732e0d6134b744516eea"}, - {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2acbbfff69019d9014508c4ba0401822e8bae5a5fdc3b6814285b71231b60f3"}, - {file = "aiohttp-3.12.15-cp312-cp312-win32.whl", hash = "sha256:d849b0901b50f2185874b9a232f38e26b9b3d4810095a7572eacea939132d4e1"}, - {file = "aiohttp-3.12.15-cp312-cp312-win_amd64.whl", hash = "sha256:b390ef5f62bb508a9d67cb3bba9b8356e23b3996da7062f1a57ce1a79d2b3d34"}, - {file = "aiohttp-3.12.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9f922ffd05034d439dde1c77a20461cf4a1b0831e6caa26151fe7aa8aaebc315"}, - {file = "aiohttp-3.12.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2ee8a8ac39ce45f3e55663891d4b1d15598c157b4d494a4613e704c8b43112cd"}, - {file = "aiohttp-3.12.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3eae49032c29d356b94eee45a3f39fdf4b0814b397638c2f718e96cfadf4c4e4"}, - {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97752ff12cc12f46a9b20327104448042fce5c33a624f88c18f66f9368091c7"}, - {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:894261472691d6fe76ebb7fcf2e5870a2ac284c7406ddc95823c8598a1390f0d"}, - {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fa5d9eb82ce98959fc1031c28198b431b4d9396894f385cb63f1e2f3f20ca6b"}, - {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0fa751efb11a541f57db59c1dd821bec09031e01452b2b6217319b3a1f34f3d"}, - {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5346b93e62ab51ee2a9d68e8f73c7cf96ffb73568a23e683f931e52450e4148d"}, - {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:049ec0360f939cd164ecbfd2873eaa432613d5e77d6b04535e3d1fbae5a9e645"}, - {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b52dcf013b57464b6d1e51b627adfd69a8053e84b7103a7cd49c030f9ca44461"}, - {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b2af240143dd2765e0fb661fd0361a1b469cab235039ea57663cda087250ea9"}, - {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac77f709a2cde2cc71257ab2d8c74dd157c67a0558a0d2799d5d571b4c63d44d"}, - {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:47f6b962246f0a774fbd3b6b7be25d59b06fdb2f164cf2513097998fc6a29693"}, - {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:760fb7db442f284996e39cf9915a94492e1896baac44f06ae551974907922b64"}, - {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad702e57dc385cae679c39d318def49aef754455f237499d5b99bea4ef582e51"}, - {file = "aiohttp-3.12.15-cp313-cp313-win32.whl", hash = "sha256:f813c3e9032331024de2eb2e32a88d86afb69291fbc37a3a3ae81cc9917fb3d0"}, - {file = "aiohttp-3.12.15-cp313-cp313-win_amd64.whl", hash = "sha256:1a649001580bdb37c6fdb1bebbd7e3bc688e8ec2b5c6f52edbb664662b17dc84"}, - {file = "aiohttp-3.12.15-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:691d203c2bdf4f4637792efbbcdcd157ae11e55eaeb5e9c360c1206fb03d4d98"}, - {file = "aiohttp-3.12.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8e995e1abc4ed2a454c731385bf4082be06f875822adc4c6d9eaadf96e20d406"}, - {file = "aiohttp-3.12.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bd44d5936ab3193c617bfd6c9a7d8d1085a8dc8c3f44d5f1dcf554d17d04cf7d"}, - {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46749be6e89cd78d6068cdf7da51dbcfa4321147ab8e4116ee6678d9a056a0cf"}, - {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0c643f4d75adea39e92c0f01b3fb83d57abdec8c9279b3078b68a3a52b3933b6"}, - {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a23918fedc05806966a2438489dcffccbdf83e921a1170773b6178d04ade142"}, - {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74bdd8c864b36c3673741023343565d95bfbd778ffe1eb4d412c135a28a8dc89"}, - {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a146708808c9b7a988a4af3821379e379e0f0e5e466ca31a73dbdd0325b0263"}, - {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7011a70b56facde58d6d26da4fec3280cc8e2a78c714c96b7a01a87930a9530"}, - {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3bdd6e17e16e1dbd3db74d7f989e8af29c4d2e025f9828e6ef45fbdee158ec75"}, - {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:57d16590a351dfc914670bd72530fd78344b885a00b250e992faea565b7fdc05"}, - {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bc9a0f6569ff990e0bbd75506c8d8fe7214c8f6579cca32f0546e54372a3bb54"}, - {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:536ad7234747a37e50e7b6794ea868833d5220b49c92806ae2d7e8a9d6b5de02"}, - {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f0adb4177fa748072546fb650d9bd7398caaf0e15b370ed3317280b13f4083b0"}, - {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:14954a2988feae3987f1eb49c706bff39947605f4b6fa4027c1d75743723eb09"}, - {file = "aiohttp-3.12.15-cp39-cp39-win32.whl", hash = "sha256:b784d6ed757f27574dca1c336f968f4e81130b27595e458e69457e6878251f5d"}, - {file = "aiohttp-3.12.15-cp39-cp39-win_amd64.whl", hash = "sha256:86ceded4e78a992f835209e236617bffae649371c4a50d5e5a3987f237db84b8"}, - {file = "aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2"}, + {file = "aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7"}, + {file = "aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821"}, + {file = "aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845"}, + {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af"}, + {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940"}, + {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160"}, + {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7"}, + {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455"}, + {file = "aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279"}, + {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e"}, + {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d"}, + {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808"}, + {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40"}, + {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29"}, + {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11"}, + {file = "aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd"}, + {file = "aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c"}, + {file = "aiohttp-3.13.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b6073099fb654e0a068ae678b10feff95c5cae95bbfcbfa7af669d361a8aa6b"}, + {file = "aiohttp-3.13.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cb93e166e6c28716c8c6aeb5f99dfb6d5ccf482d29fe9bf9a794110e6d0ab64"}, + {file = "aiohttp-3.13.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e027cf2f6b641693a09f631759b4d9ce9165099d2b5d92af9bd4e197690eea"}, + {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b61b7169ababd7802f9568ed96142616a9118dd2be0d1866e920e77ec8fa92a"}, + {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:80dd4c21b0f6237676449c6baaa1039abae86b91636b6c91a7f8e61c87f89540"}, + {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65d2ccb7eabee90ce0503c17716fc77226be026dcc3e65cce859a30db715025b"}, + {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b179331a481cb5529fca8b432d8d3c7001cb217513c94cd72d668d1248688a3"}, + {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d4c940f02f49483b18b079d1c27ab948721852b281f8b015c058100e9421dd1"}, + {file = "aiohttp-3.13.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f9444f105664c4ce47a2a7171a2418bce5b7bae45fb610f4e2c36045d85911d3"}, + {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:694976222c711d1d00ba131904beb60534f93966562f64440d0c9d41b8cdb440"}, + {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f33ed1a2bf1997a36661874b017f5c4b760f41266341af36febaf271d179f6d7"}, + {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e636b3c5f61da31a92bf0d91da83e58fdfa96f178ba682f11d24f31944cdd28c"}, + {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5d2d94f1f5fcbe40838ac51a6ab5704a6f9ea42e72ceda48de5e6b898521da51"}, + {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2be0e9ccf23e8a94f6f0650ce06042cefc6ac703d0d7ab6c7a917289f2539ad4"}, + {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9af5e68ee47d6534d36791bbe9b646d2a7c7deb6fc24d7943628edfbb3581f29"}, + {file = "aiohttp-3.13.3-cp311-cp311-win32.whl", hash = "sha256:a2212ad43c0833a873d0fb3c63fa1bacedd4cf6af2fee62bf4b739ceec3ab239"}, + {file = "aiohttp-3.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:642f752c3eb117b105acbd87e2c143de710987e09860d674e068c4c2c441034f"}, + {file = "aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c"}, + {file = "aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168"}, + {file = "aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d"}, + {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29"}, + {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3"}, + {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d"}, + {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463"}, + {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc"}, + {file = "aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf"}, + {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033"}, + {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f"}, + {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679"}, + {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423"}, + {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce"}, + {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a"}, + {file = "aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046"}, + {file = "aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57"}, + {file = "aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c"}, + {file = "aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9"}, + {file = "aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3"}, + {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf"}, + {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6"}, + {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d"}, + {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261"}, + {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0"}, + {file = "aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730"}, + {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91"}, + {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3"}, + {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4"}, + {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998"}, + {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0"}, + {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591"}, + {file = "aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf"}, + {file = "aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e"}, + {file = "aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808"}, + {file = "aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415"}, + {file = "aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f"}, + {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6"}, + {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687"}, + {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26"}, + {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a"}, + {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1"}, + {file = "aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25"}, + {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603"}, + {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a"}, + {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926"}, + {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba"}, + {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c"}, + {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43"}, + {file = "aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1"}, + {file = "aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984"}, + {file = "aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c"}, + {file = "aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592"}, + {file = "aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f"}, + {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29"}, + {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc"}, + {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2"}, + {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587"}, + {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8"}, + {file = "aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632"}, + {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64"}, + {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0"}, + {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56"}, + {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72"}, + {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df"}, + {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa"}, + {file = "aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767"}, + {file = "aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344"}, + {file = "aiohttp-3.13.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31a83ea4aead760dfcb6962efb1d861db48c34379f2ff72db9ddddd4cda9ea2e"}, + {file = "aiohttp-3.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:988a8c5e317544fdf0d39871559e67b6341065b87fceac641108c2096d5506b7"}, + {file = "aiohttp-3.13.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9b174f267b5cfb9a7dba9ee6859cecd234e9a681841eb85068059bc867fb8f02"}, + {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:947c26539750deeaee933b000fb6517cc770bbd064bad6033f1cff4803881e43"}, + {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9ebf57d09e131f5323464bd347135a88622d1c0976e88ce15b670e7ad57e4bd6"}, + {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4ae5b5a0e1926e504c81c5b84353e7a5516d8778fbbff00429fe7b05bb25cbce"}, + {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2ba0eea45eb5cc3172dbfc497c066f19c41bac70963ea1a67d51fc92e4cf9a80"}, + {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bae5c2ed2eae26cc382020edad80d01f36cb8e746da40b292e68fec40421dc6a"}, + {file = "aiohttp-3.13.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8a60e60746623925eab7d25823329941aee7242d559baa119ca2b253c88a7bd6"}, + {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e50a2e1404f063427c9d027378472316201a2290959a295169bcf25992d04558"}, + {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:9a9dc347e5a3dc7dfdbc1f82da0ef29e388ddb2ed281bfce9dd8248a313e62b7"}, + {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b46020d11d23fe16551466c77823df9cc2f2c1e63cc965daf67fa5eec6ca1877"}, + {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:69c56fbc1993fa17043e24a546959c0178fe2b5782405ad4559e6c13975c15e3"}, + {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:b99281b0704c103d4e11e72a76f1b543d4946fea7dd10767e7e1b5f00d4e5704"}, + {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:40c5e40ecc29ba010656c18052b877a1c28f84344825efa106705e835c28530f"}, + {file = "aiohttp-3.13.3-cp39-cp39-win32.whl", hash = "sha256:56339a36b9f1fc708260c76c87e593e2afb30d26de9ae1eb445b5e051b98a7a1"}, + {file = "aiohttp-3.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:c6b8568a3bb5819a0ad087f16d40e5a3fb6099f39ea1d5625a3edc1e923fc538"}, + {file = "aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88"}, ] [package.dependencies] @@ -142,7 +176,7 @@ propcache = ">=0.2.0" yarl = ">=1.17.0,<2.0" [package.extras] -speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "brotlicffi ; platform_python_implementation != \"CPython\""] +speedups = ["Brotli (>=1.2) ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "backports.zstd ; platform_python_implementation == \"CPython\" and python_version < \"3.14\"", "brotlicffi (>=1.2) ; platform_python_implementation != \"CPython\""] [[package]] name = "aiosignal" From 3d16c62f30da3e1a0e41990c07f271d951612190 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 15:04:53 +0100 Subject: [PATCH 021/337] build(deps): bump fastmcp from 2.13.1 to 2.14.0 in /mcp_server (#9696) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mcp_server/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mcp_server/pyproject.toml b/mcp_server/pyproject.toml index cd6e674e1b..0db6ef67f7 100644 --- a/mcp_server/pyproject.toml +++ b/mcp_server/pyproject.toml @@ -4,7 +4,7 @@ requires = ["setuptools>=61.0", "wheel"] [project] dependencies = [ - "fastmcp==2.13.1", + "fastmcp==2.14.0", "httpx>=0.28.0" ] description = "MCP server for Prowler ecosystem" From a0f9df07bd7312c0a963f98c2138ce5a59039389 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 15:40:55 +0100 Subject: [PATCH 022/337] build(deps): bump pynacl from 1.5.0 to 1.6.2 (#9726) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Pepe Fagoaga --- poetry.lock | 206 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 119 insertions(+), 87 deletions(-) diff --git a/poetry.lock b/poetry.lock index 18bb12f01c..f00add7a56 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1579,84 +1579,101 @@ files = [ [[package]] name = "cffi" -version = "1.17.1" +version = "2.0.0" description = "Foreign Function Interface for Python calling C code." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "dev"] +markers = "platform_python_implementation != \"PyPy\"" 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"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, - {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, - {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, - {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, - {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, - {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, - {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, - {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, - {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, - {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, - {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, - {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, - {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, - {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, - {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, + {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, + {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb"}, + {file = "cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a"}, + {file = "cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743"}, + {file = "cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5"}, + {file = "cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5"}, + {file = "cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187"}, + {file = "cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18"}, + {file = "cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5"}, + {file = "cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b"}, + {file = "cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27"}, + {file = "cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75"}, + {file = "cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1"}, + {file = "cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f"}, + {file = "cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25"}, + {file = "cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4"}, + {file = "cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e"}, + {file = "cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6"}, + {file = "cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322"}, + {file = "cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a"}, + {file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"}, + {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"}, ] -markers = {dev = "platform_python_implementation != \"PyPy\""} [package.dependencies] -pycparser = "*" +pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} [[package]] name = "cfgv" @@ -4563,11 +4580,11 @@ description = "C parser in Python" optional = false python-versions = ">=3.8" groups = ["main", "dev"] +markers = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] -markers = {dev = "platform_python_implementation != \"PyPy\""} [[package]] name = "pydantic" @@ -4804,30 +4821,45 @@ testutils = ["gitpython (>3)"] [[package]] name = "pynacl" -version = "1.5.0" +version = "1.6.2" description = "Python binding to the Networking and Cryptography (NaCl) library" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" groups = ["main"] files = [ - {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858"}, - {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b"}, - {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff"}, - {file = "PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"}, - {file = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"}, - {file = "PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba"}, + {file = "pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14"}, + {file = "pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444"}, + {file = "pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b"}, + {file = "pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145"}, + {file = "pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590"}, + {file = "pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2"}, + {file = "pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6"}, + {file = "pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e"}, + {file = "pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577"}, + {file = "pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa"}, + {file = "pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0"}, + {file = "pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c"}, + {file = "pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c"}, ] [package.dependencies] -cffi = ">=1.4.1" +cffi = {version = ">=2.0.0", markers = "platform_python_implementation != \"PyPy\" and python_version >= \"3.9\""} [package.extras] -docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] -tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] +docs = ["sphinx (<7)", "sphinx_rtd_theme"] +tests = ["hypothesis (>=3.27.0)", "pytest (>=7.4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] [[package]] name = "pyopenssl" From 64ab8e64b094e529e0a206ceede4cb223f179491 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 15:41:39 +0100 Subject: [PATCH 023/337] build(deps): bump urllib3 from 1.26.20 to 2.6.3 (#9734) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index f00add7a56..208437c62f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -6046,22 +6046,22 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "urllib3" -version = "2.5.0" +version = "2.6.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" groups = ["main", "dev"] markers = "python_version >= \"3.10\"" files = [ - {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, - {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, + {file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"}, + {file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"}, ] [package.extras] -brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] +brotli = ["brotli (>=1.2.0) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=1.2.0.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] +zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] [[package]] name = "virtualenv" From 795220e290de11d57d96b8d5cfd0502eb9042efb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 15:41:48 +0100 Subject: [PATCH 024/337] build(deps): bump werkzeug from 3.1.3 to 3.1.4 (#9399) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Pepe Fagoaga --- poetry.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 208437c62f..f7243ed271 100644 --- a/poetry.lock +++ b/poetry.lock @@ -6118,18 +6118,18 @@ test = ["websockets"] [[package]] name = "werkzeug" -version = "3.1.3" +version = "3.1.4" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e"}, - {file = "werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746"}, + {file = "werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905"}, + {file = "werkzeug-3.1.4.tar.gz", hash = "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e"}, ] [package.dependencies] -MarkupSafe = ">=2.1.1" +markupsafe = ">=2.1.1" [package.extras] watchdog = ["watchdog (>=2.3)"] From 27492cbd42e019cfce2c75a9125b327dfb1e0f76 Mon Sep 17 00:00:00 2001 From: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Date: Thu, 8 Jan 2026 15:47:26 +0100 Subject: [PATCH 025/337] fix(oci): validate credentials before scanning (#9738) --- .../providers/oci/authentication.mdx | 4 +- .../providers/oci/getting-started-oci.mdx | 2 +- prowler/CHANGELOG.md | 7 + .../oraclecloud/oraclecloud_provider.py | 161 +++++++------- .../oraclecloud/oraclecloud_provider_test.py | 201 ++++++++++++++++++ 5 files changed, 292 insertions(+), 83 deletions(-) create mode 100644 tests/providers/oraclecloud/oraclecloud_provider_test.py diff --git a/docs/user-guide/providers/oci/authentication.mdx b/docs/user-guide/providers/oci/authentication.mdx index 2ae73fb3af..7f0c493e76 100644 --- a/docs/user-guide/providers/oci/authentication.mdx +++ b/docs/user-guide/providers/oci/authentication.mdx @@ -164,7 +164,7 @@ prowler oci --profile PRODUCTION Use a config file from a custom location: ```bash -prowler oci --config-file /path/to/custom/config +prowler oci --oci-config-file /path/to/custom/config ``` ### Setting Up API Keys @@ -377,7 +377,7 @@ ls -la ~/.oci/config mkdir -p ~/.oci # Specify custom location -prowler oci --config-file /path/to/config +prowler oci --oci-config-file /path/to/config ``` #### Error: "InvalidKeyOrSignature" diff --git a/docs/user-guide/providers/oci/getting-started-oci.mdx b/docs/user-guide/providers/oci/getting-started-oci.mdx index 80c008480d..8affa2f992 100644 --- a/docs/user-guide/providers/oci/getting-started-oci.mdx +++ b/docs/user-guide/providers/oci/getting-started-oci.mdx @@ -122,7 +122,7 @@ prowler oci --profile production ##### Using a Custom Config File ```bash -prowler oci --config-file /path/to/custom/config +prowler oci --oci-config-file /path/to/custom/config ``` #### Instance Principal Authentication diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 5fd9ca66f4..7fd5b6b734 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -42,6 +42,13 @@ All notable changes to the **Prowler SDK** are documented in this file. --- +## [5.16.2] (Prowler v5.16.2) (UNRELEASED) + +### Fixed +- Fix OCI authentication error handling and validation [(#9738)](https://github.com/prowler-cloud/prowler/pull/9738) + +--- + ## [5.16.1] (Prowler v5.16.1) ### Fixed diff --git a/prowler/providers/oraclecloud/oraclecloud_provider.py b/prowler/providers/oraclecloud/oraclecloud_provider.py index 08d654d580..3ff83e7c22 100644 --- a/prowler/providers/oraclecloud/oraclecloud_provider.py +++ b/prowler/providers/oraclecloud/oraclecloud_provider.py @@ -266,7 +266,6 @@ class OraclecloudProvider(Provider): # If API key credentials are provided directly, create config from them if user and fingerprint and tenancy and region: import base64 - import tempfile logger.info("Using API key credentials from direct parameters") @@ -280,21 +279,19 @@ class OraclecloudProvider(Provider): # Handle private key if key_content: - # Decode base64 key content and write to temp file + # Decode base64 key content try: key_data = base64.b64decode(key_content) - temp_key_file = tempfile.NamedTemporaryFile( - mode="wb", delete=False, suffix=".pem" - ) - temp_key_file.write(key_data) - temp_key_file.close() - config["key_file"] = temp_key_file.name + decoded_key = key_data.decode("utf-8") except Exception as decode_error: logger.error(f"Failed to decode key_content: {decode_error}") raise OCIInvalidConfigError( file=pathlib.Path(__file__).name, message="Failed to decode key_content. Ensure it is base64 encoded.", ) + + # Use OCI SDK's native key_content support + config["key_content"] = decoded_key elif key_file: config["key_file"] = os.path.expanduser(key_file) else: @@ -428,78 +425,85 @@ class OraclecloudProvider(Provider): Raises: - OCIAuthenticationError: If authentication fails. """ - try: - # Get tenancy from config - tenancy_id = session.config.get("tenancy") + # Get tenancy from config + tenancy_id = session.config.get("tenancy") - if not tenancy_id: - raise OCINoCredentialsError( - file=pathlib.Path(__file__).name, - message="Tenancy ID not found in configuration", - ) - - # Validate tenancy OCID format - if not OraclecloudProvider.validate_ocid(tenancy_id, "tenancy"): - raise OCIInvalidTenancyError( - file=pathlib.Path(__file__).name, - message=f"Invalid tenancy OCID format: {tenancy_id}", - ) - - # Get user from config (not available in instance principal) - user_id = session.config.get("user", "instance-principal") - - # Get region from config or use provided region - if not region: - region = session.config.get("region", "us-ashburn-1") - - # Validate region - if region not in OCI_REGIONS: - raise OCIInvalidRegionError( - file=pathlib.Path(__file__).name, - message=f"Invalid region: {region}", - ) - - # Get tenancy name using Identity service - tenancy_name = "unknown" - try: - # Create identity client with proper authentication handling - if session.signer: - identity_client = oci.identity.IdentityClient( - config=session.config, signer=session.signer - ) - else: - identity_client = oci.identity.IdentityClient(config=session.config) - - tenancy = identity_client.get_tenancy(tenancy_id).data - tenancy_name = tenancy.name - logger.info(f"Tenancy Name: {tenancy_name}") - except Exception as error: - logger.warning( - f"Could not retrieve tenancy name: {error}. Using 'unknown'" - ) - - logger.info(f"OCI Tenancy ID: {tenancy_id}") - logger.info(f"OCI User ID: {user_id}") - logger.info(f"OCI Region: {region}") - - return OCIIdentityInfo( - tenancy_id=tenancy_id, - tenancy_name=tenancy_name, - user_id=user_id, - region=region, - profile=session.profile, - audited_regions=set([region]) if region else set(), - audited_compartments=compartment_ids if compartment_ids else [], + if not tenancy_id: + raise OCINoCredentialsError( + file=pathlib.Path(__file__).name, + message="Tenancy ID not found in configuration", ) - except Exception as error: + # Validate tenancy OCID format + if not OraclecloudProvider.validate_ocid(tenancy_id, "tenancy"): + raise OCIInvalidTenancyError( + file=pathlib.Path(__file__).name, + message=f"Invalid tenancy OCID format: {tenancy_id}", + ) + + # Get user from config (not available in instance principal) + user_id = session.config.get("user", "instance-principal") + + # Get region from config or use provided region + if not region: + region = session.config.get("region", "us-ashburn-1") + + # Validate region + if region not in OCI_REGIONS: + raise OCIInvalidRegionError( + file=pathlib.Path(__file__).name, + message=f"Invalid region: {region}", + ) + + # Validate credentials by calling OCI Identity service + try: + if session.signer: + identity_client = oci.identity.IdentityClient( + config=session.config, signer=session.signer + ) + else: + identity_client = oci.identity.IdentityClient(config=session.config) + + tenancy = identity_client.get_tenancy(tenancy_id).data + tenancy_name = tenancy.name + logger.info(f"Tenancy Name: {tenancy_name}") + except oci.exceptions.ServiceError as error: logger.critical( - f"OCIAuthenticationError[{error.__traceback__.tb_lineno}]: {error}" + f"OCI credential validation failed (HTTP {error.status}): {error.message}" ) raise OCIAuthenticationError( - original_exception=error, file=pathlib.Path(__file__).name, + message=f"OCI credential validation failed: {error.message}. Please verify your credentials and try again.", + original_exception=error, ) + except oci.exceptions.InvalidPrivateKey as error: + logger.critical(f"Invalid OCI private key: {error}") + raise OCIAuthenticationError( + file=pathlib.Path(__file__).name, + message="Invalid OCI private key format. Ensure the key is a valid PEM-encoded private key.", + original_exception=error, + ) + except Exception as error: + logger.critical(f"OCI authentication error: {error}") + raise OCIAuthenticationError( + file=pathlib.Path(__file__).name, + message=f"Failed to authenticate with OCI: {error}", + original_exception=error, + ) + + logger.info(f"OCI Tenancy ID: {tenancy_id}") + logger.info(f"OCI User ID: {user_id}") + logger.info(f"OCI Region: {region}") + + return OCIIdentityInfo( + tenancy_id=tenancy_id, + tenancy_name=tenancy_name, + user_id=user_id, + region=region, + profile=session.profile, + audited_regions=set([region]) if region else set(), + audited_compartments=compartment_ids if compartment_ids else [], + ) @staticmethod def validate_ocid(ocid: str, resource_type: str = None) -> bool: @@ -838,7 +842,6 @@ class OraclecloudProvider(Provider): # If API key credentials are provided directly, create config from them if user and fingerprint and tenancy and region: import base64 - import tempfile logger.info("Using API key credentials from direct parameters") @@ -852,21 +855,19 @@ class OraclecloudProvider(Provider): # Handle private key if key_content: - # Decode base64 key content and write to temp file + # Decode base64 key content try: key_data = base64.b64decode(key_content) - temp_key_file = tempfile.NamedTemporaryFile( - mode="wb", delete=False, suffix=".pem" - ) - temp_key_file.write(key_data) - temp_key_file.close() - config["key_file"] = temp_key_file.name + decoded_key = key_data.decode("utf-8") except Exception as decode_error: logger.error(f"Failed to decode key_content: {decode_error}") raise OCIInvalidConfigError( file=pathlib.Path(__file__).name, message="Failed to decode key_content. Ensure it is base64 encoded.", ) + + # Use OCI SDK's native key_content support + config["key_content"] = decoded_key elif key_file: config["key_file"] = os.path.expanduser(key_file) else: diff --git a/tests/providers/oraclecloud/oraclecloud_provider_test.py b/tests/providers/oraclecloud/oraclecloud_provider_test.py new file mode 100644 index 0000000000..dd3b7b7d27 --- /dev/null +++ b/tests/providers/oraclecloud/oraclecloud_provider_test.py @@ -0,0 +1,201 @@ +from unittest.mock import MagicMock, patch + +import pytest + +from prowler.providers.oraclecloud.exceptions.exceptions import ( + OCIAuthenticationError, + OCIInvalidConfigError, +) +from prowler.providers.oraclecloud.models import OCISession +from prowler.providers.oraclecloud.oraclecloud_provider import OraclecloudProvider + + +class TestSetIdentityAuthenticationErrors: + """Tests for authentication error handling in set_identity()""" + + @pytest.fixture + def mock_session(self): + """Create a mock OCI session.""" + session = OCISession( + config={ + "tenancy": "ocid1.tenancy.oc1..aaaaaaaexample", + "user": "ocid1.user.oc1..aaaaaaaexample", + "region": "us-ashburn-1", + "fingerprint": "aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99", + }, + signer=None, + profile="DEFAULT", + ) + return session + + def test_authentication_error_401_raises_exception(self, mock_session): + """Test 401 error raises OCIAuthenticationError.""" + with patch("oci.identity.IdentityClient") as mock_identity_client: + mock_client_instance = MagicMock() + mock_client_instance.get_tenancy.side_effect = self._create_service_error( + 401, "Authentication failed" + ) + mock_identity_client.return_value = mock_client_instance + + with pytest.raises(OCIAuthenticationError) as exc_info: + OraclecloudProvider.set_identity(mock_session) + + assert "OCI credential validation failed" in str(exc_info.value) + + def test_authentication_error_403_raises_exception(self, mock_session): + """Test 403 error raises OCIAuthenticationError.""" + with patch("oci.identity.IdentityClient") as mock_identity_client: + mock_client_instance = MagicMock() + mock_client_instance.get_tenancy.side_effect = self._create_service_error( + 403, "Forbidden access" + ) + mock_identity_client.return_value = mock_client_instance + + with pytest.raises(OCIAuthenticationError) as exc_info: + OraclecloudProvider.set_identity(mock_session) + + assert "OCI credential validation failed" in str(exc_info.value) + + def test_authentication_error_404_raises_exception(self, mock_session): + """Test 404 error raises OCIAuthenticationError.""" + with patch("oci.identity.IdentityClient") as mock_identity_client: + mock_client_instance = MagicMock() + mock_client_instance.get_tenancy.side_effect = self._create_service_error( + 404, "Resource not found" + ) + mock_identity_client.return_value = mock_client_instance + + with pytest.raises(OCIAuthenticationError) as exc_info: + OraclecloudProvider.set_identity(mock_session) + + assert "OCI credential validation failed" in str(exc_info.value) + + def test_service_error_500_raises_exception(self, mock_session): + """Test 500 error raises OCIAuthenticationError (can't validate credentials).""" + with patch("oci.identity.IdentityClient") as mock_identity_client: + mock_client_instance = MagicMock() + mock_client_instance.get_tenancy.side_effect = self._create_service_error( + 500, "Internal server error" + ) + mock_identity_client.return_value = mock_client_instance + + with pytest.raises(OCIAuthenticationError) as exc_info: + OraclecloudProvider.set_identity(mock_session) + + assert "OCI credential validation failed" in str(exc_info.value) + + def test_invalid_private_key_raises_exception(self, mock_session): + """Test InvalidPrivateKey exception raises OCIAuthenticationError.""" + with patch("oci.identity.IdentityClient") as mock_identity_client: + import oci + + mock_client_instance = MagicMock() + mock_client_instance.get_tenancy.side_effect = ( + oci.exceptions.InvalidPrivateKey("Invalid private key") + ) + mock_identity_client.return_value = mock_client_instance + + with pytest.raises(OCIAuthenticationError) as exc_info: + OraclecloudProvider.set_identity(mock_session) + + assert "Invalid OCI private key format" in str(exc_info.value) + + def test_generic_exception_raises_authentication_error(self, mock_session): + """Test generic exception raises OCIAuthenticationError.""" + with patch("oci.identity.IdentityClient") as mock_identity_client: + mock_client_instance = MagicMock() + mock_client_instance.get_tenancy.side_effect = Exception("Unexpected error") + mock_identity_client.return_value = mock_client_instance + + with pytest.raises(OCIAuthenticationError) as exc_info: + OraclecloudProvider.set_identity(mock_session) + + assert "Failed to authenticate with OCI" in str(exc_info.value) + + def test_successful_authentication(self, mock_session): + """Test successful authentication returns identity info.""" + with patch("oci.identity.IdentityClient") as mock_identity_client: + mock_tenancy = MagicMock() + mock_tenancy.name = "test-tenancy" + mock_response = MagicMock() + mock_response.data = mock_tenancy + + mock_client_instance = MagicMock() + mock_client_instance.get_tenancy.return_value = mock_response + mock_identity_client.return_value = mock_client_instance + + identity = OraclecloudProvider.set_identity(mock_session) + + assert identity.tenancy_name == "test-tenancy" + assert identity.tenancy_id == "ocid1.tenancy.oc1..aaaaaaaexample" + assert identity.user_id == "ocid1.user.oc1..aaaaaaaexample" + assert identity.region == "us-ashburn-1" + + @staticmethod + def _create_service_error(status, message): + """Helper to create an OCI ServiceError.""" + import oci + + error = oci.exceptions.ServiceError( + status=status, + code="TestError", + headers={}, + message=message, + ) + return error + + +class TestTestConnectionKeyValidation: + """Tests for key_content validation in test_connection()""" + + def test_test_connection_invalid_base64_key_raises_error(self): + """Test invalid base64 key content raises OCIInvalidConfigError.""" + with pytest.raises(OCIInvalidConfigError) as exc_info: + OraclecloudProvider.test_connection( + oci_config_file=None, + profile=None, + key_content="not-valid-base64!!!", + user="ocid1.user.oc1..aaaaaaaexample", + fingerprint="aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99", + tenancy="ocid1.tenancy.oc1..aaaaaaaexample", + region="us-ashburn-1", + ) + + assert "Failed to decode key_content" in str(exc_info.value) + + def test_test_connection_valid_key_content_proceeds(self): + """Test valid base64 key content proceeds to authentication.""" + import base64 + + # The SDK will validate the actual key format during authentication + valid_key = """-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEA0Z3VS5JJcds3xfn/ygWyF8n0sMcD/QHWCJ7yGSEtLN2T +...key content... +-----END RSA PRIVATE KEY-----""" + encoded_key = base64.b64encode(valid_key.encode("utf-8")).decode("utf-8") + + with ( + patch("oci.config.validate_config"), + patch("oci.identity.IdentityClient") as mock_identity_client, + ): + mock_tenancy = MagicMock() + mock_tenancy.name = "test-tenancy" + mock_response = MagicMock() + mock_response.data = mock_tenancy + + mock_client_instance = MagicMock() + mock_client_instance.get_tenancy.return_value = mock_response + mock_identity_client.return_value = mock_client_instance + + connection = OraclecloudProvider.test_connection( + oci_config_file=None, + profile=None, + key_content=encoded_key, + user="ocid1.user.oc1..aaaaaaaexample", + fingerprint="aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99", + tenancy="ocid1.tenancy.oc1..aaaaaaaexample", + region="us-ashburn-1", + raise_on_exception=False, + ) + + assert connection.is_connected is True From f3ba70dd6b1d983fcd12bb34a9ea7afaee34b714 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Thu, 8 Jan 2026 17:03:38 +0100 Subject: [PATCH 026/337] docs: add warning about changes not complaining with roadmap (#9741) --- docs/developer-guide/introduction.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/developer-guide/introduction.mdx b/docs/developer-guide/introduction.mdx index 5377991fac..3f77c53ab5 100644 --- a/docs/developer-guide/introduction.mdx +++ b/docs/developer-guide/introduction.mdx @@ -6,6 +6,10 @@ Thanks for your interest in contributing to Prowler! Prowler can be extended in various ways. This guide provides the different ways to contribute and how to get started. + +Maintainers will assess whether a change fits the project roadmap and scope before merging. + + ## Contributing to Prowler ### Review Current Issues From 8d8b7aad15486dac7328defddb2dff946f8af682 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 08:22:37 +0100 Subject: [PATCH 027/337] build(deps): bump werkzeug from 3.1.4 to 3.1.5 (#9744) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index f7243ed271..3189aa7b0f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -6118,14 +6118,14 @@ test = ["websockets"] [[package]] name = "werkzeug" -version = "3.1.4" +version = "3.1.5" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905"}, - {file = "werkzeug-3.1.4.tar.gz", hash = "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e"}, + {file = "werkzeug-3.1.5-py3-none-any.whl", hash = "sha256:5111e36e91086ece91f93268bb39b4a35c1e6f1feac762c9c822ded0a4e322dc"}, + {file = "werkzeug-3.1.5.tar.gz", hash = "sha256:6a548b0e88955dd07ccb25539d7d0cc97417ee9e179677d22c7041c8f078ce67"}, ] [package.dependencies] From d04716ea952df2c9e3e3eb0bc45cddc04f9fee69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 08:23:58 +0100 Subject: [PATCH 028/337] build(deps): bump werkzeug from 3.1.4 to 3.1.5 in /api (#9743) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- api/poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index b12a734dc9..fa0df098eb 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -7374,14 +7374,14 @@ test = ["websockets"] [[package]] name = "werkzeug" -version = "3.1.4" +version = "3.1.5" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905"}, - {file = "werkzeug-3.1.4.tar.gz", hash = "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e"}, + {file = "werkzeug-3.1.5-py3-none-any.whl", hash = "sha256:5111e36e91086ece91f93268bb39b4a35c1e6f1feac762c9c822ded0a4e322dc"}, + {file = "werkzeug-3.1.5.tar.gz", hash = "sha256:6a548b0e88955dd07ccb25539d7d0cc97417ee9e179677d22c7041c8f078ce67"}, ] [package.dependencies] From 68684b107a0ff9aa7373d25ef5816b4d99a369d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 08:25:25 +0100 Subject: [PATCH 029/337] build(deps-dev): bump authlib from 1.6.5 to 1.6.6 in /api (#9742) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- api/poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index fa0df098eb..bde85eb28a 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -847,14 +847,14 @@ tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" a [[package]] name = "authlib" -version = "1.6.5" +version = "1.6.6" description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "authlib-1.6.5-py2.py3-none-any.whl", hash = "sha256:3e0e0507807f842b02175507bdee8957a1d5707fd4afb17c32fb43fee90b6e3a"}, - {file = "authlib-1.6.5.tar.gz", hash = "sha256:6aaf9c79b7cc96c900f0b284061691c5d4e61221640a948fe690b556a6d6d10b"}, + {file = "authlib-1.6.6-py2.py3-none-any.whl", hash = "sha256:7d9e9bc535c13974313a87f53e8430eb6ea3d1cf6ae4f6efcd793f2e949143fd"}, + {file = "authlib-1.6.6.tar.gz", hash = "sha256:45770e8e056d0f283451d9996fbb59b70d45722b45d854d58f32878d0a40c38e"}, ] [package.dependencies] From 7c1bcfc7817fed7cfd62b38ace5a47eac662b2f0 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Fri, 9 Jan 2026 11:32:10 +0100 Subject: [PATCH 030/337] fix: typo in subscription error (#9745) Co-authored-by: Alan Buscaglia --- .../workflow/forms/test-connection-form.tsx | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/ui/components/providers/workflow/forms/test-connection-form.tsx b/ui/components/providers/workflow/forms/test-connection-form.tsx index fecced7c6b..d7f5344b61 100644 --- a/ui/components/providers/workflow/forms/test-connection-form.tsx +++ b/ui/components/providers/workflow/forms/test-connection-form.tsx @@ -4,6 +4,7 @@ import { Checkbox } from "@heroui/checkbox"; import { zodResolver } from "@hookform/resolvers/zod"; import { Icon } from "@iconify/react"; import { Loader2 } from "lucide-react"; +import Link from "next/link"; import { useRouter } from "next/navigation"; import { useState } from "react"; import { useForm } from "react-hook-form"; @@ -18,7 +19,6 @@ import { getTask } from "@/actions/task/tasks"; import { CheckIcon, RocketIcon } from "@/components/icons"; import { Button } from "@/components/shadcn"; import { useToast } from "@/components/ui"; -import { CustomLink } from "@/components/ui/custom/custom-link"; import { Form } from "@/components/ui/form"; import { checkTaskStatus } from "@/lib/helper"; import { ProviderType } from "@/types"; @@ -144,6 +144,11 @@ export const TestConnectionForm = ({ type: "server", message: data.error, }); + toast({ + variant: "destructive", + title: "Oops! Something went wrong", + description: data.error, + }); } else { setIsRedirecting(true); router.push("/scans"); @@ -239,8 +244,8 @@ export const TestConnectionForm = ({ {apiErrorMessage && ( - - {`Provider ID ${apiErrorMessage?.toLowerCase()}. Please check and try again.`} + + {apiErrorMessage} )} @@ -297,17 +302,9 @@ export const TestConnectionForm = ({ {apiErrorMessage ? ( - - - Back to providers - + + Back to providers + ) : connectionStatus?.error ? ( router.back() : onResetCredentials} From 42ae5b6e3ebef8c5ce4f035fa110c98c8da5f19b Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Fri, 9 Jan 2026 14:42:07 +0100 Subject: [PATCH 031/337] chore(template): PR Community Checklist (#9748) --- .github/pull_request_template.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 497c4d6214..e3b870ff2a 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -14,14 +14,26 @@ Please add a detailed description of how to review this PR. ### Checklist -- Are there new checks included in this PR? Yes / No - - If so, do we need to update permissions for the provider? Please review this carefully. + + +Community Checklist + +- [ ] This feature/issue is listed in [here](https://github.com/prowler-cloud/prowler/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen) or roadmap.prowler.com +- [ ] Is it assigned to me, if not, request it via the issue/feature in [here](https://github.com/prowler-cloud/prowler/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen) or [Prowler Community Slack](goto.prowler.com/slack) + + + + - [ ] Review if the code is being covered by tests. - [ ] Review if code is being documented following this specification https://github.com/google/styleguide/blob/gh-pages/pyguide.md#38-comments-and-docstrings - [ ] Review if backport is needed. - [ ] Review if is needed to change the [Readme.md](https://github.com/prowler-cloud/prowler/blob/master/README.md) - [ ] Ensure new entries are added to [CHANGELOG.md](https://github.com/prowler-cloud/prowler/blob/master/prowler/CHANGELOG.md), if applicable. +#### SDK/CLI +- Are there new checks included in this PR? Yes / No + - If so, do we need to update permissions for the provider? Please review this carefully. + #### UI - [ ] All issue/task requirements work as expected on the UI - [ ] Screenshots/Video of the functionality flow (if applicable) - Mobile (X < 640px) From 7f2fa275c6a1941ff5070283e147166c8da4cfcd Mon Sep 17 00:00:00 2001 From: Alan Buscaglia Date: Fri, 9 Jan 2026 15:01:18 +0100 Subject: [PATCH 032/337] feat: add AI skills pack for Claude Code and OpenCode (#9728) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rubén De la Torre Vico Co-authored-by: Adrián Jesús Peña Rodríguez Co-authored-by: Pepe Fagoaga --- .github/workflows/sdk-code-quality.yml | 4 +- .gitignore | 9 + .pre-commit-config.yaml | 9 +- AGENTS.md | 150 +++---- README.md | 39 ++ api/AGENTS.md | 137 ++++++ docs/developer-guide/ai-skills.mdx | 216 ++++++++++ docs/docs.json | 3 +- mcp_server/AGENTS.md | 306 ++----------- prowler/AGENTS.md | 401 ++++-------------- prowler/CHANGELOG.md | 1 + skills/README.md | 127 ++++++ skills/ai-sdk-5/SKILL.md | 234 ++++++++++ skills/django-drf/SKILL.md | 184 ++++++++ skills/nextjs-15/SKILL.md | 148 +++++++ skills/playwright/SKILL.md | 324 ++++++++++++++ skills/playwright/references/prowler-e2e.md | 16 + skills/prowler-api/SKILL.md | 137 ++++++ skills/prowler-api/references/api-docs.md | 21 + skills/prowler-compliance/SKILL.md | 113 +++++ .../assets/cis_framework.json | 76 ++++ .../references/compliance-docs.md | 15 + skills/prowler-docs/SKILL.md | 122 ++++++ .../references/documentation-docs.md | 15 + skills/prowler-mcp/SKILL.md | 78 ++++ skills/prowler-mcp/assets/base_tool.py | 62 +++ skills/prowler-mcp/assets/models.py | 146 +++++++ .../prowler-mcp/assets/tool_implementation.py | 95 +++++ skills/prowler-pr/SKILL.md | 125 ++++++ skills/prowler-pr/references/pr-docs.md | 15 + skills/prowler-provider/SKILL.md | 143 +++++++ skills/prowler-provider/assets/client.py | 56 +++ skills/prowler-provider/assets/provider.py | 143 +++++++ skills/prowler-provider/assets/service.py | 119 ++++++ .../references/provider-docs.md | 28 ++ skills/prowler-sdk-check/SKILL.md | 257 +++++++++++ skills/prowler-sdk-check/assets/aws_check.py | 20 + .../assets/aws_metadata.json | 35 ++ .../prowler-sdk-check/assets/azure_check.py | 25 ++ .../assets/azure_metadata.json | 33 ++ skills/prowler-sdk-check/assets/gcp_check.py | 29 ++ .../assets/gcp_metadata.json | 37 ++ .../references/metadata-docs.md | 19 + skills/prowler-test-api/SKILL.md | 118 ++++++ .../references/test-api-docs.md | 18 + skills/prowler-test-sdk/SKILL.md | 321 ++++++++++++++ skills/prowler-test-sdk/assets/aws_test.py | 149 +++++++ skills/prowler-test-sdk/assets/azure_test.py | 137 ++++++ skills/prowler-test-sdk/assets/gcp_test.py | 126 ++++++ .../references/testing-docs.md | 17 + skills/prowler-test-ui/SKILL.md | 190 +++++++++ skills/prowler-test-ui/references/e2e-docs.md | 17 + skills/prowler-ui/SKILL.md | 210 +++++++++ skills/prowler-ui/references/ui-docs.md | 14 + skills/prowler/SKILL.md | 63 +++ skills/prowler/references/prowler-docs.md | 14 + skills/pytest/SKILL.md | 192 +++++++++ skills/pytest/references/prowler-testing.md | 16 + skills/react-19/SKILL.md | 122 ++++++ skills/setup.sh | 119 ++++++ skills/skill-creator/SKILL.md | 169 ++++++++ skills/skill-creator/assets/SKILL-TEMPLATE.md | 78 ++++ skills/tailwind-4/SKILL.md | 197 +++++++++ skills/typescript/SKILL.md | 108 +++++ skills/zod-4/SKILL.md | 214 ++++++++++ skills/zustand-5/SKILL.md | 220 ++++++++++ ui/AGENTS.md | 193 +++------ 67 files changed, 6486 insertions(+), 808 deletions(-) create mode 100644 api/AGENTS.md create mode 100644 docs/developer-guide/ai-skills.mdx create mode 100644 skills/README.md create mode 100644 skills/ai-sdk-5/SKILL.md create mode 100644 skills/django-drf/SKILL.md create mode 100644 skills/nextjs-15/SKILL.md create mode 100644 skills/playwright/SKILL.md create mode 100644 skills/playwright/references/prowler-e2e.md create mode 100644 skills/prowler-api/SKILL.md create mode 100644 skills/prowler-api/references/api-docs.md create mode 100644 skills/prowler-compliance/SKILL.md create mode 100644 skills/prowler-compliance/assets/cis_framework.json create mode 100644 skills/prowler-compliance/references/compliance-docs.md create mode 100644 skills/prowler-docs/SKILL.md create mode 100644 skills/prowler-docs/references/documentation-docs.md create mode 100644 skills/prowler-mcp/SKILL.md create mode 100644 skills/prowler-mcp/assets/base_tool.py create mode 100644 skills/prowler-mcp/assets/models.py create mode 100644 skills/prowler-mcp/assets/tool_implementation.py create mode 100644 skills/prowler-pr/SKILL.md create mode 100644 skills/prowler-pr/references/pr-docs.md create mode 100644 skills/prowler-provider/SKILL.md create mode 100644 skills/prowler-provider/assets/client.py create mode 100644 skills/prowler-provider/assets/provider.py create mode 100644 skills/prowler-provider/assets/service.py create mode 100644 skills/prowler-provider/references/provider-docs.md create mode 100644 skills/prowler-sdk-check/SKILL.md create mode 100644 skills/prowler-sdk-check/assets/aws_check.py create mode 100644 skills/prowler-sdk-check/assets/aws_metadata.json create mode 100644 skills/prowler-sdk-check/assets/azure_check.py create mode 100644 skills/prowler-sdk-check/assets/azure_metadata.json create mode 100644 skills/prowler-sdk-check/assets/gcp_check.py create mode 100644 skills/prowler-sdk-check/assets/gcp_metadata.json create mode 100644 skills/prowler-sdk-check/references/metadata-docs.md create mode 100644 skills/prowler-test-api/SKILL.md create mode 100644 skills/prowler-test-api/references/test-api-docs.md create mode 100644 skills/prowler-test-sdk/SKILL.md create mode 100644 skills/prowler-test-sdk/assets/aws_test.py create mode 100644 skills/prowler-test-sdk/assets/azure_test.py create mode 100644 skills/prowler-test-sdk/assets/gcp_test.py create mode 100644 skills/prowler-test-sdk/references/testing-docs.md create mode 100644 skills/prowler-test-ui/SKILL.md create mode 100644 skills/prowler-test-ui/references/e2e-docs.md create mode 100644 skills/prowler-ui/SKILL.md create mode 100644 skills/prowler-ui/references/ui-docs.md create mode 100644 skills/prowler/SKILL.md create mode 100644 skills/prowler/references/prowler-docs.md create mode 100644 skills/pytest/SKILL.md create mode 100644 skills/pytest/references/prowler-testing.md create mode 100644 skills/react-19/SKILL.md create mode 100755 skills/setup.sh create mode 100644 skills/skill-creator/SKILL.md create mode 100644 skills/skill-creator/assets/SKILL-TEMPLATE.md create mode 100644 skills/tailwind-4/SKILL.md create mode 100644 skills/typescript/SKILL.md create mode 100644 skills/zod-4/SKILL.md create mode 100644 skills/zustand-5/SKILL.md diff --git a/.github/workflows/sdk-code-quality.yml b/.github/workflows/sdk-code-quality.yml index 49f01f7fab..068b482f1c 100644 --- a/.github/workflows/sdk-code-quality.yml +++ b/.github/workflows/sdk-code-quality.yml @@ -79,11 +79,11 @@ jobs: - name: Lint with flake8 if: steps.check-changes.outputs.any_changed == 'true' - run: poetry run flake8 . --ignore=E266,W503,E203,E501,W605,E128 --exclude contrib,ui,api + run: poetry run flake8 . --ignore=E266,W503,E203,E501,W605,E128 --exclude contrib,ui,api,skills - name: Check format with black if: steps.check-changes.outputs.any_changed == 'true' - run: poetry run black --exclude api ui --check . + run: poetry run black --exclude api ui skills --check . - name: Lint with pylint if: steps.check-changes.outputs.any_changed == 'true' diff --git a/.gitignore b/.gitignore index e1f49be87c..ffad8a7d37 100644 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,9 @@ continue.json .continuerc .continuerc.json +# AI Coding Assistants - OpenCode +opencode.json + # AI Coding Assistants - GitHub Copilot .copilot/ .github/copilot/ @@ -152,3 +155,9 @@ CLAUDE.md # Compliance report *.pdf + +# AI Skills symlinks (generated by skills/setup.sh) +.claude/skills +.codex/skills +.github/skills +.gemini/skills diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ea9954f082..24f8f0f211 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,6 +34,7 @@ repos: rev: v2.3.1 hooks: - id: autoflake + exclude: ^skills/ args: [ "--in-place", @@ -45,18 +46,20 @@ repos: rev: 5.13.2 hooks: - id: isort + exclude: ^skills/ args: ["--profile", "black"] - repo: https://github.com/psf/black rev: 24.4.2 hooks: - id: black + exclude: ^skills/ - repo: https://github.com/pycqa/flake8 rev: 7.0.0 hooks: - id: flake8 - exclude: contrib + exclude: (contrib|^skills/) args: ["--ignore=E266,W503,E203,E501,W605"] - repo: https://github.com/python-poetry/poetry @@ -109,7 +112,7 @@ repos: - id: bandit name: bandit description: "Bandit is a tool for finding common security issues in Python code" - entry: bash -c 'bandit -q -lll -x '*_test.py,./contrib/,./.venv/' -r .' + entry: bash -c 'bandit -q -lll -x '*_test.py,./contrib/,./.venv/,./skills/' -r .' language: system files: '.*\.py' @@ -123,7 +126,7 @@ repos: - id: vulture name: vulture description: "Vulture finds unused code in Python programs." - entry: bash -c 'vulture --exclude "contrib,.venv,api/src/backend/api/tests/,api/src/backend/conftest.py,api/src/backend/tasks/tests/" --min-confidence 100 .' + entry: bash -c 'vulture --exclude "contrib,.venv,api/src/backend/api/tests/,api/src/backend/conftest.py,api/src/backend/tasks/tests/,skills/" --min-confidence 100 .' language: system files: '.*\.py' diff --git a/AGENTS.md b/AGENTS.md index c6a6027c18..a982b82fae 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,109 +2,83 @@ ## How to Use This Guide -- Start here for cross-project norms, Prowler is a monorepo with several components. Every component should have an `AGENTS.md` file that contains the guidelines for the agents in that component. The file is located beside the code you are touching (e.g. `api/AGENTS.md`, `ui/AGENTS.md`, `prowler/AGENTS.md`). -- Follow the stricter rule when guidance conflicts; component docs override this file for their scope. -- Keep instructions synchronized. When you add new workflows or scripts, update both, the relevant component `AGENTS.md` and this file if they apply broadly. +- Start here for cross-project norms. Prowler is a monorepo with several components. +- Each component has an `AGENTS.md` file with specific guidelines (e.g., `api/AGENTS.md`, `ui/AGENTS.md`). +- Component docs override this file when guidance conflicts. + +## Available Skills + +Use these skills for detailed patterns on-demand: + +### Generic Skills (Any Project) +| Skill | Description | URL | +|-------|-------------|-----| +| `typescript` | Const types, flat interfaces, utility types | [SKILL.md](skills/typescript/SKILL.md) | +| `react-19` | No useMemo/useCallback, React Compiler | [SKILL.md](skills/react-19/SKILL.md) | +| `nextjs-15` | App Router, Server Actions, streaming | [SKILL.md](skills/nextjs-15/SKILL.md) | +| `tailwind-4` | cn() utility, no var() in className | [SKILL.md](skills/tailwind-4/SKILL.md) | +| `playwright` | Page Object Model, MCP workflow, selectors | [SKILL.md](skills/playwright/SKILL.md) | +| `pytest` | Fixtures, mocking, markers, parametrize | [SKILL.md](skills/pytest/SKILL.md) | +| `django-drf` | ViewSets, Serializers, Filters | [SKILL.md](skills/django-drf/SKILL.md) | +| `zod-4` | New API (z.email(), z.uuid()) | [SKILL.md](skills/zod-4/SKILL.md) | +| `zustand-5` | Persist, selectors, slices | [SKILL.md](skills/zustand-5/SKILL.md) | +| `ai-sdk-5` | UIMessage, streaming, LangChain | [SKILL.md](skills/ai-sdk-5/SKILL.md) | + +### Prowler-Specific Skills +| Skill | Description | URL | +|-------|-------------|-----| +| `prowler` | Project overview, component navigation | [SKILL.md](skills/prowler/SKILL.md) | +| `prowler-api` | Django + RLS + JSON:API patterns | [SKILL.md](skills/prowler-api/SKILL.md) | +| `prowler-ui` | Next.js + shadcn conventions | [SKILL.md](skills/prowler-ui/SKILL.md) | +| `prowler-sdk-check` | Create new security checks | [SKILL.md](skills/prowler-sdk-check/SKILL.md) | +| `prowler-mcp` | MCP server tools and models | [SKILL.md](skills/prowler-mcp/SKILL.md) | +| `prowler-test-sdk` | SDK testing (pytest + moto) | [SKILL.md](skills/prowler-test-sdk/SKILL.md) | +| `prowler-test-api` | API testing (pytest-django + RLS) | [SKILL.md](skills/prowler-test-api/SKILL.md) | +| `prowler-test-ui` | E2E testing (Playwright) | [SKILL.md](skills/prowler-test-ui/SKILL.md) | +| `prowler-compliance` | Compliance framework structure | [SKILL.md](skills/prowler-compliance/SKILL.md) | +| `prowler-provider` | Add new cloud providers | [SKILL.md](skills/prowler-provider/SKILL.md) | +| `prowler-pr` | Pull request conventions | [SKILL.md](skills/prowler-pr/SKILL.md) | +| `prowler-docs` | Documentation style guide | [SKILL.md](skills/prowler-docs/SKILL.md) | +| `skill-creator` | Create new AI agent skills | [SKILL.md](skills/skill-creator/SKILL.md) | + +--- ## Project Overview -Prowler is an open-source cloud security assessment tool that supports multiple cloud providers (AWS, Azure, GCP, Kubernetes, GitHub, M365, etc.). The project consists in a monorepo with the following main components: +Prowler is an open-source cloud security assessment tool supporting AWS, Azure, GCP, Kubernetes, GitHub, M365, and more. -- **Prowler SDK**: Python SDK, includes the Prowler CLI, providers, services, checks, compliances, config, etc. (`prowler/`) -- **Prowler API**: Django-based REST API backend (`api/`) -- **Prowler UI**: Next.js frontend application (`ui/`) -- **Prowler MCP Server**: Model Context Protocol server that gives access to the entire Prowler ecosystem for LLMs (`mcp_server/`) -- **Prowler Dashboard**: Prowler CLI feature that allows to visualize the results of the scans in a simple dashboard (`dashboard/`) +| Component | Location | Tech Stack | +|-----------|----------|------------| +| SDK | `prowler/` | Python 3.9+, Poetry | +| API | `api/` | Django 5.1, DRF, Celery | +| UI | `ui/` | Next.js 15, React 19, Tailwind 4 | +| MCP Server | `mcp_server/` | FastMCP, Python 3.12+ | +| Dashboard | `dashboard/` | Dash, Plotly | -### Project Structure (Key Folders & Files) - -- `prowler/`: Main source code for Prowler SDK (CLI, providers, services, checks, compliances, config, etc.) -- `api/`: Django-based REST API backend components -- `ui/`: Next.js frontend application -- `mcp_server/`: Model Context Protocol server that gives access to the entire Prowler ecosystem for LLMs -- `dashboard/`: Prowler CLI feature that allows to visualize the results of the scans in a simple dashboard -- `docs/`: Documentation -- `examples/`: Example output formats for providers and scripts -- `permissions/`: Permission-related files and policies -- `contrib/`: Community-contributed scripts or modules -- `tests/`: Prowler SDK test suite -- `docker-compose.yml`: Docker compose file to run the Prowler App (API + UI) production environment -- `docker-compose-dev.yml`: Docker compose file to run the Prowler App (API + UI) development environment -- `pyproject.toml`: Poetry Prowler SDK project file -- `.pre-commit-config.yaml`: Pre-commit hooks configuration -- `Makefile`: Makefile to run the project -- `LICENSE`: License file -- `README.md`: README file -- `CONTRIBUTING.md`: Contributing guide +--- ## Python Development -Most of the code is written in Python, so the main files in the root are focused on Python code. - -### Poetry Dev Environment - -For developing in Python we recommend using `poetry` to manage the dependencies. The minimal version is `2.1.1`. So it is recommended to run all commands using `poetry run ...`. - -To install the core dependencies to develop it is needed to run `poetry install --with dev`. - -### Pre-commit hooks - -The project has pre-commit hooks to lint and format the code. They are installed by running `poetry run pre-commit install`. - -When commiting a change, the hooks will be run automatically. Some of them are: - -- Code formatting (black, isort) -- Linting (flake8, pylint) -- Security checks (bandit, safety, trufflehog) -- YAML/JSON validation -- Poetry lock file validation - - -### Linting and Formatting - -We use the following tools to lint and format the code: - -- `flake8`: for linting the code -- `black`: for formatting the code -- `pylint`: for linting the code - -You can run all using the `make` command: ```bash +# Setup +poetry install --with dev +poetry run pre-commit install + +# Code quality poetry run make lint poetry run make format +poetry run pre-commit run --all-files ``` -Or they will be run automatically when you commit your changes using pre-commit hooks. +--- ## Commit & Pull Request Guidelines -For the commit messages and pull requests name follow the conventional-commit style. +Follow conventional-commit style: `[scope]: ` -Befire creating a pull request, complete the checklist in `.github/pull_request_template.md`. Summaries should explain deployment impact, highlight review steps, and note changelog or permission updates. Run all relevant tests and linters before requesting review and link screenshots for UI or dashboard changes. +**Types:** `feat`, `fix`, `docs`, `chore`, `perf`, `refactor`, `style`, `test` -### Conventional Commit Style - -The Conventional Commits specification is a lightweight convention on top of commit messages. It provides an easy set of rules for creating an explicit commit history; which makes it easier to write automated tools on top of. - -The commit message should be structured as follows: - -``` -[optional scope]: - -[optional body] - -[optional footer(s)] -``` - -Any line of the commit message cannot be longer 100 characters! This allows the message to be easier to read on GitHub as well as in various git tools - -#### Commit Types - -- **feat**: code change introuce new functionality to the application -- **fix**: code change that solve a bug in the codebase -- **docs**: documentation only changes -- **chore**: changes related to the build process or auxiliary tools and libraries, that do not affect the application's functionality -- **perf**: code change that improves performance -- **refactor**: code change that neither fixes a bug nor adds a feature -- **style**: changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) -- **test**: adding missing tests or correcting existing tests +Before creating a PR: +1. Complete checklist in `.github/pull_request_template.md` +2. Run all relevant tests and linters +3. Link screenshots for UI changes diff --git a/README.md b/README.md index a1e71e23be..bdf08ee20a 100644 --- a/README.md +++ b/README.md @@ -310,6 +310,45 @@ And many more environments.  +# 🤖 AI Skills for Development + +Prowler includes a comprehensive set of **AI Skills** that help AI coding assistants understand Prowler's codebase patterns and conventions. + +## What are AI Skills? + +Skills are structured instructions that give AI assistants the context they need to write code that follows Prowler's standards. They include: + +- **Coding patterns** for each component (SDK, API, UI, MCP Server) +- **Testing conventions** (pytest, Playwright) +- **Architecture guidelines** (Clean Architecture, RLS patterns) +- **Framework-specific rules** (React 19, Next.js 15, Django DRF, Tailwind 4) + +## Available Skills + +| Category | Skills | +|----------|--------| +| **Generic** | `typescript`, `react-19`, `nextjs-15`, `tailwind-4`, `playwright`, `pytest`, `django-drf`, `zod-4`, `zustand-5`, `ai-sdk-5` | +| **Prowler** | `prowler`, `prowler-api`, `prowler-ui`, `prowler-mcp`, `prowler-sdk-check`, `prowler-test-ui`, `prowler-test-api`, `prowler-test-sdk`, `prowler-compliance`, `prowler-provider`, `prowler-pr`, `prowler-docs` | + +## Setup + +```bash +./skills/setup.sh +``` + +This configures skills for AI coding assistants that follow the [agentskills.io](https://agentskills.io) standard: + +| Tool | Configuration | +|------|---------------| +| **Claude Code** | `.claude/skills/` (symlink) | +| **OpenCode** | `.claude/skills/` (symlink) | +| **Codex (OpenAI)** | `.codex/skills/` (symlink) | +| **GitHub Copilot** | `.github/skills/` (symlink) | +| **Gemini CLI** | `.gemini/skills/` (symlink) | + +> **Note:** Restart your AI coding assistant after running setup to load the skills. +> Gemini CLI requires `experimental.skills` enabled in settings. + # 📖 Documentation For installation instructions, usage details, tutorials, and the Developer Guide, visit https://docs.prowler.com/ diff --git a/api/AGENTS.md b/api/AGENTS.md new file mode 100644 index 0000000000..9ae73401c6 --- /dev/null +++ b/api/AGENTS.md @@ -0,0 +1,137 @@ +# Prowler API - AI Agent Ruleset + +> **Skills Reference**: For detailed patterns, use these skills: +> - [`prowler-api`](../skills/prowler-api/SKILL.md) - Models, Serializers, Views, RLS patterns +> - [`prowler-test-api`](../skills/prowler-test-api/SKILL.md) - Testing patterns (pytest-django) +> - [`django-drf`](../skills/django-drf/SKILL.md) - Generic DRF patterns +> - [`pytest`](../skills/pytest/SKILL.md) - Generic pytest patterns + +## CRITICAL RULES - NON-NEGOTIABLE + +### Models +- ALWAYS: UUIDv4 PKs, `inserted_at`/`updated_at` timestamps, `JSONAPIMeta` class +- ALWAYS: Inherit from `RowLevelSecurityProtectedModel` for tenant-scoped data +- NEVER: Auto-increment integer PKs, models without tenant isolation + +### Serializers +- ALWAYS: Separate serializers for Create/Update operations +- ALWAYS: Inherit from `RLSSerializer` for tenant-scoped models +- NEVER: Write logic in serializers (use services/utils) + +### Views +- ALWAYS: Inherit from `BaseRLSViewSet` for tenant-scoped resources +- ALWAYS: Define `filterset_class`, use `@extend_schema` for OpenAPI +- NEVER: Raw SQL queries, business logic in views + +### Row-Level Security (RLS) +- ALWAYS: Use `rls_transaction(tenant_id)` context manager +- NEVER: Query across tenants, trust client-provided tenant_id + +### Celery Tasks +- ALWAYS: `@shared_task` with `name`, `queue`, `RLSTask` base class +- NEVER: Long-running ops in views, request context in tasks + +--- + +## DECISION TREES + +### Serializer Selection +``` +Read → Serializer +Create → CreateSerializer +Update → UpdateSerializer +Nested read → IncludeSerializer +``` + +### Task vs View +``` +< 100ms → View +> 100ms or external API → Celery task +Needs retry → Celery task +``` + +--- + +## TECH STACK + +Django 5.1.x | DRF 3.15.x | djangorestframework-jsonapi 7.x | Celery 5.4.x | PostgreSQL 16 | pytest 8.x + +--- + +## PROJECT STRUCTURE + +``` +api/src/backend/ +├── api/ # Main Django app +│ ├── v1/ # API version 1 (views, serializers, urls) +│ ├── models.py # Django models +│ ├── filters.py # FilterSet classes +│ ├── base_views.py # Base ViewSet classes +│ ├── rls.py # Row-Level Security +│ └── tests/ # Unit tests +├── config/ # Django configuration +└── tasks/ # Celery tasks +``` + +--- + +## COMMANDS + +```bash +# Development +poetry run python src/backend/manage.py runserver +poetry run celery -A config.celery worker -l INFO + +# Database +poetry run python src/backend/manage.py makemigrations +poetry run python src/backend/manage.py migrate + +# Testing & Linting +poetry run pytest -x --tb=short +poetry run make lint +``` + +--- + +## QA CHECKLIST + +- [ ] `poetry run pytest` passes +- [ ] `poetry run make lint` passes +- [ ] Migrations created if models changed +- [ ] New endpoints have `@extend_schema` decorators +- [ ] RLS properly applied for tenant data +- [ ] Tests cover success and error cases + +--- + +## NAMING CONVENTIONS + +| Entity | Pattern | Example | +|--------|---------|---------| +| Serializer (read) | `Serializer` | `ProviderSerializer` | +| Serializer (create) | `CreateSerializer` | `ProviderCreateSerializer` | +| Serializer (update) | `UpdateSerializer` | `ProviderUpdateSerializer` | +| Filter | `Filter` | `ProviderFilter` | +| ViewSet | `ViewSet` | `ProviderViewSet` | +| Task | `__task` | `sync_provider_resources_task` | + +--- + +## API CONVENTIONS (JSON:API) + +```json +{ + "data": { + "type": "providers", + "id": "uuid", + "attributes": { "name": "value" }, + "relationships": { "tenant": { "data": { "type": "tenants", "id": "uuid" } } } + } +} +``` + +- Content-Type: `application/vnd.api+json` +- Pagination: `?page[number]=1&page[size]=20` +- Filtering: `?filter[field]=value`, `?filter[field__in]=val1,val2` +- Sorting: `?sort=field`, `?sort=-field` +- Including: `?include=provider,findings` diff --git a/docs/developer-guide/ai-skills.mdx b/docs/developer-guide/ai-skills.mdx new file mode 100644 index 0000000000..d595c3ab11 --- /dev/null +++ b/docs/developer-guide/ai-skills.mdx @@ -0,0 +1,216 @@ +--- +title: 'AI Skills System' +--- + +This guide explains the AI Skills system that provides on-demand context and patterns to AI agents working with the Prowler codebase. + + +**What are AI Skills?** Skills are structured instructions that help AI agents (Claude Code, Cursor, Copilot, etc.) understand Prowler's conventions, patterns, and best practices. + + +## Architecture Overview + +```mermaid +graph LR + subgraph FLOW["AI Skills Architecture"] + A["AI Agent"] -->|"1. matches trigger"| B["AGENTS.md"] + B -->|"2. loads"| C["Skill"] + C -->|"3. provides"| D["PatternsTemplatesCommands"] + C -->|"4. references"| E["Local Docs"] + D --> F["Correct Output"] + E --> F + end + + style A fill:#1e3a5f,stroke:#4a9eff,color:#fff + style B fill:#5c4d1a,stroke:#ffd700,color:#fff + style C fill:#1a4d1a,stroke:#4caf50,color:#fff + style E fill:#4a1a4d,stroke:#ba68c8,color:#fff + style F fill:#1a4d2e,stroke:#66bb6a,color:#fff +``` + +## How It Works + +```mermaid +sequenceDiagram + participant U as User + participant A as AI Agent + participant R as AGENTS.md + participant S as Skill + participant AS as assets/ + participant RF as references/ + participant D as Local Docs + + U->>A: "Create an AWS security check" + + Note over A: Analyze request context + + A->>R: Find matching skill trigger + R-->>A: prowler-sdk-check matches + + A->>S: Load SKILL.md + S-->>A: Patterns, rules, templates, commands + + Note over A: Need code template? + + A->>AS: Read assets/aws_check.py + AS-->>A: Check implementation template + + Note over A: Need more details? + + A->>RF: Read references/metadata-docs.md + RF-->>A: Points to local docs + + A->>D: Read docs/developer-guide/checks.mdx + D-->>A: Full documentation + + Note over A: Execute with full context + + A->>U: Creates check with correct patterns +``` + +## Before vs After + +```mermaid +graph TD + subgraph COMPARISON["BEFORE vs AFTER"] + direction LR + + subgraph BEFORE["Without Skills"] + B1["AI guesses conventions"] + B2["Wrong structure"] + B3["Multiple iterations"] + B4["Web searches for docs"] + B5["Inconsistent patterns"] + end + + subgraph AFTER["With Skills"] + A1["AI loads exact patterns"] + A2["Correct structure"] + A3["First-time right"] + A4["Local docs referenced"] + A5["Consistent patterns"] + end + end + + style BEFORE fill:#5c1a1a,stroke:#ef5350,color:#fff + style AFTER fill:#1a4d1a,stroke:#66bb6a,color:#fff +``` + +## Complete Architecture + +```mermaid +flowchart TB + subgraph ENTRY["ENTRY POINT"] + AGENTS["AGENTS.md━━━━━━━━━━━━━━━━━• Available skills registry• Skill → Trigger mapping• Component navigation"] + end + + subgraph SKILLS["SKILLS LIBRARY"] + direction TB + + subgraph GENERIC["Generic Skills"] + G1["typescript"] + G2["react-19"] + G3["nextjs-15"] + G4["tailwind-4"] + G5["pytest"] + G6["playwright"] + G7["django-drf"] + G8["zod-4"] + G9["zustand-5"] + G10["ai-sdk-5"] + end + + subgraph PROWLER["Prowler Skills"] + P1["prowler"] + P2["prowler-sdk-check"] + P3["prowler-api"] + P4["prowler-ui"] + P5["prowler-mcp"] + P6["prowler-provider"] + P7["prowler-compliance"] + P8["prowler-docs"] + P9["prowler-pr"] + end + + subgraph TESTING["Testing Skills"] + T1["prowler-test-sdk"] + T2["prowler-test-api"] + T3["prowler-test-ui"] + end + + subgraph META["Meta Skills"] + M1["skill-creator"] + end + end + + subgraph STRUCTURE["SKILL STRUCTURE"] + direction LR + + SKILLMD["SKILL.md━━━━━━━━━━━━━━• Frontmatter• Critical patterns• Decision trees• Code examples• Commands• Keywords"] + + ASSETS["assets/━━━━━━━━━━━━━━• Code templates• JSON schemas• Config examples"] + + REFS["references/━━━━━━━━━━━━━━• Local doc paths• No web URLs• Single source"] + end + + subgraph DOCS["DOCUMENTATION"] + direction TB + DD["docs/developer-guide/"] + D1["checks.mdx"] + D2["unit-testing.mdx"] + D3["provider.mdx"] + D4["mcp-server.mdx"] + D5["..."] + + DD --> D1 + DD --> D2 + DD --> D3 + DD --> D4 + DD --> D5 + end + + ENTRY --> SKILLS + SKILLS --> STRUCTURE + SKILLMD --> ASSETS + SKILLMD --> REFS + REFS -.->|"points to"| DOCS + + style ENTRY fill:#1e3a5f,stroke:#4a9eff,color:#fff + style GENERIC fill:#5c4d1a,stroke:#ffd700,color:#fff + style PROWLER fill:#1a4d1a,stroke:#66bb6a,color:#fff + style TESTING fill:#4d1a3d,stroke:#f06292,color:#fff + style META fill:#4a1a4d,stroke:#ba68c8,color:#fff + style STRUCTURE fill:#5c3d1a,stroke:#ffb74d,color:#fff + style DOCS fill:#1a3d4d,stroke:#4dd0e1,color:#fff +``` + +## Skills Included + +| Type | Skills | +|------|--------| +| **Generic** | typescript, react-19, nextjs-15, tailwind-4, pytest, playwright, django-drf, zod-4, zustand-5, ai-sdk-5 | +| **Prowler** | prowler, prowler-sdk-check, prowler-api, prowler-ui, prowler-mcp, prowler-provider, prowler-compliance, prowler-docs, prowler-pr | +| **Testing** | prowler-test-sdk, prowler-test-api, prowler-test-ui | +| **Meta** | skill-creator | + +## Skill Structure + +Each skill follows the [Agent Skills spec](https://agentskills.io): + +``` +skills/{skill-name}/ +├── SKILL.md # Patterns, rules, decision trees +├── assets/ # Code templates, schemas +└── references/ # Links to local docs (single source of truth) +``` + +## Key Design Decisions + +1. **Self-contained skills** - Critical patterns inline for fast loading +2. **Local doc references** - No web URLs, points to `docs/developer-guide/*.mdx` +3. **Single source of truth** - Skills reference docs, no duplication +4. **On-demand loading** - AI loads only what's needed for the task + +## Creating New Skills + +Use the `skill-creator` meta-skill to create new skills that follow the Agent Skills spec. See `AGENTS.md` for the full list of available skills and their triggers. diff --git a/docs/docs.json b/docs/docs.json index 65cf7d3070..f6e5876bb7 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -285,7 +285,8 @@ "developer-guide/integrations", "developer-guide/security-compliance-framework", "developer-guide/lighthouse", - "developer-guide/mcp-server" + "developer-guide/mcp-server", + "developer-guide/ai-skills" ] }, { diff --git a/mcp_server/AGENTS.md b/mcp_server/AGENTS.md index fdc1ce5535..bbefa2db57 100644 --- a/mcp_server/AGENTS.md +++ b/mcp_server/AGENTS.md @@ -1,310 +1,88 @@ # Prowler MCP Server - AI Agent Ruleset -**Complete guide for AI agents and developers working on the Prowler MCP Server - the Model Context Protocol server that provides AI agents access to the Prowler ecosystem.** +> **Skills Reference**: For detailed patterns, use the [`prowler-mcp`](../skills/prowler-mcp/SKILL.md) skill. ## Project Overview -The Prowler MCP Server brings the entire Prowler ecosystem to AI assistants through -the Model Context Protocol (MCP). It enables seamless integration with AI tools -like Claude Desktop, Cursor, and other MCP hosts, allowing interaction with -Prowler's security capabilities through natural language. +The Prowler MCP Server provides AI agents access to the Prowler ecosystem through the Model Context Protocol (MCP). It integrates with Claude Desktop, Cursor, and other MCP hosts. --- -## Critical Rules +## CRITICAL RULES ### Tool Implementation - -- **ALWAYS**: Extend `BaseTool` ABC for new Prowler App tools (auto-registration) -- **ALWAYS**: Use `@mcp.tool()` decorator for Hub/Docs tools (manual registration) -- **NEVER**: Manually register BaseTool subclasses (auto-discovered via `load_all_tools()`) -- **NEVER**: Import tools directly in server.py (tool_loader handles discovery) +- ALWAYS: Extend `BaseTool` ABC for Prowler App tools (auto-registration) +- ALWAYS: Use `@mcp.tool()` decorator for Hub/Docs tools +- NEVER: Manually register BaseTool subclasses +- NEVER: Import tools directly in server.py ### Models - -- **ALWAYS**: Use `MinimalSerializerMixin` for LLM-optimized responses -- **ALWAYS**: Implement `from_api_response()` factory method for API transformations -- **ALWAYS**: Use two-tier models (Simplified for lists, Detailed for single items) -- **NEVER**: Return raw API responses (transform to simplified models) +- ALWAYS: Use `MinimalSerializerMixin` for LLM-optimized responses +- ALWAYS: Implement `from_api_response()` factory method +- ALWAYS: Two-tier models (Simplified for lists, Detailed for single items) +- NEVER: Return raw API responses ### API Client - -- **ALWAYS**: Use singleton `ProwlerAPIClient` via `self.api_client` in tools -- **ALWAYS**: Use `build_filter_params()` for query parameter normalization -- **NEVER**: Create new httpx clients in tools (use shared client) +- ALWAYS: Use singleton `ProwlerAPIClient` via `self.api_client` +- ALWAYS: Use `build_filter_params()` for query parameters +- NEVER: Create new httpx clients in tools --- -## Architecture +## ARCHITECTURE -### Three Sub-Servers Pattern - -The main server (`server.py`) orchestrates three independent sub-servers with prefixed tool namespacing: +### Three Sub-Servers ```python -# server.py imports sub-servers with prefixes await prowler_mcp_server.import_server(hub_mcp_server, prefix="prowler_hub") await prowler_mcp_server.import_server(app_mcp_server, prefix="prowler_app") await prowler_mcp_server.import_server(docs_mcp_server, prefix="prowler_docs") ``` -This pattern ensures: -- Failures in one sub-server do not block others -- Clear tool namespacing for LLM disambiguation -- Independent development and testing - -### Tool Naming Convention - -All tools follow a consistent naming pattern with prefixes: -- `prowler_hub_*` - Prowler Hub catalog and compliance tools -- `prowler_docs_*` - Prowler documentation search and retrieval -- `prowler_app_*` - Prowler Cloud and App (Self-Managed) management tools - -### Tool Registration Patterns - -**Pattern 1: Prowler Hub/Docs (Direct Decorators)** - -```python -# prowler_hub/server.py or prowler_documentation/server.py -hub_mcp_server = FastMCP("prowler-hub") - -@hub_mcp_server.tool() -async def get_checks(providers: str | None = None) -> dict: - """Tool docstring becomes LLM description.""" - # Direct implementation - response = prowler_hub_client.get("/check", params=params) - return response.json() -``` - -**Pattern 2: Prowler App (BaseTool Auto-Registration)** - -```python -# prowler_app/tools/findings.py -class FindingsTools(BaseTool): - async def search_security_findings( - self, - severity: list[str] = Field(default=[], description="Filter by severity") - ) -> dict: - """Docstring becomes LLM description.""" - response = await self.api_client.get("/api/v1/findings") - return SimplifiedFinding.from_api_response(response).model_dump() -``` - -NOTE: Only public methods of `BaseTool` subclasses are registered as tools. +### Tool Naming +- `prowler_hub_*` - Catalog and compliance (no auth) +- `prowler_docs_*` - Documentation search (no auth) +- `prowler_app_*` - Cloud/App management (auth required) --- -## Tech Stack +## TECH STACK -- **Language**: Python 3.12+ -- **MCP Framework**: FastMCP 2.13.1 -- **HTTP Client**: httpx (async) -- **Validation**: Pydantic with MinimalSerializerMixin -- **Package Manager**: uv +Python 3.12+ | FastMCP 2.13.1 | httpx (async) | Pydantic | uv --- -## Project Structure +## PROJECT STRUCTURE ``` -mcp_server/ -├── README.md # User documentation -├── AGENTS.md # This file - AI agent guidelines -├── CHANGELOG.md # Version history -├── pyproject.toml # Project metadata and dependencies -├── Dockerfile # Container image definition -├── entrypoint.sh # Docker entrypoint script -└── prowler_mcp_server/ - ├── __init__.py # Version info - ├── main.py # CLI entry point - ├── server.py # Main FastMCP server orchestration - ├── lib/ - │ └── logger.py # Structured logging - ├── prowler_hub/ - │ └── server.py # Hub tools (10 tools, no auth) - ├── prowler_app/ - │ ├── server.py # App server initialization - │ ├── tools/ - │ │ ├── base.py # BaseTool abstract class - │ │ ├── findings.py # Findings tools - │ │ ├── providers.py # Provider tools - │ │ ├── scans.py # Scan tools - │ │ ├── resources.py # Resource tools - │ │ └── muting.py # Muting tools - │ ├── models/ - │ │ ├── base.py # MinimalSerializerMixin - │ │ ├── findings.py # Finding models - │ │ ├── providers.py # Provider models - │ │ ├── scans.py # Scan models - │ │ ├── resources.py # Resource models - │ │ └── muting.py # Muting models - │ └── utils/ - │ ├── api_client.py # ProwlerAPIClient singleton - │ ├── auth.py # ProwlerAppAuth (STDIO/HTTP) - │ └── tool_loader.py # Auto-discovery and registration - └── prowler_documentation/ - ├── server.py # Documentation tools (2 tools, no auth) - └── search_engine.py # Mintlify API integration +mcp_server/prowler_mcp_server/ +├── server.py # Main orchestration +├── prowler_hub/server.py # Hub tools (no auth) +├── prowler_app/ +│ ├── server.py +│ ├── tools/{feature}.py # BaseTool subclasses +│ ├── models/{feature}.py # Pydantic models +│ └── utils/api_client.py # ProwlerAPIClient +└── prowler_documentation/ + └── server.py # Docs tools (no auth) ``` --- -## Commands - -NOTE: To run a python command always use `uv run ` from within the `mcp_server/` directory. - -### Development +## COMMANDS ```bash -# Navigate to MCP server directory -cd mcp_server - -# Run in STDIO mode (default) -uv run prowler-mcp - -# Run in HTTP mode -uv run prowler-mcp --transport http --host 0.0.0.0 --port 8000 - -# Run from anywhere using uvx -uvx /path/to/prowler/mcp_server/ +cd mcp_server && uv run prowler-mcp # STDIO mode +cd mcp_server && uv run prowler-mcp --transport http --port 8000 # HTTP mode ``` --- -## Development Patterns +## QA CHECKLIST -### Adding New Tools to Prowler App - -1. **Create or extend a tool class** in `prowler_app/tools/`: - -```python -# prowler_app/tools/new_feature.py -from pydantic import Field -from prowler_mcp_server.prowler_app.tools.base import BaseTool -from prowler_mcp_server.prowler_app.models.new_feature import FeatureResponse - -class NewFeatureTools(BaseTool): - async def list_features( - self, - status: str | None = Field(default=None, description="Filter by status") - ) -> dict: - """List all features with optional filtering. - - Returns a simplified list of features optimized for LLM consumption. - """ - params = {} - if status: - params["filter[status]"] = status - - clean_params = self.api_client.build_filter_params(params) - response = await self.api_client.get("/api/v1/features", params=clean_params) - - return FeatureResponse.from_api_response(response).model_dump() -``` - -2. **Create corresponding models** in `prowler_app/models/`: - -```python -# prowler_app/models/new_feature.py -from pydantic import Field -from prowler_mcp_server.prowler_app.models.base import MinimalSerializerMixin - -class SimplifiedFeature(MinimalSerializerMixin): - """Lightweight feature for list operations.""" - id: str - name: str - status: str - -class DetailedFeature(SimplifiedFeature): - """Extended feature with complete details.""" - description: str | None = None - created_at: str - updated_at: str - - @classmethod - def from_api_response(cls, data: dict) -> "DetailedFeature": - """Transform API response to model.""" - attributes = data.get("attributes", {}) - return cls( - id=data["id"], - name=attributes["name"], - status=attributes["status"], - description=attributes.get("description"), - created_at=attributes["created_at"], - updated_at=attributes["updated_at"], - ) -``` - -3. **No registration needed** - the tool loader auto-discovers BaseTool subclasses - -### Adding Tools to Prowler Hub/Docs - -Use the `@mcp.tool()` decorator directly: - -```python -# prowler_hub/server.py -@hub_mcp_server.tool() -async def new_hub_tool(param: str) -> dict: - """Tool description for LLM.""" - response = prowler_hub_client.get("/endpoint") - return response.json() -``` - ---- - -## Code Quality Standards - -### Tool Docstrings - -Tool docstrings become AI agent descriptions. Write them in a clear, concise manner focusing on LLM-relevant behavior: - -```python -async def search_security_findings( - self, - severity: list[str] = Field(default=[], description="Filter by severity levels") -) -> dict: - """Search security findings with advanced filtering. - - Returns a lightweight list of findings optimized for LLM consumption. - Use get_finding_details for complete information about a specific finding. - """ -``` - -### Model Design - -- Use `MinimalSerializerMixin` to exclude None/empty values -- Implement `from_api_response()` for consistent API transformation -- Create two-tier models: Simplified (lists) and Detailed (single items) - -### Error Handling - -Return structured error responses rather than raising exceptions: - -```python -try: - response = await self.api_client.get(f"/api/v1/items/{item_id}") - return DetailedItem.from_api_response(response["data"]).model_dump() -except Exception as e: - self.logger.error(f"Failed to get item {item_id}: {e}") - return {"error": str(e), "status": "failed"} -``` - ---- - -## QA Checklist Before Commit - -- [ ] Tool docstrings are clear and describe LLM-relevant behavior -- [ ] Models use `MinimalSerializerMixin` for LLM optimization -- [ ] API responses are transformed to simplified models -- [ ] No hardcoded secrets or API keys +- [ ] Tool docstrings describe LLM-relevant behavior +- [ ] Models use `MinimalSerializerMixin` +- [ ] API responses transformed to simplified models +- [ ] No hardcoded secrets - [ ] Error handling returns structured responses -- [ ] New tools are auto-discovered (BaseTool subclass) or properly decorated -- [ ] Parameter descriptions use Pydantic `Field()` with clear descriptions - ---- - -## References - -- **Root Project Guide**: `../AGENTS.md` -- **FastMCP Documentation**: https://gofastmcp.com/llms.txt -- **Prowler API Documentation**: https://api.prowler.com/api/v1/docs +- [ ] Parameter descriptions use Pydantic `Field()` diff --git a/prowler/AGENTS.md b/prowler/AGENTS.md index 0a9fb455e8..86c2244edf 100644 --- a/prowler/AGENTS.md +++ b/prowler/AGENTS.md @@ -1,366 +1,125 @@ # Prowler SDK Agent Guide -**Complete guide for AI agents and developers working on the Prowler SDK - the core Python security scanning engine.** +> **Skills Reference**: For detailed patterns, use these skills: +> - [`prowler-sdk-check`](../skills/prowler-sdk-check/SKILL.md) - Create new security checks (step-by-step) +> - [`prowler-provider`](../skills/prowler-provider/SKILL.md) - Add new cloud providers +> - [`prowler-test-sdk`](../skills/prowler-test-sdk/SKILL.md) - pytest patterns for SDK +> - [`prowler-compliance`](../skills/prowler-compliance/SKILL.md) - Compliance framework structure +> - [`pytest`](../skills/pytest/SKILL.md) - Generic pytest patterns ## Project Overview -The Prowler SDK is the core Python engine that powers Prowler's cloud security assessment capabilities. It provides: - -- **Multi-cloud Security Scanning**: AWS, Azure, GCP, Kubernetes, GitHub, M365, Oracle Cloud, MongoDB Atlas, and more -- **Compliance Frameworks**: 30+ frameworks including CIS, NIST, PCI-DSS, SOC2, GDPR -- **1000+ Security Checks**: Comprehensive coverage across all supported providers -- **Multiple Output Formats**: JSON, CSV, HTML, ASFF, OCSF, and compliance-specific formats - -## Mission & Scope - -- Maintain and enhance the core Prowler SDK functionality with security and stability as top priorities -- Follow best practices for Python patterns, code style, security, and comprehensive testing -- To get more information about development guidelines, please refer to the Prowler Developer Guide in `docs/developer-guide/` +The Prowler SDK is the core Python engine powering cloud security assessments across AWS, Azure, GCP, Kubernetes, GitHub, M365, and more. It includes 1000+ security checks and 30+ compliance frameworks. --- -## Architecture Rules +## CRITICAL RULES -### 1. Provider Architecture Pattern - -All Prowler providers MUST follow the established pattern: +### Provider Architecture ``` prowler/providers/{provider}/ -├── {provider}_provider.py # Main provider class -├── models.py # Provider-specific models -├── config.py # Provider configuration -├── exceptions/ # Provider-specific exceptions -├── lib/ # Provider libraries (as minimun it should have implemented the next folders: service, arguments, mutelist) -│ ├── service/ # Provider-specific service class to be inherited by all services of the provider -│ ├── arguments/ # Provider-specific CLI arguments parser -│ └── mutelist/ # Provider-specific mutelist functionality -└── services/ # All provider services to be audited - └── {service}/ # Individual service - ├── {service}_service.py # Class to fetch the needed resources from the API and store them to be used by the checks - ├── {service}_client.py # Python instance of the service class to be used by the checks - └── {check_name}/ # Individual check folder - ├── {check_name}.py # Python class to implement the check logic - └── {check_name}.metadata.json # JSON file to store the check metadata - └── {check_name_2}/ # Other checks can be added to the same service folder - ├── {check_name_2}.py - └── {check_name_2}.metadata.json - ... - └── {service_2}/ # Other services can be added to the same provider folder - ... +├── {provider}_provider.py # Main provider class +├── models.py # Provider-specific models +├── lib/ # service/, arguments/, mutelist/ +└── services/{service}/ + ├── {service}_service.py # Resource fetcher + ├── {service}_client.py # Singleton instance + └── {check_name}/ # Individual checks + ├── {check_name}.py + └── {check_name}.metadata.json ``` -### 2. Check Implementation Standards - -Every security check MUST implement: +### Check Implementation ```python -from prowler.lib.check.models import Check, CheckReport -from prowler.providers..services.._client import _client +from prowler.lib.check.models import Check, CheckReport{Provider} +from prowler.providers.{provider}.services.{service}.{service}_client import {service}_client -class check_name(Check): - """Ensure that meets .""" - def execute(self) -> list[CheckReport]: - """Execute the check logic. - - Returns: - A list of reports containing the result of the check. - """ +class {check_name}(Check): + def execute(self) -> list[CheckReport{Provider}]: findings = [] - # Check implementation here - for resource in _client.: - # Security validation logic - report = CheckReport(metadata=self.metadata(), resource=resource) - report.status = "PASS" | "FAIL" + for resource in {service}_client.{resources}: + report = CheckReport{Provider}(metadata=self.metadata(), resource=resource) + report.status = "PASS" if resource.is_compliant else "FAIL" report.status_extended = "Detailed explanation" - findings.append(report) # Add the report to the list of findings + findings.append(report) return findings ``` -### 3. Compliance Framework Integration +### Code Style -All compliance frameworks must be defined in: -- `prowler/compliance/{provider}/{framework}.json` -- Follow the established Compliance model structure -- Include proper requirement mappings and metadata +- Type hints required for all public functions +- Docstrings required for classes and methods (Google style) +- PEP 8 compliance enforced by black/flake8 +- Import order: standard → third-party → local --- -## Tech Stack +## TECH STACK -- **Language**: Python 3.9+ -- **Dependency Management**: Poetry 2+ -- **CLI Framework**: Custom argument parser with provider-specific subcommands -- **Testing**: Pytest with extensive unit and integration tests -- **Code Quality**: Pre-commit hooks for Black, Flake8, Pylint, Bandit for security scanning +Python 3.9+ | Poetry 2+ | pytest | moto (AWS mocking) | Pre-commit hooks (black, flake8, pylint, bandit) -## Commands +--- -### Development Environment - -```bash -# Core development setup -poetry install --with dev # Install all dependencies -poetry run pre-commit install # Install pre-commit hooks - -# Code quality -poetry run pre-commit run --all-files - -# Run tests -poetry run pytest -n auto -vvv -s -x tests/ -``` - -### Running Prowler CLI - -```bash -# Run Prowler -poetry run python prowler-cli.py --help - -# Run Prowler with a specific provider -poetry run python prowler-cli.py - -# Run Prowler with error logging -poetry run python prowler-cli.py --log-level ERROR --verbose - -# Run specific checks -poetry run python prowler-cli.py --checks -``` - -## Project Structure +## PROJECT STRUCTURE ``` prowler/ -├── __main__.py # Main CLI entry point -├── config/ # Global configuration -│ ├── config.py # Core configuration settings -│ └── __init__.py -├── lib/ # Core library functions -│ ├── check/ # Check execution engine -│ │ ├── check.py # Check execution logic -│ │ ├── checks_loader.py # Dynamic check loading -│ │ ├── compliance.py # Compliance framework handling -│ │ └── models.py # Check and report models -│ ├── cli/ # Command-line interface -│ │ └── parser.py # Argument parsing -│ ├── outputs/ # Output format handlers -│ │ ├── csv/ # CSV output -│ │ ├── html/ # HTML reports -│ │ ├── json/ # JSON formats -│ │ └── compliance/ # Compliance reports -│ ├── scan/ # Scan orchestration -│ ├── utils/ # Utility functions -│ └── mutelist/ # Mute list functionality -├── providers/ # Cloud provider implementations -│ ├── aws/ # AWS provider -│ ├── azure/ # Azure provider -│ ├── gcp/ # Google Cloud provider -│ ├── kubernetes/ # Kubernetes provider -│ ├── github/ # GitHub provider -│ ├── m365/ # Microsoft 365 provider -│ ├── mongodbatlas/ # MongoDB Atlas provider -│ ├── oci/ # Oracle Cloud provider -│ ├── ... -│ └── common/ # Shared provider utilities -├── compliance/ # Compliance framework definitions -│ ├── aws/ # AWS compliance frameworks -│ ├── azure/ # Azure compliance frameworks -│ ├── gcp/ # GCP compliance frameworks -│ ├── ... -└── exceptions/ # Global exception definitions +├── __main__.py # CLI entry point +├── config/ # Global configuration +├── lib/ +│ ├── check/ # Check execution engine +│ ├── cli/ # Command-line interface +│ ├── outputs/ # Output format handlers (JSON, CSV, HTML, ASFF, OCSF) +│ └── mutelist/ # Mute list functionality +├── providers/ # Cloud providers (aws, azure, gcp, kubernetes, github, m365...) +│ └── common/ # Shared provider utilities +├── compliance/ # Compliance framework definitions (CIS, NIST, PCI-DSS, SOC2...) +└── exceptions/ # Global exceptions ``` -## Key Components +--- -### 1. Provider System +## COMMANDS -Each cloud provider implements: - -```python -class Provider: - """Base provider class""" - - def __init__(self, arguments): - self.session = self._setup_session(arguments) - self.regions = self._get_regions() - # Initialize all services - - def _setup_session(self, arguments): - """Provider-specific authentication""" - pass - - def _get_regions(self): - """Get available regions for provider""" - pass -``` - -### 2. Check Engine - -The check execution system: - -- **Dynamic Loading**: Automatically discovers and loads checks -- **Parallel Execution**: Runs checks in parallel for performance -- **Error Isolation**: Individual check failures don't affect others -- **Comprehensive Reporting**: Detailed findings with remediation guidance - -### 3. Compliance Framework Engine - -Compliance frameworks are defined as JSON files mapping checks to requirements: - -```json -{ - "Framework": "CIS", - "Name": "CIS Amazon Web Services Foundations Benchmark v2.0.0", - "Version": "2.0", - "Provider": "AWS", - "Description": "The CIS Amazon Web Services Foundations Benchmark provides prescriptive guidance for configuring security options for a subset of Amazon Web Services with an emphasis on foundational, testable, and architecture agnostic settings.", - "Requirements": [ - { - "Id": "1.1", - "Description": "Maintain current contact details", - "Checks": ["account_contact_details_configured"] - } - ] -} -``` - -### 4. Output System - -Multiple output formats supported: - -- **JSON**: Machine-readable findings -- **CSV**: Spreadsheet-compatible format -- **HTML**: Interactive web reports -- **ASFF**: AWS Security Finding Format -- **OCSF**: Open Cybersecurity Schema Framework - -## Development Patterns - -### Adding New Cloud Providers - -1. **Create Provider Structure**: ```bash -mkdir -p prowler/providers/{provider} -mkdir -p prowler/providers/{provider}/services -mkdir -p prowler/providers/{provider}/lib/{service,arguments,mutelist} -mkdir -p prowler/providers/{provider}/exceptions +# Setup +poetry install --with dev +poetry run pre-commit install + +# Run Prowler +poetry run python prowler-cli.py {provider} +poetry run python prowler-cli.py {provider} --check {check_name} +poetry run python prowler-cli.py {provider} --list-checks + +# Testing +poetry run pytest -n auto -vvv tests/ +poetry run pytest tests/providers/{provider}/services/{service}/ -v + +# Code Quality +poetry run pre-commit run --all-files ``` -2. **Implement Provider Class**: -```python -from prowler.providers.common.provider import Provider +--- -class NewProvider(Provider): - def __init__(self, arguments): - super().__init__(arguments) - # Provider-specific initialization -``` +## CREATING NEW CHECKS (Quick Reference) -3. **Add Provider to CLI**: -Update `prowler/lib/cli/parser.py` to include new provider arguments. +1. Verify check doesn't exist: `--list-checks | grep {check_name}` +2. Create folder: `prowler/providers/{provider}/services/{service}/{check_name}/` +3. Create files: `__init__.py`, `{check_name}.py`, `{check_name}.metadata.json` +4. Implement check logic +5. Test locally: `--check {check_name}` +6. Write tests -### Adding New Security Checks +**For detailed guidance, use the `prowler-sdk-check` skill.** -The most common high level steps to create a new check are: +--- -1. Prerequisites: - - Verify the check does not already exist by searching in the same service folder as `prowler/providers//services///`. - - Ensure required provider and service exist. If not, you will need to create them first. - - Confirm the service has implemented all required methods and attributes for the check (in most cases, you will need to add or modify some methods in the service to get the data you need for the check). -2. Navigate to the service directory. The path should be as follows: `prowler/providers//services/`. -3. Create a check-specific folder. The path should follow this pattern: `prowler/providers//services//`. Adhere to the [Naming Format for Checks](/developer-guide/checks#naming-format-for-checks). -4. Create the check files, you can use next commands: -```bash -mkdir -p prowler/providers//services// -touch prowler/providers//services///__init__.py -touch prowler/providers//services///.py -touch prowler/providers//services///.metadata.json -``` -5. Run the check locally to ensure it works as expected. For checking you can use the CLI in the next way: - - To ensure the check has been detected by Prowler: `poetry run python prowler-cli.py --list-checks | grep `. - - To run the check, to find possible issues: `poetry run python prowler-cli.py --log-level ERROR --verbose --check `. -6. Create comprehensive tests for the check that cover multiple scenarios including both PASS (compliant) and FAIL (non-compliant) cases. For detailed information about test structure and implementation guidelines, refer to the [Testing](/developer-guide/unit-testing) documentation. -7. If the check and its corresponding tests are working as expected, you can submit a PR to Prowler. +## QA CHECKLIST -### Adding Compliance Frameworks - -1. **Create Framework File**: -```bash -# Create prowler/compliance/{provider}/{framework}.json -``` - -2. **Define Requirements**: -Map framework requirements to existing checks. - -3. **Test Compliance**: -```bash -poetry run python -m prowler {provider} --compliance {framework} -``` - -## Code Quality Standards - -### 1. Python Style - -- **PEP 8 Compliance**: Enforced by black and flake8 -- **Type Hints**: Required for all public functions -- **Docstrings**: Required for all classes and methods -- **Import Organization**: Use isort for consistent import ordering - -```python -import standard_library - -from third_party import library - -from prowler.lib import internal_module - -class ExampleClass: - """Class docstring.""" - - def method(self, param: str) -> dict | list | None: - """Method docstring. - - Args: - param: Description of parameter - - Returns: - Description of return value - """ - return None -``` - -### 2. Error Handling - -```python -from prowler.lib.logger import logger - -try: - # Risky operation - result = api_call() -except ProviderSpecificException as e: - logger.error(f"Provider error: {e}") - # Graceful handling -except Exception as e: - logger.error(f"Unexpected error: {e}") - # Never let checks crash the entire scan -``` - -### 3. Security Practices - -- **No Hardcoded Secrets**: Use environment variables or secure credential management -- **Input Validation**: Validate all external inputs -- **Principle of Least Privilege**: Request minimal necessary permissions -- **Secure Defaults**: Default to secure configurations - -## Testing Guidelines - -### Unit Tests - -- **100% Coverage Goal**: Aim for complete test coverage -- **Mock External Services**: Use mock objects to simulate the external services -- **Test Edge Cases**: Include error conditions and boundary cases - -## References - -- **Root Project Guide**: `../AGENTS.md` (takes priority for cross-component guidance) -- **Provider Examples**: Reference existing providers for implementation patterns -- **Check Examples**: Study existing checks for proper implementation patterns -- **Compliance Framework Examples**: Review existing frameworks for structure +- [ ] `poetry run pytest` passes +- [ ] `poetry run pre-commit run --all-files` passes +- [ ] Check metadata JSON is valid +- [ ] Tests cover PASS, FAIL, and empty resource scenarios +- [ ] Docstrings follow Google style diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 7fd5b6b734..b202455fa0 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to the **Prowler SDK** are documented in this file. ## [5.17.0] (Prowler UNRELEASED) ### Added +- AI Skills pack for AI coding assistants (Claude Code, OpenCode, Codex) following agentskills.io standard [(#9728)](https://github.com/prowler-cloud/prowler/pull/9728) - Add Prowler ThreatScore for the Alibaba Cloud provider [(#9511)](https://github.com/prowler-cloud/prowler/pull/9511) - `compute_instance_group_multiple_zones` check for GCP provider [(#9566)](https://github.com/prowler-cloud/prowler/pull/9566) - `compute_instance_group_autohealing_enabled` check for GCP provider [(#9690)](https://github.com/prowler-cloud/prowler/pull/9690) diff --git a/skills/README.md b/skills/README.md new file mode 100644 index 0000000000..becdffaf9b --- /dev/null +++ b/skills/README.md @@ -0,0 +1,127 @@ +# AI Agent Skills + +This directory contains **Agent Skills** following the [Agent Skills open standard](https://agentskills.io). Skills provide domain-specific patterns, conventions, and guardrails that help AI coding assistants (Claude Code, OpenCode, Cursor, etc.) understand project-specific requirements. + +## What Are Skills? + +[Agent Skills](https://agentskills.io) is an open standard format for extending AI agent capabilities with specialized knowledge. Originally developed by Anthropic and released as an open standard, it is now adopted by multiple agent products. + +Skills teach AI assistants how to perform specific tasks. When an AI loads a skill, it gains context about: + +- Critical rules (what to always/never do) +- Code patterns and conventions +- Project-specific workflows +- References to detailed documentation + +## Setup + +Run the setup script to configure skills for all supported AI coding assistants: + +```bash +./skills/setup.sh +``` + +This creates symlinks so each tool finds skills in its expected location: + +| Tool | Symlink Created | +|------|-----------------| +| Claude Code / OpenCode | `.claude/skills/` | +| Codex (OpenAI) | `.codex/skills/` | +| GitHub Copilot | `.github/skills/` | +| Gemini CLI | `.gemini/skills/` | + +After running setup, restart your AI coding assistant to load the skills. + +## How to Use Skills + +Skills are automatically discovered by the AI agent. To manually load a skill during a session: + +``` +Read skills/{skill-name}/SKILL.md +``` + +## Available Skills + +### Generic Skills + +Reusable patterns for common technologies: + +| Skill | Description | +|-------|-------------| +| `typescript` | Const types, flat interfaces, utility types | +| `react-19` | React 19 patterns, React Compiler | +| `nextjs-15` | App Router, Server Actions, streaming | +| `tailwind-4` | cn() utility, Tailwind 4 patterns | +| `playwright` | Page Object Model, selectors | +| `pytest` | Fixtures, mocking, markers | +| `django-drf` | ViewSets, Serializers, Filters | +| `zod-4` | Zod 4 API patterns | +| `zustand-5` | Persist, selectors, slices | +| `ai-sdk-5` | Vercel AI SDK patterns | + +### Prowler-Specific Skills + +Patterns tailored for Prowler development: + +| Skill | Description | +|-------|-------------| +| `prowler` | Project overview, component navigation | +| `prowler-api` | Django + RLS + JSON:API patterns | +| `prowler-ui` | Next.js + shadcn conventions | +| `prowler-sdk-check` | Create new security checks | +| `prowler-mcp` | MCP server tools and models | +| `prowler-test-sdk` | SDK testing (pytest + moto) | +| `prowler-test-api` | API testing (pytest-django + RLS) | +| `prowler-test-ui` | E2E testing (Playwright) | +| `prowler-compliance` | Compliance framework structure | +| `prowler-provider` | Add new cloud providers | +| `prowler-pr` | Pull request conventions | +| `prowler-docs` | Documentation style guide | + +### Meta Skills + +| Skill | Description | +|-------|-------------| +| `skill-creator` | Create new AI agent skills | + +## Directory Structure + +``` +skills/ +├── {skill-name}/ +│ ├── SKILL.md # Required - main instrunsction and metadata +│ ├── scripts/ # Optional - executable code +│ ├── assets/ # Optional - templates, schemas, resources +│ └── references/ # Optional - links to local docs +└── README.md # This file +``` + +## Creating New Skills + +Use the `skill-creator` skill for guidance: + +``` +Read skills/skill-creator/SKILL.md +``` + +### Quick Checklist + +1. Create directory: `skills/{skill-name}/` +2. Add `SKILL.md` with required frontmatter +3. Keep content concise (under 500 lines) +4. Reference existing docs instead of duplicating +5. Add to `AGENTS.md` skills table + +## Design Principles + +- **Concise**: Only include what AI doesn't already know +- **Progressive disclosure**: Point to detailed docs, don't duplicate +- **Critical rules first**: Lead with ALWAYS/NEVER patterns +- **Minimal examples**: Show patterns, not tutorials + +## Resources + +- [Agent Skills Standard](https://agentskills.io) - Open standard specification +- [Agent Skills GitHub](https://github.com/anthropics/skills) - Example skills +- [Claude Code Best Practices](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices) - Skill authoring guide +- [Prowler AGENTS.md](../AGENTS.md) - AI agent general rules diff --git a/skills/ai-sdk-5/SKILL.md b/skills/ai-sdk-5/SKILL.md new file mode 100644 index 0000000000..3b1c979f73 --- /dev/null +++ b/skills/ai-sdk-5/SKILL.md @@ -0,0 +1,234 @@ +--- +name: ai-sdk-5 +description: > + Vercel AI SDK 5 patterns. + Trigger: When building AI chat features - breaking changes from v4. +license: Apache-2.0 +metadata: + author: prowler-cloud + version: "1.0" +allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task +--- + +## Breaking Changes from AI SDK 4 + +```typescript +// ❌ AI SDK 4 (OLD) +import { useChat } from "ai"; +const { messages, handleSubmit, input, handleInputChange } = useChat({ + api: "/api/chat", +}); + +// ✅ AI SDK 5 (NEW) +import { useChat } from "@ai-sdk/react"; +import { DefaultChatTransport } from "ai"; + +const { messages, sendMessage } = useChat({ + transport: new DefaultChatTransport({ api: "/api/chat" }), +}); +``` + +## Client Setup + +```typescript +import { useChat } from "@ai-sdk/react"; +import { DefaultChatTransport } from "ai"; +import { useState } from "react"; + +export function Chat() { + const [input, setInput] = useState(""); + + const { messages, sendMessage, isLoading, error } = useChat({ + transport: new DefaultChatTransport({ api: "/api/chat" }), + }); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + if (!input.trim()) return; + sendMessage({ text: input }); + setInput(""); + }; + + return ( + + + {messages.map((message) => ( + + ))} + + + + setInput(e.target.value)} + placeholder="Type a message..." + disabled={isLoading} + /> + + Send + + + + {error && Error: {error.message}} + + ); +} +``` + +## UIMessage Structure (v5) + +```typescript +// ❌ Old: message.content was a string +// ✅ New: message.parts is an array + +interface UIMessage { + id: string; + role: "user" | "assistant" | "system"; + parts: MessagePart[]; +} + +type MessagePart = + | { type: "text"; text: string } + | { type: "image"; image: string } + | { type: "tool-call"; toolCallId: string; toolName: string; args: unknown } + | { type: "tool-result"; toolCallId: string; result: unknown }; + +// Extract text from parts +function getMessageText(message: UIMessage): string { + return message.parts + .filter((part): part is { type: "text"; text: string } => part.type === "text") + .map((part) => part.text) + .join(""); +} + +// Render message +function Message({ message }: { message: UIMessage }) { + return ( + + {message.parts.map((part, index) => { + if (part.type === "text") { + return {part.text}; + } + if (part.type === "image") { + return ; + } + return null; + })} + + ); +} +``` + +## Server-Side (Route Handler) + +```typescript +// app/api/chat/route.ts +import { openai } from "@ai-sdk/openai"; +import { streamText } from "ai"; + +export async function POST(req: Request) { + const { messages } = await req.json(); + + const result = await streamText({ + model: openai("gpt-4o"), + messages, + system: "You are a helpful assistant.", + }); + + return result.toDataStreamResponse(); +} +``` + +## With LangChain + +```typescript +// app/api/chat/route.ts +import { toUIMessageStream } from "@ai-sdk/langchain"; +import { ChatOpenAI } from "@langchain/openai"; +import { HumanMessage, AIMessage } from "@langchain/core/messages"; + +export async function POST(req: Request) { + const { messages } = await req.json(); + + const model = new ChatOpenAI({ + modelName: "gpt-4o", + streaming: true, + }); + + // Convert UI messages to LangChain format + const langchainMessages = messages.map((m) => { + const text = m.parts + .filter((p) => p.type === "text") + .map((p) => p.text) + .join(""); + return m.role === "user" + ? new HumanMessage(text) + : new AIMessage(text); + }); + + const stream = await model.stream(langchainMessages); + + return toUIMessageStream(stream).toDataStreamResponse(); +} +``` + +## Streaming with Tools + +```typescript +import { openai } from "@ai-sdk/openai"; +import { streamText, tool } from "ai"; +import { z } from "zod"; + +const result = await streamText({ + model: openai("gpt-4o"), + messages, + tools: { + getWeather: tool({ + description: "Get weather for a location", + parameters: z.object({ + location: z.string().describe("City name"), + }), + execute: async ({ location }) => { + // Fetch weather data + return { temperature: 72, condition: "sunny" }; + }, + }), + }, +}); +``` + +## useCompletion (Text Generation) + +```typescript +import { useCompletion } from "@ai-sdk/react"; +import { DefaultCompletionTransport } from "ai"; + +const { completion, complete, isLoading } = useCompletion({ + transport: new DefaultCompletionTransport({ api: "/api/complete" }), +}); + +// Trigger completion +await complete("Write a haiku about"); +``` + +## Error Handling + +```typescript +const { error, messages, sendMessage } = useChat({ + transport: new DefaultChatTransport({ api: "/api/chat" }), + onError: (error) => { + console.error("Chat error:", error); + toast.error("Failed to send message"); + }, +}); + +// Display error +{error && ( + + {error.message} + sendMessage({ text: lastInput })}> + Retry + + +)} +``` diff --git a/skills/django-drf/SKILL.md b/skills/django-drf/SKILL.md new file mode 100644 index 0000000000..03b43fc64e --- /dev/null +++ b/skills/django-drf/SKILL.md @@ -0,0 +1,184 @@ +--- +name: django-drf +description: > + Django REST Framework patterns. + Trigger: When building REST APIs with Django - ViewSets, Serializers, Filters. +license: Apache-2.0 +metadata: + author: prowler-cloud + version: "1.0" +allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task +--- + +## ViewSet Pattern + +```python +from rest_framework import viewsets, status +from rest_framework.response import Response +from rest_framework.decorators import action + +class UserViewSet(viewsets.ModelViewSet): + queryset = User.objects.all() + serializer_class = UserSerializer + filterset_class = UserFilter + permission_classes = [IsAuthenticated] + + def get_serializer_class(self): + if self.action == "create": + return UserCreateSerializer + if self.action in ["update", "partial_update"]: + return UserUpdateSerializer + return UserSerializer + + @action(detail=True, methods=["post"]) + def activate(self, request, pk=None): + user = self.get_object() + user.is_active = True + user.save() + return Response({"status": "activated"}) +``` + +## Serializer Patterns + +```python +from rest_framework import serializers + +# Read Serializer +class UserSerializer(serializers.ModelSerializer): + full_name = serializers.SerializerMethodField() + + class Meta: + model = User + fields = ["id", "email", "full_name", "created_at"] + read_only_fields = ["id", "created_at"] + + def get_full_name(self, obj): + return f"{obj.first_name} {obj.last_name}" + +# Create Serializer +class UserCreateSerializer(serializers.ModelSerializer): + password = serializers.CharField(write_only=True) + + class Meta: + model = User + fields = ["email", "password", "first_name", "last_name"] + + def create(self, validated_data): + password = validated_data.pop("password") + user = User(**validated_data) + user.set_password(password) + user.save() + return user + +# Update Serializer +class UserUpdateSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = ["first_name", "last_name"] +``` + +## Filters + +```python +from django_filters import rest_framework as filters + +class UserFilter(filters.FilterSet): + email = filters.CharFilter(lookup_expr="icontains") + is_active = filters.BooleanFilter() + created_after = filters.DateTimeFilter( + field_name="created_at", + lookup_expr="gte" + ) + created_before = filters.DateTimeFilter( + field_name="created_at", + lookup_expr="lte" + ) + + class Meta: + model = User + fields = ["email", "is_active"] +``` + +## Permissions + +```python +from rest_framework.permissions import BasePermission + +class IsOwner(BasePermission): + def has_object_permission(self, request, view, obj): + return obj.owner == request.user + +class IsAdminOrReadOnly(BasePermission): + def has_permission(self, request, view): + if request.method in ["GET", "HEAD", "OPTIONS"]: + return True + return request.user.is_staff +``` + +## Pagination + +```python +from rest_framework.pagination import PageNumberPagination + +class StandardPagination(PageNumberPagination): + page_size = 20 + page_size_query_param = "page_size" + max_page_size = 100 + +# settings.py +REST_FRAMEWORK = { + "DEFAULT_PAGINATION_CLASS": "api.pagination.StandardPagination", +} +``` + +## URL Routing + +```python +from rest_framework.routers import DefaultRouter + +router = DefaultRouter() +router.register(r"users", UserViewSet, basename="user") +router.register(r"posts", PostViewSet, basename="post") + +urlpatterns = [ + path("api/v1/", include(router.urls)), +] +``` + +## Testing + +```python +import pytest +from rest_framework import status +from rest_framework.test import APIClient + +@pytest.fixture +def api_client(): + return APIClient() + +@pytest.fixture +def authenticated_client(api_client, user): + api_client.force_authenticate(user=user) + return api_client + +@pytest.mark.django_db +class TestUserViewSet: + def test_list_users(self, authenticated_client): + response = authenticated_client.get("/api/v1/users/") + assert response.status_code == status.HTTP_200_OK + + def test_create_user(self, authenticated_client): + data = {"email": "new@test.com", "password": "pass123"} + response = authenticated_client.post("/api/v1/users/", data) + assert response.status_code == status.HTTP_201_CREATED +``` + +## Commands + +```bash +python manage.py runserver +python manage.py makemigrations +python manage.py migrate +python manage.py createsuperuser +python manage.py shell +``` diff --git a/skills/nextjs-15/SKILL.md b/skills/nextjs-15/SKILL.md new file mode 100644 index 0000000000..4fa47fd619 --- /dev/null +++ b/skills/nextjs-15/SKILL.md @@ -0,0 +1,148 @@ +--- +name: nextjs-15 +description: > + Next.js 15 App Router patterns. + Trigger: When working with Next.js - routing, Server Actions, data fetching. +license: Apache-2.0 +metadata: + author: prowler-cloud + version: "1.0" +allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task +--- + +## App Router File Conventions + +``` +app/ +├── layout.tsx # Root layout (required) +├── page.tsx # Home page (/) +├── loading.tsx # Loading UI (Suspense) +├── error.tsx # Error boundary +├── not-found.tsx # 404 page +├── (auth)/ # Route group (no URL impact) +│ ├── login/page.tsx # /login +│ └── signup/page.tsx # /signup +├── api/ +│ └── route.ts # API handler +└── _components/ # Private folder (not routed) +``` + +## Server Components (Default) + +```typescript +// No directive needed - async by default +export default async function Page() { + const data = await db.query(); + return ; +} +``` + +## Server Actions + +```typescript +// app/actions.ts +"use server"; + +import { revalidatePath } from "next/cache"; +import { redirect } from "next/navigation"; + +export async function createUser(formData: FormData) { + const name = formData.get("name") as string; + + await db.users.create({ data: { name } }); + + revalidatePath("/users"); + redirect("/users"); +} + +// Usage + + + Create + +``` + +## Data Fetching + +```typescript +// Parallel +async function Page() { + const [users, posts] = await Promise.all([ + getUsers(), + getPosts(), + ]); + return ; +} + +// Streaming with Suspense +}> + + +``` + +## Route Handlers (API) + +```typescript +// app/api/users/route.ts +import { NextRequest, NextResponse } from "next/server"; + +export async function GET(request: NextRequest) { + const users = await db.users.findMany(); + return NextResponse.json(users); +} + +export async function POST(request: NextRequest) { + const body = await request.json(); + const user = await db.users.create({ data: body }); + return NextResponse.json(user, { status: 201 }); +} +``` + +## Middleware + +```typescript +// middleware.ts (root level) +import { NextResponse } from "next/server"; +import type { NextRequest } from "next/server"; + +export function middleware(request: NextRequest) { + const token = request.cookies.get("token"); + + if (!token && request.nextUrl.pathname.startsWith("/dashboard")) { + return NextResponse.redirect(new URL("/login", request.url)); + } + + return NextResponse.next(); +} + +export const config = { + matcher: ["/dashboard/:path*"], +}; +``` + +## Metadata + +```typescript +// Static +export const metadata = { + title: "My App", + description: "Description", +}; + +// Dynamic +export async function generateMetadata({ params }) { + const product = await getProduct(params.id); + return { title: product.name }; +} +``` + +## server-only Package + +```typescript +import "server-only"; + +// This will error if imported in client component +export async function getSecretData() { + return db.secrets.findMany(); +} +``` diff --git a/skills/playwright/SKILL.md b/skills/playwright/SKILL.md new file mode 100644 index 0000000000..34e71aadd1 --- /dev/null +++ b/skills/playwright/SKILL.md @@ -0,0 +1,324 @@ +--- +name: playwright +description: > + Playwright E2E testing patterns. + Trigger: When writing E2E tests - Page Objects, selectors, MCP workflow. +license: Apache-2.0 +metadata: + author: prowler-cloud + version: "1.0" +allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task +--- + +## MCP Workflow (MANDATORY If Available) + +**⚠️ If you have Playwright MCP tools, ALWAYS use them BEFORE creating any test:** + +1. **Navigate** to target page +2. **Take snapshot** to see page structure and elements +3. **Interact** with forms/elements to verify exact user flow +4. **Take screenshots** to document expected states +5. **Verify page transitions** through complete flow (loading, success, error) +6. **Document actual selectors** from snapshots (use real refs and labels) +7. **Only after exploring** create test code with verified selectors + +**If MCP NOT available:** Proceed with test creation based on docs and code analysis. + +**Why This Matters:** +- ✅ Precise tests - exact steps needed, no assumptions +- ✅ Accurate selectors - real DOM structure, not imagined +- ✅ Real flow validation - verify journey actually works +- ✅ Avoid over-engineering - minimal tests for what exists +- ✅ Prevent flaky tests - real exploration = stable tests +- ❌ Never assume how UI "should" work + +## File Structure + +``` +tests/ +├── base-page.ts # Parent class for ALL pages +├── helpers.ts # Shared utilities +└── {page-name}/ + ├── {page-name}-page.ts # Page Object Model + ├── {page-name}.spec.ts # ALL tests here (NO separate files!) + └── {page-name}.md # Test documentation +``` + +**File Naming:** +- ✅ `sign-up.spec.ts` (all sign-up tests) +- ✅ `sign-up-page.ts` (page object) +- ✅ `sign-up.md` (documentation) +- ❌ `sign-up-critical-path.spec.ts` (WRONG - no separate files) +- ❌ `sign-up-validation.spec.ts` (WRONG) + +## Selector Priority (REQUIRED) + +```typescript +// 1. BEST - getByRole for interactive elements +this.submitButton = page.getByRole("button", { name: "Submit" }); +this.navLink = page.getByRole("link", { name: "Dashboard" }); + +// 2. BEST - getByLabel for form controls +this.emailInput = page.getByLabel("Email"); +this.passwordInput = page.getByLabel("Password"); + +// 3. SPARINGLY - getByText for static content only +this.errorMessage = page.getByText("Invalid credentials"); +this.pageTitle = page.getByText("Welcome"); + +// 4. LAST RESORT - getByTestId when above fail +this.customWidget = page.getByTestId("date-picker"); + +// ❌ AVOID fragile selectors +this.button = page.locator(".btn-primary"); // NO +this.input = page.locator("#email"); // NO +``` + +## Scope Detection (ASK IF AMBIGUOUS) + +| User Says | Action | +|-----------|--------| +| "a test", "one test", "new test", "add test" | Create ONE test() in existing spec | +| "comprehensive tests", "all tests", "test suite", "generate tests" | Create full suite | + +**Examples:** +- "Create a test for user sign-up" → ONE test only +- "Generate E2E tests for login page" → Full suite +- "Add a test to verify form validation" → ONE test to existing spec + +## Page Object Pattern + +```typescript +import { Page, Locator, expect } from "@playwright/test"; + +// BasePage - ALL pages extend this +export class BasePage { + constructor(protected page: Page) {} + + async goto(path: string): Promise { + await this.page.goto(path); + await this.page.waitForLoadState("networkidle"); + } + + // Common methods go here (see Refactoring Guidelines) + async waitForNotification(): Promise { + await this.page.waitForSelector('[role="status"]'); + } + + async verifyNotificationMessage(message: string): Promise { + const notification = this.page.locator('[role="status"]'); + await expect(notification).toContainText(message); + } +} + +// Page-specific implementation +export interface LoginData { + email: string; + password: string; +} + +export class LoginPage extends BasePage { + readonly emailInput: Locator; + readonly passwordInput: Locator; + readonly submitButton: Locator; + + constructor(page: Page) { + super(page); + this.emailInput = page.getByLabel("Email"); + this.passwordInput = page.getByLabel("Password"); + this.submitButton = page.getByRole("button", { name: "Sign in" }); + } + + async goto(): Promise { + await super.goto("/login"); + } + + async login(data: LoginData): Promise { + await this.emailInput.fill(data.email); + await this.passwordInput.fill(data.password); + await this.submitButton.click(); + } + + async verifyCriticalOutcome(): Promise { + await expect(this.page).toHaveURL("/dashboard"); + } +} +``` + +## Page Object Reuse (CRITICAL) + +**Always check existing page objects before creating new ones!** + +```typescript +// ✅ GOOD: Reuse existing page objects +import { SignInPage } from "../sign-in/sign-in-page"; +import { HomePage } from "../home/home-page"; + +test("User can sign up and login", async ({ page }) => { + const signUpPage = new SignUpPage(page); + const signInPage = new SignInPage(page); // REUSE + const homePage = new HomePage(page); // REUSE + + await signUpPage.signUp(userData); + await homePage.verifyPageLoaded(); // REUSE method + await homePage.signOut(); // REUSE method + await signInPage.login(credentials); // REUSE method +}); + +// ❌ BAD: Recreating existing functionality +export class SignUpPage extends BasePage { + async logout() { /* ... */ } // ❌ HomePage already has this + async login() { /* ... */ } // ❌ SignInPage already has this +} +``` + +**Guidelines:** +- Check `tests/` for existing page objects first +- Import and reuse existing pages +- Create page objects only when page doesn't exist +- If test requires multiple pages, ensure all page objects exist (create if needed) + +## Refactoring Guidelines + +### Move to `BasePage` when: +- ✅ Navigation helpers used by multiple pages (`waitForPageLoad()`, `getCurrentUrl()`) +- ✅ Common UI interactions (notifications, modals, theme toggles) +- ✅ Verification patterns repeated across pages (`isVisible()`, `waitForVisible()`) +- ✅ Error handling that applies to all pages +- ✅ Screenshot utilities for debugging + +### Move to `helpers.ts` when: +- ✅ Test data generation (`generateUniqueEmail()`, `generateTestUser()`) +- ✅ Setup/teardown utilities (`createTestUser()`, `cleanupTestData()`) +- ✅ Custom assertions (`expectNotificationToContain()`) +- ✅ API helpers for test setup (`seedDatabase()`, `resetState()`) +- ✅ Time utilities (`waitForCondition()`, `retryAction()`) + +**Before (BAD):** +```typescript +// Repeated in multiple page objects +export class SignUpPage extends BasePage { + async waitForNotification(): Promise { + await this.page.waitForSelector('[role="status"]'); + } +} +export class SignInPage extends BasePage { + async waitForNotification(): Promise { + await this.page.waitForSelector('[role="status"]'); // DUPLICATED! + } +} +``` + +**After (GOOD):** +```typescript +// BasePage - shared across all pages +export class BasePage { + async waitForNotification(): Promise { + await this.page.waitForSelector('[role="status"]'); + } +} + +// helpers.ts - data generation +export function generateUniqueEmail(): string { + return `test.${Date.now()}@example.com`; +} + +export function generateTestUser() { + return { + name: "Test User", + email: generateUniqueEmail(), + password: "TestPassword123!", + }; +} +``` + +## Test Pattern with Tags + +```typescript +import { test, expect } from "@playwright/test"; +import { LoginPage } from "./login-page"; + +test.describe("Login", () => { + test("User can login successfully", + { tag: ["@critical", "@e2e", "@login", "@LOGIN-E2E-001"] }, + async ({ page }) => { + const loginPage = new LoginPage(page); + + await loginPage.goto(); + await loginPage.login({ email: "user@test.com", password: "pass123" }); + + await expect(page).toHaveURL("/dashboard"); + } + ); +}); +``` + +**Tag Categories:** +- Priority: `@critical`, `@high`, `@medium`, `@low` +- Type: `@e2e` +- Feature: `@signup`, `@signin`, `@dashboard` +- Test ID: `@SIGNUP-E2E-001`, `@LOGIN-E2E-002` + +## Test Documentation Format ({page-name}.md) + +```markdown +### E2E Tests: {Feature Name} + +**Suite ID:** `{SUITE-ID}` +**Feature:** {Feature description} + +--- + +## Test Case: `{TEST-ID}` - {Test case title} + +**Priority:** `{critical|high|medium|low}` + +**Tags:** +- type → @e2e +- feature → @{feature-name} + +**Description/Objective:** {Brief description} + +**Preconditions:** +- {Prerequisites for test to run} +- {Required data or state} + +### Flow Steps: +1. {Step 1} +2. {Step 2} +3. {Step 3} + +### Expected Result: +- {Expected outcome 1} +- {Expected outcome 2} + +### Key verification points: +- {Assertion 1} +- {Assertion 2} + +### Notes: +- {Additional considerations} +``` + +**Documentation Rules:** +- ❌ NO general test running instructions +- ❌ NO file structure explanations +- ❌ NO code examples or tutorials +- ❌ NO troubleshooting sections +- ✅ Focus ONLY on specific test case +- ✅ Keep under 60 lines when possible + +## Commands + +```bash +npx playwright test # Run all +npx playwright test --grep "login" # Filter by name +npx playwright test --ui # Interactive UI +npx playwright test --debug # Debug mode +npx playwright test tests/login/ # Run specific folder +``` + +## Prowler-Specific Patterns + +For Prowler UI E2E testing with authentication setup, environment variables, and test IDs, see: +- **Documentation**: [references/prowler-e2e.md](references/prowler-e2e.md) diff --git a/skills/playwright/references/prowler-e2e.md b/skills/playwright/references/prowler-e2e.md new file mode 100644 index 0000000000..bc9efaf78e --- /dev/null +++ b/skills/playwright/references/prowler-e2e.md @@ -0,0 +1,16 @@ +# Prowler-Specific E2E Patterns + +## Local Documentation + +For Prowler-specific Playwright patterns, see: + +- `docs/developer-guide/end2end-testing.mdx` - Complete E2E testing guide + +## Contents + +The Prowler documentation covers patterns NOT in the generic playwright skill: +- Authentication setup projects (`admin.auth.setup`, `member.auth.setup`, etc.) +- Environment variables (`E2E_AWS_PROVIDER_ACCOUNT_ID`, etc.) +- Page Object location (`ui/tests/`) +- Test ID conventions (`@PROVIDER-E2E-001`, `@SCANS-E2E-001`) +- Serial test requirements for data-dependent tests diff --git a/skills/prowler-api/SKILL.md b/skills/prowler-api/SKILL.md new file mode 100644 index 0000000000..62f3c15156 --- /dev/null +++ b/skills/prowler-api/SKILL.md @@ -0,0 +1,137 @@ +--- +name: prowler-api +description: > + Prowler API patterns: RLS, RBAC, providers, Celery tasks. + Trigger: When working on api/ - models, serializers, views, filters, tasks. +license: Apache-2.0 +metadata: + author: prowler-cloud + version: "1.0" +allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task +--- + +## Critical Rules + +- ALWAYS use `rls_transaction(tenant_id)` when querying outside ViewSet context +- ALWAYS use `get_role()` before checking permissions (returns FIRST role only) +- NEVER access `Provider.objects` without RLS context in Celery tasks +- ALWAYS use `@set_tenant` then `@handle_provider_deletion` decorator order + +--- + +## 1. Providers (10 Supported) + +UID validation is dynamic: `getattr(self, f"validate_{self.provider}_uid")(self.uid)` + +| Provider | UID Format | Example | +|----------|-----------|---------| +| AWS | 12 digits | `123456789012` | +| Azure | UUID v4 | `a1b2c3d4-e5f6-...` | +| GCP | 6-30 chars, lowercase, letter start | `my-gcp-project` | +| M365 | Valid domain | `contoso.onmicrosoft.com` | +| Kubernetes | 2-251 chars | `arn:aws:eks:...` | +| GitHub | 1-39 chars | `my-org` | +| IaC | Git URL | `https://github.com/user/repo.git` | +| Oracle Cloud | OCID format | `ocid1.tenancy.oc1..` | +| MongoDB Atlas | 24-char hex | `507f1f77bcf86cd799439011` | +| Alibaba Cloud | 16 digits | `1234567890123456` | + +**Adding new provider**: Add to `ProviderChoices` enum + create `validate_
{`Provider ID ${apiErrorMessage?.toLowerCase()}. Please check and try again.`}
{apiErrorMessage}
{part.text}