mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-05-19 18:53:33 +00:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cebe6cf8e2 | |||
| eaa746f7b9 | |||
| 57222f6e0b | |||
| 75ee07c6e1 | |||
| ddc5d879e0 | |||
| 006c2dc754 | |||
| 4981d3fc38 | |||
| cceaf1ea54 | |||
| b436da27c8 | |||
| 82be83c668 | |||
| 4f18bfc33c | |||
| 941f9b7e0b | |||
| 9da0b0c0b1 | |||
| 8c1da0732d | |||
| 02b58d8a31 | |||
| 3defbcd386 | |||
| ceb4691c36 | |||
| 4be8831ee1 | |||
| da23d62e6a | |||
| 222db94a48 | |||
| c33565a127 | |||
| 961b247d36 | |||
| 6abd5186aa | |||
| 627088e214 | |||
| 93ac38ca90 | |||
| aa7490aab4 | |||
| b94c8a5e5e | |||
| e6bea9f25a | |||
| 1f4e308374 | |||
| 4d569d5b79 | |||
| 5b038e631a | |||
| c5707ae9f1 | |||
| 29090adb03 | |||
| 78bd9adeed | |||
| f55983a77d | |||
| 52f98f1704 | |||
| 3afa98084f | |||
| b0ee914825 | |||
| eabe488437 | |||
| 8104382cc1 | |||
| 592c7bac81 | |||
| 3aefde14aa | |||
| 02f3e77eaf | |||
| bcd7b2d723 | |||
| 86946f3a84 | |||
| fce1e4f3d2 | |||
| 5d490fa185 | |||
| ea847d8824 | |||
| c5f7e80b20 | |||
| f5345a3982 | |||
| b539514d8d | |||
| 9acef41f96 | |||
| c40adce2ff | |||
| 378c2ff7f6 | |||
| d54095abde | |||
| a12cb5b6d6 | |||
| dde42b6a84 | |||
| 3316ec8d23 | |||
| 71220b2696 | |||
| dd730eec94 | |||
| afe2e0a09e | |||
| 507d163a50 | |||
| 530fef5106 | |||
| 5cbbceb3be | |||
| fa189e7eb9 | |||
| fb966213cc | |||
| 097a60ebc9 | |||
| db03556ef6 | |||
| ecc8eaf366 | |||
| 619d1ffc62 | |||
| 9e20cb2e5a | |||
| cb76e77851 | |||
| a24f818547 | |||
| e07687ce67 |
+10
-7
@@ -14,7 +14,7 @@ ignored:
|
||||
- "*.md"
|
||||
- "**/*.md"
|
||||
- mkdocs.yml
|
||||
|
||||
|
||||
# Config files that don't affect runtime
|
||||
- .gitignore
|
||||
- .gitattributes
|
||||
@@ -23,7 +23,7 @@ ignored:
|
||||
- .backportrc.json
|
||||
- CODEOWNERS
|
||||
- LICENSE
|
||||
|
||||
|
||||
# IDE/Editor configs
|
||||
- .vscode/**
|
||||
- .idea/**
|
||||
@@ -31,10 +31,13 @@ ignored:
|
||||
# Examples and contrib (not production code)
|
||||
- examples/**
|
||||
- contrib/**
|
||||
|
||||
|
||||
# Skills (AI agent configs, not runtime)
|
||||
- skills/**
|
||||
|
||||
|
||||
# E2E setup helpers (not runnable tests)
|
||||
- ui/tests/setups/**
|
||||
|
||||
# Permissions docs
|
||||
- permissions/**
|
||||
|
||||
@@ -47,18 +50,18 @@ critical:
|
||||
- prowler/config/**
|
||||
- prowler/exceptions/**
|
||||
- prowler/providers/common/**
|
||||
|
||||
|
||||
# API Core
|
||||
- api/src/backend/api/models.py
|
||||
- api/src/backend/config/**
|
||||
- api/src/backend/conftest.py
|
||||
|
||||
|
||||
# UI Core
|
||||
- ui/lib/**
|
||||
- ui/types/**
|
||||
- ui/config/**
|
||||
- ui/middleware.ts
|
||||
|
||||
|
||||
# CI/CD changes
|
||||
- .github/workflows/**
|
||||
- .github/test-impact.yml
|
||||
|
||||
@@ -51,18 +51,16 @@ jobs:
|
||||
"amitsharm"
|
||||
"andoniaf"
|
||||
"cesararroba"
|
||||
"Chan9390"
|
||||
"danibarranqueroo"
|
||||
"HugoPBrito"
|
||||
"jfagoagas"
|
||||
"josemazo"
|
||||
"josema-xyz"
|
||||
"lydiavilchez"
|
||||
"mmuller88"
|
||||
"MrCloudSec"
|
||||
# "MrCloudSec"
|
||||
"pedrooot"
|
||||
"prowler-bot"
|
||||
"puchy22"
|
||||
"rakan-pro"
|
||||
"RosaRivasProwler"
|
||||
"StylusFrost"
|
||||
"toniblyx"
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
name: 'SDK: Refresh OCI Regions'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 9 * * 1' # Every Monday at 09:00 UTC
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
PYTHON_VERSION: '3.12'
|
||||
|
||||
jobs:
|
||||
refresh-oci-regions:
|
||||
if: github.repository == 'prowler-cloud/prowler'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
ref: 'master'
|
||||
|
||||
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
cache: 'pip'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install oci
|
||||
|
||||
- name: Update OCI regions
|
||||
env:
|
||||
OCI_CLI_USER: ${{ secrets.E2E_OCI_USER_ID }}
|
||||
OCI_CLI_FINGERPRINT: ${{ secrets.E2E_OCI_FINGERPRINT }}
|
||||
OCI_CLI_TENANCY: ${{ secrets.E2E_OCI_TENANCY_ID }}
|
||||
OCI_CLI_KEY_CONTENT: ${{ secrets.E2E_OCI_KEY_CONTENT }}
|
||||
OCI_CLI_REGION: ${{ secrets.E2E_OCI_REGION }}
|
||||
run: python util/update_oci_regions.py
|
||||
|
||||
- name: Create pull request
|
||||
id: create-pr
|
||||
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>'
|
||||
committer: 'github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>'
|
||||
commit-message: 'feat(oraclecloud): update commercial regions'
|
||||
branch: 'oci-regions-update-${{ github.run_number }}'
|
||||
title: 'feat(oraclecloud): Update commercial regions'
|
||||
labels: |
|
||||
status/waiting-for-revision
|
||||
severity/low
|
||||
provider/oraclecloud
|
||||
no-changelog
|
||||
body: |
|
||||
### Description
|
||||
|
||||
Automated update of OCI commercial regions from the official Oracle Cloud Infrastructure Identity service.
|
||||
|
||||
**Trigger:** ${{ github.event_name == 'schedule' && 'Scheduled (weekly)' || github.event_name == 'workflow_dispatch' && 'Manual' || 'Workflow update' }}
|
||||
**Run:** [#${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
||||
|
||||
### Changes
|
||||
|
||||
This PR updates the `OCI_COMMERCIAL_REGIONS` dictionary in `prowler/providers/oraclecloud/config.py` with the latest regions fetched from the OCI Identity API (`list_regions()`).
|
||||
|
||||
- Government regions (`OCI_GOVERNMENT_REGIONS`) are preserved unchanged
|
||||
- Region display names are mapped from Oracle's official documentation
|
||||
|
||||
### Checklist
|
||||
|
||||
- [x] This is an automated update from OCI official sources
|
||||
- [x] Government regions (us-langley-1, us-luke-1) preserved
|
||||
- [x] No manual review of region data required
|
||||
|
||||
### License
|
||||
|
||||
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
|
||||
|
||||
- name: PR creation result
|
||||
run: |
|
||||
if [[ "${{ steps.create-pr.outputs.pull-request-number }}" ]]; then
|
||||
echo "✓ Pull request #${{ steps.create-pr.outputs.pull-request-number }} created successfully"
|
||||
echo "URL: ${{ steps.create-pr.outputs.pull-request-url }}"
|
||||
else
|
||||
echo "✓ No changes detected - OCI regions are up to date"
|
||||
fi
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
e2e-tests:
|
||||
needs: impact-analysis
|
||||
if: |
|
||||
github.repository == 'prowler-cloud/prowler' &&
|
||||
github.repository == 'prowler-cloud/prowler' &&
|
||||
(needs.impact-analysis.outputs.has-ui-e2e == 'true' || needs.impact-analysis.outputs.run-all == 'true')
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
@@ -65,6 +65,10 @@ jobs:
|
||||
E2E_OCI_KEY_CONTENT: ${{ secrets.E2E_OCI_KEY_CONTENT }}
|
||||
E2E_OCI_REGION: ${{ secrets.E2E_OCI_REGION }}
|
||||
E2E_NEW_USER_PASSWORD: ${{ secrets.E2E_NEW_USER_PASSWORD }}
|
||||
E2E_ALIBABACLOUD_ACCOUNT_ID: ${{ secrets.E2E_ALIBABACLOUD_ACCOUNT_ID }}
|
||||
E2E_ALIBABACLOUD_ACCESS_KEY_ID: ${{ secrets.E2E_ALIBABACLOUD_ACCESS_KEY_ID }}
|
||||
E2E_ALIBABACLOUD_ACCESS_KEY_SECRET: ${{ secrets.E2E_ALIBABACLOUD_ACCESS_KEY_SECRET }}
|
||||
E2E_ALIBABACLOUD_ROLE_ARN: ${{ secrets.E2E_ALIBABACLOUD_ROLE_ARN }}
|
||||
# Pass E2E paths from impact analysis
|
||||
E2E_TEST_PATHS: ${{ needs.impact-analysis.outputs.ui-e2e }}
|
||||
RUN_ALL_TESTS: ${{ needs.impact-analysis.outputs.run-all }}
|
||||
@@ -200,7 +204,14 @@ jobs:
|
||||
# e.g., "ui/tests/providers/**" -> "tests/providers"
|
||||
TEST_PATHS="${{ env.E2E_TEST_PATHS }}"
|
||||
# Remove ui/ prefix and convert ** to empty (playwright handles recursion)
|
||||
TEST_PATHS=$(echo "$TEST_PATHS" | sed 's|ui/||g' | sed 's|\*\*||g' | tr ' ' '\n' | sort -u | tr '\n' ' ')
|
||||
TEST_PATHS=$(echo "$TEST_PATHS" | sed 's|ui/||g' | sed 's|\*\*||g' | tr ' ' '\n' | sort -u)
|
||||
# Drop auth setup helpers (not runnable test suites)
|
||||
TEST_PATHS=$(echo "$TEST_PATHS" | grep -v '^tests/setups/')
|
||||
if [[ -z "$TEST_PATHS" ]]; then
|
||||
echo "No runnable E2E test paths after filtering setups"
|
||||
exit 0
|
||||
fi
|
||||
TEST_PATHS=$(echo "$TEST_PATHS" | tr '\n' ' ')
|
||||
echo "Resolved test paths: $TEST_PATHS"
|
||||
pnpm exec playwright test $TEST_PATHS
|
||||
fi
|
||||
@@ -222,8 +233,8 @@ jobs:
|
||||
skip-e2e:
|
||||
needs: impact-analysis
|
||||
if: |
|
||||
github.repository == 'prowler-cloud/prowler' &&
|
||||
needs.impact-analysis.outputs.has-ui-e2e != 'true' &&
|
||||
github.repository == 'prowler-cloud/prowler' &&
|
||||
needs.impact-analysis.outputs.has-ui-e2e != 'true' &&
|
||||
needs.impact-analysis.outputs.run-all != 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
name: UI - E2E Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- "v5.*"
|
||||
paths:
|
||||
- '.github/workflows/ui-e2e-tests.yml'
|
||||
- 'ui/**'
|
||||
|
||||
jobs:
|
||||
|
||||
e2e-tests:
|
||||
if: github.repository == 'prowler-cloud/prowler'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
AUTH_SECRET: 'fallback-ci-secret-for-testing'
|
||||
AUTH_TRUST_HOST: true
|
||||
NEXTAUTH_URL: 'http://localhost:3000'
|
||||
NEXT_PUBLIC_API_BASE_URL: 'http://localhost:8080/api/v1'
|
||||
E2E_ADMIN_USER: ${{ secrets.E2E_ADMIN_USER }}
|
||||
E2E_ADMIN_PASSWORD: ${{ secrets.E2E_ADMIN_PASSWORD }}
|
||||
E2E_AWS_PROVIDER_ACCOUNT_ID: ${{ secrets.E2E_AWS_PROVIDER_ACCOUNT_ID }}
|
||||
E2E_AWS_PROVIDER_ACCESS_KEY: ${{ secrets.E2E_AWS_PROVIDER_ACCESS_KEY }}
|
||||
E2E_AWS_PROVIDER_SECRET_KEY: ${{ secrets.E2E_AWS_PROVIDER_SECRET_KEY }}
|
||||
E2E_AWS_PROVIDER_ROLE_ARN: ${{ secrets.E2E_AWS_PROVIDER_ROLE_ARN }}
|
||||
E2E_AZURE_SUBSCRIPTION_ID: ${{ secrets.E2E_AZURE_SUBSCRIPTION_ID }}
|
||||
E2E_AZURE_CLIENT_ID: ${{ secrets.E2E_AZURE_CLIENT_ID }}
|
||||
E2E_AZURE_SECRET_ID: ${{ secrets.E2E_AZURE_SECRET_ID }}
|
||||
E2E_AZURE_TENANT_ID: ${{ secrets.E2E_AZURE_TENANT_ID }}
|
||||
E2E_M365_DOMAIN_ID: ${{ secrets.E2E_M365_DOMAIN_ID }}
|
||||
E2E_M365_CLIENT_ID: ${{ secrets.E2E_M365_CLIENT_ID }}
|
||||
E2E_M365_SECRET_ID: ${{ secrets.E2E_M365_SECRET_ID }}
|
||||
E2E_M365_TENANT_ID: ${{ secrets.E2E_M365_TENANT_ID }}
|
||||
E2E_M365_CERTIFICATE_CONTENT: ${{ secrets.E2E_M365_CERTIFICATE_CONTENT }}
|
||||
E2E_KUBERNETES_CONTEXT: 'kind-kind'
|
||||
E2E_KUBERNETES_KUBECONFIG_PATH: /home/runner/.kube/config
|
||||
E2E_GCP_BASE64_SERVICE_ACCOUNT_KEY: ${{ secrets.E2E_GCP_BASE64_SERVICE_ACCOUNT_KEY }}
|
||||
E2E_GCP_PROJECT_ID: ${{ secrets.E2E_GCP_PROJECT_ID }}
|
||||
E2E_GITHUB_APP_ID: ${{ secrets.E2E_GITHUB_APP_ID }}
|
||||
E2E_GITHUB_BASE64_APP_PRIVATE_KEY: ${{ secrets.E2E_GITHUB_BASE64_APP_PRIVATE_KEY }}
|
||||
E2E_GITHUB_USERNAME: ${{ secrets.E2E_GITHUB_USERNAME }}
|
||||
E2E_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.E2E_GITHUB_PERSONAL_ACCESS_TOKEN }}
|
||||
E2E_GITHUB_ORGANIZATION: ${{ secrets.E2E_GITHUB_ORGANIZATION }}
|
||||
E2E_GITHUB_ORGANIZATION_ACCESS_TOKEN: ${{ secrets.E2E_GITHUB_ORGANIZATION_ACCESS_TOKEN }}
|
||||
E2E_ORGANIZATION_ID: ${{ secrets.E2E_ORGANIZATION_ID }}
|
||||
E2E_OCI_TENANCY_ID: ${{ secrets.E2E_OCI_TENANCY_ID }}
|
||||
E2E_OCI_USER_ID: ${{ secrets.E2E_OCI_USER_ID }}
|
||||
E2E_OCI_FINGERPRINT: ${{ secrets.E2E_OCI_FINGERPRINT }}
|
||||
E2E_OCI_KEY_CONTENT: ${{ secrets.E2E_OCI_KEY_CONTENT }}
|
||||
E2E_OCI_REGION: ${{ secrets.E2E_OCI_REGION }}
|
||||
E2E_NEW_USER_PASSWORD: ${{ secrets.E2E_NEW_USER_PASSWORD }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
- name: Create k8s Kind Cluster
|
||||
uses: helm/kind-action@v1
|
||||
with:
|
||||
cluster_name: kind
|
||||
- name: Modify kubeconfig
|
||||
run: |
|
||||
# Modify the kubeconfig to use the kind cluster server to https://kind-control-plane:6443
|
||||
# from worker service into docker-compose.yml
|
||||
kubectl config set-cluster kind-kind --server=https://kind-control-plane:6443
|
||||
kubectl config view
|
||||
- name: Add network kind to docker compose
|
||||
run: |
|
||||
# Add the network kind to the docker compose to interconnect to kind cluster
|
||||
yq -i '.networks.kind.external = true' docker-compose.yml
|
||||
# Add network kind to worker service and default network too
|
||||
yq -i '.services.worker.networks = ["kind","default"]' docker-compose.yml
|
||||
- name: Fix API data directory permissions
|
||||
run: docker run --rm -v $(pwd)/_data/api:/data alpine chown -R 1000:1000 /data
|
||||
- name: Add AWS credentials for testing AWS SDK Default Adding Provider
|
||||
run: |
|
||||
echo "Adding AWS credentials for testing AWS SDK Default Adding Provider..."
|
||||
echo "AWS_ACCESS_KEY_ID=${{ secrets.E2E_AWS_PROVIDER_ACCESS_KEY }}" >> .env
|
||||
echo "AWS_SECRET_ACCESS_KEY=${{ secrets.E2E_AWS_PROVIDER_SECRET_KEY }}" >> .env
|
||||
- name: Start API services
|
||||
run: |
|
||||
# Override docker-compose image tag to use latest instead of stable
|
||||
# This overrides any PROWLER_API_VERSION set in .env file
|
||||
export PROWLER_API_VERSION=latest
|
||||
echo "Using PROWLER_API_VERSION=${PROWLER_API_VERSION}"
|
||||
docker compose up -d api worker worker-beat
|
||||
- name: Wait for API to be ready
|
||||
run: |
|
||||
echo "Waiting for prowler-api..."
|
||||
timeout=150 # 5 minutes max
|
||||
elapsed=0
|
||||
while [ $elapsed -lt $timeout ]; do
|
||||
if curl -s ${NEXT_PUBLIC_API_BASE_URL}/docs >/dev/null 2>&1; then
|
||||
echo "Prowler API is ready!"
|
||||
exit 0
|
||||
fi
|
||||
echo "Waiting for prowler-api... (${elapsed}s elapsed)"
|
||||
sleep 5
|
||||
elapsed=$((elapsed + 5))
|
||||
done
|
||||
echo "Timeout waiting for prowler-api to start"
|
||||
exit 1
|
||||
- name: Load database fixtures for E2E tests
|
||||
run: |
|
||||
docker compose exec -T api sh -c '
|
||||
echo "Loading all fixtures from api/fixtures/dev/..."
|
||||
for fixture in api/fixtures/dev/*.json; do
|
||||
if [ -f "$fixture" ]; then
|
||||
echo "Loading $fixture"
|
||||
poetry run python manage.py loaddata "$fixture" --database admin
|
||||
fi
|
||||
done
|
||||
echo "All database fixtures loaded successfully!"
|
||||
'
|
||||
- name: Setup Node.js environment
|
||||
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
|
||||
with:
|
||||
node-version: '24.13.0'
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
run_install: false
|
||||
- name: Get pnpm store directory
|
||||
shell: bash
|
||||
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||
- name: Setup pnpm and Next.js cache
|
||||
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
|
||||
with:
|
||||
path: |
|
||||
${{ env.STORE_PATH }}
|
||||
./ui/node_modules
|
||||
./ui/.next/cache
|
||||
key: ${{ runner.os }}-pnpm-nextjs-${{ hashFiles('ui/pnpm-lock.yaml') }}-${{ hashFiles('ui/**/*.ts', 'ui/**/*.tsx', 'ui/**/*.js', 'ui/**/*.jsx') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-nextjs-${{ hashFiles('ui/pnpm-lock.yaml') }}-
|
||||
${{ runner.os }}-pnpm-nextjs-
|
||||
- name: Install UI dependencies
|
||||
working-directory: ./ui
|
||||
run: pnpm install --frozen-lockfile --prefer-offline
|
||||
- name: Build UI application
|
||||
working-directory: ./ui
|
||||
run: pnpm run build
|
||||
- name: Cache Playwright browsers
|
||||
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
|
||||
id: playwright-cache
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('ui/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-playwright-
|
||||
- name: Install Playwright browsers
|
||||
working-directory: ./ui
|
||||
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
||||
run: pnpm run test:e2e:install
|
||||
- name: Run E2E tests
|
||||
working-directory: ./ui
|
||||
run: pnpm run test:e2e
|
||||
- name: Upload test reports
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
if: failure()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: ui/playwright-report/
|
||||
retention-days: 30
|
||||
- name: Cleanup services
|
||||
if: always()
|
||||
run: |
|
||||
echo "Shutting down services..."
|
||||
docker compose down -v || true
|
||||
echo "Cleanup completed"
|
||||
@@ -44,6 +44,7 @@ Use these skills for detailed patterns on-demand:
|
||||
| `prowler-commit` | Professional commits (conventional-commits) | [SKILL.md](skills/prowler-commit/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) |
|
||||
| `prowler-attack-paths-query` | Create Attack Paths openCypher queries | [SKILL.md](skills/prowler-attack-paths-query/SKILL.md) |
|
||||
| `skill-creator` | Create new AI agent skills | [SKILL.md](skills/skill-creator/SKILL.md) |
|
||||
|
||||
### Auto-invoke Skills
|
||||
@@ -56,6 +57,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
| Adding DRF pagination or permissions | `django-drf` |
|
||||
| Adding new providers | `prowler-provider` |
|
||||
| Adding services to existing providers | `prowler-provider` |
|
||||
| Adding privilege escalation detection queries | `prowler-attack-paths-query` |
|
||||
| After creating/modifying a skill | `skill-sync` |
|
||||
| App Router / Server Actions | `nextjs-15` |
|
||||
| Building AI chat features | `ai-sdk-5` |
|
||||
@@ -63,6 +65,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
| Create PR that requires changelog entry | `prowler-changelog` |
|
||||
| Create a PR with gh pr create | `prowler-pr` |
|
||||
| Creating API endpoints | `jsonapi` |
|
||||
| Creating Attack Paths queries | `prowler-attack-paths-query` |
|
||||
| Creating ViewSets, serializers, or filters in api/ | `django-drf` |
|
||||
| Creating Zod schemas | `zod-4` |
|
||||
| Creating a git commit | `prowler-commit` |
|
||||
@@ -92,6 +95,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
| Understand changelog gate and no-changelog label behavior | `prowler-ci` |
|
||||
| Understand review ownership with CODEOWNERS | `prowler-pr` |
|
||||
| Update CHANGELOG.md in any component | `prowler-changelog` |
|
||||
| Updating existing Attack Paths queries | `prowler-attack-paths-query` |
|
||||
| Updating existing checks and metadata | `prowler-sdk-check` |
|
||||
| Using Zustand stores | `zustand-5` |
|
||||
| Working on MCP server tools | `prowler-mcp` |
|
||||
|
||||
@@ -104,18 +104,19 @@ Every AWS provider scan will enqueue an Attack Paths ingestion job automatically
|
||||
|
||||
| Provider | Checks | Services | [Compliance Frameworks](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/compliance/) | [Categories](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/misc/#categories) | Support | Interface |
|
||||
|---|---|---|---|---|---|---|
|
||||
| AWS | 584 | 84 | 40 | 17 | Official | UI, API, CLI |
|
||||
| Azure | 169 | 22 | 16 | 12 | Official | UI, API, CLI |
|
||||
| AWS | 585 | 84 | 40 | 17 | Official | UI, API, CLI |
|
||||
| Azure | 169 | 22 | 17 | 13 | Official | UI, API, CLI |
|
||||
| GCP | 100 | 17 | 14 | 7 | Official | UI, API, CLI |
|
||||
| Kubernetes | 84 | 7 | 7 | 9 | Official | UI, API, CLI |
|
||||
| GitHub | 20 | 2 | 1 | 2 | Official | UI, API, CLI |
|
||||
| M365 | 71 | 7 | 4 | 3 | Official | UI, API, CLI |
|
||||
| M365 | 72 | 7 | 4 | 4 | Official | UI, API, CLI |
|
||||
| OCI | 52 | 14 | 1 | 12 | Official | UI, API, CLI |
|
||||
| Alibaba Cloud | 64 | 9 | 2 | 9 | Official | UI, API, CLI |
|
||||
| Cloudflare | 23 | 2 | 0 | 5 | Official | CLI |
|
||||
| Cloudflare | 29 | 3 | 0 | 5 | Official | CLI |
|
||||
| IaC | [See `trivy` docs.](https://trivy.dev/latest/docs/coverage/iac/) | N/A | N/A | N/A | Official | UI, API, CLI |
|
||||
| MongoDB Atlas | 10 | 3 | 0 | 3 | Official | UI, API, CLI |
|
||||
| LLM | [See `promptfoo` docs.](https://www.promptfoo.dev/docs/red-team/plugins/) | N/A | N/A | N/A | Official | CLI |
|
||||
| OpenStack | 1 | 1 | 0 | 2 | Official | CLI |
|
||||
| NHN | 6 | 2 | 1 | 0 | Unofficial | CLI |
|
||||
|
||||
> [!Note]
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
> **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)
|
||||
> - [`prowler-attack-paths-query`](../skills/prowler-attack-paths-query/SKILL.md) - Attack Paths openCypher queries
|
||||
> - [`django-drf`](../skills/django-drf/SKILL.md) - Generic DRF patterns
|
||||
> - [`jsonapi`](../skills/jsonapi/SKILL.md) - Strict JSON:API v1.1 spec compliance
|
||||
> - [`pytest`](../skills/pytest/SKILL.md) - Generic pytest patterns
|
||||
@@ -15,9 +16,11 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
|--------|-------|
|
||||
| Add changelog entry for a PR or feature | `prowler-changelog` |
|
||||
| Adding DRF pagination or permissions | `django-drf` |
|
||||
| Adding privilege escalation detection queries | `prowler-attack-paths-query` |
|
||||
| Committing changes | `prowler-commit` |
|
||||
| Create PR that requires changelog entry | `prowler-changelog` |
|
||||
| Creating API endpoints | `jsonapi` |
|
||||
| Creating Attack Paths queries | `prowler-attack-paths-query` |
|
||||
| Creating ViewSets, serializers, or filters in api/ | `django-drf` |
|
||||
| Creating a git commit | `prowler-commit` |
|
||||
| Creating/modifying models, views, serializers | `prowler-api` |
|
||||
@@ -27,6 +30,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
| Reviewing JSON:API compliance | `jsonapi` |
|
||||
| Testing RLS tenant isolation | `prowler-test-api` |
|
||||
| Update CHANGELOG.md in any component | `prowler-changelog` |
|
||||
| Updating existing Attack Paths queries | `prowler-attack-paths-query` |
|
||||
| Writing Prowler API tests | `prowler-test-api` |
|
||||
| Writing Python tests with pytest | `pytest` |
|
||||
|
||||
|
||||
@@ -2,6 +2,38 @@
|
||||
|
||||
All notable changes to the **Prowler API** are documented in this file.
|
||||
|
||||
## [1.20.0] (Prowler UNRELEASED)
|
||||
|
||||
### 🚀 Added
|
||||
|
||||
- OpenStack provider support [(#10003)](https://github.com/prowler-cloud/prowler/pull/10003)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
- Attack Paths: Queries definition now has short description and attribution [(#9983)](https://github.com/prowler-cloud/prowler/pull/9983)
|
||||
- Attack Paths: Internet node is created while scan [(#9992)](https://github.com/prowler-cloud/prowler/pull/9992)
|
||||
- Attack Paths: Add full paths set from [pathfinding.cloud](https://pathfinding.cloud/) [(#10008)](https://github.com/prowler-cloud/prowler/pull/10008)
|
||||
- Support CSA CCM 4.0 for the AWS provider [(#10018)](https://github.com/prowler-cloud/prowler/pull/10018)
|
||||
- Support CSA CCM 4.0 for the GCP provider [(#10042)](https://github.com/prowler-cloud/prowler/pull/10042)
|
||||
- Support CSA CCM 4.0 for the Azure provider [(#10039)](https://github.com/prowler-cloud/prowler/pull/10039)
|
||||
- Support CSA CCM 4.0 for the Oracle Cloud provider [(#10057)](https://github.com/prowler-cloud/prowler/pull/10057)
|
||||
- Support CSA CCM 4.0 for the Alibaba Cloud provider [(#10061)](https://github.com/prowler-cloud/prowler/pull/10061)
|
||||
- Attack Paths: Mark attack Paths scan as failed when Celery task fails outside job error handling [(#10065)](https://github.com/prowler-cloud/prowler/pull/10065)
|
||||
|
||||
### 🔐 Security
|
||||
|
||||
- Bump `Pillow` to 12.1.1 (CVE-2021-25289) [(#10027)](https://github.com/prowler-cloud/prowler/pull/10027)
|
||||
|
||||
---
|
||||
|
||||
## [1.19.2] (Prowler v5.18.2)
|
||||
|
||||
### 🐞 Fixed
|
||||
|
||||
- SAML role mapping now prevents removing the last MANAGE_ACCOUNT user [(#10007)](https://github.com/prowler-cloud/prowler/pull/10007)
|
||||
|
||||
---
|
||||
|
||||
## [1.19.0] (Prowler v5.18.0)
|
||||
|
||||
### 🚀 Added
|
||||
|
||||
Generated
+148
-182
@@ -2508,43 +2508,49 @@ dev = ["bandit", "coverage", "flake8", "pydocstyle", "pylint", "pytest", "pytest
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "44.0.1"
|
||||
version = "44.0.3"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
optional = false
|
||||
python-versions = "!=3.9.0,!=3.9.1,>=3.7"
|
||||
groups = ["main", "dev"]
|
||||
files = [
|
||||
{file = "cryptography-44.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf688f615c29bfe9dfc44312ca470989279f0e94bb9f631f85e3459af8efc009"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd7c7e2d71d908dc0f8d2027e1604102140d84b155e658c20e8ad1304317691f"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887143b9ff6bad2b7570da75a7fe8bbf5f65276365ac259a5d2d5147a73775f2"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:322eb03ecc62784536bc173f1483e76747aafeb69c8728df48537eb431cd1911"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:21377472ca4ada2906bc313168c9dc7b1d7ca417b63c1c3011d0c74b7de9ae69"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:df978682c1504fc93b3209de21aeabf2375cb1571d4e61907b3e7a2540e83026"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:eb3889330f2a4a148abead555399ec9a32b13b7c8ba969b72d8e500eb7ef84cd"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:8e6a85a93d0642bd774460a86513c5d9d80b5c002ca9693e63f6e540f1815ed0"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6f76fdd6fd048576a04c5210d53aa04ca34d2ed63336d4abd306d0cbe298fddf"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6c8acf6f3d1f47acb2248ec3ea261171a671f3d9428e34ad0357148d492c7864"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-win32.whl", hash = "sha256:24979e9f2040c953a94bf3c6782e67795a4c260734e5264dceea65c8f4bae64a"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:fd0ee90072861e276b0ff08bd627abec29e32a53b2be44e41dbcdf87cbee2b00"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a2d8a7045e1ab9b9f803f0d9531ead85f90c5f2859e653b61497228b18452008"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8272f257cf1cbd3f2e120f14c68bff2b6bdfcc157fafdee84a1b795efd72862"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e8d181e90a777b63f3f0caa836844a1182f1f265687fac2115fcf245f5fbec3"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:436df4f203482f41aad60ed1813811ac4ab102765ecae7a2bbb1dbb66dcff5a7"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4f422e8c6a28cf8b7f883eb790695d6d45b0c385a2583073f3cec434cc705e1a"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:72198e2b5925155497a5a3e8c216c7fb3e64c16ccee11f0e7da272fa93b35c4c"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:2a46a89ad3e6176223b632056f321bc7de36b9f9b93b2cc1cccf935a3849dc62"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:53f23339864b617a3dfc2b0ac8d5c432625c80014c25caac9082314e9de56f41"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:888fcc3fce0c888785a4876ca55f9f43787f4c5c1cc1e2e0da71ad481ff82c5b"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:00918d859aa4e57db8299607086f793fa7813ae2ff5a4637e318a25ef82730f7"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-win32.whl", hash = "sha256:9b336599e2cb77b1008cb2ac264b290803ec5e8e89d618a5e978ff5eb6f715d9"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:e403f7f766ded778ecdb790da786b418a9f2394f36e8cc8b796cc056ab05f44f"},
|
||||
{file = "cryptography-44.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1f9a92144fa0c877117e9748c74501bea842f93d21ee00b0cf922846d9d0b183"},
|
||||
{file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:610a83540765a8d8ce0f351ce42e26e53e1f774a6efb71eb1b41eb01d01c3d12"},
|
||||
{file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:5fed5cd6102bb4eb843e3315d2bf25fede494509bddadb81e03a859c1bc17b83"},
|
||||
{file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:f4daefc971c2d1f82f03097dc6f216744a6cd2ac0f04c68fb935ea2ba2a0d420"},
|
||||
{file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:94f99f2b943b354a5b6307d7e8d19f5c423a794462bde2bf310c770ba052b1c4"},
|
||||
{file = "cryptography-44.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d9c5b9f698a83c8bd71e0f4d3f9f839ef244798e5ffe96febfa9714717db7af7"},
|
||||
{file = "cryptography-44.0.1.tar.gz", hash = "sha256:f51f5705ab27898afda1aaa430f34ad90dc117421057782022edf0600bec5f14"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:962bc30480a08d133e631e8dfd4783ab71cc9e33d5d7c1e192f0b7c06397bb88"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffc61e8f3bf5b60346d89cd3d37231019c17a081208dfbbd6e1605ba03fa137"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58968d331425a6f9eedcee087f77fd3c927c88f55368f43ff7e0a19891f2642c"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e28d62e59a4dbd1d22e747f57d4f00c459af22181f0b2f787ea83f5a876d7c76"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af653022a0c25ef2e3ffb2c673a50e5a0d02fecc41608f4954176f1933b12359"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:157f1f3b8d941c2bd8f3ffee0af9b049c9665c39d3da9db2dc338feca5e98a43"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:c6cd67722619e4d55fdb42ead64ed8843d64638e9c07f4011163e46bc512cf01"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b424563394c369a804ecbee9b06dfb34997f19d00b3518e39f83a5642618397d"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c91fc8e8fd78af553f98bc7f2a1d8db977334e4eea302a4bfd75b9461c2d8904"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:25cd194c39fa5a0aa4169125ee27d1172097857b27109a45fadc59653ec06f44"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-win32.whl", hash = "sha256:3be3f649d91cb182c3a6bd336de8b61a0a71965bd13d1a04a0e15b39c3d5809d"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:3883076d5c4cc56dbef0b898a74eb6992fdac29a7b9013870b34efe4ddb39a0d"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:5639c2b16764c6f76eedf722dbad9a0914960d3489c0cc38694ddf9464f1bb2f"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3ffef566ac88f75967d7abd852ed5f182da252d23fac11b4766da3957766759"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:192ed30fac1728f7587c6f4613c29c584abdc565d7417c13904708db10206645"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7d5fe7195c27c32a64955740b949070f21cba664604291c298518d2e255931d2"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3f07943aa4d7dad689e3bb1638ddc4944cc5e0921e3c227486daae0e31a05e54"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb90f60e03d563ca2445099edf605c16ed1d5b15182d21831f58460c48bffb93"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:ab0b005721cc0039e885ac3503825661bd9810b15d4f374e473f8c89b7d5460c"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:3bb0847e6363c037df8f6ede57d88eaf3410ca2267fb12275370a76f85786a6f"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b0cc66c74c797e1db750aaa842ad5b8b78e14805a9b5d1348dc603612d3e3ff5"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6866df152b581f9429020320e5eb9794c8780e90f7ccb021940d7f50ee00ae0b"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-win32.whl", hash = "sha256:c138abae3a12a94c75c10499f1cbae81294a6f983b3af066390adee73f433028"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:5d186f32e52e66994dce4f766884bcb9c68b8da62d61d9d215bfe5fb56d21334"},
|
||||
{file = "cryptography-44.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:cad399780053fb383dc067475135e41c9fe7d901a97dd5d9c5dfb5611afc0d7d"},
|
||||
{file = "cryptography-44.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:21a83f6f35b9cc656d71b5de8d519f566df01e660ac2578805ab245ffd8523f8"},
|
||||
{file = "cryptography-44.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fc3c9babc1e1faefd62704bb46a69f359a9819eb0292e40df3fb6e3574715cd4"},
|
||||
{file = "cryptography-44.0.3-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:e909df4053064a97f1e6565153ff8bb389af12c5c8d29c343308760890560aff"},
|
||||
{file = "cryptography-44.0.3-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:dad80b45c22e05b259e33ddd458e9e2ba099c86ccf4e88db7bbab4b747b18d06"},
|
||||
{file = "cryptography-44.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:479d92908277bed6e1a1c69b277734a7771c2b78633c224445b5c60a9f4bc1d9"},
|
||||
{file = "cryptography-44.0.3-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:896530bc9107b226f265effa7ef3f21270f18a2026bc09fed1ebd7b66ddf6375"},
|
||||
{file = "cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9b4d4a5dbee05a2c390bf212e78b99434efec37b17a4bff42f50285c5c8c9647"},
|
||||
{file = "cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02f55fb4f8b79c1221b0961488eaae21015b69b210e18c386b69de182ebb1259"},
|
||||
{file = "cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:dd3db61b8fe5be220eee484a17233287d0be6932d056cf5738225b9c05ef4fff"},
|
||||
{file = "cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:978631ec51a6bbc0b7e58f23b68a8ce9e5f09721940933e9c217068388789fe5"},
|
||||
{file = "cryptography-44.0.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:5d20cc348cca3a8aa7312f42ab953a56e15323800ca3ab0706b8cd452a3a056c"},
|
||||
{file = "cryptography-44.0.3.tar.gz", hash = "sha256:fe19d8bc5536a91a24a8133328880a41831b6c5df54599a8417b62fe015d3053"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -2557,7 +2563,7 @@ nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_version >= \"3.8\""]
|
||||
pep8test = ["check-sdist ; python_version >= \"3.8\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"]
|
||||
sdist = ["build (>=1.0.0)"]
|
||||
ssh = ["bcrypt (>=3.1.5)"]
|
||||
test = ["certifi (>=2024)", "cryptography-vectors (==44.0.1)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"]
|
||||
test = ["certifi (>=2024)", "cryptography-vectors (==44.0.3)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"]
|
||||
test-randomorder = ["pytest-randomly"]
|
||||
|
||||
[[package]]
|
||||
@@ -5830,46 +5836,6 @@ files = [
|
||||
{file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "netifaces"
|
||||
version = "0.11.0"
|
||||
description = "Portable network interface information."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "netifaces-0.11.0-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eb4813b77d5df99903af4757ce980a98c4d702bbcb81f32a0b305a1537bdf0b1"},
|
||||
{file = "netifaces-0.11.0-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:5f9ca13babe4d845e400921973f6165a4c2f9f3379c7abfc7478160e25d196a4"},
|
||||
{file = "netifaces-0.11.0-cp27-cp27m-win32.whl", hash = "sha256:7dbb71ea26d304e78ccccf6faccef71bb27ea35e259fb883cfd7fd7b4f17ecb1"},
|
||||
{file = "netifaces-0.11.0-cp27-cp27m-win_amd64.whl", hash = "sha256:0f6133ac02521270d9f7c490f0c8c60638ff4aec8338efeff10a1b51506abe85"},
|
||||
{file = "netifaces-0.11.0-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:08e3f102a59f9eaef70948340aeb6c89bd09734e0dca0f3b82720305729f63ea"},
|
||||
{file = "netifaces-0.11.0-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c03fb2d4ef4e393f2e6ffc6376410a22a3544f164b336b3a355226653e5efd89"},
|
||||
{file = "netifaces-0.11.0-cp34-cp34m-win32.whl", hash = "sha256:73ff21559675150d31deea8f1f8d7e9a9a7e4688732a94d71327082f517fc6b4"},
|
||||
{file = "netifaces-0.11.0-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:815eafdf8b8f2e61370afc6add6194bd5a7252ae44c667e96c4c1ecf418811e4"},
|
||||
{file = "netifaces-0.11.0-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:50721858c935a76b83dd0dd1ab472cad0a3ef540a1408057624604002fcfb45b"},
|
||||
{file = "netifaces-0.11.0-cp35-cp35m-win32.whl", hash = "sha256:c9a3a47cd3aaeb71e93e681d9816c56406ed755b9442e981b07e3618fb71d2ac"},
|
||||
{file = "netifaces-0.11.0-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:aab1dbfdc55086c789f0eb37affccf47b895b98d490738b81f3b2360100426be"},
|
||||
{file = "netifaces-0.11.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c37a1ca83825bc6f54dddf5277e9c65dec2f1b4d0ba44b8fd42bc30c91aa6ea1"},
|
||||
{file = "netifaces-0.11.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:28f4bf3a1361ab3ed93c5ef360c8b7d4a4ae060176a3529e72e5e4ffc4afd8b0"},
|
||||
{file = "netifaces-0.11.0-cp36-cp36m-win32.whl", hash = "sha256:2650beee182fed66617e18474b943e72e52f10a24dc8cac1db36c41ee9c041b7"},
|
||||
{file = "netifaces-0.11.0-cp36-cp36m-win_amd64.whl", hash = "sha256:cb925e1ca024d6f9b4f9b01d83215fd00fe69d095d0255ff3f64bffda74025c8"},
|
||||
{file = "netifaces-0.11.0-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:84e4d2e6973eccc52778735befc01638498781ce0e39aa2044ccfd2385c03246"},
|
||||
{file = "netifaces-0.11.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:18917fbbdcb2d4f897153c5ddbb56b31fa6dd7c3fa9608b7e3c3a663df8206b5"},
|
||||
{file = "netifaces-0.11.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:48324183af7f1bc44f5f197f3dad54a809ad1ef0c78baee2c88f16a5de02c4c9"},
|
||||
{file = "netifaces-0.11.0-cp37-cp37m-win32.whl", hash = "sha256:8f7da24eab0d4184715d96208b38d373fd15c37b0dafb74756c638bd619ba150"},
|
||||
{file = "netifaces-0.11.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2479bb4bb50968089a7c045f24d120f37026d7e802ec134c4490eae994c729b5"},
|
||||
{file = "netifaces-0.11.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:3ecb3f37c31d5d51d2a4d935cfa81c9bc956687c6f5237021b36d6fdc2815b2c"},
|
||||
{file = "netifaces-0.11.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:96c0fe9696398253f93482c84814f0e7290eee0bfec11563bd07d80d701280c3"},
|
||||
{file = "netifaces-0.11.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c92ff9ac7c2282009fe0dcb67ee3cd17978cffbe0c8f4b471c00fe4325c9b4d4"},
|
||||
{file = "netifaces-0.11.0-cp38-cp38-win32.whl", hash = "sha256:d07b01c51b0b6ceb0f09fc48ec58debd99d2c8430b09e56651addeaf5de48048"},
|
||||
{file = "netifaces-0.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:469fc61034f3daf095e02f9f1bbac07927b826c76b745207287bc594884cfd05"},
|
||||
{file = "netifaces-0.11.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5be83986100ed1fdfa78f11ccff9e4757297735ac17391b95e17e74335c2047d"},
|
||||
{file = "netifaces-0.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:54ff6624eb95b8a07e79aa8817288659af174e954cca24cdb0daeeddfc03c4ff"},
|
||||
{file = "netifaces-0.11.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:841aa21110a20dc1621e3dd9f922c64ca64dd1eb213c47267a2c324d823f6c8f"},
|
||||
{file = "netifaces-0.11.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e76c7f351e0444721e85f975ae92718e21c1f361bda946d60a214061de1f00a1"},
|
||||
{file = "netifaces-0.11.0.tar.gz", hash = "sha256:043a79146eb2907edf439899f262b3dfe41717d34124298ed281139a8b93ca32"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nltk"
|
||||
version = "3.9.2"
|
||||
@@ -6037,14 +6003,14 @@ voice-helpers = ["numpy (>=2.0.2)", "sounddevice (>=0.5.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "openstacksdk"
|
||||
version = "4.0.1"
|
||||
version = "4.2.0"
|
||||
description = "An SDK for building applications to work with OpenStack"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "openstacksdk-4.0.1-py3-none-any.whl", hash = "sha256:d63187a006fff7c1de1486c9e2e1073a787af402620c3c0ed0cf5291225998ac"},
|
||||
{file = "openstacksdk-4.0.1.tar.gz", hash = "sha256:19faa1d5e6a78a2c1dc06a171e65e776ba82e9df23e1d08586225dc5ade9fc63"},
|
||||
{file = "openstacksdk-4.2.0-py3-none-any.whl", hash = "sha256:238be0fa5d9899872b00787ab38e84f92fd6dc87525fde0965dadcdc12196dc6"},
|
||||
{file = "openstacksdk-4.2.0.tar.gz", hash = "sha256:5cb9450dcce8054a2caf89d8be9e55057ddfa219a954e781032241eb29280445"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -6055,10 +6021,10 @@ iso8601 = ">=0.1.11"
|
||||
jmespath = ">=0.9.0"
|
||||
jsonpatch = ">=1.16,<1.20 || >1.20"
|
||||
keystoneauth1 = ">=3.18.0"
|
||||
netifaces = ">=0.10.4"
|
||||
os-service-types = ">=1.7.0"
|
||||
pbr = ">=2.0.0,<2.1.0 || >2.1.0"
|
||||
platformdirs = ">=3"
|
||||
psutil = ">=3.2.2"
|
||||
PyYAML = ">=3.13"
|
||||
requestsexceptions = ">=1.2.0"
|
||||
|
||||
@@ -6258,103 +6224,103 @@ urllib3 = "*"
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
version = "12.1.0"
|
||||
version = "12.1.1"
|
||||
description = "Python Imaging Library (fork)"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "pillow-12.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:fb125d860738a09d363a88daa0f59c4533529a90e564785e20fe875b200b6dbd"},
|
||||
{file = "pillow-12.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cad302dc10fac357d3467a74a9561c90609768a6f73a1923b0fd851b6486f8b0"},
|
||||
{file = "pillow-12.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a40905599d8079e09f25027423aed94f2823adaf2868940de991e53a449e14a8"},
|
||||
{file = "pillow-12.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:92a7fe4225365c5e3a8e598982269c6d6698d3e783b3b1ae979e7819f9cd55c1"},
|
||||
{file = "pillow-12.1.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f10c98f49227ed8383d28174ee95155a675c4ed7f85e2e573b04414f7e371bda"},
|
||||
{file = "pillow-12.1.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8637e29d13f478bc4f153d8daa9ffb16455f0a6cb287da1b432fdad2bfbd66c7"},
|
||||
{file = "pillow-12.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:21e686a21078b0f9cb8c8a961d99e6a4ddb88e0fc5ea6e130172ddddc2e5221a"},
|
||||
{file = "pillow-12.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2415373395a831f53933c23ce051021e79c8cd7979822d8cc478547a3f4da8ef"},
|
||||
{file = "pillow-12.1.0-cp310-cp310-win32.whl", hash = "sha256:e75d3dba8fc1ddfec0cd752108f93b83b4f8d6ab40e524a95d35f016b9683b09"},
|
||||
{file = "pillow-12.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:64efdf00c09e31efd754448a383ea241f55a994fd079866b92d2bbff598aad91"},
|
||||
{file = "pillow-12.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:f188028b5af6b8fb2e9a76ac0f841a575bd1bd396e46ef0840d9b88a48fdbcea"},
|
||||
{file = "pillow-12.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:a83e0850cb8f5ac975291ebfc4170ba481f41a28065277f7f735c202cd8e0af3"},
|
||||
{file = "pillow-12.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b6e53e82ec2db0717eabb276aa56cf4e500c9a7cec2c2e189b55c24f65a3e8c0"},
|
||||
{file = "pillow-12.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:40a8e3b9e8773876d6e30daed22f016509e3987bab61b3b7fe309d7019a87451"},
|
||||
{file = "pillow-12.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:800429ac32c9b72909c671aaf17ecd13110f823ddb7db4dfef412a5587c2c24e"},
|
||||
{file = "pillow-12.1.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b022eaaf709541b391ee069f0022ee5b36c709df71986e3f7be312e46f42c84"},
|
||||
{file = "pillow-12.1.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f345e7bc9d7f368887c712aa5054558bad44d2a301ddf9248599f4161abc7c0"},
|
||||
{file = "pillow-12.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d70347c8a5b7ccd803ec0c85c8709f036e6348f1e6a5bf048ecd9c64d3550b8b"},
|
||||
{file = "pillow-12.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1fcc52d86ce7a34fd17cb04e87cfdb164648a3662a6f20565910a99653d66c18"},
|
||||
{file = "pillow-12.1.0-cp311-cp311-win32.whl", hash = "sha256:3ffaa2f0659e2f740473bcf03c702c39a8d4b2b7ffc629052028764324842c64"},
|
||||
{file = "pillow-12.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:806f3987ffe10e867bab0ddad45df1148a2b98221798457fa097ad85d6e8bc75"},
|
||||
{file = "pillow-12.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:9f5fefaca968e700ad1a4a9de98bf0869a94e397fe3524c4c9450c1445252304"},
|
||||
{file = "pillow-12.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a332ac4ccb84b6dde65dbace8431f3af08874bf9770719d32a635c4ef411b18b"},
|
||||
{file = "pillow-12.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:907bfa8a9cb790748a9aa4513e37c88c59660da3bcfffbd24a7d9e6abf224551"},
|
||||
{file = "pillow-12.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:efdc140e7b63b8f739d09a99033aa430accce485ff78e6d311973a67b6bf3208"},
|
||||
{file = "pillow-12.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bef9768cab184e7ae6e559c032e95ba8d07b3023c289f79a2bd36e8bf85605a5"},
|
||||
{file = "pillow-12.1.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:742aea052cf5ab5034a53c3846165bc3ce88d7c38e954120db0ab867ca242661"},
|
||||
{file = "pillow-12.1.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6dfc2af5b082b635af6e08e0d1f9f1c4e04d17d4e2ca0ef96131e85eda6eb17"},
|
||||
{file = "pillow-12.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:609e89d9f90b581c8d16358c9087df76024cf058fa693dd3e1e1620823f39670"},
|
||||
{file = "pillow-12.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:43b4899cfd091a9693a1278c4982f3e50f7fb7cff5153b05174b4afc9593b616"},
|
||||
{file = "pillow-12.1.0-cp312-cp312-win32.whl", hash = "sha256:aa0c9cc0b82b14766a99fbe6084409972266e82f459821cd26997a488a7261a7"},
|
||||
{file = "pillow-12.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:d70534cea9e7966169ad29a903b99fc507e932069a881d0965a1a84bb57f6c6d"},
|
||||
{file = "pillow-12.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:65b80c1ee7e14a87d6a068dd3b0aea268ffcabfe0498d38661b00c5b4b22e74c"},
|
||||
{file = "pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:7b5dd7cbae20285cdb597b10eb5a2c13aa9de6cde9bb64a3c1317427b1db1ae1"},
|
||||
{file = "pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:29a4cef9cb672363926f0470afc516dbf7305a14d8c54f7abbb5c199cd8f8179"},
|
||||
{file = "pillow-12.1.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:681088909d7e8fa9e31b9799aaa59ba5234c58e5e4f1951b4c4d1082a2e980e0"},
|
||||
{file = "pillow-12.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:983976c2ab753166dc66d36af6e8ec15bb511e4a25856e2227e5f7e00a160587"},
|
||||
{file = "pillow-12.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:db44d5c160a90df2d24a24760bbd37607d53da0b34fb546c4c232af7192298ac"},
|
||||
{file = "pillow-12.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6b7a9d1db5dad90e2991645874f708e87d9a3c370c243c2d7684d28f7e133e6b"},
|
||||
{file = "pillow-12.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6258f3260986990ba2fa8a874f8b6e808cf5abb51a94015ca3dc3c68aa4f30ea"},
|
||||
{file = "pillow-12.1.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e115c15e3bc727b1ca3e641a909f77f8ca72a64fff150f666fcc85e57701c26c"},
|
||||
{file = "pillow-12.1.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6741e6f3074a35e47c77b23a4e4f2d90db3ed905cb1c5e6e0d49bff2045632bc"},
|
||||
{file = "pillow-12.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:935b9d1aed48fcfb3f838caac506f38e29621b44ccc4f8a64d575cb1b2a88644"},
|
||||
{file = "pillow-12.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5fee4c04aad8932da9f8f710af2c1a15a83582cfb884152a9caa79d4efcdbf9c"},
|
||||
{file = "pillow-12.1.0-cp313-cp313-win32.whl", hash = "sha256:a786bf667724d84aa29b5db1c61b7bfdde380202aaca12c3461afd6b71743171"},
|
||||
{file = "pillow-12.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:461f9dfdafa394c59cd6d818bdfdbab4028b83b02caadaff0ffd433faf4c9a7a"},
|
||||
{file = "pillow-12.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:9212d6b86917a2300669511ed094a9406888362e085f2431a7da985a6b124f45"},
|
||||
{file = "pillow-12.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:00162e9ca6d22b7c3ee8e61faa3c3253cd19b6a37f126cad04f2f88b306f557d"},
|
||||
{file = "pillow-12.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7d6daa89a00b58c37cb1747ec9fb7ac3bc5ffd5949f5888657dfddde6d1312e0"},
|
||||
{file = "pillow-12.1.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e2479c7f02f9d505682dc47df8c0ea1fc5e264c4d1629a5d63fe3e2334b89554"},
|
||||
{file = "pillow-12.1.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f188d580bd870cda1e15183790d1cc2fa78f666e76077d103edf048eed9c356e"},
|
||||
{file = "pillow-12.1.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0fde7ec5538ab5095cc02df38ee99b0443ff0e1c847a045554cf5f9af1f4aa82"},
|
||||
{file = "pillow-12.1.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ed07dca4a8464bada6139ab38f5382f83e5f111698caf3191cb8dbf27d908b4"},
|
||||
{file = "pillow-12.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f45bd71d1fa5e5749587613037b172e0b3b23159d1c00ef2fc920da6f470e6f0"},
|
||||
{file = "pillow-12.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:277518bf4fe74aa91489e1b20577473b19ee70fb97c374aa50830b279f25841b"},
|
||||
{file = "pillow-12.1.0-cp313-cp313t-win32.whl", hash = "sha256:7315f9137087c4e0ee73a761b163fc9aa3b19f5f606a7fc08d83fd3e4379af65"},
|
||||
{file = "pillow-12.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:0ddedfaa8b5f0b4ffbc2fa87b556dc59f6bb4ecb14a53b33f9189713ae8053c0"},
|
||||
{file = "pillow-12.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:80941e6d573197a0c28f394753de529bb436b1ca990ed6e765cf42426abc39f8"},
|
||||
{file = "pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:5cb7bc1966d031aec37ddb9dcf15c2da5b2e9f7cc3ca7c54473a20a927e1eb91"},
|
||||
{file = "pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:97e9993d5ed946aba26baf9c1e8cf18adbab584b99f452ee72f7ee8acb882796"},
|
||||
{file = "pillow-12.1.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:414b9a78e14ffeb98128863314e62c3f24b8a86081066625700b7985b3f529bd"},
|
||||
{file = "pillow-12.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e6bdb408f7c9dd2a5ff2b14a3b0bb6d4deb29fb9961e6eb3ae2031ae9a5cec13"},
|
||||
{file = "pillow-12.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3413c2ae377550f5487991d444428f1a8ae92784aac79caa8b1e3b89b175f77e"},
|
||||
{file = "pillow-12.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e5dcbe95016e88437ecf33544ba5db21ef1b8dd6e1b434a2cb2a3d605299e643"},
|
||||
{file = "pillow-12.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d0a7735df32ccbcc98b98a1ac785cc4b19b580be1bdf0aeb5c03223220ea09d5"},
|
||||
{file = "pillow-12.1.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c27407a2d1b96774cbc4a7594129cc027339fd800cd081e44497722ea1179de"},
|
||||
{file = "pillow-12.1.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15c794d74303828eaa957ff8070846d0efe8c630901a1c753fdc63850e19ecd9"},
|
||||
{file = "pillow-12.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c990547452ee2800d8506c4150280757f88532f3de2a58e3022e9b179107862a"},
|
||||
{file = "pillow-12.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b63e13dd27da389ed9475b3d28510f0f954bca0041e8e551b2a4eb1eab56a39a"},
|
||||
{file = "pillow-12.1.0-cp314-cp314-win32.whl", hash = "sha256:1a949604f73eb07a8adab38c4fe50791f9919344398bdc8ac6b307f755fc7030"},
|
||||
{file = "pillow-12.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:4f9f6a650743f0ddee5593ac9e954ba1bdbc5e150bc066586d4f26127853ab94"},
|
||||
{file = "pillow-12.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:808b99604f7873c800c4840f55ff389936ef1948e4e87645eaf3fccbc8477ac4"},
|
||||
{file = "pillow-12.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc11908616c8a283cf7d664f77411a5ed2a02009b0097ff8abbba5e79128ccf2"},
|
||||
{file = "pillow-12.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:896866d2d436563fa2a43a9d72f417874f16b5545955c54a64941e87c1376c61"},
|
||||
{file = "pillow-12.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8e178e3e99d3c0ea8fc64b88447f7cac8ccf058af422a6cedc690d0eadd98c51"},
|
||||
{file = "pillow-12.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:079af2fb0c599c2ec144ba2c02766d1b55498e373b3ac64687e43849fbbef5bc"},
|
||||
{file = "pillow-12.1.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdec5e43377761c5dbca620efb69a77f6855c5a379e32ac5b158f54c84212b14"},
|
||||
{file = "pillow-12.1.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:565c986f4b45c020f5421a4cea13ef294dde9509a8577f29b2fc5edc7587fff8"},
|
||||
{file = "pillow-12.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:43aca0a55ce1eefc0aefa6253661cb54571857b1a7b2964bd8a1e3ef4b729924"},
|
||||
{file = "pillow-12.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0deedf2ea233722476b3a81e8cdfbad786f7adbed5d848469fa59fe52396e4ef"},
|
||||
{file = "pillow-12.1.0-cp314-cp314t-win32.whl", hash = "sha256:b17fbdbe01c196e7e159aacb889e091f28e61020a8abeac07b68079b6e626988"},
|
||||
{file = "pillow-12.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27b9baecb428899db6c0de572d6d305cfaf38ca1596b5c0542a5182e3e74e8c6"},
|
||||
{file = "pillow-12.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:f61333d817698bdcdd0f9d7793e365ac3d2a21c1f1eb02b32ad6aefb8d8ea831"},
|
||||
{file = "pillow-12.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ca94b6aac0d7af2a10ba08c0f888b3d5114439b6b3ef39968378723622fed377"},
|
||||
{file = "pillow-12.1.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:351889afef0f485b84078ea40fe33727a0492b9af3904661b0abbafee0355b72"},
|
||||
{file = "pillow-12.1.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb0984b30e973f7e2884362b7d23d0a348c7143ee559f38ef3eaab640144204c"},
|
||||
{file = "pillow-12.1.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:84cabc7095dd535ca934d57e9ce2a72ffd216e435a84acb06b2277b1de2689bd"},
|
||||
{file = "pillow-12.1.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53d8b764726d3af1a138dd353116f774e3862ec7e3794e0c8781e30db0f35dfc"},
|
||||
{file = "pillow-12.1.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5da841d81b1a05ef940a8567da92decaa15bc4d7dedb540a8c219ad83d91808a"},
|
||||
{file = "pillow-12.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:75af0b4c229ac519b155028fa1be632d812a519abba9b46b20e50c6caa184f19"},
|
||||
{file = "pillow-12.1.0.tar.gz", hash = "sha256:5c5ae0a06e9ea030ab786b0251b32c7e4ce10e58d983c0d5c56029455180b5b9"},
|
||||
{file = "pillow-12.1.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f1625b72740fdda5d77b4def688eb8fd6490975d06b909fd19f13f391e077e0"},
|
||||
{file = "pillow-12.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:178aa072084bd88ec759052feca8e56cbb14a60b39322b99a049e58090479713"},
|
||||
{file = "pillow-12.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b66e95d05ba806247aaa1561f080abc7975daf715c30780ff92a20e4ec546e1b"},
|
||||
{file = "pillow-12.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89c7e895002bbe49cdc5426150377cbbc04767d7547ed145473f496dfa40408b"},
|
||||
{file = "pillow-12.1.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a5cbdcddad0af3da87cb16b60d23648bc3b51967eb07223e9fed77a82b457c4"},
|
||||
{file = "pillow-12.1.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9f51079765661884a486727f0729d29054242f74b46186026582b4e4769918e4"},
|
||||
{file = "pillow-12.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:99c1506ea77c11531d75e3a412832a13a71c7ebc8192ab9e4b2e355555920e3e"},
|
||||
{file = "pillow-12.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:36341d06738a9f66c8287cf8b876d24b18db9bd8740fa0672c74e259ad408cff"},
|
||||
{file = "pillow-12.1.1-cp310-cp310-win32.whl", hash = "sha256:6c52f062424c523d6c4db85518774cc3d50f5539dd6eed32b8f6229b26f24d40"},
|
||||
{file = "pillow-12.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:c6008de247150668a705a6338156efb92334113421ceecf7438a12c9a12dab23"},
|
||||
{file = "pillow-12.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:1a9b0ee305220b392e1124a764ee4265bd063e54a751a6b62eff69992f457fa9"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:e879bb6cd5c73848ef3b2b48b8af9ff08c5b71ecda8048b7dd22d8a33f60be32"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:365b10bb9417dd4498c0e3b128018c4a624dc11c7b97d8cc54effe3b096f4c38"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d4ce8e329c93845720cd2014659ca67eac35f6433fd3050393d85f3ecef0dad5"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc354a04072b765eccf2204f588a7a532c9511e8b9c7f900e1b64e3e33487090"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e7976bf1910a8116b523b9f9f58bf410f3e8aa330cd9a2bb2953f9266ab49af"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:597bd9c8419bc7c6af5604e55847789b69123bbe25d65cc6ad3012b4f3c98d8b"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2c1fc0f2ca5f96a3c8407e41cca26a16e46b21060fe6d5b099d2cb01412222f5"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:578510d88c6229d735855e1f278aa305270438d36a05031dfaae5067cc8eb04d"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-win32.whl", hash = "sha256:7311c0a0dcadb89b36b7025dfd8326ecfa36964e29913074d47382706e516a7c"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:fbfa2a7c10cc2623f412753cddf391c7f971c52ca40a3f65dc5039b2939e8563"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:b81b5e3511211631b3f672a595e3221252c90af017e399056d0faabb9538aa80"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab323b787d6e18b3d91a72fc99b1a2c28651e4358749842b8f8dfacd28ef2052"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:adebb5bee0f0af4909c30db0d890c773d1a92ffe83da908e2e9e720f8edf3984"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb66b7cc26f50977108790e2456b7921e773f23db5630261102233eb355a3b79"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aee2810642b2898bb187ced9b349e95d2a7272930796e022efaf12e99dccd293"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a0b1cd6232e2b618adcc54d9882e4e662a089d5768cd188f7c245b4c8c44a397"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7aac39bcf8d4770d089588a2e1dd111cbaa42df5a94be3114222057d68336bd0"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ab174cd7d29a62dd139c44bf74b698039328f45cb03b4596c43473a46656b2f3"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:339ffdcb7cbeaa08221cd401d517d4b1fe7a9ed5d400e4a8039719238620ca35"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-win32.whl", hash = "sha256:5d1f9575a12bed9e9eedd9a4972834b08c97a352bd17955ccdebfeca5913fa0a"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:21329ec8c96c6e979cd0dfd29406c40c1d52521a90544463057d2aaa937d66a6"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:af9a332e572978f0218686636610555ae3defd1633597be015ed50289a03c523"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d242e8ac078781f1de88bf823d70c1a9b3c7950a44cdf4b7c012e22ccbcd8e4e"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:02f84dfad02693676692746df05b89cf25597560db2857363a208e393429f5e9"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:e65498daf4b583091ccbb2556c7000abf0f3349fcd57ef7adc9a84a394ed29f6"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c6db3b84c87d48d0088943bf33440e0c42370b99b1c2a7989216f7b42eede60"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b7e5304e34942bf62e15184219a7b5ad4ff7f3bb5cca4d984f37df1a0e1aee2"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:18e5bddd742a44b7e6b1e773ab5db102bd7a94c32555ba656e76d319d19c3850"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc44ef1f3de4f45b50ccf9136999d71abb99dca7706bc75d222ed350b9fd2289"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a8eb7ed8d4198bccbd07058416eeec51686b498e784eda166395a23eb99138e"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47b94983da0c642de92ced1702c5b6c292a84bd3a8e1d1702ff923f183594717"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:518a48c2aab7ce596d3bf79d0e275661b846e86e4d0e7dec34712c30fe07f02a"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a550ae29b95c6dc13cf69e2c9dc5747f814c54eeb2e32d683e5e93af56caa029"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-win32.whl", hash = "sha256:a003d7422449f6d1e3a34e3dd4110c22148336918ddbfc6a32581cd54b2e0b2b"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:344cf1e3dab3be4b1fa08e449323d98a2a3f819ad20f4b22e77a0ede31f0faa1"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:5c0dd1636633e7e6a0afe7bf6a51a14992b7f8e60de5789018ebbdfae55b040a"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0330d233c1a0ead844fc097a7d16c0abff4c12e856c0b325f231820fee1f39da"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dae5f21afb91322f2ff791895ddd8889e5e947ff59f71b46041c8ce6db790bc"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2e0c664be47252947d870ac0d327fea7e63985a08794758aa8af5b6cb6ec0c9c"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:691ab2ac363b8217f7d31b3497108fb1f50faab2f75dfb03284ec2f217e87bf8"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9e8064fb1cc019296958595f6db671fba95209e3ceb0c4734c9baf97de04b20"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:472a8d7ded663e6162dafdf20015c486a7009483ca671cece7a9279b512fcb13"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:89b54027a766529136a06cfebeecb3a04900397a3590fd252160b888479517bf"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:86172b0831b82ce4f7877f280055892b31179e1576aa00d0df3bb1bbf8c3e524"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-win32.whl", hash = "sha256:44ce27545b6efcf0fdbdceb31c9a5bdea9333e664cda58a7e674bb74608b3986"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a285e3eb7a5a45a2ff504e31f4a8d1b12ef62e84e5411c6804a42197c1cf586c"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cc7d296b5ea4d29e6570dabeaed58d31c3fea35a633a69679fb03d7664f43fb3"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:417423db963cb4be8bac3fc1204fe61610f6abeed1580a7a2cbb2fbda20f12af"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:b957b71c6b2387610f556a7eb0828afbe40b4a98036fc0d2acfa5a44a0c2036f"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:097690ba1f2efdeb165a20469d59d8bb03c55fb6621eb2041a060ae8ea3e9642"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2815a87ab27848db0321fb78c7f0b2c8649dee134b7f2b80c6a45c6831d75ccd"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f7ed2c6543bad5a7d5530eb9e78c53132f93dfa44a28492db88b41cdab885202"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:652a2c9ccfb556235b2b501a3a7cf3742148cd22e04b5625c5fe057ea3e3191f"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6e4571eedf43af33d0fc233a382a76e849badbccdf1ac438841308652a08e1f"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b574c51cf7d5d62e9be37ba446224b59a2da26dc4c1bb2ecbe936a4fb1a7cb7f"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a37691702ed687799de29a518d63d4682d9016932db66d4e90c345831b02fb4e"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f95c00d5d6700b2b890479664a06e754974848afaae5e21beb4d83c106923fd0"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:559b38da23606e68681337ad74622c4dbba02254fc9cb4488a305dd5975c7eeb"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-win32.whl", hash = "sha256:03edcc34d688572014ff223c125a3f77fb08091e4607e7745002fc214070b35f"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:50480dcd74fa63b8e78235957d302d98d98d82ccbfac4c7e12108ba9ecbdba15"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:5cb1785d97b0c3d1d1a16bc1d710c4a0049daefc4935f3a8f31f827f4d3d2e7f"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1f90cff8aa76835cba5769f0b3121a22bd4eb9e6884cfe338216e557a9a548b8"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f1be78ce9466a7ee64bfda57bdba0f7cc499d9794d518b854816c41bf0aa4e9"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:42fc1f4677106188ad9a55562bbade416f8b55456f522430fadab3cef7cd4e60"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98edb152429ab62a1818039744d8fbb3ccab98a7c29fc3d5fcef158f3f1f68b7"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d470ab1178551dd17fdba0fef463359c41aaa613cdcd7ff8373f54be629f9f8f"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6408a7b064595afcab0a49393a413732a35788f2a5092fdc6266952ed67de586"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5d8c41325b382c07799a3682c1c258469ea2ff97103c53717b7893862d0c98ce"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c7697918b5be27424e9ce568193efd13d925c4481dd364e43f5dff72d33e10f8"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-win32.whl", hash = "sha256:d2912fd8114fc5545aa3a4b5576512f64c55a03f3ebcca4c10194d593d43ea36"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:4ceb838d4bd9dab43e06c363cab2eebf63846d6a4aeaea283bbdfd8f1a8ed58b"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7b03048319bfc6170e93bd60728a1af51d3dd7704935feb228c4d4faab35d334"},
|
||||
{file = "pillow-12.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:600fd103672b925fe62ed08e0d874ea34d692474df6f4bf7ebe148b30f89f39f"},
|
||||
{file = "pillow-12.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:665e1b916b043cef294bc54d47bf02d87e13f769bc4bc5fa225a24b3a6c5aca9"},
|
||||
{file = "pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:495c302af3aad1ca67420ddd5c7bd480c8867ad173528767d906428057a11f0e"},
|
||||
{file = "pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8fd420ef0c52c88b5a035a0886f367748c72147b2b8f384c9d12656678dfdfa9"},
|
||||
{file = "pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f975aa7ef9684ce7e2c18a3aa8f8e2106ce1e46b94ab713d156b2898811651d3"},
|
||||
{file = "pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8089c852a56c2966cf18835db62d9b34fef7ba74c726ad943928d494fa7f4735"},
|
||||
{file = "pillow-12.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:cb9bb857b2d057c6dfc72ac5f3b44836924ba15721882ef103cecb40d002d80e"},
|
||||
{file = "pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@@ -6660,7 +6626,7 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "prowler"
|
||||
version = "5.18.0"
|
||||
version = "5.19.0"
|
||||
description = "Prowler is an Open Source security tool to perform AWS, GCP and Azure security best practices assessments, audits, incident response, continuous monitoring, hardening and forensics readiness. It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, FedRAMP, PCI-DSS, GDPR, HIPAA, FFIEC, SOC2, GXP, AWS Well-Architected Framework Security Pillar, AWS Foundational Technical Review (FTR), ENS (Spanish National Security Scheme) and your custom security frameworks."
|
||||
optional = false
|
||||
python-versions = ">3.9.1,<3.13"
|
||||
@@ -6715,7 +6681,7 @@ boto3 = "1.40.61"
|
||||
botocore = "1.40.61"
|
||||
cloudflare = "4.3.1"
|
||||
colorama = "0.4.6"
|
||||
cryptography = "44.0.1"
|
||||
cryptography = "44.0.3"
|
||||
dash = "3.1.1"
|
||||
dash-bootstrap-components = "2.0.3"
|
||||
detect-secrets = "1.5.0"
|
||||
@@ -6730,10 +6696,10 @@ microsoft-kiota-abstractions = "1.9.2"
|
||||
msgraph-sdk = "1.23.0"
|
||||
numpy = "2.0.2"
|
||||
oci = "2.160.3"
|
||||
openstacksdk = "4.0.1"
|
||||
openstacksdk = "4.2.0"
|
||||
pandas = "2.2.3"
|
||||
py-iam-expand = "0.1.0"
|
||||
py-ocsf-models = "0.5.0"
|
||||
py-ocsf-models = "0.8.1"
|
||||
pydantic = ">=2.0,<3.0"
|
||||
pygithub = "2.5.0"
|
||||
python-dateutil = ">=2.9.0.post0,<3.0.0"
|
||||
@@ -6748,7 +6714,7 @@ tzlocal = "5.3.1"
|
||||
type = "git"
|
||||
url = "https://github.com/prowler-cloud/prowler.git"
|
||||
reference = "master"
|
||||
resolved_reference = "b1f99716171856bf787a7695a588ffad6bf8d596"
|
||||
resolved_reference = "ceb4691c3657e7db3d178896bfc241d14f194295"
|
||||
|
||||
[[package]]
|
||||
name = "psutil"
|
||||
@@ -6896,20 +6862,20 @@ iamdata = ">=0.1.202504091"
|
||||
|
||||
[[package]]
|
||||
name = "py-ocsf-models"
|
||||
version = "0.5.0"
|
||||
version = "0.8.1"
|
||||
description = "This is a Python implementation of the OCSF models. The models are used to represent the data of the OCSF Schema defined in https://schema.ocsf.io/."
|
||||
optional = false
|
||||
python-versions = "<3.14,>3.9.1"
|
||||
python-versions = "<3.15,>3.9.1"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "py_ocsf_models-0.5.0-py3-none-any.whl", hash = "sha256:7933253f56782c04c412d976796db429577810b951fe4195351794500b5962d8"},
|
||||
{file = "py_ocsf_models-0.5.0.tar.gz", hash = "sha256:bf05e955809d1ec3ab1007e4a4b2a8a0afa74b6e744ea8ffbf386e46b3af0a76"},
|
||||
{file = "py_ocsf_models-0.8.1-py3-none-any.whl", hash = "sha256:061eb446c4171534c09a8b37f5a9d2a2fe9f87c5db32edbd1182446bc5fd097e"},
|
||||
{file = "py_ocsf_models-0.8.1.tar.gz", hash = "sha256:c9045237857f951e073c9f9d1f57954c90d86875b469260725292d47f7a7d73c"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
cryptography = "44.0.1"
|
||||
cryptography = ">=44.0.3,<47"
|
||||
email-validator = "2.2.0"
|
||||
pydantic = ">=2.9.2,<3.0.0"
|
||||
pydantic = ">=2.12.0,<3.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "pyasn1"
|
||||
@@ -9400,4 +9366,4 @@ files = [
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.11,<3.13"
|
||||
content-hash = "bada7223d576ddd48ff74aa101d18e7465492cf014006e17354dbe2190a02b29"
|
||||
content-hash = "c575bc849038db5b5d0882bec441529bf474a42b28c96718372ad4ceb388432c"
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ name = "prowler-api"
|
||||
package-mode = false
|
||||
# Needed for the SDK compatibility
|
||||
requires-python = ">=3.11,<3.13"
|
||||
version = "1.19.0"
|
||||
version = "1.20.0"
|
||||
|
||||
[project.scripts]
|
||||
celery = "src.backend.config.settings.celery"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,14 @@
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
|
||||
@dataclass
|
||||
class AttackPathsQueryAttribution:
|
||||
"""Source attribution for an Attack Path query."""
|
||||
|
||||
text: str
|
||||
link: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class AttackPathsQueryParameterDefinition:
|
||||
"""
|
||||
@@ -23,7 +31,9 @@ class AttackPathsQueryDefinition:
|
||||
|
||||
id: str
|
||||
name: str
|
||||
short_description: str
|
||||
description: str
|
||||
provider: str
|
||||
cypher: str
|
||||
attribution: AttackPathsQueryAttribution | None = None
|
||||
parameters: list[AttackPathsQueryParameterDefinition] = field(default_factory=list)
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# Generated by Django migration for OpenStack provider support
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
import api.db_utils
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("api", "0075_cloudflare_provider"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="provider",
|
||||
name="provider",
|
||||
field=api.db_utils.ProviderEnumField(
|
||||
choices=[
|
||||
("aws", "AWS"),
|
||||
("azure", "Azure"),
|
||||
("gcp", "GCP"),
|
||||
("kubernetes", "Kubernetes"),
|
||||
("m365", "M365"),
|
||||
("github", "GitHub"),
|
||||
("mongodbatlas", "MongoDB Atlas"),
|
||||
("iac", "IaC"),
|
||||
("oraclecloud", "Oracle Cloud Infrastructure"),
|
||||
("alibabacloud", "Alibaba Cloud"),
|
||||
("cloudflare", "Cloudflare"),
|
||||
("openstack", "OpenStack"),
|
||||
],
|
||||
default="aws",
|
||||
),
|
||||
),
|
||||
migrations.RunSQL(
|
||||
"ALTER TYPE provider ADD VALUE IF NOT EXISTS 'openstack';",
|
||||
reverse_sql=migrations.RunSQL.noop,
|
||||
),
|
||||
]
|
||||
@@ -288,6 +288,7 @@ class Provider(RowLevelSecurityProtectedModel):
|
||||
ORACLECLOUD = "oraclecloud", _("Oracle Cloud Infrastructure")
|
||||
ALIBABACLOUD = "alibabacloud", _("Alibaba Cloud")
|
||||
CLOUDFLARE = "cloudflare", _("Cloudflare")
|
||||
OPENSTACK = "openstack", _("OpenStack")
|
||||
|
||||
@staticmethod
|
||||
def validate_aws_uid(value):
|
||||
@@ -410,6 +411,15 @@ class Provider(RowLevelSecurityProtectedModel):
|
||||
pointer="/data/attributes/uid",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def validate_openstack_uid(value):
|
||||
if not re.match(r"^[a-zA-Z0-9][a-zA-Z0-9._-]{0,254}$", value):
|
||||
raise ModelValidationError(
|
||||
detail="OpenStack provider ID must be a valid project ID (UUID or project name).",
|
||||
code="openstack-uid",
|
||||
pointer="/data/attributes/uid",
|
||||
)
|
||||
|
||||
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
|
||||
inserted_at = models.DateTimeField(auto_now_add=True, editable=False)
|
||||
updated_at = models.DateTimeField(auto_now=True, editable=False)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Prowler API
|
||||
version: 1.19.0
|
||||
version: 1.20.0
|
||||
description: |-
|
||||
Prowler API specification.
|
||||
|
||||
@@ -367,6 +367,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -380,6 +381,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -398,6 +400,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -413,6 +416,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -616,7 +620,7 @@ paths:
|
||||
operationId: attack_paths_scans_queries_retrieve
|
||||
description: Retrieve the catalog of Attack Paths queries available for this
|
||||
Attack Paths scan.
|
||||
summary: List attack paths queries
|
||||
summary: List Attack Paths queries
|
||||
parameters:
|
||||
- in: query
|
||||
name: fields[attack-paths-scans]
|
||||
@@ -714,7 +718,7 @@ paths:
|
||||
description: Bad request (e.g., Unknown Attack Paths query for the selected
|
||||
provider)
|
||||
'404':
|
||||
description: No attack paths found for the given query and parameters
|
||||
description: No Attack Paths found for the given query and parameters
|
||||
'500':
|
||||
description: Attack Paths query execution failed due to a database error
|
||||
/api/v1/compliance-overviews:
|
||||
@@ -1348,6 +1352,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -1361,6 +1366,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -1379,6 +1385,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -1394,6 +1401,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -1938,6 +1946,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -1951,6 +1960,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -1969,6 +1979,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -1984,6 +1995,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -2436,6 +2448,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -2449,6 +2462,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -2467,6 +2481,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -2482,6 +2497,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -2932,6 +2948,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -2945,6 +2962,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -2963,6 +2981,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -2978,6 +2997,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -3416,6 +3436,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -3429,6 +3450,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -3447,6 +3469,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -3462,6 +3485,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -5241,6 +5265,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -5254,6 +5279,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -5272,6 +5298,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -5287,6 +5314,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- name: filter[search]
|
||||
@@ -5404,6 +5432,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -5417,6 +5446,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -5435,6 +5465,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -5450,6 +5481,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- name: filter[search]
|
||||
@@ -5556,6 +5588,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -5569,6 +5602,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -5586,6 +5620,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -5601,6 +5636,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- name: filter[search]
|
||||
@@ -5739,6 +5775,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -5752,6 +5789,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -5770,6 +5808,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -5785,6 +5824,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -5936,6 +5976,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -5949,6 +5990,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -5967,6 +6009,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -5982,6 +6025,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -6127,6 +6171,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -6140,6 +6185,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -6157,6 +6203,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -6172,6 +6219,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- name: filter[search]
|
||||
@@ -6359,6 +6407,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -6372,6 +6421,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -6390,6 +6440,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -6405,6 +6456,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -6521,6 +6573,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -6534,6 +6587,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -6552,6 +6606,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -6567,6 +6622,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -6707,6 +6763,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -6720,6 +6777,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -6738,6 +6796,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -6753,6 +6812,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -7534,6 +7594,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -7547,6 +7608,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider__in]
|
||||
schema:
|
||||
@@ -7565,6 +7627,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -7580,6 +7643,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -7598,6 +7662,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -7611,6 +7676,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -7629,6 +7695,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -7644,6 +7711,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- name: filter[search]
|
||||
@@ -8285,6 +8353,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -8298,6 +8367,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -8316,6 +8386,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -8331,6 +8402,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -8787,6 +8859,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -8800,6 +8873,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -8818,6 +8892,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -8833,6 +8908,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -9102,6 +9178,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -9115,6 +9192,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -9133,6 +9211,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -9148,6 +9227,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -9423,6 +9503,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -9436,6 +9517,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -9454,6 +9536,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -9469,6 +9552,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -10278,6 +10362,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -10291,6 +10376,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
- in: query
|
||||
name: filter[provider_type__in]
|
||||
schema:
|
||||
@@ -10309,6 +10395,7 @@ paths:
|
||||
- kubernetes
|
||||
- m365
|
||||
- mongodbatlas
|
||||
- openstack
|
||||
- oraclecloud
|
||||
description: |-
|
||||
Multiple values may be separated by commas.
|
||||
@@ -10324,6 +10411,7 @@ paths:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
explode: false
|
||||
style: form
|
||||
- in: query
|
||||
@@ -12438,6 +12526,8 @@ components:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
short_description:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
provider:
|
||||
@@ -12446,12 +12536,42 @@ components:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/AttackPathsQueryParameter'
|
||||
attribution:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/AttackPathsQueryAttribution'
|
||||
nullable: true
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
- short_description
|
||||
- description
|
||||
- provider
|
||||
- parameters
|
||||
AttackPathsQueryAttribution:
|
||||
type: object
|
||||
required:
|
||||
- type
|
||||
- id
|
||||
additionalProperties: false
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
description: The [type](https://jsonapi.org/format/#document-resource-object-identification)
|
||||
member is used to describe resource objects that share common attributes
|
||||
and relationships.
|
||||
enum:
|
||||
- attack-paths-query-attributions
|
||||
id: {}
|
||||
attributes:
|
||||
type: object
|
||||
properties:
|
||||
text:
|
||||
type: string
|
||||
link:
|
||||
type: string
|
||||
required:
|
||||
- text
|
||||
- link
|
||||
AttackPathsQueryParameter:
|
||||
type: object
|
||||
required:
|
||||
@@ -17316,6 +17436,50 @@ components:
|
||||
required:
|
||||
- api_key
|
||||
- api_email
|
||||
- type: object
|
||||
title: OpenStack clouds.yaml Credentials
|
||||
properties:
|
||||
clouds_yaml_content:
|
||||
type: string
|
||||
description: The full content of a clouds.yaml configuration
|
||||
file.
|
||||
clouds_yaml_cloud:
|
||||
type: string
|
||||
description: The name of the cloud to use from the clouds.yaml
|
||||
file.
|
||||
required:
|
||||
- clouds_yaml_content
|
||||
- clouds_yaml_cloud
|
||||
- type: object
|
||||
title: OpenStack Explicit Credentials
|
||||
properties:
|
||||
auth_url:
|
||||
type: string
|
||||
description: OpenStack Keystone authentication URL (e.g.,
|
||||
https://openstack.example.com:5000/v3).
|
||||
username:
|
||||
type: string
|
||||
description: OpenStack username for authentication.
|
||||
password:
|
||||
type: string
|
||||
description: OpenStack password for authentication.
|
||||
region_name:
|
||||
type: string
|
||||
description: OpenStack region name (e.g., RegionOne).
|
||||
identity_api_version:
|
||||
type: string
|
||||
description: Keystone API version (default: 3).
|
||||
user_domain_name:
|
||||
type: string
|
||||
description: User domain name (default: Default).
|
||||
project_domain_name:
|
||||
type: string
|
||||
description: Project domain name (default: Default).
|
||||
required:
|
||||
- auth_url
|
||||
- username
|
||||
- password
|
||||
- region_name
|
||||
writeOnly: true
|
||||
required:
|
||||
- secret
|
||||
@@ -18315,6 +18479,7 @@ components:
|
||||
- oraclecloud
|
||||
- alibabacloud
|
||||
- cloudflare
|
||||
- openstack
|
||||
type: string
|
||||
description: |-
|
||||
* `aws` - AWS
|
||||
@@ -18328,6 +18493,7 @@ components:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
x-spec-enum-id: 2d8d323e9cc0044b
|
||||
uid:
|
||||
type: string
|
||||
@@ -18445,6 +18611,7 @@ components:
|
||||
- oraclecloud
|
||||
- alibabacloud
|
||||
- cloudflare
|
||||
- openstack
|
||||
type: string
|
||||
x-spec-enum-id: 2d8d323e9cc0044b
|
||||
description: |-
|
||||
@@ -18461,6 +18628,7 @@ components:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
uid:
|
||||
type: string
|
||||
title: Unique identifier for the provider, set by the provider
|
||||
@@ -18509,6 +18677,7 @@ components:
|
||||
- oraclecloud
|
||||
- alibabacloud
|
||||
- cloudflare
|
||||
- openstack
|
||||
type: string
|
||||
x-spec-enum-id: 2d8d323e9cc0044b
|
||||
description: |-
|
||||
@@ -18525,6 +18694,7 @@ components:
|
||||
* `oraclecloud` - Oracle Cloud Infrastructure
|
||||
* `alibabacloud` - Alibaba Cloud
|
||||
* `cloudflare` - Cloudflare
|
||||
* `openstack` - OpenStack
|
||||
uid:
|
||||
type: string
|
||||
minLength: 3
|
||||
@@ -19346,6 +19516,48 @@ components:
|
||||
required:
|
||||
- api_key
|
||||
- api_email
|
||||
- type: object
|
||||
title: OpenStack clouds.yaml Credentials
|
||||
properties:
|
||||
clouds_yaml_content:
|
||||
type: string
|
||||
description: The full content of a clouds.yaml configuration file.
|
||||
clouds_yaml_cloud:
|
||||
type: string
|
||||
description: The name of the cloud to use from the clouds.yaml
|
||||
file.
|
||||
required:
|
||||
- clouds_yaml_content
|
||||
- clouds_yaml_cloud
|
||||
- type: object
|
||||
title: OpenStack Explicit Credentials
|
||||
properties:
|
||||
auth_url:
|
||||
type: string
|
||||
description: OpenStack Keystone authentication URL (e.g., https://openstack.example.com:5000/v3).
|
||||
username:
|
||||
type: string
|
||||
description: OpenStack username for authentication.
|
||||
password:
|
||||
type: string
|
||||
description: OpenStack password for authentication.
|
||||
region_name:
|
||||
type: string
|
||||
description: OpenStack region name (e.g., RegionOne).
|
||||
identity_api_version:
|
||||
type: string
|
||||
description: Keystone API version (default: 3).
|
||||
user_domain_name:
|
||||
type: string
|
||||
description: User domain name (default: Default).
|
||||
project_domain_name:
|
||||
type: string
|
||||
description: Project domain name (default: Default).
|
||||
required:
|
||||
- auth_url
|
||||
- username
|
||||
- password
|
||||
- region_name
|
||||
writeOnly: true
|
||||
required:
|
||||
- secret_type
|
||||
@@ -19732,6 +19944,50 @@ components:
|
||||
required:
|
||||
- api_key
|
||||
- api_email
|
||||
- type: object
|
||||
title: OpenStack clouds.yaml Credentials
|
||||
properties:
|
||||
clouds_yaml_content:
|
||||
type: string
|
||||
description: The full content of a clouds.yaml configuration
|
||||
file.
|
||||
clouds_yaml_cloud:
|
||||
type: string
|
||||
description: The name of the cloud to use from the clouds.yaml
|
||||
file.
|
||||
required:
|
||||
- clouds_yaml_content
|
||||
- clouds_yaml_cloud
|
||||
- type: object
|
||||
title: OpenStack Explicit Credentials
|
||||
properties:
|
||||
auth_url:
|
||||
type: string
|
||||
description: OpenStack Keystone authentication URL (e.g.,
|
||||
https://openstack.example.com:5000/v3).
|
||||
username:
|
||||
type: string
|
||||
description: OpenStack username for authentication.
|
||||
password:
|
||||
type: string
|
||||
description: OpenStack password for authentication.
|
||||
region_name:
|
||||
type: string
|
||||
description: OpenStack region name (e.g., RegionOne).
|
||||
identity_api_version:
|
||||
type: string
|
||||
description: Keystone API version (default: 3).
|
||||
user_domain_name:
|
||||
type: string
|
||||
description: User domain name (default: Default).
|
||||
project_domain_name:
|
||||
type: string
|
||||
description: Project domain name (default: Default).
|
||||
required:
|
||||
- auth_url
|
||||
- username
|
||||
- password
|
||||
- region_name
|
||||
writeOnly: true
|
||||
required:
|
||||
- secret_type
|
||||
@@ -20130,6 +20386,48 @@ components:
|
||||
required:
|
||||
- api_key
|
||||
- api_email
|
||||
- type: object
|
||||
title: OpenStack clouds.yaml Credentials
|
||||
properties:
|
||||
clouds_yaml_content:
|
||||
type: string
|
||||
description: The full content of a clouds.yaml configuration file.
|
||||
clouds_yaml_cloud:
|
||||
type: string
|
||||
description: The name of the cloud to use from the clouds.yaml
|
||||
file.
|
||||
required:
|
||||
- clouds_yaml_content
|
||||
- clouds_yaml_cloud
|
||||
- type: object
|
||||
title: OpenStack Explicit Credentials
|
||||
properties:
|
||||
auth_url:
|
||||
type: string
|
||||
description: OpenStack Keystone authentication URL (e.g., https://openstack.example.com:5000/v3).
|
||||
username:
|
||||
type: string
|
||||
description: OpenStack username for authentication.
|
||||
password:
|
||||
type: string
|
||||
description: OpenStack password for authentication.
|
||||
region_name:
|
||||
type: string
|
||||
description: OpenStack region name (e.g., RegionOne).
|
||||
identity_api_version:
|
||||
type: string
|
||||
description: Keystone API version (default: 3).
|
||||
user_domain_name:
|
||||
type: string
|
||||
description: User domain name (default: Default).
|
||||
project_domain_name:
|
||||
type: string
|
||||
description: Project domain name (default: Default).
|
||||
required:
|
||||
- auth_url
|
||||
- username
|
||||
- password
|
||||
- region_name
|
||||
writeOnly: true
|
||||
required:
|
||||
- secret
|
||||
|
||||
@@ -83,6 +83,7 @@ def test_execute_attack_paths_query_serializes_graph(
|
||||
definition = attack_paths_query_definition_factory(
|
||||
id="aws-rds",
|
||||
name="RDS",
|
||||
short_description="Short desc",
|
||||
description="",
|
||||
cypher="MATCH (n) RETURN n",
|
||||
parameters=[],
|
||||
@@ -143,6 +144,7 @@ def test_execute_attack_paths_query_wraps_graph_errors(
|
||||
definition = attack_paths_query_definition_factory(
|
||||
id="aws-rds",
|
||||
name="RDS",
|
||||
short_description="Short desc",
|
||||
description="",
|
||||
cypher="MATCH (n) RETURN n",
|
||||
parameters=[],
|
||||
|
||||
@@ -27,6 +27,7 @@ from prowler.providers.iac.iac_provider import IacProvider
|
||||
from prowler.providers.kubernetes.kubernetes_provider import KubernetesProvider
|
||||
from prowler.providers.m365.m365_provider import M365Provider
|
||||
from prowler.providers.mongodbatlas.mongodbatlas_provider import MongodbatlasProvider
|
||||
from prowler.providers.openstack.openstack_provider import OpenstackProvider
|
||||
from prowler.providers.oraclecloud.oraclecloud_provider import OraclecloudProvider
|
||||
|
||||
|
||||
@@ -120,6 +121,7 @@ class TestReturnProwlerProvider:
|
||||
(Provider.ProviderChoices.IAC.value, IacProvider),
|
||||
(Provider.ProviderChoices.ALIBABACLOUD.value, AlibabacloudProvider),
|
||||
(Provider.ProviderChoices.CLOUDFLARE.value, CloudflareProvider),
|
||||
(Provider.ProviderChoices.OPENSTACK.value, OpenstackProvider),
|
||||
],
|
||||
)
|
||||
def test_return_prowler_provider(self, provider_type, expected_provider):
|
||||
@@ -227,6 +229,10 @@ class TestGetProwlerProviderKwargs:
|
||||
Provider.ProviderChoices.CLOUDFLARE.value,
|
||||
{"filter_accounts": ["provider_uid"]},
|
||||
),
|
||||
(
|
||||
Provider.ProviderChoices.OPENSTACK.value,
|
||||
{},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_get_prowler_provider_kwargs(self, provider_type, expected_extra_kwargs):
|
||||
|
||||
@@ -1179,6 +1179,11 @@ class TestProviderViewSet:
|
||||
"uid": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
|
||||
"alias": "Cloudflare Account",
|
||||
},
|
||||
{
|
||||
"provider": "openstack",
|
||||
"uid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"alias": "OpenStack Project",
|
||||
},
|
||||
]
|
||||
),
|
||||
)
|
||||
@@ -1598,6 +1603,26 @@ class TestProviderViewSet:
|
||||
"cloudflare-uid",
|
||||
"uid",
|
||||
),
|
||||
# OpenStack UID validation - starts with special character
|
||||
(
|
||||
{
|
||||
"provider": "openstack",
|
||||
"uid": "-invalid-project",
|
||||
"alias": "test",
|
||||
},
|
||||
"openstack-uid",
|
||||
"uid",
|
||||
),
|
||||
# OpenStack UID validation - too short (below min_length)
|
||||
(
|
||||
{
|
||||
"provider": "openstack",
|
||||
"uid": "ab",
|
||||
"alias": "test",
|
||||
},
|
||||
"min_length",
|
||||
"uid",
|
||||
),
|
||||
]
|
||||
),
|
||||
)
|
||||
@@ -1771,21 +1796,21 @@ class TestProviderViewSet:
|
||||
(
|
||||
"uid.icontains",
|
||||
"1",
|
||||
9,
|
||||
10,
|
||||
),
|
||||
("alias", "aws_testing_1", 1),
|
||||
("alias.icontains", "aws", 2),
|
||||
("inserted_at", TODAY, 10),
|
||||
("inserted_at", TODAY, 11),
|
||||
(
|
||||
"inserted_at.gte",
|
||||
"2024-01-01",
|
||||
10,
|
||||
11,
|
||||
),
|
||||
("inserted_at.lte", "2024-01-01", 0),
|
||||
(
|
||||
"updated_at.gte",
|
||||
"2024-01-01",
|
||||
10,
|
||||
11,
|
||||
),
|
||||
("updated_at.lte", "2024-01-01", 0),
|
||||
]
|
||||
@@ -2392,6 +2417,15 @@ class TestProviderSecretViewSet:
|
||||
"api_email": "user@example.com",
|
||||
},
|
||||
),
|
||||
# OpenStack with clouds.yaml content
|
||||
(
|
||||
Provider.ProviderChoices.OPENSTACK.value,
|
||||
ProviderSecret.TypeChoices.STATIC,
|
||||
{
|
||||
"clouds_yaml_content": "clouds:\n mycloud:\n auth:\n auth_url: https://openstack.example.com:5000/v3\n",
|
||||
"clouds_yaml_cloud": "mycloud",
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_provider_secrets_create_valid(
|
||||
@@ -3830,6 +3864,7 @@ class TestAttackPathsScanViewSet:
|
||||
AttackPathsQueryDefinition(
|
||||
id="aws-rds",
|
||||
name="RDS inventory",
|
||||
short_description="List account RDS assets.",
|
||||
description="List account RDS assets",
|
||||
provider=provider.provider,
|
||||
cypher="MATCH (n) RETURN n",
|
||||
@@ -3892,6 +3927,7 @@ class TestAttackPathsScanViewSet:
|
||||
query_definition = AttackPathsQueryDefinition(
|
||||
id="aws-rds",
|
||||
name="RDS inventory",
|
||||
short_description="List account RDS assets.",
|
||||
description="List account RDS assets",
|
||||
provider=provider.provider,
|
||||
cypher="MATCH (n) RETURN n",
|
||||
@@ -4049,6 +4085,7 @@ class TestAttackPathsScanViewSet:
|
||||
query_definition = AttackPathsQueryDefinition(
|
||||
id="aws-empty",
|
||||
name="empty",
|
||||
short_description="",
|
||||
description="",
|
||||
provider=provider.provider,
|
||||
cypher="MATCH (n) RETURN n",
|
||||
@@ -10841,25 +10878,20 @@ class TestTenantFinishACSView:
|
||||
assert "sso_saml_failed=true" in response.url
|
||||
|
||||
def test_dispatch_skips_role_mapping_when_single_manage_account_user(
|
||||
self, create_test_user, tenants_fixture, saml_setup, settings, monkeypatch
|
||||
self,
|
||||
create_test_user,
|
||||
tenants_fixture,
|
||||
admin_role_fixture,
|
||||
saml_setup,
|
||||
settings,
|
||||
monkeypatch,
|
||||
):
|
||||
"""Test that role mapping is skipped when tenant has only one user with MANAGE_ACCOUNT role"""
|
||||
monkeypatch.setenv("SAML_SSO_CALLBACK_URL", "http://localhost/sso-complete")
|
||||
user = create_test_user
|
||||
tenant = tenants_fixture[0]
|
||||
|
||||
# Create a single role with manage_account=True for the user
|
||||
admin_role = Role.objects.using(MainRouter.admin_db).create(
|
||||
name="admin",
|
||||
tenant=tenant,
|
||||
manage_account=True,
|
||||
manage_users=True,
|
||||
manage_billing=True,
|
||||
manage_providers=True,
|
||||
manage_integrations=True,
|
||||
manage_scans=True,
|
||||
unlimited_visibility=True,
|
||||
)
|
||||
admin_role = admin_role_fixture
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db).create(
|
||||
user=user, role=admin_role, tenant_id=tenant.id
|
||||
)
|
||||
@@ -10930,35 +10962,26 @@ class TestTenantFinishACSView:
|
||||
.exists()
|
||||
)
|
||||
|
||||
def test_dispatch_applies_role_mapping_when_multiple_manage_account_users(
|
||||
self, create_test_user, tenants_fixture, saml_setup, settings, monkeypatch
|
||||
def test_dispatch_skips_role_mapping_when_last_manage_account_user_maps_to_existing_role(
|
||||
self,
|
||||
create_test_user,
|
||||
tenants_fixture,
|
||||
admin_role_fixture,
|
||||
roles_fixture,
|
||||
saml_setup,
|
||||
settings,
|
||||
monkeypatch,
|
||||
):
|
||||
"""Test that role mapping is applied when tenant has multiple users with MANAGE_ACCOUNT role"""
|
||||
"""Test that role mapping is skipped when it would remove the last MANAGE_ACCOUNT user"""
|
||||
monkeypatch.setenv("SAML_SSO_CALLBACK_URL", "http://localhost/sso-complete")
|
||||
user = create_test_user
|
||||
tenant = tenants_fixture[0]
|
||||
|
||||
# Create a second user with manage_account=True
|
||||
second_admin = User.objects.using(MainRouter.admin_db).create(
|
||||
email="admin2@prowler.com", name="Second Admin"
|
||||
)
|
||||
admin_role = Role.objects.using(MainRouter.admin_db).create(
|
||||
name="admin",
|
||||
tenant=tenant,
|
||||
manage_account=True,
|
||||
manage_users=True,
|
||||
manage_billing=True,
|
||||
manage_providers=True,
|
||||
manage_integrations=True,
|
||||
manage_scans=True,
|
||||
unlimited_visibility=True,
|
||||
)
|
||||
admin_role = admin_role_fixture
|
||||
viewer_role = roles_fixture[3]
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db).create(
|
||||
user=user, role=admin_role, tenant_id=tenant.id
|
||||
)
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db).create(
|
||||
user=second_admin, role=admin_role, tenant_id=tenant.id
|
||||
)
|
||||
|
||||
social_account = SocialAccount(
|
||||
user=user,
|
||||
@@ -10967,7 +10990,7 @@ class TestTenantFinishACSView:
|
||||
"firstName": ["John"],
|
||||
"lastName": ["Doe"],
|
||||
"organization": ["testing_company"],
|
||||
"userType": ["viewer"], # This SHOULD be applied
|
||||
"userType": [viewer_role.name],
|
||||
},
|
||||
)
|
||||
|
||||
@@ -11005,10 +11028,91 @@ class TestTenantFinishACSView:
|
||||
|
||||
assert response.status_code == 302
|
||||
|
||||
# Verify the viewer role was created and assigned (role mapping was applied)
|
||||
viewer_role = Role.objects.using(MainRouter.admin_db).get(
|
||||
name="viewer", tenant=tenant
|
||||
assert (
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db)
|
||||
.filter(user=user, role=admin_role, tenant_id=tenant.id)
|
||||
.exists()
|
||||
)
|
||||
assert not (
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db)
|
||||
.filter(user=user, role=viewer_role, tenant_id=tenant.id)
|
||||
.exists()
|
||||
)
|
||||
|
||||
def test_dispatch_applies_role_mapping_when_multiple_manage_account_users(
|
||||
self,
|
||||
create_test_user,
|
||||
tenants_fixture,
|
||||
admin_role_fixture,
|
||||
roles_fixture,
|
||||
saml_setup,
|
||||
settings,
|
||||
monkeypatch,
|
||||
):
|
||||
"""Test that role mapping is applied when tenant has multiple users with MANAGE_ACCOUNT role"""
|
||||
monkeypatch.setenv("SAML_SSO_CALLBACK_URL", "http://localhost/sso-complete")
|
||||
user = create_test_user
|
||||
tenant = tenants_fixture[0]
|
||||
|
||||
# Create a second user with manage_account=True
|
||||
second_admin = User.objects.using(MainRouter.admin_db).create(
|
||||
email="admin2@prowler.com", name="Second Admin"
|
||||
)
|
||||
admin_role = admin_role_fixture
|
||||
viewer_role = roles_fixture[3]
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db).create(
|
||||
user=user, role=admin_role, tenant_id=tenant.id
|
||||
)
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db).create(
|
||||
user=second_admin, role=admin_role, tenant_id=tenant.id
|
||||
)
|
||||
|
||||
social_account = SocialAccount(
|
||||
user=user,
|
||||
provider="saml",
|
||||
extra_data={
|
||||
"firstName": ["John"],
|
||||
"lastName": ["Doe"],
|
||||
"organization": ["testing_company"],
|
||||
"userType": [viewer_role.name], # This SHOULD be applied
|
||||
},
|
||||
)
|
||||
|
||||
request = RequestFactory().get(
|
||||
reverse("saml_finish_acs", kwargs={"organization_slug": "testtenant"})
|
||||
)
|
||||
request.user = user
|
||||
request.session = {}
|
||||
|
||||
with (
|
||||
patch(
|
||||
"allauth.socialaccount.providers.saml.views.get_app_or_404"
|
||||
) as mock_get_app_or_404,
|
||||
patch(
|
||||
"allauth.socialaccount.models.SocialApp.objects.get"
|
||||
) as mock_socialapp_get,
|
||||
patch(
|
||||
"allauth.socialaccount.models.SocialAccount.objects.get"
|
||||
) as mock_sa_get,
|
||||
patch("api.models.SAMLDomainIndex.objects.get") as mock_saml_domain_get,
|
||||
patch("api.models.SAMLConfiguration.objects.get") as mock_saml_config_get,
|
||||
patch("api.models.User.objects.get") as mock_user_get,
|
||||
):
|
||||
mock_get_app_or_404.return_value = MagicMock(
|
||||
provider="saml", client_id="testtenant", name="Test App", settings={}
|
||||
)
|
||||
mock_sa_get.return_value = social_account
|
||||
mock_socialapp_get.return_value = MagicMock(provider_id="saml")
|
||||
mock_saml_domain_get.return_value = SimpleNamespace(tenant_id=tenant.id)
|
||||
mock_saml_config_get.return_value = MagicMock()
|
||||
mock_user_get.return_value = user
|
||||
|
||||
view = TenantFinishACSView.as_view()
|
||||
response = view(request, organization_slug="testtenant")
|
||||
|
||||
assert response.status_code == 302
|
||||
|
||||
# Verify the viewer role was assigned (role mapping was applied)
|
||||
assert (
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db)
|
||||
.filter(user=user, role=viewer_role, tenant_id=tenant.id)
|
||||
@@ -11022,6 +11126,86 @@ class TestTenantFinishACSView:
|
||||
.exists()
|
||||
)
|
||||
|
||||
def test_dispatch_applies_role_mapping_for_non_admin_user_with_single_admin(
|
||||
self,
|
||||
create_test_user,
|
||||
tenants_fixture,
|
||||
admin_role_fixture,
|
||||
roles_fixture,
|
||||
saml_setup,
|
||||
settings,
|
||||
monkeypatch,
|
||||
):
|
||||
"""Test that role mapping is applied for a non-admin user when a single admin exists"""
|
||||
monkeypatch.setenv("SAML_SSO_CALLBACK_URL", "http://localhost/sso-complete")
|
||||
admin_user = create_test_user
|
||||
tenant = tenants_fixture[0]
|
||||
non_admin_user = User.objects.using(MainRouter.admin_db).create(
|
||||
email="viewer@prowler.com", name="Viewer"
|
||||
)
|
||||
|
||||
admin_role = admin_role_fixture
|
||||
viewer_role = roles_fixture[3]
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db).create(
|
||||
user=admin_user, role=admin_role, tenant_id=tenant.id
|
||||
)
|
||||
|
||||
social_account = SocialAccount(
|
||||
user=non_admin_user,
|
||||
provider="saml",
|
||||
extra_data={
|
||||
"firstName": ["Jane"],
|
||||
"lastName": ["Doe"],
|
||||
"organization": ["testing_company"],
|
||||
"userType": [viewer_role.name],
|
||||
},
|
||||
)
|
||||
|
||||
request = RequestFactory().get(
|
||||
reverse("saml_finish_acs", kwargs={"organization_slug": "testtenant"})
|
||||
)
|
||||
request.user = non_admin_user
|
||||
request.session = {}
|
||||
|
||||
with (
|
||||
patch(
|
||||
"allauth.socialaccount.providers.saml.views.get_app_or_404"
|
||||
) as mock_get_app_or_404,
|
||||
patch(
|
||||
"allauth.socialaccount.models.SocialApp.objects.get"
|
||||
) as mock_socialapp_get,
|
||||
patch(
|
||||
"allauth.socialaccount.models.SocialAccount.objects.get"
|
||||
) as mock_sa_get,
|
||||
patch("api.models.SAMLDomainIndex.objects.get") as mock_saml_domain_get,
|
||||
patch("api.models.SAMLConfiguration.objects.get") as mock_saml_config_get,
|
||||
patch("api.models.User.objects.get") as mock_user_get,
|
||||
):
|
||||
mock_get_app_or_404.return_value = MagicMock(
|
||||
provider="saml", client_id="testtenant", name="Test App", settings={}
|
||||
)
|
||||
mock_sa_get.return_value = social_account
|
||||
mock_socialapp_get.return_value = MagicMock(provider_id="saml")
|
||||
mock_saml_domain_get.return_value = SimpleNamespace(tenant_id=tenant.id)
|
||||
mock_saml_config_get.return_value = MagicMock()
|
||||
mock_user_get.return_value = non_admin_user
|
||||
|
||||
view = TenantFinishACSView.as_view()
|
||||
response = view(request, organization_slug="testtenant")
|
||||
|
||||
assert response.status_code == 302
|
||||
|
||||
assert (
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db)
|
||||
.filter(user=non_admin_user, role=viewer_role, tenant_id=tenant.id)
|
||||
.exists()
|
||||
)
|
||||
assert (
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db)
|
||||
.filter(user=admin_user, role=admin_role, tenant_id=tenant.id)
|
||||
.exists()
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
class TestLighthouseConfigViewSet:
|
||||
|
||||
@@ -33,6 +33,7 @@ if TYPE_CHECKING:
|
||||
from prowler.providers.mongodbatlas.mongodbatlas_provider import (
|
||||
MongodbatlasProvider,
|
||||
)
|
||||
from prowler.providers.openstack.openstack_provider import OpenstackProvider
|
||||
from prowler.providers.oraclecloud.oraclecloud_provider import OraclecloudProvider
|
||||
|
||||
|
||||
@@ -78,12 +79,14 @@ def return_prowler_provider(
|
||||
AlibabacloudProvider
|
||||
| AwsProvider
|
||||
| AzureProvider
|
||||
| CloudflareProvider
|
||||
| GcpProvider
|
||||
| GithubProvider
|
||||
| IacProvider
|
||||
| KubernetesProvider
|
||||
| M365Provider
|
||||
| MongodbatlasProvider
|
||||
| OpenstackProvider
|
||||
| OraclecloudProvider
|
||||
):
|
||||
"""Return the Prowler provider class based on the given provider type.
|
||||
@@ -92,7 +95,7 @@ def return_prowler_provider(
|
||||
provider (Provider): The provider object containing the provider type and associated secrets.
|
||||
|
||||
Returns:
|
||||
AlibabacloudProvider | AwsProvider | AzureProvider | CloudflareProvider | GcpProvider | GithubProvider | IacProvider | KubernetesProvider | M365Provider | MongodbatlasProvider | OraclecloudProvider: The corresponding provider class.
|
||||
AlibabacloudProvider | AwsProvider | AzureProvider | CloudflareProvider | GcpProvider | GithubProvider | IacProvider | KubernetesProvider | M365Provider | MongodbatlasProvider | OpenstackProvider | OraclecloudProvider: The corresponding provider class.
|
||||
|
||||
Raises:
|
||||
ValueError: If the provider type specified in `provider.provider` is not supported.
|
||||
@@ -152,6 +155,10 @@ def return_prowler_provider(
|
||||
)
|
||||
|
||||
prowler_provider = CloudflareProvider
|
||||
case Provider.ProviderChoices.OPENSTACK.value:
|
||||
from prowler.providers.openstack.openstack_provider import OpenstackProvider
|
||||
|
||||
prowler_provider = OpenstackProvider
|
||||
case _:
|
||||
raise ValueError(f"Provider type {provider.provider} not supported")
|
||||
return prowler_provider
|
||||
@@ -208,6 +215,12 @@ def get_prowler_provider_kwargs(
|
||||
**prowler_provider_kwargs,
|
||||
"filter_accounts": [provider.uid],
|
||||
}
|
||||
elif provider.provider == Provider.ProviderChoices.OPENSTACK.value:
|
||||
# No extra kwargs needed: clouds_yaml_content and clouds_yaml_cloud from the
|
||||
# secret are sufficient. Validating project_id (provider.uid) against the
|
||||
# clouds.yaml is not feasible because not all auth methods include it and the
|
||||
# Keystone API is unavailable on public clouds.
|
||||
pass
|
||||
|
||||
if mutelist_processor:
|
||||
mutelist_content = mutelist_processor.configuration.get("Mutelist", {})
|
||||
@@ -232,6 +245,7 @@ def initialize_prowler_provider(
|
||||
| KubernetesProvider
|
||||
| M365Provider
|
||||
| MongodbatlasProvider
|
||||
| OpenstackProvider
|
||||
| OraclecloudProvider
|
||||
):
|
||||
"""Initialize a Prowler provider instance based on the given provider type.
|
||||
@@ -241,7 +255,7 @@ def initialize_prowler_provider(
|
||||
mutelist_processor (Processor): The mutelist processor object containing the mutelist configuration.
|
||||
|
||||
Returns:
|
||||
AlibabacloudProvider | AwsProvider | AzureProvider | CloudflareProvider | GcpProvider | GithubProvider | IacProvider | KubernetesProvider | M365Provider | MongodbatlasProvider | OraclecloudProvider: An instance of the corresponding provider class
|
||||
AlibabacloudProvider | AwsProvider | AzureProvider | CloudflareProvider | GcpProvider | GithubProvider | IacProvider | KubernetesProvider | M365Provider | MongodbatlasProvider | OpenstackProvider | OraclecloudProvider: An instance of the corresponding provider class
|
||||
initialized with the provider's secrets.
|
||||
"""
|
||||
prowler_provider = return_prowler_provider(provider)
|
||||
@@ -276,6 +290,13 @@ def prowler_provider_connection_test(provider: Provider) -> Connection:
|
||||
if "access_token" in prowler_provider_kwargs:
|
||||
iac_test_kwargs["access_token"] = prowler_provider_kwargs["access_token"]
|
||||
return prowler_provider.test_connection(**iac_test_kwargs)
|
||||
elif provider.provider == Provider.ProviderChoices.OPENSTACK.value:
|
||||
openstack_kwargs = {
|
||||
"clouds_yaml_content": prowler_provider_kwargs["clouds_yaml_content"],
|
||||
"clouds_yaml_cloud": prowler_provider_kwargs["clouds_yaml_cloud"],
|
||||
"raise_on_exception": False,
|
||||
}
|
||||
return prowler_provider.test_connection(**openstack_kwargs)
|
||||
else:
|
||||
return prowler_provider.test_connection(
|
||||
**prowler_provider_kwargs,
|
||||
|
||||
@@ -373,6 +373,21 @@ from rest_framework_json_api import serializers
|
||||
},
|
||||
"required": ["api_key", "api_email"],
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"title": "OpenStack clouds.yaml Credentials",
|
||||
"properties": {
|
||||
"clouds_yaml_content": {
|
||||
"type": "string",
|
||||
"description": "The full content of a clouds.yaml configuration file.",
|
||||
},
|
||||
"clouds_yaml_cloud": {
|
||||
"type": "string",
|
||||
"description": "The name of the cloud to use from the clouds.yaml file.",
|
||||
},
|
||||
},
|
||||
"required": ["clouds_yaml_content", "clouds_yaml_cloud"],
|
||||
},
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1176,6 +1176,14 @@ class AttackPathsScanSerializer(RLSSerializer):
|
||||
return provider.uid if provider else None
|
||||
|
||||
|
||||
class AttackPathsQueryAttributionSerializer(BaseSerializerV1):
|
||||
text = serializers.CharField()
|
||||
link = serializers.CharField()
|
||||
|
||||
class JSONAPIMeta:
|
||||
resource_name = "attack-paths-query-attributions"
|
||||
|
||||
|
||||
class AttackPathsQueryParameterSerializer(BaseSerializerV1):
|
||||
name = serializers.CharField()
|
||||
label = serializers.CharField()
|
||||
@@ -1190,7 +1198,9 @@ class AttackPathsQueryParameterSerializer(BaseSerializerV1):
|
||||
class AttackPathsQuerySerializer(BaseSerializerV1):
|
||||
id = serializers.CharField()
|
||||
name = serializers.CharField()
|
||||
short_description = serializers.CharField()
|
||||
description = serializers.CharField()
|
||||
attribution = AttackPathsQueryAttributionSerializer(allow_null=True, required=False)
|
||||
provider = serializers.CharField()
|
||||
parameters = AttackPathsQueryParameterSerializer(many=True)
|
||||
|
||||
@@ -1515,6 +1525,8 @@ class BaseWriteProviderSecretSerializer(BaseWriteSerializer):
|
||||
"or both 'api_key' and 'api_email'."
|
||||
}
|
||||
)
|
||||
elif provider_type == Provider.ProviderChoices.OPENSTACK.value:
|
||||
serializer = OpenStackCloudsYamlProviderSecret(data=secret)
|
||||
else:
|
||||
raise serializers.ValidationError(
|
||||
{"provider": f"Provider type not supported {provider_type}"}
|
||||
@@ -1681,6 +1693,14 @@ class CloudflareApiKeyProviderSecret(serializers.Serializer):
|
||||
resource_name = "provider-secrets"
|
||||
|
||||
|
||||
class OpenStackCloudsYamlProviderSecret(serializers.Serializer):
|
||||
clouds_yaml_content = serializers.CharField()
|
||||
clouds_yaml_cloud = serializers.CharField()
|
||||
|
||||
class Meta:
|
||||
resource_name = "provider-secrets"
|
||||
|
||||
|
||||
class AlibabaCloudProviderSecret(serializers.Serializer):
|
||||
access_key_id = serializers.CharField()
|
||||
access_key_secret = serializers.CharField()
|
||||
|
||||
@@ -392,7 +392,7 @@ class SchemaView(SpectacularAPIView):
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
spectacular_settings.TITLE = "Prowler API"
|
||||
spectacular_settings.VERSION = "1.19.0"
|
||||
spectacular_settings.VERSION = "1.20.0"
|
||||
spectacular_settings.DESCRIPTION = (
|
||||
"Prowler API specification.\n\nThis file is auto-generated."
|
||||
)
|
||||
@@ -763,27 +763,40 @@ class TenantFinishACSView(FinishACSView):
|
||||
.tenant
|
||||
)
|
||||
|
||||
# Check if tenant has only one user with MANAGE_ACCOUNT role
|
||||
users_with_manage_account = (
|
||||
role_name = (
|
||||
extra.get("userType", ["no_permissions"])[0].strip()
|
||||
if extra.get("userType")
|
||||
else "no_permissions"
|
||||
)
|
||||
role = (
|
||||
Role.objects.using(MainRouter.admin_db)
|
||||
.filter(name=role_name, tenant=tenant)
|
||||
.first()
|
||||
)
|
||||
|
||||
# Only skip mapping if it would remove the last MANAGE_ACCOUNT user
|
||||
remaining_manage_account_users = (
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db)
|
||||
.filter(role__manage_account=True, tenant_id=tenant.id)
|
||||
.exclude(user_id=user_id)
|
||||
.values("user")
|
||||
.distinct()
|
||||
.count()
|
||||
)
|
||||
user_has_manage_account = (
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db)
|
||||
.filter(role__manage_account=True, tenant_id=tenant.id, user_id=user_id)
|
||||
.exists()
|
||||
)
|
||||
role_manage_account = role.manage_account if role else False
|
||||
would_remove_last_manage_account = (
|
||||
user_has_manage_account
|
||||
and remaining_manage_account_users == 0
|
||||
and not role_manage_account
|
||||
)
|
||||
|
||||
# Only apply role mapping from userType if tenant does NOT have exactly one user with MANAGE_ACCOUNT
|
||||
if users_with_manage_account != 1:
|
||||
role_name = (
|
||||
extra.get("userType", ["no_permissions"])[0].strip()
|
||||
if extra.get("userType")
|
||||
else "no_permissions"
|
||||
)
|
||||
try:
|
||||
role = Role.objects.using(MainRouter.admin_db).get(
|
||||
name=role_name, tenant=tenant
|
||||
)
|
||||
except Role.DoesNotExist:
|
||||
if not would_remove_last_manage_account:
|
||||
if role is None:
|
||||
role = Role.objects.using(MainRouter.admin_db).create(
|
||||
name=role_name,
|
||||
tenant=tenant,
|
||||
|
||||
@@ -18,6 +18,10 @@ DATABASES = {
|
||||
|
||||
DATABASE_ROUTERS = []
|
||||
TESTING = True
|
||||
# Override page size for testing to a value only slightly above the current fixture count.
|
||||
# We explicitly set PAGE_SIZE to 15 (round number just above fixture) to avoid masking pagination bugs, while not setting it excessively high.
|
||||
# If you add more providers to the fixture, please review that the total value is below the current one and update this value if needed.
|
||||
REST_FRAMEWORK["PAGE_SIZE"] = 15 # noqa: F405
|
||||
SECRETS_ENCRYPTION_KEY = "ZMiYVo7m4Fbe2eXXPyrwxdJss2WSalXSv3xHBcJkPl0="
|
||||
|
||||
# DRF Simple API Key settings
|
||||
|
||||
@@ -537,6 +537,12 @@ def providers_fixture(tenants_fixture):
|
||||
alias="cloudflare_testing",
|
||||
tenant_id=tenant.id,
|
||||
)
|
||||
provider11 = Provider.objects.create(
|
||||
provider="openstack",
|
||||
uid="a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
alias="openstack_testing",
|
||||
tenant_id=tenant.id,
|
||||
)
|
||||
|
||||
return (
|
||||
provider1,
|
||||
@@ -549,6 +555,7 @@ def providers_fixture(tenants_fixture):
|
||||
provider8,
|
||||
provider9,
|
||||
provider10,
|
||||
provider11,
|
||||
)
|
||||
|
||||
|
||||
@@ -1663,6 +1670,7 @@ def attack_paths_query_definition_factory():
|
||||
definition_payload = {
|
||||
"id": "aws-test",
|
||||
"name": "Attack Paths Test Query",
|
||||
"short_description": "Synthetic short description for tests.",
|
||||
"description": "Synthetic Attack Paths definition for tests.",
|
||||
"provider": "aws",
|
||||
"cypher": "RETURN 1",
|
||||
|
||||
@@ -12,8 +12,10 @@ BATCH_SIZE = env.int("ATTACK_PATHS_BATCH_SIZE", 1000)
|
||||
# Neo4j internal labels (Prowler-specific, not provider-specific)
|
||||
# - `ProwlerFinding`: Label for finding nodes created by Prowler and linked to cloud resources.
|
||||
# - `ProviderResource`: Added to ALL synced nodes for provider isolation and drop/query ops.
|
||||
# - `Internet`: Singleton node representing external internet access for exposed-resource queries.
|
||||
PROWLER_FINDING_LABEL = "ProwlerFinding"
|
||||
PROVIDER_RESOURCE_LABEL = "ProviderResource"
|
||||
INTERNET_NODE_LABEL = "Internet"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
||||
@@ -86,7 +86,11 @@ def finish_attack_paths_scan(
|
||||
) -> None:
|
||||
with rls_transaction(attack_paths_scan.tenant_id):
|
||||
now = datetime.now(tz=timezone.utc)
|
||||
duration = int((now - attack_paths_scan.started_at).total_seconds())
|
||||
duration = (
|
||||
int((now - attack_paths_scan.started_at).total_seconds())
|
||||
if attack_paths_scan.started_at
|
||||
else 0
|
||||
)
|
||||
|
||||
attack_paths_scan.state = state
|
||||
attack_paths_scan.progress = 100
|
||||
@@ -144,3 +148,24 @@ def update_old_attack_paths_scan(
|
||||
with rls_transaction(old_attack_paths_scan.tenant_id):
|
||||
old_attack_paths_scan.is_graph_database_deleted = True
|
||||
old_attack_paths_scan.save(update_fields=["is_graph_database_deleted"])
|
||||
|
||||
|
||||
def fail_attack_paths_scan(
|
||||
tenant_id: str,
|
||||
scan_id: str,
|
||||
error: str,
|
||||
) -> None:
|
||||
"""
|
||||
Mark the `AttackPathsScan` row as `FAILED` unless it's already `COMPLETED` or `FAILED`.
|
||||
Used as a safety net when the Celery task fails outside the job's own error handling.
|
||||
"""
|
||||
attack_paths_scan = retrieve_attack_paths_scan(tenant_id, scan_id)
|
||||
if attack_paths_scan and attack_paths_scan.state not in (
|
||||
StateChoices.COMPLETED,
|
||||
StateChoices.FAILED,
|
||||
):
|
||||
finish_attack_paths_scan(
|
||||
attack_paths_scan,
|
||||
StateChoices.FAILED,
|
||||
{"global_error": error},
|
||||
)
|
||||
|
||||
@@ -6,6 +6,7 @@ from cartography.client.core.tx import run_write_query
|
||||
from celery.utils.log import get_task_logger
|
||||
|
||||
from tasks.jobs.attack_paths.config import (
|
||||
INTERNET_NODE_LABEL,
|
||||
PROWLER_FINDING_LABEL,
|
||||
PROVIDER_RESOURCE_LABEL,
|
||||
)
|
||||
@@ -30,6 +31,8 @@ FINDINGS_INDEX_STATEMENTS = [
|
||||
f"CREATE INDEX prowler_finding_provider_uid IF NOT EXISTS FOR (n:{PROWLER_FINDING_LABEL}) ON (n.provider_uid);",
|
||||
f"CREATE INDEX prowler_finding_lastupdated IF NOT EXISTS FOR (n:{PROWLER_FINDING_LABEL}) ON (n.lastupdated);",
|
||||
f"CREATE INDEX prowler_finding_status IF NOT EXISTS FOR (n:{PROWLER_FINDING_LABEL}) ON (n.status);",
|
||||
# Internet node index for MERGE lookups
|
||||
f"CREATE INDEX internet_id IF NOT EXISTS FOR (n:{INTERNET_NODE_LABEL}) ON (n.id);",
|
||||
]
|
||||
|
||||
# Indexes for provider resource sync operations
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
"""
|
||||
Internet node enrichment for Attack Paths graph.
|
||||
|
||||
Creates a real Internet node and CAN_ACCESS relationships to
|
||||
internet-exposed resources (EC2Instance, LoadBalancer, LoadBalancerV2)
|
||||
in the temporary scan database before sync.
|
||||
"""
|
||||
|
||||
import neo4j
|
||||
|
||||
from cartography.config import Config as CartographyConfig
|
||||
from celery.utils.log import get_task_logger
|
||||
|
||||
from api.models import Provider
|
||||
from prowler.config import config as ProwlerConfig
|
||||
from tasks.jobs.attack_paths.config import get_root_node_label
|
||||
from tasks.jobs.attack_paths.queries import (
|
||||
CREATE_CAN_ACCESS_RELATIONSHIPS_TEMPLATE,
|
||||
CREATE_INTERNET_NODE,
|
||||
render_cypher_template,
|
||||
)
|
||||
|
||||
logger = get_task_logger(__name__)
|
||||
|
||||
|
||||
def analysis(
|
||||
neo4j_session: neo4j.Session,
|
||||
prowler_api_provider: Provider,
|
||||
config: CartographyConfig,
|
||||
) -> int:
|
||||
"""
|
||||
Create Internet node and CAN_ACCESS relationships to exposed resources.
|
||||
|
||||
Args:
|
||||
neo4j_session: Active Neo4j session (temp database).
|
||||
prowler_api_provider: The Prowler API provider instance.
|
||||
config: Cartography configuration with update_tag.
|
||||
|
||||
Returns:
|
||||
Number of CAN_ACCESS relationships created.
|
||||
"""
|
||||
provider_uid = str(prowler_api_provider.uid)
|
||||
|
||||
parameters = {
|
||||
"provider_uid": provider_uid,
|
||||
"last_updated": config.update_tag,
|
||||
"prowler_version": ProwlerConfig.prowler_version,
|
||||
}
|
||||
|
||||
logger.info(f"Creating Internet node for provider {provider_uid}")
|
||||
neo4j_session.run(CREATE_INTERNET_NODE, parameters)
|
||||
|
||||
query = render_cypher_template(
|
||||
CREATE_CAN_ACCESS_RELATIONSHIPS_TEMPLATE,
|
||||
{"__ROOT_LABEL__": get_root_node_label(prowler_api_provider.provider)},
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"Creating CAN_ACCESS relationships from Internet to exposed resources for {provider_uid}"
|
||||
)
|
||||
result = neo4j_session.run(query, parameters)
|
||||
relationships_merged = result.single().get("relationships_merged", 0)
|
||||
|
||||
logger.info(
|
||||
f"Created {relationships_merged} CAN_ACCESS relationships for provider {provider_uid}"
|
||||
)
|
||||
return relationships_merged
|
||||
@@ -1,5 +1,6 @@
|
||||
# Cypher query templates for Attack Paths operations
|
||||
from tasks.jobs.attack_paths.config import (
|
||||
INTERNET_NODE_LABEL,
|
||||
PROWLER_FINDING_LABEL,
|
||||
PROVIDER_RESOURCE_LABEL,
|
||||
)
|
||||
@@ -91,6 +92,37 @@ CLEANUP_FINDINGS_TEMPLATE = f"""
|
||||
RETURN COUNT(finding) AS deleted_findings_count
|
||||
"""
|
||||
|
||||
# Internet queries (used by internet.py)
|
||||
# ---------------------------------------
|
||||
|
||||
CREATE_INTERNET_NODE = f"""
|
||||
MERGE (internet:{INTERNET_NODE_LABEL} {{id: 'Internet'}})
|
||||
ON CREATE SET
|
||||
internet.name = 'Internet',
|
||||
internet.firstseen = timestamp(),
|
||||
internet.lastupdated = $last_updated,
|
||||
internet._module_name = 'cartography:prowler',
|
||||
internet._module_version = $prowler_version
|
||||
ON MATCH SET
|
||||
internet.lastupdated = $last_updated
|
||||
"""
|
||||
|
||||
CREATE_CAN_ACCESS_RELATIONSHIPS_TEMPLATE = f"""
|
||||
MATCH (account:__ROOT_LABEL__ {{id: $provider_uid}})-->(resource)
|
||||
WHERE resource.exposed_internet = true
|
||||
WITH resource
|
||||
MATCH (internet:{INTERNET_NODE_LABEL} {{id: 'Internet'}})
|
||||
MERGE (internet)-[r:CAN_ACCESS]->(resource)
|
||||
ON CREATE SET
|
||||
r.firstseen = timestamp(),
|
||||
r.lastupdated = $last_updated,
|
||||
r._module_name = 'cartography:prowler',
|
||||
r._module_version = $prowler_version
|
||||
ON MATCH SET
|
||||
r.lastupdated = $last_updated
|
||||
RETURN COUNT(r) AS relationships_merged
|
||||
"""
|
||||
|
||||
# Sync queries (used by sync.py)
|
||||
# -------------------------------
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ from api.models import (
|
||||
StateChoices,
|
||||
)
|
||||
from api.utils import initialize_prowler_provider
|
||||
from tasks.jobs.attack_paths import db_utils, findings, sync, utils
|
||||
from tasks.jobs.attack_paths import db_utils, findings, internet, sync, utils
|
||||
from tasks.jobs.attack_paths.config import get_cartography_ingestion_function
|
||||
|
||||
# Without this Celery goes crazy with Cartography logging
|
||||
@@ -135,7 +135,15 @@ def run(tenant_id: str, scan_id: str, task_id: str) -> dict[str, Any]:
|
||||
cartography_analysis.run(tmp_neo4j_session, tmp_cartography_config)
|
||||
db_utils.update_attack_paths_scan_progress(attack_paths_scan, 96)
|
||||
|
||||
# Adding Prowler nodes and relationships
|
||||
# Creating Internet node and CAN_ACCESS relationships
|
||||
logger.info(
|
||||
f"Creating Internet graph for AWS account {prowler_api_provider.uid}"
|
||||
)
|
||||
internet.analysis(
|
||||
tmp_neo4j_session, prowler_api_provider, tmp_cartography_config
|
||||
)
|
||||
|
||||
# Adding Prowler Finding nodes and relationships
|
||||
logger.info(
|
||||
f"Syncing Prowler analysis for AWS account {prowler_api_provider.uid}"
|
||||
)
|
||||
@@ -220,10 +228,16 @@ def run(tenant_id: str, scan_id: str, task_id: str) -> dict[str, Any]:
|
||||
except Exception as e:
|
||||
exception_message = utils.stringify_exception(e, "Cartography failed")
|
||||
logger.error(exception_message)
|
||||
ingestion_exceptions["global_cartography_error"] = exception_message
|
||||
ingestion_exceptions["global_error"] = exception_message
|
||||
|
||||
# Handling databases changes
|
||||
graph_database.drop_database(tmp_cartography_config.neo4j_database)
|
||||
try:
|
||||
graph_database.drop_database(tmp_cartography_config.neo4j_database)
|
||||
except Exception:
|
||||
logger.exception(
|
||||
f"Failed to drop temporary Neo4j database {tmp_cartography_config.neo4j_database} during cleanup"
|
||||
)
|
||||
|
||||
db_utils.finish_attack_paths_scan(
|
||||
attack_paths_scan, StateChoices.FAILED, ingestion_exceptions
|
||||
)
|
||||
|
||||
@@ -35,6 +35,11 @@ from prowler.lib.outputs.compliance.cis.cis_github import GithubCIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_kubernetes import KubernetesCIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_m365 import M365CIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_oraclecloud import OracleCloudCIS
|
||||
from prowler.lib.outputs.compliance.csa.csa_alibabacloud import AlibabaCloudCSA
|
||||
from prowler.lib.outputs.compliance.csa.csa_aws import AWSCSA
|
||||
from prowler.lib.outputs.compliance.csa.csa_azure import AzureCSA
|
||||
from prowler.lib.outputs.compliance.csa.csa_gcp import GCPCSA
|
||||
from prowler.lib.outputs.compliance.csa.csa_oraclecloud import OracleCloudCSA
|
||||
from prowler.lib.outputs.compliance.ens.ens_aws import AWSENS
|
||||
from prowler.lib.outputs.compliance.ens.ens_azure import AzureENS
|
||||
from prowler.lib.outputs.compliance.ens.ens_gcp import GCPENS
|
||||
@@ -90,6 +95,7 @@ COMPLIANCE_CLASS_MAP = {
|
||||
(lambda name: name == "prowler_threatscore_aws", ProwlerThreatScoreAWS),
|
||||
(lambda name: name == "ccc_aws", CCC_AWS),
|
||||
(lambda name: name.startswith("c5_"), AWSC5),
|
||||
(lambda name: name.startswith("csa_"), AWSCSA),
|
||||
],
|
||||
"azure": [
|
||||
(lambda name: name.startswith("cis_"), AzureCIS),
|
||||
@@ -99,6 +105,7 @@ COMPLIANCE_CLASS_MAP = {
|
||||
(lambda name: name == "ccc_azure", CCC_Azure),
|
||||
(lambda name: name == "prowler_threatscore_azure", ProwlerThreatScoreAzure),
|
||||
(lambda name: name == "c5_azure", AzureC5),
|
||||
(lambda name: name.startswith("csa_"), AzureCSA),
|
||||
],
|
||||
"gcp": [
|
||||
(lambda name: name.startswith("cis_"), GCPCIS),
|
||||
@@ -108,6 +115,7 @@ COMPLIANCE_CLASS_MAP = {
|
||||
(lambda name: name == "prowler_threatscore_gcp", ProwlerThreatScoreGCP),
|
||||
(lambda name: name == "ccc_gcp", CCC_GCP),
|
||||
(lambda name: name == "c5_gcp", GCPC5),
|
||||
(lambda name: name.startswith("csa_"), GCPCSA),
|
||||
],
|
||||
"kubernetes": [
|
||||
(lambda name: name.startswith("cis_"), KubernetesCIS),
|
||||
@@ -131,9 +139,11 @@ COMPLIANCE_CLASS_MAP = {
|
||||
],
|
||||
"oraclecloud": [
|
||||
(lambda name: name.startswith("cis_"), OracleCloudCIS),
|
||||
(lambda name: name.startswith("csa_"), OracleCloudCSA),
|
||||
],
|
||||
"alibabacloud": [
|
||||
(lambda name: name.startswith("cis_"), AlibabaCloudCIS),
|
||||
(lambda name: name.startswith("csa_"), AlibabaCloudCSA),
|
||||
(
|
||||
lambda name: name == "prowler_threatscore_alibabacloud",
|
||||
ProwlerThreatScoreAlibaba,
|
||||
|
||||
@@ -10,6 +10,7 @@ from config.django.base import DJANGO_FINDINGS_BATCH_SIZE, DJANGO_TMP_OUTPUT_DIR
|
||||
from django_celery_beat.models import PeriodicTask
|
||||
from tasks.jobs.attack_paths import (
|
||||
attack_paths_scan,
|
||||
db_utils as attack_paths_db_utils,
|
||||
can_provider_run_attack_paths_scan,
|
||||
)
|
||||
from tasks.jobs.backfill import (
|
||||
@@ -359,8 +360,25 @@ def perform_scan_summary_task(tenant_id: str, scan_id: str):
|
||||
return aggregate_findings(tenant_id=tenant_id, scan_id=scan_id)
|
||||
|
||||
|
||||
class AttackPathsScanRLSTask(RLSTask):
|
||||
"""
|
||||
RLS task that marks the `AttackPathsScan` DB row as `FAILED` when the Celery task fails.
|
||||
|
||||
Covers failures that happen outside the job's own try/except (e.g. provider lookup,
|
||||
SDK initialization, or Neo4j configuration errors during setup).
|
||||
"""
|
||||
|
||||
def on_failure(self, exc, task_id, args, kwargs, _einfo):
|
||||
tenant_id = kwargs.get("tenant_id")
|
||||
scan_id = kwargs.get("scan_id")
|
||||
|
||||
if tenant_id and scan_id:
|
||||
logger.error(f"Attack paths scan task {task_id} failed: {exc}")
|
||||
attack_paths_db_utils.fail_attack_paths_scan(tenant_id, scan_id, str(exc))
|
||||
|
||||
|
||||
@shared_task(
|
||||
base=RLSTask,
|
||||
base=AttackPathsScanRLSTask,
|
||||
bind=True,
|
||||
name="attack-paths-scan-perform",
|
||||
queue="attack-paths-scans",
|
||||
|
||||
@@ -4,6 +4,7 @@ from unittest.mock import MagicMock, call, patch
|
||||
|
||||
import pytest
|
||||
from tasks.jobs.attack_paths import findings as findings_module
|
||||
from tasks.jobs.attack_paths import internet as internet_module
|
||||
from tasks.jobs.attack_paths.scan import run as attack_paths_run
|
||||
|
||||
from api.models import (
|
||||
@@ -37,6 +38,7 @@ class TestAttackPathsRun:
|
||||
@patch("tasks.jobs.attack_paths.scan.sync.sync_graph")
|
||||
@patch("tasks.jobs.attack_paths.scan.graph_database.drop_subgraph")
|
||||
@patch("tasks.jobs.attack_paths.scan.sync.create_sync_indexes")
|
||||
@patch("tasks.jobs.attack_paths.scan.internet.analysis")
|
||||
@patch("tasks.jobs.attack_paths.scan.findings.analysis")
|
||||
@patch("tasks.jobs.attack_paths.scan.findings.create_findings_indexes")
|
||||
@patch("tasks.jobs.attack_paths.scan.cartography_ontology.run")
|
||||
@@ -67,6 +69,7 @@ class TestAttackPathsRun:
|
||||
mock_cartography_ontology,
|
||||
mock_findings_indexes,
|
||||
mock_findings_analysis,
|
||||
mock_internet_analysis,
|
||||
mock_sync_indexes,
|
||||
mock_drop_subgraph,
|
||||
mock_sync,
|
||||
@@ -139,6 +142,7 @@ class TestAttackPathsRun:
|
||||
# These use tmp_cartography_config (neo4j_database="db-scan-id")
|
||||
mock_cartography_analysis.assert_called_once()
|
||||
mock_cartography_ontology.assert_called_once()
|
||||
mock_internet_analysis.assert_called_once()
|
||||
mock_findings_analysis.assert_called_once()
|
||||
mock_drop_subgraph.assert_called_once_with(
|
||||
database="tenant-db",
|
||||
@@ -207,6 +211,7 @@ class TestAttackPathsRun:
|
||||
patch("tasks.jobs.attack_paths.scan.cartography_create_indexes.run"),
|
||||
patch("tasks.jobs.attack_paths.scan.cartography_analysis.run"),
|
||||
patch("tasks.jobs.attack_paths.scan.findings.create_findings_indexes"),
|
||||
patch("tasks.jobs.attack_paths.scan.internet.analysis"),
|
||||
patch("tasks.jobs.attack_paths.scan.findings.analysis"),
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.scan.db_utils.retrieve_attack_paths_scan",
|
||||
@@ -239,9 +244,91 @@ class TestAttackPathsRun:
|
||||
failure_args = mock_finish.call_args[0]
|
||||
assert failure_args[0] is attack_paths_scan
|
||||
assert failure_args[1] == StateChoices.FAILED
|
||||
assert failure_args[2] == {
|
||||
"global_cartography_error": "Cartography failed: ingestion boom"
|
||||
}
|
||||
assert failure_args[2] == {"global_error": "Cartography failed: ingestion boom"}
|
||||
|
||||
def test_run_failure_marks_scan_failed_even_when_drop_database_fails(
|
||||
self, tenants_fixture, providers_fixture, scans_fixture
|
||||
):
|
||||
tenant = tenants_fixture[0]
|
||||
provider = providers_fixture[0]
|
||||
provider.provider = Provider.ProviderChoices.AWS
|
||||
provider.save()
|
||||
scan = scans_fixture[0]
|
||||
scan.provider = provider
|
||||
scan.save()
|
||||
|
||||
attack_paths_scan = AttackPathsScan.objects.create(
|
||||
tenant_id=tenant.id,
|
||||
provider=provider,
|
||||
scan=scan,
|
||||
state=StateChoices.SCHEDULED,
|
||||
)
|
||||
|
||||
mock_session = MagicMock()
|
||||
session_ctx = MagicMock()
|
||||
session_ctx.__enter__.return_value = mock_session
|
||||
session_ctx.__exit__.return_value = False
|
||||
ingestion_fn = MagicMock(side_effect=RuntimeError("ingestion boom"))
|
||||
|
||||
with (
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.scan.rls_transaction",
|
||||
new=lambda *args, **kwargs: nullcontext(),
|
||||
),
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.scan.initialize_prowler_provider",
|
||||
return_value=MagicMock(_enabled_regions=["us-east-1"]),
|
||||
),
|
||||
patch("tasks.jobs.attack_paths.scan.graph_database.get_uri"),
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.scan.graph_database.get_database_name",
|
||||
return_value="db-scan-id",
|
||||
),
|
||||
patch("tasks.jobs.attack_paths.scan.graph_database.create_database"),
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.scan.graph_database.get_session",
|
||||
return_value=session_ctx,
|
||||
),
|
||||
patch("tasks.jobs.attack_paths.scan.cartography_create_indexes.run"),
|
||||
patch("tasks.jobs.attack_paths.scan.cartography_analysis.run"),
|
||||
patch("tasks.jobs.attack_paths.scan.findings.create_findings_indexes"),
|
||||
patch("tasks.jobs.attack_paths.scan.internet.analysis"),
|
||||
patch("tasks.jobs.attack_paths.scan.findings.analysis"),
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.scan.db_utils.retrieve_attack_paths_scan",
|
||||
return_value=attack_paths_scan,
|
||||
),
|
||||
patch("tasks.jobs.attack_paths.scan.db_utils.starting_attack_paths_scan"),
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.scan.db_utils.update_attack_paths_scan_progress"
|
||||
),
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.scan.db_utils.finish_attack_paths_scan"
|
||||
) as mock_finish,
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.scan.graph_database.drop_database",
|
||||
side_effect=ConnectionError("neo4j down"),
|
||||
),
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.scan.get_cartography_ingestion_function",
|
||||
return_value=ingestion_fn,
|
||||
),
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.scan.utils.call_within_event_loop",
|
||||
side_effect=lambda fn, *a, **kw: fn(*a, **kw),
|
||||
),
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.scan.utils.stringify_exception",
|
||||
return_value="Cartography failed: ingestion boom",
|
||||
),
|
||||
):
|
||||
with pytest.raises(RuntimeError, match="ingestion boom"):
|
||||
attack_paths_run(str(tenant.id), str(scan.id), "task-789")
|
||||
|
||||
failure_args = mock_finish.call_args[0]
|
||||
assert failure_args[0] is attack_paths_scan
|
||||
assert failure_args[1] == StateChoices.FAILED
|
||||
assert failure_args[2] == {"global_error": "Cartography failed: ingestion boom"}
|
||||
|
||||
def test_run_returns_early_for_unsupported_provider(self, tenants_fixture):
|
||||
tenant = tenants_fixture[0]
|
||||
@@ -286,6 +373,142 @@ class TestAttackPathsRun:
|
||||
mock_retrieve.assert_called_once_with(str(tenant.id), str(scan.id))
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
class TestFailAttackPathsScan:
|
||||
def test_marks_executing_scan_as_failed(
|
||||
self, tenants_fixture, providers_fixture, scans_fixture
|
||||
):
|
||||
from tasks.jobs.attack_paths.db_utils import (
|
||||
fail_attack_paths_scan,
|
||||
)
|
||||
|
||||
tenant = tenants_fixture[0]
|
||||
provider = providers_fixture[0]
|
||||
provider.provider = Provider.ProviderChoices.AWS
|
||||
provider.save()
|
||||
scan = scans_fixture[0]
|
||||
scan.provider = provider
|
||||
scan.save()
|
||||
|
||||
attack_paths_scan = AttackPathsScan.objects.create(
|
||||
tenant_id=tenant.id,
|
||||
provider=provider,
|
||||
scan=scan,
|
||||
state=StateChoices.EXECUTING,
|
||||
)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.db_utils.retrieve_attack_paths_scan",
|
||||
return_value=attack_paths_scan,
|
||||
) as mock_retrieve,
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.db_utils.finish_attack_paths_scan"
|
||||
) as mock_finish,
|
||||
):
|
||||
fail_attack_paths_scan(str(tenant.id), str(scan.id), "setup exploded")
|
||||
|
||||
mock_retrieve.assert_called_once_with(str(tenant.id), str(scan.id))
|
||||
mock_finish.assert_called_once_with(
|
||||
attack_paths_scan,
|
||||
StateChoices.FAILED,
|
||||
{"global_error": "setup exploded"},
|
||||
)
|
||||
|
||||
def test_skips_already_failed_scan(
|
||||
self, tenants_fixture, providers_fixture, scans_fixture
|
||||
):
|
||||
from tasks.jobs.attack_paths.db_utils import (
|
||||
fail_attack_paths_scan,
|
||||
)
|
||||
|
||||
tenant = tenants_fixture[0]
|
||||
provider = providers_fixture[0]
|
||||
provider.provider = Provider.ProviderChoices.AWS
|
||||
provider.save()
|
||||
scan = scans_fixture[0]
|
||||
scan.provider = provider
|
||||
scan.save()
|
||||
|
||||
attack_paths_scan = AttackPathsScan.objects.create(
|
||||
tenant_id=tenant.id,
|
||||
provider=provider,
|
||||
scan=scan,
|
||||
state=StateChoices.FAILED,
|
||||
)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.db_utils.retrieve_attack_paths_scan",
|
||||
return_value=attack_paths_scan,
|
||||
),
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.db_utils.finish_attack_paths_scan"
|
||||
) as mock_finish,
|
||||
):
|
||||
fail_attack_paths_scan(str(tenant.id), str(scan.id), "setup exploded")
|
||||
|
||||
mock_finish.assert_not_called()
|
||||
|
||||
def test_skips_when_no_scan_found(self, tenants_fixture):
|
||||
from tasks.jobs.attack_paths.db_utils import (
|
||||
fail_attack_paths_scan,
|
||||
)
|
||||
|
||||
tenant = tenants_fixture[0]
|
||||
|
||||
with (
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.db_utils.retrieve_attack_paths_scan",
|
||||
return_value=None,
|
||||
),
|
||||
patch(
|
||||
"tasks.jobs.attack_paths.db_utils.finish_attack_paths_scan"
|
||||
) as mock_finish,
|
||||
):
|
||||
fail_attack_paths_scan(str(tenant.id), "nonexistent", "setup exploded")
|
||||
|
||||
mock_finish.assert_not_called()
|
||||
|
||||
|
||||
class TestAttackPathsScanRLSTaskOnFailure:
|
||||
def test_on_failure_delegates_to_fail_attack_paths_scan(self):
|
||||
from tasks.tasks import AttackPathsScanRLSTask
|
||||
|
||||
task = AttackPathsScanRLSTask()
|
||||
|
||||
with patch(
|
||||
"tasks.tasks.attack_paths_db_utils.fail_attack_paths_scan"
|
||||
) as mock_fail:
|
||||
task.on_failure(
|
||||
exc=RuntimeError("boom"),
|
||||
task_id="task-abc",
|
||||
args=(),
|
||||
kwargs={"tenant_id": "t-1", "scan_id": "s-1"},
|
||||
_einfo=None,
|
||||
)
|
||||
|
||||
mock_fail.assert_called_once_with("t-1", "s-1", "boom")
|
||||
|
||||
def test_on_failure_skips_when_missing_kwargs(self):
|
||||
from tasks.tasks import AttackPathsScanRLSTask
|
||||
|
||||
task = AttackPathsScanRLSTask()
|
||||
|
||||
with patch(
|
||||
"tasks.tasks.attack_paths_db_utils.fail_attack_paths_scan"
|
||||
) as mock_fail:
|
||||
task.on_failure(
|
||||
exc=RuntimeError("boom"),
|
||||
task_id="task-abc",
|
||||
args=(),
|
||||
kwargs={},
|
||||
_einfo=None,
|
||||
)
|
||||
|
||||
mock_fail.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
class TestAttackPathsFindingsHelpers:
|
||||
def test_create_findings_indexes_executes_all_statements(self):
|
||||
@@ -757,3 +980,45 @@ class TestAttackPathsFindingsHelpers:
|
||||
findings_module.load_findings(mock_session, empty_gen(), provider, config)
|
||||
|
||||
mock_session.run.assert_not_called()
|
||||
|
||||
|
||||
class TestInternetAnalysis:
|
||||
def _make_provider_and_config(self):
|
||||
provider = MagicMock()
|
||||
provider.provider = "aws"
|
||||
provider.uid = "123456789012"
|
||||
config = SimpleNamespace(update_tag=1234567890)
|
||||
return provider, config
|
||||
|
||||
def test_analysis_creates_node_and_relationships(self):
|
||||
"""Verify both Cypher statements are executed and relationship count returned."""
|
||||
mock_session = MagicMock()
|
||||
mock_result = MagicMock()
|
||||
mock_result.single.return_value = {"relationships_merged": 3}
|
||||
mock_session.run.side_effect = [None, mock_result]
|
||||
provider, config = self._make_provider_and_config()
|
||||
|
||||
with patch(
|
||||
"tasks.jobs.attack_paths.internet.get_root_node_label",
|
||||
return_value="AWSAccount",
|
||||
):
|
||||
result = internet_module.analysis(mock_session, provider, config)
|
||||
|
||||
assert mock_session.run.call_count == 2
|
||||
assert result == 3
|
||||
|
||||
def test_analysis_zero_exposed_resources(self):
|
||||
"""When no resources are exposed, zero relationships are created."""
|
||||
mock_session = MagicMock()
|
||||
mock_result = MagicMock()
|
||||
mock_result.single.return_value = {"relationships_merged": 0}
|
||||
mock_session.run.side_effect = [None, mock_result]
|
||||
provider, config = self._make_provider_and_config()
|
||||
|
||||
with patch(
|
||||
"tasks.jobs.attack_paths.internet.get_root_node_label",
|
||||
return_value="AWSAccount",
|
||||
):
|
||||
result = internet_module.analysis(mock_session, provider, config)
|
||||
|
||||
assert result == 0
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
examples
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
@@ -0,0 +1,12 @@
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
repository: oci://registry-1.docker.io/bitnamicharts
|
||||
version: 18.2.0
|
||||
- name: valkey
|
||||
repository: https://valkey.io/valkey-helm/
|
||||
version: 0.9.3
|
||||
- name: neo4j
|
||||
repository: https://helm.neo4j.com/neo4j
|
||||
version: 2025.12.1
|
||||
digest: sha256:da19233c6832727345fcdb314d683d30aa347d349f270023f3a67149bffb009b
|
||||
generated: "2026-01-26T12:00:06.798702+02:00"
|
||||
@@ -0,0 +1,33 @@
|
||||
apiVersion: v2
|
||||
name: prowler
|
||||
description: Prowler is an Open Cloud Security tool for AWS, Azure, GCP and Kubernetes. It helps for continuous monitoring, security assessments and audits, incident response, compliance, hardening and forensics readiness.
|
||||
type: application
|
||||
version: 0.0.1
|
||||
appVersion: "5.17.0"
|
||||
home: https://prowler.com
|
||||
icon: https://cdn.prod.website-files.com/68c4ec3f9fb7b154fbcb6e36/68c5e0fea5d0059b9e05834b_Link.png
|
||||
keywords:
|
||||
- security
|
||||
- aws
|
||||
- azure
|
||||
- gcp
|
||||
- kubernetes
|
||||
maintainers:
|
||||
- name: Mihai
|
||||
email: mihai.legat@gmail.com
|
||||
dependencies:
|
||||
# https://artifacthub.io/packages/helm/bitnami/postgresql
|
||||
- name: postgresql
|
||||
version: 18.2.0
|
||||
repository: oci://registry-1.docker.io/bitnamicharts
|
||||
condition: postgresql.enabled
|
||||
# https://valkey.io/valkey-helm/
|
||||
- name: valkey
|
||||
version: 0.9.3
|
||||
repository: https://valkey.io/valkey-helm/
|
||||
condition: valkey.enabled
|
||||
# https://helm.neo4j.com/neo4j
|
||||
- name: neo4j
|
||||
version: 2025.12.1
|
||||
repository: https://helm.neo4j.com/neo4j
|
||||
condition: neo4j.enabled
|
||||
@@ -0,0 +1,143 @@
|
||||
<!--
|
||||
This README is the one shown on Artifact Hub.
|
||||
Images should use absolute URLs.
|
||||
-->
|
||||
|
||||
# Prowler App Helm Chart
|
||||
|
||||

|
||||

|
||||
|
||||
Prowler is an Open Cloud Security tool for AWS, Azure, GCP and Kubernetes. It helps for continuous monitoring, security assessments and audits, incident response, compliance, hardening and forensics readiness. Includes CIS, NIST 800, NIST CSF, CISA, FedRAMP, PCI-DSS, GDPR, HIPAA, FFIEC, SOC2, GXP, Well-Architected Security, ENS and more.
|
||||
|
||||
## Architecture
|
||||
|
||||
The Prowler App consists of three main components:
|
||||
|
||||
- **Prowler UI**: A user-friendly web interface for running Prowler and viewing results, powered by Next.js.
|
||||
- **Prowler API**: The backend API that executes Prowler scans and stores the results, built with Django REST Framework.
|
||||
- **Prowler SDK**: A Python SDK that integrates with the Prowler CLI for advanced functionality.
|
||||
|
||||
The app leverages the following supporting infrastructure:
|
||||
|
||||
- **PostgreSQL**: Used for persistent storage of scan results.
|
||||
- **Celery Workers**: Facilitate asynchronous execution of Prowler scans.
|
||||
- **Valkey**: An in-memory database serving as a message broker for the Celery workers.
|
||||
- **Neo4j**: Graph Database
|
||||
- **Keda**: Kubernetes Event-driven Autoscaling (Keda) automatically scales the number of Celery worker pods based on the workload, ensuring efficient resource utilization and responsiveness.
|
||||
|
||||
## Setup
|
||||
|
||||
This guide walks you through installing Prowler App using Helm. For a minimal installation example, see the [minimal installation example](./examples/minimal-installation/).
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Kubernetes cluster (1.24+)
|
||||
- Helm 3.x installed
|
||||
- `kubectl` configured to access your cluster
|
||||
- Access to the Prowler Helm chart repository (or local chart)
|
||||
|
||||
### Step 1: Create Required Secrets
|
||||
|
||||
Before installing the Helm chart, you must create a Kubernetes Secret containing the required authentication keys and secrets.
|
||||
|
||||
1. **Generate the required keys and secrets:**
|
||||
|
||||
```bash
|
||||
# Generate Django token signing key (private key)
|
||||
openssl genrsa -out private.pem 2048
|
||||
|
||||
# Generate Django token verifying key (public key)
|
||||
openssl rsa -in private.pem -pubout -out public.pem
|
||||
|
||||
# Generate Django secrets encryption key
|
||||
openssl rand -base64 32
|
||||
|
||||
# Generate Auth secret
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
2. **Create the secret file:**
|
||||
|
||||
Create a file named `secrets.yaml` with the following structure:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
type: Opaque
|
||||
metadata:
|
||||
name: prowler-secret
|
||||
stringData:
|
||||
DJANGO_TOKEN_SIGNING_KEY: |
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
[paste your private key here]
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
DJANGO_TOKEN_VERIFYING_KEY: |
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
[paste your public key here]
|
||||
-----END PUBLIC KEY-----
|
||||
|
||||
DJANGO_SECRETS_ENCRYPTION_KEY: "[paste your encryption key here]"
|
||||
|
||||
AUTH_SECRET: "[paste your auth secret here]"
|
||||
|
||||
NEO4J_PASSWORD: "[prowler-password]"
|
||||
NEO4J_AUTH: "neo4j/[prowler-password]"
|
||||
```
|
||||
|
||||
> **Note:** You can use the [example secrets file](./examples/minimal-installation/secrets.yaml) as a template, but **always replace the placeholder values with your own secure keys** before applying.
|
||||
|
||||
3. **Apply the secret to your cluster:**
|
||||
|
||||
```bash
|
||||
kubectl apply -f secrets.yaml
|
||||
```
|
||||
|
||||
### Step 2: Configure Values
|
||||
|
||||
Create a `values.yaml` file to customize your installation. At minimum, you need to configure the UI access method.
|
||||
|
||||
**Option A: Using Ingress (Recommended for production)**
|
||||
|
||||
```yaml
|
||||
ui:
|
||||
ingress:
|
||||
enabled: true
|
||||
hosts:
|
||||
- host: prowler.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: ImplementationSpecific
|
||||
```
|
||||
|
||||
**Option B: Using authUrl (For proxy setups)**
|
||||
|
||||
```yaml
|
||||
ui:
|
||||
authUrl: prowler.example.com
|
||||
```
|
||||
|
||||
> **Note:** See the [minimal installation example](./examples/minimal-installation/values.yaml) for a complete reference.
|
||||
|
||||
### Step 3: Install the Chart
|
||||
|
||||
Install Prowler App using Helm:
|
||||
|
||||
```bash
|
||||
helm dependency update
|
||||
helm install prowler prowler/prowler-app -f values.yaml
|
||||
```
|
||||
|
||||
### Using Existing PostgreSQL and Valkey Instances
|
||||
|
||||
By default, this Chart uses Bitnami's Charts to deploy [PostgreSQL](https://artifacthub.io/packages/helm/bitnami/postgresql), [Neo4j](https://helm.neo4j.com/neo4j) and [Valkey official helm chart](https://valkey.io/valkey-helm/). **Note:** This default setup is not production-ready.
|
||||
|
||||
To connect to existing PostgreSQL, Neo4j and Valkey instances:
|
||||
|
||||
1. Create a `Secret` containing the correct database and message broker credentials
|
||||
2. Reference the secret in the [values.yaml](values.yaml) file api->secrets list
|
||||
|
||||
## Contributing
|
||||
|
||||
Feel free to contact the maintainer of this repository for any questions or concerns. Contributions are encouraged and appreciated.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Minimal Installation Example
|
||||
|
||||
This example demonstrates a minimal installation of Prowler in a Kubernetes cluster.
|
||||
|
||||
## Installation
|
||||
|
||||
To install Prowler using this example:
|
||||
|
||||
1. First, create the required secret:
|
||||
```bash
|
||||
# Edit secret.yaml and set secure values before applying
|
||||
kubectl apply -f secret.yaml
|
||||
```
|
||||
|
||||
1. Install the chart using the base values file:
|
||||
```bash
|
||||
# Basic installation
|
||||
helm install prowler prowler/prowler-app -f values.yaml
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The example contains the following configuration files:
|
||||
|
||||
### `secret.yaml`
|
||||
Contains all required secrets for the Prowler installation. **Must be applied before installing the Helm chart**. Make sure to replace all placeholder values with secure values before applying.
|
||||
|
||||
### `values.yaml`
|
||||
```yaml
|
||||
ui:
|
||||
# Note: You should set either `authUrl` if you use prowler behind a proxy or enable `ingress`.
|
||||
|
||||
# Example with authUrl:
|
||||
# authUrl: example.prowler.com
|
||||
|
||||
# Example with ingress:
|
||||
ingress:
|
||||
enabled: true
|
||||
hosts:
|
||||
- host: example.prowler.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: ImplementationSpecific
|
||||
```
|
||||
|
||||
Make sure to adjust the hostname in the values file to match your environment before installing.
|
||||
@@ -0,0 +1,58 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
type: Opaque
|
||||
metadata:
|
||||
name: prowler-secret
|
||||
stringData:
|
||||
# openssl genrsa -out private.pem 2048
|
||||
DJANGO_TOKEN_SIGNING_KEY: |
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCIro0QiLAxw7rF
|
||||
GO0NgAWJfkpYE5ysMGDCbId07HUrv+/SCoRjqKVzGJVIvmNP5oByzSehPgswW9v3
|
||||
3dqe2r9sCS1JyMa+XO3qfZCR0uRDcPCwZjIyr0QQLpWAymdBa8baeHsU1/3Orjcb
|
||||
Vrr+lNx4HQJOiSn094iXPReW/25hYeq/SXs79V2CR87PGdoZAhb8IllAxJgdfkeB
|
||||
/iWohY/1vfRTmIuMweWGXk0aKzPsBdvE/DqG4HjiNVEPh18G3vid0YTZNmm7u8vO
|
||||
Cue3x9NQWGHA4QtxNtLtxlHcOEryqZ9ChO2nC+ew0Xl/v706XFNyLFicjisIKNQo
|
||||
qdkaMS33AgMBAAECggEAGdJIChCYoL4mYafk2MEPyrrWFq+V0J3PGcvhB0DInfxD
|
||||
tT2RZzZsE0NYqIZ3Qpf8OjPxwa9z863W74u1Cn+u3B0bti29BieONteD4VijEO6c
|
||||
OecEorijth7m1Y7nVN+kkI9kSTrI0yvsczi+WOwMfpCUZ/vXtlSxNEkxVLBqzPCo
|
||||
9VxAFIjgWOj2rpw8nxPedves36PUrC5ghLqrOTe1jmw/Di0++47AXG+DsTXc00sc
|
||||
5+oybopm3Kimsxrqbf9s8SZf2A8NiwqcbLj8OtP2j2g4TCEgZYLD5Zmt+JN/wN4B
|
||||
WsQG/Hwp4KPPm9QTHEpuuoPFP1CZWZeq8gPcV4apYQKBgQC+TuXjJCYhZqNIttTZ
|
||||
z/i3hkKUEKQLkzTZnXaDzL5wHyEMVqM2E/WkilO0C9ZZwh0ENPzkp+JsHf7LEhHy
|
||||
wSHOti81VzUCjN/YpCBKlOlClqSiDlOonImrobLei8xgvmA0VmGtirCXZyyzZUoV
|
||||
OyPr17WpK6G/M5piX59MvKQg0QKBgQC33NBoQFD8A6FjrTopYmWfK099k9uQh9NE
|
||||
bvUYsNAPunSDslmc/0PPHQC7fRX5Ime2BinXAN1PYtB/Fsu3jv/+FCUM5hVil0Dd
|
||||
KBvt13+RYSCJKlhcGP1EkWoIg1F2XXBOZKJrC8VQ+Vyl2t06UcWQqy5M9J4VZaqI
|
||||
fruOLU/URwKBgE55GjJfZZnASPRi78IhD94dbra/ZeWf/dr+IzCV7LEvJOGBmCtk
|
||||
b5Y5s+o6N1krwetKLj3bPHJ4q+fwu5XuLZKfbTgBjcpPbL5YbzhRzx22IIzye2y7
|
||||
n8k2FBvQaaY62lC6jeyRk9/am4Qd8D5w9I77k9z+MOQ20yJda8KoxsUBAoGBAIQ9
|
||||
5QPmppjsf4ry0C9t30uhWhYnX7fPiYviBpVQrwVxBVan076Q9xOjd6BicohzT4bj
|
||||
XfqPW546o12VZsbKqqLzmEZzwpPb2EJ5E8V4xv8ojb86Xr03GArWUB55XQE2aY1o
|
||||
4kz99VitUg7UoWPN5ryL8sxU8NLRAdwU0w+K1a0HAoGAZaU7O94u9IIPZ6Ohobs2
|
||||
Vjf/eV0brCKgX61b4z/YhuJdZsyTujhBZUihZwqR696kiFKuzmHx1ghE2ITvnPVN
|
||||
q0iHxRZzBCnRQ+mQlS0trzphaCP0NVy3osFeAD9mJfnOnSmkU0ua4F81mkvke1eN
|
||||
6nnaoAdy2lmMr96/Tye2ty4=
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
# openssl rsa -in private.pem -pubout -out public.pem
|
||||
DJANGO_TOKEN_VERIFYING_KEY: |
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiK6NEIiwMcO6xRjtDYAF
|
||||
iX5KWBOcrDBgwmyHdOx1K7/v0gqEY6ilcxiVSL5jT+aAcs0noT4LMFvb993antq/
|
||||
bAktScjGvlzt6n2QkdLkQ3DwsGYyMq9EEC6VgMpnQWvG2nh7FNf9zq43G1a6/pTc
|
||||
eB0CTokp9PeIlz0Xlv9uYWHqv0l7O/VdgkfOzxnaGQIW/CJZQMSYHX5Hgf4lqIWP
|
||||
9b30U5iLjMHlhl5NGisz7AXbxPw6huB44jVRD4dfBt74ndGE2TZpu7vLzgrnt8fT
|
||||
UFhhwOELcTbS7cZR3DhK8qmfQoTtpwvnsNF5f7+9OlxTcixYnI4rCCjUKKnZGjEt
|
||||
9wIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
|
||||
# openssl rand -base64 32
|
||||
DJANGO_SECRETS_ENCRYPTION_KEY: "qYAIWnRK52aBT5YQkBoMEw08j7j3+QIPZXS6+A8Su44="
|
||||
|
||||
# openssl rand -base64 32
|
||||
AUTH_SECRET: "CM9w3Nco2P1RdHaYmD+fmy2nJmSofusdHd4g7Z4KDG4="
|
||||
|
||||
# Unfortunatelly, we need to duplicate the password in two different keys because the Neo4j Helm Chart expects the password in the NEO4J_AUTH key and the application expects it in the NEO4J_PASSWORD key.
|
||||
NEO4J_PASSWORD: "prowler-password-fake"
|
||||
NEO4J_AUTH: "neo4j/prowler-password-fake"
|
||||
@@ -0,0 +1,11 @@
|
||||
ui:
|
||||
ingress:
|
||||
enabled: true
|
||||
hosts:
|
||||
- host: 127.0.0.1.nip.io
|
||||
paths:
|
||||
- path: /
|
||||
pathType: ImplementationSpecific
|
||||
|
||||
# or use authUrl if you use prowler behind a proxy
|
||||
# authUrl: 127.0.0.1.nip.io
|
||||
@@ -0,0 +1,134 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "prowler.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "prowler.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "prowler.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "prowler.labels" -}}
|
||||
helm.sh/chart: {{ include "prowler.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Django environment variables for api, worker, and worker_beat.
|
||||
*/}}
|
||||
{{- define "prowler.django.env" -}}
|
||||
- name: DJANGO_TOKEN_SIGNING_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.djangoTokenSigningKey.secretKeyRef.name }}
|
||||
key: {{ .Values.djangoTokenSigningKey.secretKeyRef.key }}
|
||||
- name: DJANGO_TOKEN_VERIFYING_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.djangoTokenVerifyingKey.secretKeyRef.name }}
|
||||
key: {{ .Values.djangoTokenVerifyingKey.secretKeyRef.key }}
|
||||
- name: DJANGO_SECRETS_ENCRYPTION_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.djangoSecretsEncryptionKey.secretKeyRef.name }}
|
||||
key: {{ .Values.djangoSecretsEncryptionKey.secretKeyRef.key }}
|
||||
{{- end }}
|
||||
|
||||
|
||||
{{/*
|
||||
PostgreSQL environment variables for api, worker, and worker_beat.
|
||||
Outputs nothing when postgresql.enabled is false.
|
||||
*/}}
|
||||
{{- define "prowler.postgresql.env" -}}
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
{{- if .Values.postgresql.auth.username }}
|
||||
- name: POSTGRES_USER
|
||||
value: {{ .Values.postgresql.auth.username | quote }}
|
||||
{{- end }}
|
||||
- name: POSTGRES_PASSWORD
|
||||
{{- if .Values.postgresql.auth.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.postgresql.auth.existingSecret }}
|
||||
key: {{ required "postgresql.auth.secretKeys.userPasswordKey is required when using an existing secret" .Values.postgresql.auth.secretKeys.userPasswordKey }}
|
||||
{{- else if .Values.postgresql.auth.password }}
|
||||
value: {{ .Values.postgresql.auth.password | quote }}
|
||||
{{- else }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Release.Name }}-postgresql
|
||||
key: password
|
||||
{{- end }}
|
||||
- name: POSTGRES_DB
|
||||
value: {{ .Values.postgresql.auth.database | quote }}
|
||||
- name: POSTGRES_HOST
|
||||
value: {{ .Release.Name }}-postgresql
|
||||
- name: POSTGRES_PORT
|
||||
value: "5432"
|
||||
- name: POSTGRES_ADMIN_USER
|
||||
value: postgres
|
||||
- name: POSTGRES_ADMIN_PASSWORD
|
||||
{{- if .Values.postgresql.auth.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.postgresql.auth.existingSecret }}
|
||||
key: {{ required "postgresql.auth.secretKeys.adminPasswordKey is required when using an existing secret" .Values.postgresql.auth.secretKeys.adminPasswordKey }}
|
||||
{{- else if .Values.postgresql.auth.postgresPassword }}
|
||||
value: {{ .Values.postgresql.auth.postgresPassword | quote }}
|
||||
{{- else }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Release.Name }}-postgresql
|
||||
key: postgres-password
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Neo4j environment variables for api, worker, and worker_beat.
|
||||
Outputs nothing when neo4j.enabled is false.
|
||||
*/}}
|
||||
{{- define "prowler.neo4j.env" -}}
|
||||
{{- if .Values.neo4j.enabled }}
|
||||
- name: NEO4J_HOST
|
||||
value: {{ .Release.Name }}
|
||||
- name: NEO4J_PORT
|
||||
value: "7687"
|
||||
- name: NEO4J_USER
|
||||
value: "neo4j"
|
||||
- name: NEO4J_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ required "neo4j.neo4j.passwordFromSecret is required" .Values.neo4j.neo4j.passwordFromSecret }}
|
||||
key: NEO4J_PASSWORD
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,10 @@
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "prowler.api.serviceAccountName" -}}
|
||||
{{- if .Values.api.serviceAccount.create }}
|
||||
{{- default (printf "%s-%s" (include "prowler.fullname" .) "api") .Values.api.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.api.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,10 @@
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-api
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
data:
|
||||
{{- range $key, $value := .Values.api.djangoConfig }}
|
||||
{{ $key }}: {{ $value | quote }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,105 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-api
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.api.autoscaling.enabled }}
|
||||
replicas: {{ .Values.api.replicaCount }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "prowler.fullname" . }}-api
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
secret-hash: "{{ printf "%s%s%s" (.Files.Get "templates/api/configmap.yaml" | sha256sum) (.Files.Get "templates/api/secret-valkey.yaml" | sha256sum) | sha256sum }}"
|
||||
{{- with .Values.api.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 8 }}
|
||||
app.kubernetes.io/name: {{ include "prowler.fullname" . }}-api
|
||||
{{- with .Values.api.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.api.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "prowler.api.serviceAccountName" . }}
|
||||
{{- with .Values.api.podSecurityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: api
|
||||
{{- with .Values.api.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
image: "{{ .Values.api.image.repository }}:{{ .Values.api.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.api.image.pullPolicy }}
|
||||
{{- with .Values.api.command }}
|
||||
command:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.api.args }}
|
||||
args:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.api.service.port }}
|
||||
protocol: TCP
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: {{ include "prowler.fullname" . }}-api
|
||||
{{- if .Values.valkey.enabled }}
|
||||
- secretRef:
|
||||
name: {{ include "prowler.fullname" . }}-api-valkey
|
||||
{{- end }}
|
||||
{{- with .Values.api.secrets }}
|
||||
{{- range $index, $secret := . }}
|
||||
- secretRef:
|
||||
name: {{ $secret }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
env:
|
||||
{{- include "prowler.django.env" . | nindent 12 }}
|
||||
{{- include "prowler.postgresql.env" . | nindent 12 }}
|
||||
{{- include "prowler.neo4j.env" . | nindent 12 }}
|
||||
{{- with .Values.api.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.api.readinessProbe }}
|
||||
readinessProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.api.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.api.volumeMounts }}
|
||||
volumeMounts:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.api.volumes }}
|
||||
volumes:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.api.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.api.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.api.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,32 @@
|
||||
{{- if .Values.api.autoscaling.enabled }}
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-api
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "prowler.fullname" . }}-api
|
||||
minReplicas: {{ .Values.api.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.api.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.api.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.api.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.api.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.api.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,43 @@
|
||||
{{- if .Values.api.ingress.enabled -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-api
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
{{- with .Values.api.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.api.ingress.className }}
|
||||
ingressClassName: {{ . }}
|
||||
{{- end }}
|
||||
{{- if .Values.api.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.api.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.api.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
{{- with .pathType }}
|
||||
pathType: {{ . }}
|
||||
{{- end }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "prowler.fullname" $ }}-api
|
||||
port:
|
||||
number: {{ $.Values.api.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,29 @@
|
||||
# https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/prowler-app/#step-44-kubernetes-credentials
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-api
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods", "configmaps", "nodes", "namespaces"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||
resources: ["clusterrolebindings", "rolebindings", "clusterroles", "roles"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-api
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: {{ include "prowler.fullname" . }}-api
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "prowler.api.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
@@ -0,0 +1,13 @@
|
||||
{{- if .Values.valkey.enabled -}}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-api-valkey
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
VALKEY_HOST: "{{ include "prowler.fullname" . }}-valkey"
|
||||
VALKEY_PORT: "6379"
|
||||
VALKEY_DB: "0"
|
||||
{{- end -}}
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-api
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.api.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.api.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ include "prowler.fullname" . }}-api
|
||||
@@ -0,0 +1,13 @@
|
||||
{{- if .Values.api.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "prowler.api.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
{{- with .Values.api.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
automountServiceAccountToken: {{ .Values.api.serviceAccount.automount }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,10 @@
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "prowler.ui.serviceAccountName" -}}
|
||||
{{- if .Values.ui.serviceAccount.create }}
|
||||
{{- default (printf "%s-%s" (include "prowler.fullname" .) "ui") .Values.ui.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.ui.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,18 @@
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-ui
|
||||
data:
|
||||
PROWLER_UI_VERSION: "stable"
|
||||
{{- if .Values.ui.ingress.enabled }}
|
||||
{{- with (first .Values.ui.ingress.hosts) }}
|
||||
AUTH_URL: "https://{{ .host }}"
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
AUTH_URL: {{ .Values.ui.authUrl | quote }}
|
||||
{{- end }}
|
||||
API_BASE_URL: "http://{{ include "prowler.fullname" . }}-api:{{ .Values.api.service.port }}/api/v1"
|
||||
NEXT_PUBLIC_API_BASE_URL: "http://{{ include "prowler.fullname" . }}-api:{{ .Values.api.service.port }}/api/v1"
|
||||
NEXT_PUBLIC_API_DOCS_URL: "http://{{ include "prowler.fullname" . }}-api:{{ .Values.api.service.port }}/api/v1/docs"
|
||||
AUTH_TRUST_HOST: "true"
|
||||
UI_PORT: {{ .Values.ui.service.port | quote }}
|
||||
@@ -0,0 +1,95 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-ui
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.ui.autoscaling.enabled }}
|
||||
replicas: {{ .Values.ui.replicaCount }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "prowler.fullname" . }}-ui
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
secret-hash: {{ .Files.Get "templates/ui/configmap.yaml" | sha256sum }}
|
||||
{{- with .Values.ui.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 8 }}
|
||||
app.kubernetes.io/name: {{ include "prowler.fullname" . }}-ui
|
||||
{{- with .Values.ui.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.ui.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "prowler.ui.serviceAccountName" . }}
|
||||
{{- with .Values.ui.podSecurityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: ui
|
||||
{{- with .Values.ui.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
image: "{{ .Values.ui.image.repository }}:{{ .Values.ui.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.ui.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.ui.service.port }}
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: AUTH_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.ui.authSecret.secretKeyRef.name }}
|
||||
key: {{ .Values.ui.authSecret.secretKeyRef.key }}
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: {{ include "prowler.fullname" . }}-ui
|
||||
{{- with .Values.ui.secrets }}
|
||||
{{- range $index, $secret := . }}
|
||||
- secretRef:
|
||||
name: {{ $secret }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Values.ui.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.ui.readinessProbe }}
|
||||
readinessProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.ui.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.ui.volumeMounts }}
|
||||
volumeMounts:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.ui.volumes }}
|
||||
volumes:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.ui.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.ui.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.ui.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,32 @@
|
||||
{{- if .Values.ui.autoscaling.enabled }}
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-ui
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "prowler.fullname" . }}-ui
|
||||
minReplicas: {{ .Values.ui.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.ui.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.ui.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.ui.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.ui.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.ui.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,43 @@
|
||||
{{- if .Values.ui.ingress.enabled -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-ui
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
{{- with .Values.ui.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.ui.ingress.className }}
|
||||
ingressClassName: {{ . }}
|
||||
{{- end }}
|
||||
{{- if .Values.ui.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ui.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ui.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
{{- with .pathType }}
|
||||
pathType: {{ . }}
|
||||
{{- end }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "prowler.fullname" $ }}-ui
|
||||
port:
|
||||
number: {{ $.Values.ui.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-ui
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.ui.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.ui.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ include "prowler.fullname" . }}-ui
|
||||
@@ -0,0 +1,13 @@
|
||||
{{- if .Values.ui.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "prowler.ui.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
{{- with .Values.ui.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
automountServiceAccountToken: {{ .Values.ui.serviceAccount.automount }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,10 @@
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "prowler.worker.serviceAccountName" -}}
|
||||
{{- if .Values.worker.serviceAccount.create }}
|
||||
{{- default (printf "%s-%s" (include "prowler.fullname" .) "worker") .Values.worker.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.worker.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,101 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-worker
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.worker.autoscaling.enabled }}
|
||||
replicas: {{ .Values.worker.replicaCount }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "prowler.fullname" . }}-worker
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
secret-hash: "{{ printf "%s%s%s" (.Files.Get "templates/api/configmap.yaml" | sha256sum) (.Files.Get "templates/api/secret-valkey.yaml" | sha256sum) | sha256sum }}"
|
||||
{{- with .Values.worker.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 8 }}
|
||||
app.kubernetes.io/name: {{ include "prowler.fullname" . }}-worker
|
||||
{{- with .Values.worker.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.worker.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "prowler.worker.serviceAccountName" . }}
|
||||
{{- with .Values.worker.podSecurityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: worker
|
||||
{{- with .Values.worker.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
image: "{{ .Values.worker.image.repository }}:{{ .Values.worker.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.worker.image.pullPolicy }}
|
||||
{{- with .Values.worker.command }}
|
||||
command:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker.args }}
|
||||
args:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: {{ include "prowler.fullname" . }}-api
|
||||
{{- if .Values.valkey.enabled }}
|
||||
- secretRef:
|
||||
name: {{ include "prowler.fullname" . }}-api-valkey
|
||||
{{- end }}
|
||||
{{- with .Values.api.secrets }}
|
||||
{{- range $index, $secret := . }}
|
||||
- secretRef:
|
||||
name: {{ $secret }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
env:
|
||||
{{- include "prowler.django.env" . | nindent 12 }}
|
||||
{{- include "prowler.postgresql.env" . | nindent 12 }}
|
||||
{{- include "prowler.neo4j.env" . | nindent 12 }}
|
||||
{{- with .Values.worker.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker.readinessProbe }}
|
||||
readinessProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker.volumeMounts }}
|
||||
volumeMounts:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker.volumes }}
|
||||
volumes:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,32 @@
|
||||
{{- if .Values.worker.autoscaling.enabled }}
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-worker
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "prowler.fullname" . }}-worker
|
||||
minReplicas: {{ .Values.worker.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.worker.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.worker.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.worker.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.worker.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.worker.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,32 @@
|
||||
{{- if .Values.worker.keda.enabled }}
|
||||
apiVersion: keda.sh/v1alpha1
|
||||
kind: ScaledObject
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-worker
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
name: {{ include "prowler.fullname" . }}-worker
|
||||
envSourceContainerName: worker
|
||||
kind: Deployment
|
||||
minReplicaCount: {{ .Values.worker.keda.minReplicas }}
|
||||
maxReplicaCount: {{ .Values.worker.keda.maxReplicas }}
|
||||
pollingInterval: {{ .Values.worker.keda.pollingInterval }}
|
||||
cooldownPeriod: {{ .Values.worker.keda.cooldownPeriod }}
|
||||
triggers:
|
||||
- type: {{ .Values.worker.keda.triggerType }}
|
||||
metadata:
|
||||
userName: "postgres"
|
||||
passwordFromEnv: POSTGRES_ADMIN_PASSWORD
|
||||
host: {{ .Release.Name }}-postgresql
|
||||
port: {{ .Values.postgresql.port | quote }}
|
||||
dbName: {{ .Values.postgresql.auth.database | quote }}
|
||||
sslmode: disable
|
||||
# Query for KEDA to count the number of scans that are in executing, available, or scheduled states,
|
||||
# where the scheduled time is within the last 2 hours and is before NOW(). Used for scaling workers.
|
||||
query: >-
|
||||
SELECT COUNT(*) FROM scans WHERE ((state='executing' OR state='available' OR state='scheduled') and scheduled_at < NOW() and scheduled_at > NOW() - INTERVAL '2 hours')
|
||||
targetQueryValue: "1"
|
||||
{{- end }}
|
||||
@@ -0,0 +1,13 @@
|
||||
{{- if .Values.worker.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "prowler.worker.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
{{- with .Values.worker.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
automountServiceAccountToken: {{ .Values.worker.serviceAccount.automount }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,10 @@
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "prowler.worker_beat.serviceAccountName" -}}
|
||||
{{- if .Values.worker_beat.serviceAccount.create }}
|
||||
{{- default (printf "%s-%s" (include "prowler.fullname" .) "worker-beat") .Values.worker_beat.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.worker_beat.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,99 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "prowler.fullname" . }}-worker-beat
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.worker_beat.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "prowler.fullname" . }}-worker-beat
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
secret-hash: "{{ printf "%s%s%s" (.Files.Get "templates/api/configmap.yaml" | sha256sum) (.Files.Get "templates/api/secret-valkey.yaml" | sha256sum) | sha256sum }}"
|
||||
{{- with .Values.worker.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 8 }}
|
||||
app.kubernetes.io/name: {{ include "prowler.fullname" . }}-worker-beat
|
||||
{{- with .Values.worker_beat.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.worker_beat.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "prowler.worker_beat.serviceAccountName" . }}
|
||||
{{- with .Values.worker_beat.podSecurityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: worker-beat
|
||||
{{- with .Values.worker_beat.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
image: "{{ .Values.worker_beat.image.repository }}:{{ .Values.worker_beat.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.worker_beat.image.pullPolicy }}
|
||||
{{- with .Values.worker_beat.command }}
|
||||
command:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker_beat.args }}
|
||||
args:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: {{ include "prowler.fullname" . }}-api
|
||||
{{- if .Values.valkey.enabled }}
|
||||
- secretRef:
|
||||
name: {{ include "prowler.fullname" . }}-api-valkey
|
||||
{{- end }}
|
||||
{{- with .Values.api.secrets }}
|
||||
{{- range $index, $secret := . }}
|
||||
- secretRef:
|
||||
name: {{ $secret }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
env:
|
||||
{{- include "prowler.django.env" . | nindent 12 }}
|
||||
{{- include "prowler.postgresql.env" . | nindent 12 }}
|
||||
{{- include "prowler.neo4j.env" . | nindent 12 }}
|
||||
{{- with .Values.worker_beat.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker_beat.readinessProbe }}
|
||||
readinessProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker_beat.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker_beat.volumeMounts }}
|
||||
volumeMounts:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker_beat.volumes }}
|
||||
volumes:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker_beat.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker_beat.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker_beat.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,13 @@
|
||||
{{- if .Values.worker_beat.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "prowler.worker_beat.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "prowler.labels" . | nindent 4 }}
|
||||
{{- with .Values.worker_beat.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
automountServiceAccountToken: {{ .Values.worker_beat.serviceAccount.automount }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,566 @@
|
||||
# This is to override the chart name.
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
# Reference to the secret containing the API authentication secret.
|
||||
# Used to inject the environment variable for the API container.
|
||||
djangoTokenSigningKey:
|
||||
secretKeyRef:
|
||||
name: prowler-secret
|
||||
key: DJANGO_TOKEN_SIGNING_KEY
|
||||
djangoTokenVerifyingKey:
|
||||
secretKeyRef:
|
||||
name: prowler-secret
|
||||
key: DJANGO_TOKEN_VERIFYING_KEY
|
||||
djangoSecretsEncryptionKey:
|
||||
secretKeyRef:
|
||||
name: prowler-secret
|
||||
key: DJANGO_SECRETS_ENCRYPTION_KEY
|
||||
|
||||
ui:
|
||||
# This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/
|
||||
replicaCount: 1
|
||||
|
||||
# This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/
|
||||
image:
|
||||
repository: prowlercloud/prowler-ui
|
||||
# This sets the pull policy for images.
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: ""
|
||||
|
||||
# This is for the secrets for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
|
||||
imagePullSecrets: []
|
||||
|
||||
# Reference to the secret containing the UI authentication secret.
|
||||
# Used to inject the environment variable for the UI container.
|
||||
# By default, expects a Secret named 'prowler-secret' with a key 'AUTH_SECRET'.
|
||||
authSecret:
|
||||
secretKeyRef:
|
||||
name: prowler-secret
|
||||
key: AUTH_SECRET
|
||||
|
||||
# Secret names to be used as env vars.
|
||||
secrets: []
|
||||
# - "prowler-ui-secret"
|
||||
|
||||
# This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
create: true
|
||||
# Automatically mount a ServiceAccount's API credentials?
|
||||
automount: true
|
||||
# Annotations to add to the service account
|
||||
annotations: {}
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name: ""
|
||||
|
||||
# This is for setting Kubernetes Annotations to a Pod.
|
||||
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
|
||||
podAnnotations: {}
|
||||
# This is for setting Kubernetes Labels to a Pod.
|
||||
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
|
||||
podLabels: {}
|
||||
|
||||
podSecurityContext: {}
|
||||
# fsGroup: 2000
|
||||
|
||||
securityContext: {}
|
||||
# capabilities:
|
||||
# drop:
|
||||
# - ALL
|
||||
# readOnlyRootFilesystem: true
|
||||
# runAsNonRoot: true
|
||||
# runAsUser: 1000
|
||||
|
||||
# This is for setting up a service more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/
|
||||
service:
|
||||
# This sets the service type more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types
|
||||
type: ClusterIP
|
||||
# This sets the ports more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#field-spec-ports
|
||||
port: 3000
|
||||
|
||||
# The URL of the UI. This is only set if ingress is disabled.
|
||||
authUrl: ""
|
||||
|
||||
# This block is for setting up the ingress for more information can be found here: https://kubernetes.io/docs/concepts/services-networking/ingress/
|
||||
ingress:
|
||||
enabled: false
|
||||
className: ""
|
||||
annotations: {}
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
hosts:
|
||||
- host: chart-example.local
|
||||
paths:
|
||||
- path: /
|
||||
pathType: ImplementationSpecific
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
# This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
|
||||
# This section is for setting up autoscaling more information can be found here: https://kubernetes.io/docs/concepts/workloads/autoscaling/
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 100
|
||||
targetCPUUtilizationPercentage: 80
|
||||
targetMemoryUtilizationPercentage: 80
|
||||
|
||||
# Additional volumes on the output Deployment definition.
|
||||
volumes: []
|
||||
# - name: foo
|
||||
# secret:
|
||||
# secretName: mysecret
|
||||
# optional: false
|
||||
|
||||
# Additional volumeMounts on the output Deployment definition.
|
||||
volumeMounts: []
|
||||
# - name: foo
|
||||
# mountPath: "/etc/foo"
|
||||
# readOnly: true
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
|
||||
api:
|
||||
# This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/
|
||||
replicaCount: 1
|
||||
|
||||
# This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/
|
||||
image:
|
||||
repository: prowlercloud/prowler-api
|
||||
# This sets the pull policy for images.
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: ""
|
||||
|
||||
# Shared with celery-worker and celery-beat
|
||||
djangoConfig:
|
||||
# API scan settings
|
||||
# The path to the directory where scan output should be stored
|
||||
DJANGO_TMP_OUTPUT_DIRECTORY: "/tmp/prowler_api_output"
|
||||
# The maximum number of findings to process in a single batch
|
||||
DJANGO_FINDINGS_BATCH_SIZE: "1000"
|
||||
# Django settings
|
||||
DJANGO_ALLOWED_HOSTS: "*"
|
||||
DJANGO_BIND_ADDRESS: "0.0.0.0"
|
||||
DJANGO_PORT: "8080"
|
||||
DJANGO_DEBUG: "False"
|
||||
DJANGO_SETTINGS_MODULE: "config.django.production"
|
||||
# Select one of [ndjson|human_readable]
|
||||
DJANGO_LOGGING_FORMATTER: "ndjson"
|
||||
# Select one of [DEBUG|INFO|WARNING|ERROR|CRITICAL]
|
||||
# Applies to both Django and Celery Workers
|
||||
DJANGO_LOGGING_LEVEL: "INFO"
|
||||
# Defaults to the maximum available based on CPU cores if not set.
|
||||
DJANGO_WORKERS: "4"
|
||||
# Token lifetime is in minutes
|
||||
DJANGO_ACCESS_TOKEN_LIFETIME: "30"
|
||||
# Token lifetime is in minutes
|
||||
DJANGO_REFRESH_TOKEN_LIFETIME: "1440"
|
||||
DJANGO_CACHE_MAX_AGE: "3600"
|
||||
DJANGO_STALE_WHILE_REVALIDATE: "60"
|
||||
DJANGO_MANAGE_DB_PARTITIONS: "True"
|
||||
DJANGO_BROKER_VISIBILITY_TIMEOUT: "86400"
|
||||
|
||||
# Secret names to be used as env vars for api, worker, and worker_beat.
|
||||
secrets: []
|
||||
# - "prowler-api-keys"
|
||||
|
||||
command:
|
||||
- /home/prowler/docker-entrypoint.sh
|
||||
args:
|
||||
- prod
|
||||
|
||||
# This is for the secrets for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
|
||||
imagePullSecrets: []
|
||||
|
||||
# This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
create: true
|
||||
# Automatically mount a ServiceAccount's API credentials?
|
||||
automount: true
|
||||
# Annotations to add to the service account
|
||||
annotations: {}
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name: ""
|
||||
|
||||
# This is for setting Kubernetes Annotations to a Pod.
|
||||
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
|
||||
podAnnotations: {}
|
||||
# This is for setting Kubernetes Labels to a Pod.
|
||||
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
|
||||
podLabels: {}
|
||||
|
||||
podSecurityContext: {}
|
||||
# fsGroup: 2000
|
||||
|
||||
securityContext: {}
|
||||
# capabilities:
|
||||
# drop:
|
||||
# - ALL
|
||||
# readOnlyRootFilesystem: true
|
||||
# runAsNonRoot: true
|
||||
# runAsUser: 1000
|
||||
|
||||
# This is for setting up a service more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/
|
||||
service:
|
||||
# This sets the service type more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types
|
||||
type: ClusterIP
|
||||
# This sets the ports more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#field-spec-ports
|
||||
port: 8080
|
||||
|
||||
# This block is for setting up the ingress for more information can be found here: https://kubernetes.io/docs/concepts/services-networking/ingress/
|
||||
ingress:
|
||||
enabled: false
|
||||
className: ""
|
||||
annotations: {}
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
hosts:
|
||||
- host: chart-example.local
|
||||
paths:
|
||||
- path: /
|
||||
pathType: ImplementationSpecific
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
# 3m30s to setup DB
|
||||
# startupProbe:
|
||||
# httpGet:
|
||||
# path: /api/v1/docs
|
||||
# port: http
|
||||
|
||||
# This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
|
||||
livenessProbe:
|
||||
failureThreshold: 10
|
||||
httpGet:
|
||||
path: /api/v1/docs
|
||||
port: http
|
||||
periodSeconds: 20
|
||||
readinessProbe:
|
||||
failureThreshold: 10
|
||||
httpGet:
|
||||
path: /api/v1/docs
|
||||
port: http
|
||||
periodSeconds: 20
|
||||
|
||||
# This section is for setting up autoscaling more information can be found here: https://kubernetes.io/docs/concepts/workloads/autoscaling/
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 100
|
||||
targetCPUUtilizationPercentage: 80
|
||||
targetMemoryUtilizationPercentage: 80
|
||||
|
||||
# Additional volumes on the output Deployment definition.
|
||||
volumes: []
|
||||
# - name: foo
|
||||
# secret:
|
||||
# secretName: mysecret
|
||||
# optional: false
|
||||
|
||||
# Additional volumeMounts on the output Deployment definition.
|
||||
volumeMounts: []
|
||||
# - name: foo
|
||||
# mountPath: "/etc/foo"
|
||||
# readOnly: true
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
|
||||
worker:
|
||||
# This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/
|
||||
replicaCount: 1
|
||||
|
||||
# This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/
|
||||
image:
|
||||
repository: prowlercloud/prowler-api
|
||||
# This sets the pull policy for images.
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: ""
|
||||
|
||||
command:
|
||||
- /home/prowler/docker-entrypoint.sh
|
||||
args:
|
||||
- worker
|
||||
|
||||
# This is for the secrets for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
|
||||
imagePullSecrets: []
|
||||
|
||||
# This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
create: true
|
||||
# Automatically mount a ServiceAccount's API credentials?
|
||||
automount: true
|
||||
# Annotations to add to the service account
|
||||
annotations: {}
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name: ""
|
||||
|
||||
# This is for setting Kubernetes Annotations to a Pod.
|
||||
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
|
||||
podAnnotations: {}
|
||||
# This is for setting Kubernetes Labels to a Pod.
|
||||
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
|
||||
podLabels: {}
|
||||
|
||||
podSecurityContext: {}
|
||||
# fsGroup: 2000
|
||||
|
||||
securityContext: {}
|
||||
# capabilities:
|
||||
# drop:
|
||||
# - ALL
|
||||
# readOnlyRootFilesystem: true
|
||||
# runAsNonRoot: true
|
||||
# runAsUser: 1000
|
||||
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
# This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
|
||||
livenessProbe: {}
|
||||
readinessProbe: {}
|
||||
|
||||
# This section is for setting up autoscaling more information can be found here: https://kubernetes.io/docs/concepts/workloads/autoscaling/
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 10
|
||||
targetCPUUtilizationPercentage: 80
|
||||
targetMemoryUtilizationPercentage: 80
|
||||
|
||||
# Additional volumes on the output Deployment definition.
|
||||
volumes: []
|
||||
# - name: foo
|
||||
# secret:
|
||||
# secretName: mysecret
|
||||
# optional: false
|
||||
|
||||
# Additional volumeMounts on the output Deployment definition.
|
||||
volumeMounts: []
|
||||
# - name: foo
|
||||
# mountPath: "/etc/foo"
|
||||
# readOnly: true
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
|
||||
# KEDA ScaledObject configuration
|
||||
keda:
|
||||
# -- Set to `true` to enable KEDA for the worker pods
|
||||
# Note: When both KEDA and HPA are enabled, the deployment will fail.
|
||||
enabled: false
|
||||
# -- The minimum number of replicas to use for the worker pods
|
||||
minReplicas: 1
|
||||
# -- The maximum number of replicas to use for the worker pods
|
||||
maxReplicas: 2
|
||||
# -- The polling interval in seconds for checking metrics
|
||||
pollingInterval: 30
|
||||
# -- The cooldown period in seconds for scaling
|
||||
cooldownPeriod: 120
|
||||
# -- The trigger type for scaling (cpu or memory)
|
||||
triggerType: "postgresql"
|
||||
# -- The target utilization percentage for the worker pods
|
||||
value: "50"
|
||||
|
||||
worker_beat:
|
||||
# This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/
|
||||
replicaCount: 1
|
||||
|
||||
# This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/
|
||||
image:
|
||||
repository: prowlercloud/prowler-api
|
||||
# This sets the pull policy for images.
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: ""
|
||||
|
||||
command:
|
||||
- ../docker-entrypoint.sh
|
||||
args:
|
||||
- beat
|
||||
|
||||
# This is for the secrets for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
|
||||
imagePullSecrets: []
|
||||
|
||||
# This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
create: true
|
||||
# Automatically mount a ServiceAccount's API credentials?
|
||||
automount: true
|
||||
# Annotations to add to the service account
|
||||
annotations: {}
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name: ""
|
||||
|
||||
# This is for setting Kubernetes Annotations to a Pod.
|
||||
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
|
||||
podAnnotations: {}
|
||||
# This is for setting Kubernetes Labels to a Pod.
|
||||
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
|
||||
podLabels: {}
|
||||
|
||||
podSecurityContext: {}
|
||||
# fsGroup: 2000
|
||||
|
||||
securityContext: {}
|
||||
# capabilities:
|
||||
# drop:
|
||||
# - ALL
|
||||
# readOnlyRootFilesystem: true
|
||||
# runAsNonRoot: true
|
||||
# runAsUser: 1000
|
||||
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
# This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
|
||||
livenessProbe: {}
|
||||
readinessProbe: {}
|
||||
|
||||
# Additional volumes on the output Deployment definition.
|
||||
volumes: []
|
||||
# - name: foo
|
||||
# secret:
|
||||
# secretName: mysecret
|
||||
# optional: false
|
||||
|
||||
# Additional volumeMounts on the output Deployment definition.
|
||||
volumeMounts: []
|
||||
# - name: foo
|
||||
# mountPath: "/etc/foo"
|
||||
# readOnly: true
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
|
||||
postgresql:
|
||||
# -- Enable PostgreSQL deployment (via Bitnami Helm Chart). If you want to use an external Postgres server (or a managed one), set this to false
|
||||
# If enabled, it will create a Secret with the credentials.
|
||||
# Otherwise, create a secret with the following and add it to the api deployment:
|
||||
# - POSTGRES_HOST
|
||||
# - POSTGRES_PORT
|
||||
# - POSTGRES_ADMIN_USER - Existing user in charge of migrations, tables, permissions, RLS
|
||||
# - POSTGRES_ADMIN_PASSWORD
|
||||
# - POSTGRES_USER - Will be created by ADMIN_USER
|
||||
# - POSTGRES_PASSWORD
|
||||
# - POSTGRES_DB - Existing DB
|
||||
enabled: true
|
||||
image:
|
||||
repository: "bitnami/postgresql"
|
||||
auth:
|
||||
database: prowler_db
|
||||
username: prowler
|
||||
|
||||
valkey:
|
||||
# If enabled, it will create a Secret with the following.
|
||||
# Otherwise, create a secret with
|
||||
# - VALKEY_HOST
|
||||
# - VALKEY_PORT
|
||||
# - VALKEY_DB
|
||||
enabled: true
|
||||
|
||||
neo4j:
|
||||
enabled: true
|
||||
|
||||
neo4j:
|
||||
name: prowler-neo4j
|
||||
edition: community
|
||||
|
||||
# The name of the secret containing the Neo4j password with the key NEO4J_PASSWORD
|
||||
passwordFromSecret: prowler-secret
|
||||
|
||||
# Disable lookups during helm template rendering (required for ArgoCD)
|
||||
disableLookups: true
|
||||
|
||||
volumes:
|
||||
data:
|
||||
mode: defaultStorageClass
|
||||
|
||||
services:
|
||||
neo4j:
|
||||
enabled: false
|
||||
|
||||
# Neo4j Configuration (yaml format)
|
||||
config:
|
||||
dbms_security_procedures_allowlist: "apoc.*"
|
||||
dbms_security_procedures_unrestricted: "apoc.*"
|
||||
|
||||
apoc_config:
|
||||
apoc.export.file.enabled: "true"
|
||||
apoc.import.file.enabled: "true"
|
||||
apoc.import.file.use_neo4j_config: "true"
|
||||
@@ -0,0 +1,41 @@
|
||||
import warnings
|
||||
|
||||
from dashboard.common_methods import get_section_containers_cis
|
||||
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
|
||||
def get_table(data):
|
||||
"""
|
||||
Generate CIS OCI Foundations Benchmark v3.1 compliance table.
|
||||
|
||||
Args:
|
||||
data: DataFrame containing compliance check results with columns:
|
||||
- REQUIREMENTS_ID: CIS requirement ID (e.g., "1.1", "2.1")
|
||||
- REQUIREMENTS_DESCRIPTION: Description of the requirement
|
||||
- REQUIREMENTS_ATTRIBUTES_SECTION: CIS section name
|
||||
- CHECKID: Prowler check identifier
|
||||
- STATUS: Check status (PASS/FAIL)
|
||||
- REGION: OCI region
|
||||
- ACCOUNTID: OCI tenancy OCID (renamed from TENANCYID)
|
||||
- RESOURCEID: Resource OCID or identifier
|
||||
|
||||
Returns:
|
||||
Section containers organized by CIS sections for dashboard display
|
||||
"""
|
||||
aux = data[
|
||||
[
|
||||
"REQUIREMENTS_ID",
|
||||
"REQUIREMENTS_DESCRIPTION",
|
||||
"REQUIREMENTS_ATTRIBUTES_SECTION",
|
||||
"CHECKID",
|
||||
"STATUS",
|
||||
"REGION",
|
||||
"ACCOUNTID",
|
||||
"RESOURCEID",
|
||||
]
|
||||
].copy()
|
||||
|
||||
return get_section_containers_cis(
|
||||
aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION"
|
||||
)
|
||||
@@ -0,0 +1,31 @@
|
||||
import warnings
|
||||
|
||||
from dashboard.common_methods import get_section_containers_kisa_ismsp
|
||||
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
|
||||
def get_table(data):
|
||||
data["REQUIREMENTS_ID"] = (
|
||||
data["REQUIREMENTS_ID"] + " - " + data["REQUIREMENTS_DESCRIPTION"]
|
||||
)
|
||||
|
||||
data["REQUIREMENTS_ID"] = data["REQUIREMENTS_ID"].apply(
|
||||
lambda x: x[:150] + "..." if len(str(x)) > 150 else x
|
||||
)
|
||||
|
||||
aux = data[
|
||||
[
|
||||
"REQUIREMENTS_ID",
|
||||
"REQUIREMENTS_ATTRIBUTES_SECTION",
|
||||
"CHECKID",
|
||||
"STATUS",
|
||||
"REGION",
|
||||
"ACCOUNTID",
|
||||
"RESOURCEID",
|
||||
]
|
||||
].copy()
|
||||
|
||||
return get_section_containers_kisa_ismsp(
|
||||
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
|
||||
)
|
||||
@@ -0,0 +1,31 @@
|
||||
import warnings
|
||||
|
||||
from dashboard.common_methods import get_section_containers_kisa_ismsp
|
||||
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
|
||||
def get_table(data):
|
||||
data["REQUIREMENTS_ID"] = (
|
||||
data["REQUIREMENTS_ID"] + " - " + data["REQUIREMENTS_DESCRIPTION"]
|
||||
)
|
||||
|
||||
data["REQUIREMENTS_ID"] = data["REQUIREMENTS_ID"].apply(
|
||||
lambda x: x[:150] + "..." if len(str(x)) > 150 else x
|
||||
)
|
||||
|
||||
aux = data[
|
||||
[
|
||||
"REQUIREMENTS_ID",
|
||||
"REQUIREMENTS_ATTRIBUTES_SECTION",
|
||||
"CHECKID",
|
||||
"STATUS",
|
||||
"REGION",
|
||||
"ACCOUNTID",
|
||||
"RESOURCEID",
|
||||
]
|
||||
].copy()
|
||||
|
||||
return get_section_containers_kisa_ismsp(
|
||||
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
|
||||
)
|
||||
@@ -0,0 +1,31 @@
|
||||
import warnings
|
||||
|
||||
from dashboard.common_methods import get_section_containers_kisa_ismsp
|
||||
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
|
||||
def get_table(data):
|
||||
data["REQUIREMENTS_ID"] = (
|
||||
data["REQUIREMENTS_ID"] + " - " + data["REQUIREMENTS_DESCRIPTION"]
|
||||
)
|
||||
|
||||
data["REQUIREMENTS_ID"] = data["REQUIREMENTS_ID"].apply(
|
||||
lambda x: x[:150] + "..." if len(str(x)) > 150 else x
|
||||
)
|
||||
|
||||
aux = data[
|
||||
[
|
||||
"REQUIREMENTS_ID",
|
||||
"REQUIREMENTS_ATTRIBUTES_SECTION",
|
||||
"CHECKID",
|
||||
"STATUS",
|
||||
"REGION",
|
||||
"ACCOUNTID",
|
||||
"RESOURCEID",
|
||||
]
|
||||
].copy()
|
||||
|
||||
return get_section_containers_kisa_ismsp(
|
||||
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
|
||||
)
|
||||
@@ -0,0 +1,31 @@
|
||||
import warnings
|
||||
|
||||
from dashboard.common_methods import get_section_containers_kisa_ismsp
|
||||
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
|
||||
def get_table(data):
|
||||
data["REQUIREMENTS_ID"] = (
|
||||
data["REQUIREMENTS_ID"] + " - " + data["REQUIREMENTS_DESCRIPTION"]
|
||||
)
|
||||
|
||||
data["REQUIREMENTS_ID"] = data["REQUIREMENTS_ID"].apply(
|
||||
lambda x: x[:150] + "..." if len(str(x)) > 150 else x
|
||||
)
|
||||
|
||||
aux = data[
|
||||
[
|
||||
"REQUIREMENTS_ID",
|
||||
"REQUIREMENTS_ATTRIBUTES_SECTION",
|
||||
"CHECKID",
|
||||
"STATUS",
|
||||
"REGION",
|
||||
"ACCOUNTID",
|
||||
"RESOURCEID",
|
||||
]
|
||||
].copy()
|
||||
|
||||
return get_section_containers_kisa_ismsp(
|
||||
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
|
||||
)
|
||||
@@ -0,0 +1,31 @@
|
||||
import warnings
|
||||
|
||||
from dashboard.common_methods import get_section_containers_kisa_ismsp
|
||||
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
|
||||
def get_table(data):
|
||||
data["REQUIREMENTS_ID"] = (
|
||||
data["REQUIREMENTS_ID"] + " - " + data["REQUIREMENTS_DESCRIPTION"]
|
||||
)
|
||||
|
||||
data["REQUIREMENTS_ID"] = data["REQUIREMENTS_ID"].apply(
|
||||
lambda x: x[:150] + "..." if len(str(x)) > 150 else x
|
||||
)
|
||||
|
||||
aux = data[
|
||||
[
|
||||
"REQUIREMENTS_ID",
|
||||
"REQUIREMENTS_ATTRIBUTES_SECTION",
|
||||
"CHECKID",
|
||||
"STATUS",
|
||||
"REGION",
|
||||
"ACCOUNTID",
|
||||
"RESOURCEID",
|
||||
]
|
||||
].copy()
|
||||
|
||||
return get_section_containers_kisa_ismsp(
|
||||
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
|
||||
)
|
||||
@@ -284,6 +284,11 @@ def display_data(
|
||||
# Rename the column LOCATION to REGION for Alibaba Cloud
|
||||
if "alibabacloud" in analytics_input:
|
||||
data = data.rename(columns={"LOCATION": "REGION"})
|
||||
|
||||
# Rename the column TENANCYID to ACCOUNTID for Oracle Cloud
|
||||
if "oraclecloud" in analytics_input:
|
||||
data.rename(columns={"TENANCYID": "ACCOUNTID"}, inplace=True)
|
||||
|
||||
# Filter the chosen level of the CIS
|
||||
if is_level_1:
|
||||
data = data[data["REQUIREMENTS_ATTRIBUTES_PROFILE"].str.contains("Level 1")]
|
||||
|
||||
@@ -259,6 +259,8 @@ else:
|
||||
accounts.append(account + " - K8S")
|
||||
if "alibabacloud" in list(data[data["ACCOUNT_UID"] == account]["PROVIDER"]):
|
||||
accounts.append(account + " - ALIBABACLOUD")
|
||||
if "oraclecloud" in list(data[data["ACCOUNT_UID"] == account]["PROVIDER"]):
|
||||
accounts.append(account + " - OCI")
|
||||
|
||||
account_dropdown = create_account_dropdown(accounts)
|
||||
|
||||
@@ -306,6 +308,8 @@ else:
|
||||
services.append(service + " - M365")
|
||||
if "alibabacloud" in list(data[data["SERVICE_NAME"] == service]["PROVIDER"]):
|
||||
services.append(service + " - ALIBABACLOUD")
|
||||
if "oraclecloud" in list(data[data["SERVICE_NAME"] == service]["PROVIDER"]):
|
||||
services.append(service + " - OCI")
|
||||
|
||||
services = ["All"] + services
|
||||
services = [
|
||||
@@ -767,6 +771,8 @@ def filter_data(
|
||||
all_account_ids.append(account)
|
||||
if "alibabacloud" in list(data[data["ACCOUNT_UID"] == account]["PROVIDER"]):
|
||||
all_account_ids.append(account)
|
||||
if "oraclecloud" in list(data[data["ACCOUNT_UID"] == account]["PROVIDER"]):
|
||||
all_account_ids.append(account)
|
||||
|
||||
all_account_names = []
|
||||
if "ACCOUNT_NAME" in filtered_data.columns:
|
||||
@@ -793,6 +799,8 @@ def filter_data(
|
||||
data[data["ACCOUNT_UID"] == item]["PROVIDER"]
|
||||
):
|
||||
cloud_accounts_options.append(item + " - ALIBABACLOUD")
|
||||
if "oraclecloud" in list(data[data["ACCOUNT_UID"] == item]["PROVIDER"]):
|
||||
cloud_accounts_options.append(item + " - OCI")
|
||||
if "ACCOUNT_NAME" in filtered_data.columns:
|
||||
if "azure" in list(data[data["ACCOUNT_NAME"] == item]["PROVIDER"]):
|
||||
cloud_accounts_options.append(item + " - AZURE")
|
||||
@@ -925,6 +933,10 @@ def filter_data(
|
||||
filtered_data[filtered_data["SERVICE_NAME"] == item]["PROVIDER"]
|
||||
):
|
||||
service_filter_options.append(item + " - ALIBABACLOUD")
|
||||
if "oraclecloud" in list(
|
||||
filtered_data[filtered_data["SERVICE_NAME"] == item]["PROVIDER"]
|
||||
):
|
||||
service_filter_options.append(item + " - OCI")
|
||||
|
||||
# Filter Service
|
||||
if service_values == ["All"]:
|
||||
@@ -1124,6 +1136,7 @@ def filter_data(
|
||||
config={"displayModeBar": False},
|
||||
)
|
||||
table = dcc.Graph(figure=fig, config={"displayModeBar": False})
|
||||
table_row_options = []
|
||||
|
||||
else:
|
||||
# Status Pie Chart
|
||||
|
||||
@@ -255,6 +255,12 @@
|
||||
"user-guide/providers/cloudflare/authentication"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Image",
|
||||
"pages": [
|
||||
"user-guide/providers/image/getting-started-image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "LLM",
|
||||
"pages": [
|
||||
|
||||
@@ -115,8 +115,8 @@ To update the environment file:
|
||||
Edit the `.env` file and change version values:
|
||||
|
||||
```env
|
||||
PROWLER_UI_VERSION="5.17.0"
|
||||
PROWLER_API_VERSION="5.17.0"
|
||||
PROWLER_UI_VERSION="5.18.0"
|
||||
PROWLER_API_VERSION="5.18.0"
|
||||
```
|
||||
|
||||
<Note>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 77 KiB |
@@ -36,7 +36,9 @@ The supported providers right now are:
|
||||
| [Cloudflare](/user-guide/providers/cloudflare/getting-started-cloudflare) | Official | Accounts | CLI |
|
||||
| [Infra as Code](/user-guide/providers/iac/getting-started-iac) | Official | Repositories | UI, API, CLI |
|
||||
| [MongoDB Atlas](/user-guide/providers/mongodbatlas/getting-started-mongodbatlas) | Official | Organizations | UI, API, CLI |
|
||||
| [OpenStack](/user-guide/providers/openstack/getting-started-openstack) | Official | Projects | CLI |
|
||||
| [LLM](/user-guide/providers/llm/getting-started-llm) | Official | Models | CLI |
|
||||
| [Image](/user-guide/providers/image/getting-started-image) | Official | Container Images | CLI |
|
||||
| **NHN** | Unofficial | Tenants | CLI |
|
||||
|
||||
For more information about the checks and compliance of each provider visit [Prowler Hub](https://hub.prowler.com).
|
||||
|
||||
@@ -164,3 +164,44 @@ When these environment variables are set, the API will use them directly instead
|
||||
<Note>
|
||||
A fix addressing this permission issue is being evaluated in [PR #9953](https://github.com/prowler-cloud/prowler/pull/9953).
|
||||
</Note>
|
||||
|
||||
### SAML/OAuth ACS URL Incorrect When Running Behind a Proxy or Load Balancer
|
||||
|
||||
See [GitHub Issue #9724](https://github.com/prowler-cloud/prowler/issues/9724) for more details.
|
||||
|
||||
When running Prowler behind a reverse proxy (nginx, Traefik, etc.) or load balancer, the SAML ACS (Assertion Consumer Service) URL or OAuth callback URLs may be incorrectly generated using the internal container hostname (e.g., `http://prowler-api:8080/...`) instead of your external domain URL (e.g., `https://prowler.example.com/...`).
|
||||
|
||||
**Root Cause:**
|
||||
|
||||
Next.js environment variables prefixed with `NEXT_PUBLIC_` are **bundled at build time**, not runtime. The pre-built Docker images from Docker Hub (`prowlercloud/prowler-ui:stable`) are built with default internal URLs. Simply setting `NEXT_PUBLIC_API_BASE_URL` in your `.env` file or environment variables and restarting the container will **NOT** work because these values are already compiled into the JavaScript bundle.
|
||||
|
||||
**Solution:**
|
||||
|
||||
You must **rebuild** the UI Docker image with your external URL:
|
||||
|
||||
```bash
|
||||
# Clone the repository (if you haven't already)
|
||||
git clone https://github.com/prowler-cloud/prowler.git
|
||||
cd prowler/ui
|
||||
|
||||
# Build with your external URL as a build argument
|
||||
docker build \
|
||||
--build-arg NEXT_PUBLIC_API_BASE_URL=https://prowler.example.com/api/v1 \
|
||||
--build-arg NEXT_PUBLIC_API_DOCS_URL=https://prowler.example.com/api/v1/docs \
|
||||
-t prowler-ui-custom:latest \
|
||||
--target prod \
|
||||
.
|
||||
```
|
||||
|
||||
Then update your `docker-compose.yml` to use your custom image instead of the pre-built one:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
ui:
|
||||
image: prowler-ui-custom:latest # Use your custom-built image
|
||||
# ... rest of configuration
|
||||
```
|
||||
|
||||
<Note>
|
||||
The `NEXT_PUBLIC_` prefix is a Next.js convention that exposes environment variables to the browser. Since the browser bundle is compiled during `docker build`, these variables must be provided as build arguments, not runtime environment variables.
|
||||
</Note>
|
||||
|
||||
@@ -38,6 +38,7 @@ GitHub has deprecated Personal Access Tokens (classic) in favor of fine-grained
|
||||
|
||||
4. **Configure Token Settings**
|
||||
- **Token name**: Give your token a descriptive name (e.g., "Prowler Security Scanner")
|
||||
- **Resource owner**: Select the account that owns the resources to scan — either a personal account or a specific organization
|
||||
- **Expiration**: Set an appropriate expiration date (recommended: 90 days or less)
|
||||
- **Repository access**: Choose "All repositories" or "Only select repositories" based on your needs
|
||||
|
||||
@@ -56,11 +57,11 @@ GitHub has deprecated Personal Access Tokens (classic) in favor of fine-grained
|
||||
- **Metadata**: Read-only access
|
||||
- **Pull requests**: Read-only access
|
||||
|
||||
- **Organization permissions:**
|
||||
- **Organization permissions** (available when an organization is selected as Resource Owner):
|
||||
- **Administration**: Read-only access
|
||||
- **Members**: Read-only access
|
||||
|
||||
- **Account permissions:**
|
||||
- **Account permissions** (available when a personal account is selected as Resource Owner):
|
||||
- **Email addresses**: Read-only access
|
||||
|
||||
6. **Copy and Store the Token**
|
||||
|
||||
@@ -54,7 +54,7 @@ title: 'Getting Started with GitHub'
|
||||
</Tabs>
|
||||
## Prowler CLI
|
||||
|
||||
### Automatic Login Method Detection
|
||||
### Authentication
|
||||
|
||||
If no login method is explicitly provided, Prowler will automatically attempt to authenticate using environment variables in the following order of precedence:
|
||||
|
||||
@@ -68,15 +68,15 @@ Ensure the corresponding environment variables are set up before running Prowler
|
||||
</Note>
|
||||
For more details on how to set up authentication with GitHub, see [Authentication > GitHub](/user-guide/providers/github/authentication).
|
||||
|
||||
### Personal Access Token (PAT)
|
||||
#### Personal Access Token (PAT)
|
||||
|
||||
Use this method by providing your personal access token directly.
|
||||
Use this method by providing a personal access token directly.
|
||||
|
||||
```console
|
||||
prowler github --personal-access-token pat
|
||||
```
|
||||
|
||||
### OAuth App Token
|
||||
#### OAuth App Token
|
||||
|
||||
Authenticate using an OAuth app token.
|
||||
|
||||
@@ -84,9 +84,62 @@ Authenticate using an OAuth app token.
|
||||
prowler github --oauth-app-token oauth_token
|
||||
```
|
||||
|
||||
### GitHub App Credentials
|
||||
#### GitHub App Credentials
|
||||
|
||||
Use GitHub App credentials by specifying the App ID and the private key path.
|
||||
|
||||
```console
|
||||
prowler github --github-app-id app_id --github-app-key-path app_key_path
|
||||
```
|
||||
|
||||
### Scan Scoping
|
||||
|
||||
Scan scoping controls which repositories and organizations Prowler includes in a security assessment. By default, Prowler scans all repositories accessible to the authenticated user or organization. To limit the scan to specific repositories or organizations, use the following flags.
|
||||
|
||||
#### Scanning Specific Repositories
|
||||
|
||||
To restrict the scan to one or more repositories, use the `--repository` flag followed by the repository name(s) in `owner/repo-name` format:
|
||||
|
||||
```console
|
||||
prowler github --repository owner/repo-name
|
||||
```
|
||||
|
||||
To scan multiple repositories, specify them as space-separated arguments:
|
||||
|
||||
```console
|
||||
prowler github --repository owner/repo-name-1 owner/repo-name-2
|
||||
```
|
||||
|
||||
#### Scanning Specific Organizations
|
||||
|
||||
To restrict the scan to one or more organizations or user accounts, use the `--organization` flag:
|
||||
|
||||
```console
|
||||
prowler github --organization my-organization
|
||||
```
|
||||
|
||||
To scan multiple organizations, specify them as space-separated arguments:
|
||||
|
||||
```console
|
||||
prowler github --organization org-1 org-2
|
||||
```
|
||||
|
||||
#### Scanning Specific Repositories Within an Organization
|
||||
|
||||
To scan specific repositories within an organization, combine the `--organization` and `--repository` flags. The `--organization` flag qualifies unqualified repository names automatically:
|
||||
|
||||
```console
|
||||
prowler github --organization my-organization --repository my-repo
|
||||
```
|
||||
|
||||
This scans only `my-organization/my-repo`. Fully qualified repository names (`owner/repo-name`) are also supported alongside `--organization`:
|
||||
|
||||
```console
|
||||
prowler github --organization my-org --repository my-repo other-owner/other-repo
|
||||
```
|
||||
|
||||
In this case, `my-repo` is qualified as `my-org/my-repo`, while `other-owner/other-repo` is used as-is.
|
||||
|
||||
<Note>
|
||||
The `--repository` and `--organization` flags can be combined with any authentication method.
|
||||
</Note>
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
---
|
||||
title: "Getting Started with the Image Provider"
|
||||
---
|
||||
|
||||
import { VersionBadge } from "/snippets/version-badge.mdx"
|
||||
|
||||
Prowler's Image provider enables comprehensive container image security scanning by integrating with [Trivy](https://trivy.dev/). This provider detects vulnerabilities, exposed secrets, and misconfigurations in container images, converting Trivy findings into Prowler's standard reporting format for unified security assessment.
|
||||
|
||||
## How It Works
|
||||
|
||||
* **Trivy integration:** Prowler leverages [Trivy](https://trivy.dev/) to scan container images for vulnerabilities, secrets, misconfigurations, and license issues.
|
||||
* **Trivy required:** Trivy must be installed and available in the system PATH before running any scan.
|
||||
* **Authentication:** No registry authentication is required for public images. For private registries, configure Docker credentials via `docker login` before scanning.
|
||||
* **Output formats:** Results are output in the same formats as other Prowler providers (CSV, JSON, HTML, etc.).
|
||||
|
||||
## Prowler CLI
|
||||
|
||||
<VersionBadge version="5.19.0" />
|
||||
|
||||
<Note>
|
||||
The Image provider is currently available in Prowler CLI only.
|
||||
</Note>
|
||||
|
||||
### Install Trivy
|
||||
|
||||
Install Trivy using one of the following methods:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Homebrew">
|
||||
```bash
|
||||
brew install trivy
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="apt (Debian/Ubuntu)">
|
||||
```bash
|
||||
sudo apt-get install trivy
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Install Script">
|
||||
```bash
|
||||
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
For additional installation methods, see the [Trivy installation guide](https://trivy.dev/latest/getting-started/installation/).
|
||||
|
||||
|
||||
### Supported Scanners
|
||||
|
||||
Prowler CLI supports the following scanners:
|
||||
|
||||
* [Vulnerability](https://trivy.dev/docs/latest/guide/scanner/vulnerability/)
|
||||
* [Secret](https://trivy.dev/docs/latest/guide/scanner/secret/)
|
||||
* [Misconfiguration](https://trivy.dev/docs/latest/guide/scanner/misconfiguration/)
|
||||
* [License](https://trivy.dev/docs/latest/guide/scanner/license/)
|
||||
|
||||
By default, only vulnerability and secret scanners run during a scan. To specify which scanners to use, refer to the [Specify Scanners](#specify-scanners) section below.
|
||||
|
||||
### Scan Container Images
|
||||
|
||||
Use the `image` argument to run Prowler with the Image provider. Specify the images to scan using the `-I` flag or an image list file.
|
||||
|
||||
#### Scan a Single Image
|
||||
|
||||
To scan a single container image:
|
||||
|
||||
```bash
|
||||
prowler image -I alpine:3.18
|
||||
```
|
||||
|
||||
#### Scan Multiple Images
|
||||
|
||||
To scan multiple images, repeat the `-I` flag:
|
||||
|
||||
```bash
|
||||
prowler image -I nginx:latest -I redis:7 -I python:3.12-slim
|
||||
```
|
||||
|
||||
#### Scan From an Image List File
|
||||
|
||||
For large-scale scanning, provide a file containing one image per line:
|
||||
|
||||
```bash
|
||||
prowler image --image-list images.txt
|
||||
```
|
||||
|
||||
The file supports comments (lines starting with `#`) and blank lines:
|
||||
|
||||
```text
|
||||
# Production images
|
||||
nginx:1.25
|
||||
redis:7-alpine
|
||||
|
||||
# Development images
|
||||
python:3.12-slim
|
||||
node:20-bookworm
|
||||
```
|
||||
|
||||
<Note>
|
||||
Image list files are limited to a maximum of 10,000 lines. Individual image names exceeding 500 characters are automatically skipped with a warning.
|
||||
</Note>
|
||||
|
||||
<Warning>
|
||||
Image names must follow the Open Container Initiative (OCI) reference format. Valid names start with an alphanumeric character and contain only letters, digits, periods, hyphens, underscores, slashes, colons, and `@` symbols. Names containing shell metacharacters (`;`, `|`, `&`, `$`, `` ` ``) are rejected to prevent command injection.
|
||||
</Warning>
|
||||
|
||||
Valid examples:
|
||||
* **Standard tag:** `alpine:3.18`
|
||||
* **Custom registry:** `myregistry.io/myapp:v1.0`
|
||||
* **SHA digest:** `ghcr.io/org/image@sha256:abc123...`
|
||||
|
||||
#### Specify Scanners
|
||||
|
||||
To select which scanners Trivy runs, use the `--scanners` option. By default, Prowler enables `vuln` and `secret` scanners:
|
||||
|
||||
```bash
|
||||
# Vulnerability scanning only
|
||||
prowler image -I alpine:3.18 --scanners vuln
|
||||
|
||||
# All available scanners
|
||||
prowler image -I alpine:3.18 --scanners vuln secret misconfig license
|
||||
```
|
||||
|
||||
|
||||
#### Image Config Scanners
|
||||
|
||||
To scan Dockerfile-level metadata for misconfigurations or embedded secrets, use the `--image-config-scanners` option:
|
||||
|
||||
```bash
|
||||
# Scan Dockerfile for misconfigurations
|
||||
prowler image -I alpine:3.18 --image-config-scanners misconfig
|
||||
|
||||
# Scan Dockerfile for both misconfigurations and secrets
|
||||
prowler image -I alpine:3.18 --image-config-scanners misconfig secret
|
||||
```
|
||||
|
||||
Available image config scanners:
|
||||
|
||||
* **misconfig**: Detects Dockerfile misconfigurations (e.g., running as root, missing health checks)
|
||||
* **secret**: Identifies secrets embedded in Dockerfile instructions
|
||||
|
||||
<Note>
|
||||
Image config scanners are disabled by default. This option is independent from `--scanners` and specifically targets the image configuration (Dockerfile) rather than the image filesystem.
|
||||
</Note>
|
||||
|
||||
#### Filter by Severity
|
||||
|
||||
To filter findings by severity level, use the `--trivy-severity` option:
|
||||
|
||||
```bash
|
||||
# Only critical and high severity findings
|
||||
prowler image -I alpine:3.18 --trivy-severity CRITICAL HIGH
|
||||
```
|
||||
|
||||
Available severity levels: `CRITICAL`, `HIGH`, `MEDIUM`, `LOW`, `UNKNOWN`.
|
||||
|
||||
#### Ignore Unfixed Vulnerabilities
|
||||
|
||||
To exclude vulnerabilities without available fixes:
|
||||
|
||||
```bash
|
||||
prowler image -I alpine:3.18 --ignore-unfixed
|
||||
```
|
||||
|
||||
#### Configure Scan Timeout
|
||||
|
||||
To adjust the scan timeout for large images or slow network conditions, use the `--timeout` option:
|
||||
|
||||
```bash
|
||||
prowler image -I large-image:latest --timeout 10m
|
||||
```
|
||||
|
||||
The timeout accepts values in seconds (`s`), minutes (`m`), or hours (`h`). Default: `5m`.
|
||||
|
||||
### Authentication for Private Registries
|
||||
|
||||
The Image provider relies on Trivy for registry authentication. To scan images from private registries, configure Docker credentials before running the scan:
|
||||
|
||||
```bash
|
||||
# Log in to a private registry
|
||||
docker login myregistry.io
|
||||
|
||||
# Then scan the image
|
||||
prowler image -I myregistry.io/myapp:v1.0
|
||||
```
|
||||
|
||||
Trivy automatically uses credentials from Docker's credential store (`~/.docker/config.json`).
|
||||
|
||||
### Troubleshooting Common Scan Errors
|
||||
|
||||
The Image provider categorizes common Trivy errors with actionable guidance:
|
||||
|
||||
* **Authentication failure (401/403):** Registry credentials are missing or invalid. Run `docker login` for the target registry and retry the scan.
|
||||
* **Image not found (404):** The specified image name, tag, or registry is incorrect. Verify the image reference exists and is accessible.
|
||||
* **Rate limited (429):** The container registry is throttling requests. Wait before retrying, or authenticate to increase rate limits.
|
||||
* **Network issue:** Trivy cannot reach the registry due to connectivity problems. Check network access, DNS resolution, and firewall rules.
|
||||
@@ -53,7 +53,7 @@ On the profile page, find the "SAML SSO Integration" card and click "Enable" to
|
||||
|
||||

|
||||
|
||||
Next section will explain how to fill the IdP configuration based on your Identity Provider.
|
||||
The next section explains how to configure the IdP settings based on the selected Identity Provider.
|
||||
|
||||
#### Step 3: Configure the Identity Provider (IdP)
|
||||
Choose a Method:
|
||||
@@ -79,6 +79,31 @@ Choose a Method:
|
||||
|
||||
</Info>
|
||||
|
||||
**Configure Attribute Mapping in the IdP**
|
||||
|
||||
For Prowler App to correctly identify and provision users, configure the IdP to send the following attributes in the SAML assertion:
|
||||
|
||||
| Attribute Name | Description | Required |
|
||||
|----------------|---------------------------------------------------------------------------------------------------------|----------|
|
||||
| `firstName` | The user's first name. | Yes |
|
||||
| `lastName` | The user's last name. | Yes |
|
||||
| `userType` | Determines which Prowler role the user receives (e.g., `admin`, `auditor`). If a role with that name already exists, the user receives it automatically; if it does not exist, Prowler App creates a new role with that name without permissions. If `userType` is not defined, the user is assigned the `no_permissions` role. Role permissions can be edited in the [RBAC Management tab](/user-guide/tutorials/prowler-app-rbac). | No |
|
||||
| `companyName` | The user's company name. This is automatically populated if the IdP sends an `organization` attribute. | No |
|
||||
|
||||
<Info>
|
||||
**IdP Attribute Mapping**
|
||||
|
||||
Note that the attribute name is just an example and may be different depending on the IdP. For instance, if the IdP provides a `division` attribute, it can be mapped to `userType`.
|
||||

|
||||
|
||||
</Info>
|
||||
<Warning>
|
||||
**Dynamic Updates**
|
||||
|
||||
Prowler App updates these attributes each time a user logs in. Any changes made in the Identity Provider (IdP) will be reflected when the user logs in again.
|
||||
|
||||
</Warning>
|
||||
|
||||
</Tab>
|
||||
<Tab title="Okta App Catalog">
|
||||
Instead of creating a custom SAML integration, Okta administrators can configure Prowler Cloud directly from Okta's application catalog.
|
||||
@@ -105,39 +130,48 @@ Choose a Method:
|
||||
|
||||
6. **Assign Users**: Navigate to the "Assignments" tab and assign the appropriate users or groups to the Prowler application by clicking "Assign" and selecting "Assign to People" or "Assign to Groups".
|
||||
|
||||

|
||||
|
||||
7. **Configure User Attributes in Okta**: Okta acts as the central source for user profile information. Prowler App maps the following Okta user profile attributes during each SAML login:
|
||||
|
||||
* **First name** (`firstName`): Maps to the user's first name in Prowler App.
|
||||
* **Last name** (`lastName`): Maps to the user's last name in Prowler App.
|
||||
|
||||

|
||||
|
||||
* **Organization** (`organization`): Maps to the company name displayed in Prowler App. This attribute is optional.
|
||||
* **User type** (`userType`): Determines the Prowler role assigned to the user. This attribute is **case-sensitive** and must match the exact name of an existing role in Prowler App.
|
||||
|
||||

|
||||
|
||||
To modify these values, edit the user's profile directly in the Okta admin console under the "Profile" tab. Changes are reflected in Prowler App the next time the user logs in via SAML.
|
||||
|
||||
<Warning>
|
||||
**User Type and Role Assignment**
|
||||
|
||||
The `userType` attribute controls which Prowler role is assigned to the user:
|
||||
|
||||
* If a role with the specified name already exists in Prowler App, the user automatically receives that role.
|
||||
* If the role does not exist, Prowler App creates a new role with that exact name but without any permissions, preventing the user from performing any actions.
|
||||
* If `userType` is not defined in the user's Okta profile, the user is assigned the `no_permissions` role.
|
||||
|
||||
In all cases where the resulting role has no permissions, a Prowler administrator (a user whose role includes the "Manage Account" permission) must configure the appropriate permissions through the [RBAC Management tab](/user-guide/tutorials/prowler-app-rbac).
|
||||
|
||||
This behavior is intentional: by defaulting to no permissions, Prowler App ensures that a misconfiguration in Okta cannot inadvertently grant elevated access.
|
||||
|
||||
**Example:** To assign the `IT` role to a user, set the `userType` value to `IT` in Okta. If a role named `IT` already exists in Prowler App, the user receives it automatically upon login. If it does not exist, Prowler App creates a new role called `IT` without permissions, and a Prowler administrator must configure the desired permissions for it.
|
||||
|
||||
</Warning>
|
||||
|
||||
With this step, the Okta app catalog configuration is complete. Users can now access Prowler Cloud using either [IdP-initiated](#idp-initiated-sso) or [SP-initiated SSO](#sp-initiated-sso) flows.
|
||||
|
||||
7. **Download Metadata XML**: Inside the "Sign On" section, go to the "Metadata URL" and download the metadata XML file.
|
||||
8. **Download Metadata XML**: Inside the "Sign On" section, go to the "Metadata URL" and download the metadata XML file.
|
||||
|
||||
Jump to [Step 5: Upload IdP Metadata to Prowler](#step-5:-upload-idp-metadata-to-prowler).
|
||||
Jump to [Step 4: Upload IdP Metadata to Prowler](#step-4:-upload-idp-metadata-to-prowler).
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
#### Step 4: Configure Attribute Mapping in the IdP
|
||||
|
||||
For Prowler App to correctly identify and provision users, configure the IdP to send the following attributes in the SAML assertion:
|
||||
|
||||
| Attribute Name | Description | Required |
|
||||
|----------------|---------------------------------------------------------------------------------------------------------|----------|
|
||||
| `firstName` | The user's first name. | Yes |
|
||||
| `lastName` | The user's last name. | Yes |
|
||||
| `userType` | The Prowler role to be assigned to the user (e.g., `admin`, `auditor`). If a role with that name already exists, it will be used; otherwise, a new role called `no_permissions` will be created with minimal permissions. Role permissions can be edited in the [RBAC Management tab](/user-guide/tutorials/prowler-app-rbac). | No |
|
||||
| `companyName` | The user's company name. This is automatically populated if the IdP sends an `organization` attribute. | No |
|
||||
|
||||
<Info>
|
||||
**IdP Attribute Mapping**
|
||||
|
||||
Note that the attribute name is just an example and may be different depending on the IdP. For instance, if the IdP provides a `division` attribute, it can be mapped to `userType`.
|
||||

|
||||
|
||||
</Info>
|
||||
<Warning>
|
||||
**Dynamic Updates**
|
||||
|
||||
Prowler App updates these attributes each time a user logs in. Any changes made in the Identity Provider (IdP) will be reflected when the user logs in again.
|
||||
|
||||
</Warning>
|
||||
#### Step 5: Upload IdP Metadata to Prowler
|
||||
#### Step 4: Upload IdP Metadata to Prowler
|
||||
|
||||
Once the IdP is configured, it provides a **metadata XML file**. This file contains the IdP's configuration information, such as its public key and login URL.
|
||||
|
||||
@@ -151,7 +185,7 @@ To complete the Prowler App configuration:
|
||||
|
||||

|
||||
|
||||
#### Step 6: Save and Verify Configuration
|
||||
#### Step 5: Save and Verify Configuration
|
||||
|
||||
Click the "Save" button to complete the setup. The "SAML Integration" card will now display an "Active" status, indicating the configuration is complete and enabled.
|
||||
|
||||
|
||||
Generated
+225
-197
@@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry 2.3.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "about-time"
|
||||
@@ -2002,43 +2002,49 @@ toml = ["tomli ; python_full_version <= \"3.11.0a6\""]
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "44.0.1"
|
||||
version = "44.0.3"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
optional = false
|
||||
python-versions = "!=3.9.0,!=3.9.1,>=3.7"
|
||||
groups = ["main", "dev"]
|
||||
files = [
|
||||
{file = "cryptography-44.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf688f615c29bfe9dfc44312ca470989279f0e94bb9f631f85e3459af8efc009"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd7c7e2d71d908dc0f8d2027e1604102140d84b155e658c20e8ad1304317691f"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887143b9ff6bad2b7570da75a7fe8bbf5f65276365ac259a5d2d5147a73775f2"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:322eb03ecc62784536bc173f1483e76747aafeb69c8728df48537eb431cd1911"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:21377472ca4ada2906bc313168c9dc7b1d7ca417b63c1c3011d0c74b7de9ae69"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:df978682c1504fc93b3209de21aeabf2375cb1571d4e61907b3e7a2540e83026"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:eb3889330f2a4a148abead555399ec9a32b13b7c8ba969b72d8e500eb7ef84cd"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:8e6a85a93d0642bd774460a86513c5d9d80b5c002ca9693e63f6e540f1815ed0"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6f76fdd6fd048576a04c5210d53aa04ca34d2ed63336d4abd306d0cbe298fddf"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6c8acf6f3d1f47acb2248ec3ea261171a671f3d9428e34ad0357148d492c7864"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-win32.whl", hash = "sha256:24979e9f2040c953a94bf3c6782e67795a4c260734e5264dceea65c8f4bae64a"},
|
||||
{file = "cryptography-44.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:fd0ee90072861e276b0ff08bd627abec29e32a53b2be44e41dbcdf87cbee2b00"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a2d8a7045e1ab9b9f803f0d9531ead85f90c5f2859e653b61497228b18452008"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8272f257cf1cbd3f2e120f14c68bff2b6bdfcc157fafdee84a1b795efd72862"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e8d181e90a777b63f3f0caa836844a1182f1f265687fac2115fcf245f5fbec3"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:436df4f203482f41aad60ed1813811ac4ab102765ecae7a2bbb1dbb66dcff5a7"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4f422e8c6a28cf8b7f883eb790695d6d45b0c385a2583073f3cec434cc705e1a"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:72198e2b5925155497a5a3e8c216c7fb3e64c16ccee11f0e7da272fa93b35c4c"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:2a46a89ad3e6176223b632056f321bc7de36b9f9b93b2cc1cccf935a3849dc62"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:53f23339864b617a3dfc2b0ac8d5c432625c80014c25caac9082314e9de56f41"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:888fcc3fce0c888785a4876ca55f9f43787f4c5c1cc1e2e0da71ad481ff82c5b"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:00918d859aa4e57db8299607086f793fa7813ae2ff5a4637e318a25ef82730f7"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-win32.whl", hash = "sha256:9b336599e2cb77b1008cb2ac264b290803ec5e8e89d618a5e978ff5eb6f715d9"},
|
||||
{file = "cryptography-44.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:e403f7f766ded778ecdb790da786b418a9f2394f36e8cc8b796cc056ab05f44f"},
|
||||
{file = "cryptography-44.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1f9a92144fa0c877117e9748c74501bea842f93d21ee00b0cf922846d9d0b183"},
|
||||
{file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:610a83540765a8d8ce0f351ce42e26e53e1f774a6efb71eb1b41eb01d01c3d12"},
|
||||
{file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:5fed5cd6102bb4eb843e3315d2bf25fede494509bddadb81e03a859c1bc17b83"},
|
||||
{file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:f4daefc971c2d1f82f03097dc6f216744a6cd2ac0f04c68fb935ea2ba2a0d420"},
|
||||
{file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:94f99f2b943b354a5b6307d7e8d19f5c423a794462bde2bf310c770ba052b1c4"},
|
||||
{file = "cryptography-44.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d9c5b9f698a83c8bd71e0f4d3f9f839ef244798e5ffe96febfa9714717db7af7"},
|
||||
{file = "cryptography-44.0.1.tar.gz", hash = "sha256:f51f5705ab27898afda1aaa430f34ad90dc117421057782022edf0600bec5f14"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:962bc30480a08d133e631e8dfd4783ab71cc9e33d5d7c1e192f0b7c06397bb88"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffc61e8f3bf5b60346d89cd3d37231019c17a081208dfbbd6e1605ba03fa137"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58968d331425a6f9eedcee087f77fd3c927c88f55368f43ff7e0a19891f2642c"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e28d62e59a4dbd1d22e747f57d4f00c459af22181f0b2f787ea83f5a876d7c76"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af653022a0c25ef2e3ffb2c673a50e5a0d02fecc41608f4954176f1933b12359"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:157f1f3b8d941c2bd8f3ffee0af9b049c9665c39d3da9db2dc338feca5e98a43"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:c6cd67722619e4d55fdb42ead64ed8843d64638e9c07f4011163e46bc512cf01"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b424563394c369a804ecbee9b06dfb34997f19d00b3518e39f83a5642618397d"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c91fc8e8fd78af553f98bc7f2a1d8db977334e4eea302a4bfd75b9461c2d8904"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:25cd194c39fa5a0aa4169125ee27d1172097857b27109a45fadc59653ec06f44"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-win32.whl", hash = "sha256:3be3f649d91cb182c3a6bd336de8b61a0a71965bd13d1a04a0e15b39c3d5809d"},
|
||||
{file = "cryptography-44.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:3883076d5c4cc56dbef0b898a74eb6992fdac29a7b9013870b34efe4ddb39a0d"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:5639c2b16764c6f76eedf722dbad9a0914960d3489c0cc38694ddf9464f1bb2f"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3ffef566ac88f75967d7abd852ed5f182da252d23fac11b4766da3957766759"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:192ed30fac1728f7587c6f4613c29c584abdc565d7417c13904708db10206645"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7d5fe7195c27c32a64955740b949070f21cba664604291c298518d2e255931d2"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3f07943aa4d7dad689e3bb1638ddc4944cc5e0921e3c227486daae0e31a05e54"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb90f60e03d563ca2445099edf605c16ed1d5b15182d21831f58460c48bffb93"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:ab0b005721cc0039e885ac3503825661bd9810b15d4f374e473f8c89b7d5460c"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:3bb0847e6363c037df8f6ede57d88eaf3410ca2267fb12275370a76f85786a6f"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b0cc66c74c797e1db750aaa842ad5b8b78e14805a9b5d1348dc603612d3e3ff5"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6866df152b581f9429020320e5eb9794c8780e90f7ccb021940d7f50ee00ae0b"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-win32.whl", hash = "sha256:c138abae3a12a94c75c10499f1cbae81294a6f983b3af066390adee73f433028"},
|
||||
{file = "cryptography-44.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:5d186f32e52e66994dce4f766884bcb9c68b8da62d61d9d215bfe5fb56d21334"},
|
||||
{file = "cryptography-44.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:cad399780053fb383dc067475135e41c9fe7d901a97dd5d9c5dfb5611afc0d7d"},
|
||||
{file = "cryptography-44.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:21a83f6f35b9cc656d71b5de8d519f566df01e660ac2578805ab245ffd8523f8"},
|
||||
{file = "cryptography-44.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fc3c9babc1e1faefd62704bb46a69f359a9819eb0292e40df3fb6e3574715cd4"},
|
||||
{file = "cryptography-44.0.3-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:e909df4053064a97f1e6565153ff8bb389af12c5c8d29c343308760890560aff"},
|
||||
{file = "cryptography-44.0.3-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:dad80b45c22e05b259e33ddd458e9e2ba099c86ccf4e88db7bbab4b747b18d06"},
|
||||
{file = "cryptography-44.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:479d92908277bed6e1a1c69b277734a7771c2b78633c224445b5c60a9f4bc1d9"},
|
||||
{file = "cryptography-44.0.3-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:896530bc9107b226f265effa7ef3f21270f18a2026bc09fed1ebd7b66ddf6375"},
|
||||
{file = "cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9b4d4a5dbee05a2c390bf212e78b99434efec37b17a4bff42f50285c5c8c9647"},
|
||||
{file = "cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02f55fb4f8b79c1221b0961488eaae21015b69b210e18c386b69de182ebb1259"},
|
||||
{file = "cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:dd3db61b8fe5be220eee484a17233287d0be6932d056cf5738225b9c05ef4fff"},
|
||||
{file = "cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:978631ec51a6bbc0b7e58f23b68a8ce9e5f09721940933e9c217068388789fe5"},
|
||||
{file = "cryptography-44.0.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:5d20cc348cca3a8aa7312f42ab953a56e15323800ca3ab0706b8cd452a3a056c"},
|
||||
{file = "cryptography-44.0.3.tar.gz", hash = "sha256:fe19d8bc5536a91a24a8133328880a41831b6c5df54599a8417b62fe015d3053"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -2051,7 +2057,7 @@ nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_version >= \"3.8\""]
|
||||
pep8test = ["check-sdist ; python_version >= \"3.8\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"]
|
||||
sdist = ["build (>=1.0.0)"]
|
||||
ssh = ["bcrypt (>=3.1.5)"]
|
||||
test = ["certifi (>=2024)", "cryptography-vectors (==44.0.1)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"]
|
||||
test = ["certifi (>=2024)", "cryptography-vectors (==44.0.3)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"]
|
||||
test-randomorder = ["pytest-randomly"]
|
||||
|
||||
[[package]]
|
||||
@@ -4017,46 +4023,6 @@ files = [
|
||||
{file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "netifaces"
|
||||
version = "0.11.0"
|
||||
description = "Portable network interface information."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "netifaces-0.11.0-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eb4813b77d5df99903af4757ce980a98c4d702bbcb81f32a0b305a1537bdf0b1"},
|
||||
{file = "netifaces-0.11.0-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:5f9ca13babe4d845e400921973f6165a4c2f9f3379c7abfc7478160e25d196a4"},
|
||||
{file = "netifaces-0.11.0-cp27-cp27m-win32.whl", hash = "sha256:7dbb71ea26d304e78ccccf6faccef71bb27ea35e259fb883cfd7fd7b4f17ecb1"},
|
||||
{file = "netifaces-0.11.0-cp27-cp27m-win_amd64.whl", hash = "sha256:0f6133ac02521270d9f7c490f0c8c60638ff4aec8338efeff10a1b51506abe85"},
|
||||
{file = "netifaces-0.11.0-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:08e3f102a59f9eaef70948340aeb6c89bd09734e0dca0f3b82720305729f63ea"},
|
||||
{file = "netifaces-0.11.0-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c03fb2d4ef4e393f2e6ffc6376410a22a3544f164b336b3a355226653e5efd89"},
|
||||
{file = "netifaces-0.11.0-cp34-cp34m-win32.whl", hash = "sha256:73ff21559675150d31deea8f1f8d7e9a9a7e4688732a94d71327082f517fc6b4"},
|
||||
{file = "netifaces-0.11.0-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:815eafdf8b8f2e61370afc6add6194bd5a7252ae44c667e96c4c1ecf418811e4"},
|
||||
{file = "netifaces-0.11.0-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:50721858c935a76b83dd0dd1ab472cad0a3ef540a1408057624604002fcfb45b"},
|
||||
{file = "netifaces-0.11.0-cp35-cp35m-win32.whl", hash = "sha256:c9a3a47cd3aaeb71e93e681d9816c56406ed755b9442e981b07e3618fb71d2ac"},
|
||||
{file = "netifaces-0.11.0-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:aab1dbfdc55086c789f0eb37affccf47b895b98d490738b81f3b2360100426be"},
|
||||
{file = "netifaces-0.11.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c37a1ca83825bc6f54dddf5277e9c65dec2f1b4d0ba44b8fd42bc30c91aa6ea1"},
|
||||
{file = "netifaces-0.11.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:28f4bf3a1361ab3ed93c5ef360c8b7d4a4ae060176a3529e72e5e4ffc4afd8b0"},
|
||||
{file = "netifaces-0.11.0-cp36-cp36m-win32.whl", hash = "sha256:2650beee182fed66617e18474b943e72e52f10a24dc8cac1db36c41ee9c041b7"},
|
||||
{file = "netifaces-0.11.0-cp36-cp36m-win_amd64.whl", hash = "sha256:cb925e1ca024d6f9b4f9b01d83215fd00fe69d095d0255ff3f64bffda74025c8"},
|
||||
{file = "netifaces-0.11.0-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:84e4d2e6973eccc52778735befc01638498781ce0e39aa2044ccfd2385c03246"},
|
||||
{file = "netifaces-0.11.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:18917fbbdcb2d4f897153c5ddbb56b31fa6dd7c3fa9608b7e3c3a663df8206b5"},
|
||||
{file = "netifaces-0.11.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:48324183af7f1bc44f5f197f3dad54a809ad1ef0c78baee2c88f16a5de02c4c9"},
|
||||
{file = "netifaces-0.11.0-cp37-cp37m-win32.whl", hash = "sha256:8f7da24eab0d4184715d96208b38d373fd15c37b0dafb74756c638bd619ba150"},
|
||||
{file = "netifaces-0.11.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2479bb4bb50968089a7c045f24d120f37026d7e802ec134c4490eae994c729b5"},
|
||||
{file = "netifaces-0.11.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:3ecb3f37c31d5d51d2a4d935cfa81c9bc956687c6f5237021b36d6fdc2815b2c"},
|
||||
{file = "netifaces-0.11.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:96c0fe9696398253f93482c84814f0e7290eee0bfec11563bd07d80d701280c3"},
|
||||
{file = "netifaces-0.11.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c92ff9ac7c2282009fe0dcb67ee3cd17978cffbe0c8f4b471c00fe4325c9b4d4"},
|
||||
{file = "netifaces-0.11.0-cp38-cp38-win32.whl", hash = "sha256:d07b01c51b0b6ceb0f09fc48ec58debd99d2c8430b09e56651addeaf5de48048"},
|
||||
{file = "netifaces-0.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:469fc61034f3daf095e02f9f1bbac07927b826c76b745207287bc594884cfd05"},
|
||||
{file = "netifaces-0.11.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5be83986100ed1fdfa78f11ccff9e4757297735ac17391b95e17e74335c2047d"},
|
||||
{file = "netifaces-0.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:54ff6624eb95b8a07e79aa8817288659af174e954cca24cdb0daeeddfc03c4ff"},
|
||||
{file = "netifaces-0.11.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:841aa21110a20dc1621e3dd9f922c64ca64dd1eb213c47267a2c324d823f6c8f"},
|
||||
{file = "netifaces-0.11.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e76c7f351e0444721e85f975ae92718e21c1f361bda946d60a214061de1f00a1"},
|
||||
{file = "netifaces-0.11.0.tar.gz", hash = "sha256:043a79146eb2907edf439899f262b3dfe41717d34124298ed281139a8b93ca32"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "networkx"
|
||||
version = "3.2.1"
|
||||
@@ -4290,14 +4256,14 @@ openapi-schema-validator = ">=0.6.0,<0.7.0"
|
||||
|
||||
[[package]]
|
||||
name = "openstacksdk"
|
||||
version = "4.0.1"
|
||||
version = "4.2.0"
|
||||
description = "An SDK for building applications to work with OpenStack"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "openstacksdk-4.0.1-py3-none-any.whl", hash = "sha256:d63187a006fff7c1de1486c9e2e1073a787af402620c3c0ed0cf5291225998ac"},
|
||||
{file = "openstacksdk-4.0.1.tar.gz", hash = "sha256:19faa1d5e6a78a2c1dc06a171e65e776ba82e9df23e1d08586225dc5ade9fc63"},
|
||||
{file = "openstacksdk-4.2.0-py3-none-any.whl", hash = "sha256:238be0fa5d9899872b00787ab38e84f92fd6dc87525fde0965dadcdc12196dc6"},
|
||||
{file = "openstacksdk-4.2.0.tar.gz", hash = "sha256:5cb9450dcce8054a2caf89d8be9e55057ddfa219a954e781032241eb29280445"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -4308,10 +4274,10 @@ iso8601 = ">=0.1.11"
|
||||
jmespath = ">=0.9.0"
|
||||
jsonpatch = ">=1.16,<1.20 || >1.20"
|
||||
keystoneauth1 = ">=3.18.0"
|
||||
netifaces = ">=0.10.4"
|
||||
os-service-types = ">=1.7.0"
|
||||
pbr = ">=2.0.0,<2.1.0 || >2.1.0"
|
||||
platformdirs = ">=3"
|
||||
psutil = ">=3.2.2"
|
||||
PyYAML = ">=3.13"
|
||||
requestsexceptions = ">=1.2.0"
|
||||
|
||||
@@ -4768,6 +4734,41 @@ files = [
|
||||
{file = "protobuf-6.31.1.tar.gz", hash = "sha256:d8cac4c982f0b957a4dc73a80e2ea24fab08e679c0de9deb835f4a12d69aca9a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psutil"
|
||||
version = "7.2.2"
|
||||
description = "Cross-platform lib for process and system monitoring."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b"},
|
||||
{file = "psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea"},
|
||||
{file = "psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63"},
|
||||
{file = "psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312"},
|
||||
{file = "psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b"},
|
||||
{file = "psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9"},
|
||||
{file = "psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00"},
|
||||
{file = "psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9"},
|
||||
{file = "psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a"},
|
||||
{file = "psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf"},
|
||||
{file = "psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1"},
|
||||
{file = "psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841"},
|
||||
{file = "psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486"},
|
||||
{file = "psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979"},
|
||||
{file = "psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9"},
|
||||
{file = "psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e"},
|
||||
{file = "psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8"},
|
||||
{file = "psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc"},
|
||||
{file = "psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988"},
|
||||
{file = "psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee"},
|
||||
{file = "psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["abi3audit", "black", "check-manifest", "colorama ; os_name == \"nt\"", "coverage", "packaging", "psleak", "pylint", "pyperf", "pypinfo", "pyreadline3 ; os_name == \"nt\"", "pytest", "pytest-cov", "pytest-instafail", "pytest-xdist", "pywin32 ; os_name == \"nt\" and implementation_name != \"pypy\"", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "validate-pyproject[all]", "virtualenv", "vulture", "wheel", "wheel ; os_name == \"nt\" and implementation_name != \"pypy\"", "wmi ; os_name == \"nt\" and implementation_name != \"pypy\""]
|
||||
test = ["psleak", "pytest", "pytest-instafail", "pytest-xdist", "pywin32 ; os_name == \"nt\" and implementation_name != \"pypy\"", "setuptools", "wheel ; os_name == \"nt\" and implementation_name != \"pypy\"", "wmi ; os_name == \"nt\" and implementation_name != \"pypy\""]
|
||||
|
||||
[[package]]
|
||||
name = "py-iam-expand"
|
||||
version = "0.1.0"
|
||||
@@ -4785,20 +4786,20 @@ iamdata = ">=0.1.202504091"
|
||||
|
||||
[[package]]
|
||||
name = "py-ocsf-models"
|
||||
version = "0.5.0"
|
||||
version = "0.8.1"
|
||||
description = "This is a Python implementation of the OCSF models. The models are used to represent the data of the OCSF Schema defined in https://schema.ocsf.io/."
|
||||
optional = false
|
||||
python-versions = "<3.14,>3.9.1"
|
||||
python-versions = "<3.15,>3.9.1"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "py_ocsf_models-0.5.0-py3-none-any.whl", hash = "sha256:7933253f56782c04c412d976796db429577810b951fe4195351794500b5962d8"},
|
||||
{file = "py_ocsf_models-0.5.0.tar.gz", hash = "sha256:bf05e955809d1ec3ab1007e4a4b2a8a0afa74b6e744ea8ffbf386e46b3af0a76"},
|
||||
{file = "py_ocsf_models-0.8.1-py3-none-any.whl", hash = "sha256:061eb446c4171534c09a8b37f5a9d2a2fe9f87c5db32edbd1182446bc5fd097e"},
|
||||
{file = "py_ocsf_models-0.8.1.tar.gz", hash = "sha256:c9045237857f951e073c9f9d1f57954c90d86875b469260725292d47f7a7d73c"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
cryptography = "44.0.1"
|
||||
cryptography = ">=44.0.3,<47"
|
||||
email-validator = "2.2.0"
|
||||
pydantic = ">=2.9.2,<3.0.0"
|
||||
pydantic = ">=2.12.0,<3.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "py-partiql-parser"
|
||||
@@ -4861,7 +4862,7 @@ description = "C parser in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main", "dev"]
|
||||
markers = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\""
|
||||
markers = "implementation_name != \"PyPy\" and platform_python_implementation != \"PyPy\""
|
||||
files = [
|
||||
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
|
||||
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
|
||||
@@ -4869,21 +4870,21 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.11.7"
|
||||
version = "2.12.5"
|
||||
description = "Data validation using Python type hints"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main", "dev"]
|
||||
files = [
|
||||
{file = "pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b"},
|
||||
{file = "pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db"},
|
||||
{file = "pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d"},
|
||||
{file = "pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
annotated-types = ">=0.6.0"
|
||||
pydantic-core = "2.33.2"
|
||||
typing-extensions = ">=4.12.2"
|
||||
typing-inspection = ">=0.4.0"
|
||||
pydantic-core = "2.41.5"
|
||||
typing-extensions = ">=4.14.1"
|
||||
typing-inspection = ">=0.4.2"
|
||||
|
||||
[package.extras]
|
||||
email = ["email-validator (>=2.0.0)"]
|
||||
@@ -4891,115 +4892,137 @@ timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.33.2"
|
||||
version = "2.41.5"
|
||||
description = "Core functionality for Pydantic validation and serialization"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main", "dev"]
|
||||
files = [
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"},
|
||||
{file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"},
|
||||
{file = "pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146"},
|
||||
{file = "pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2"},
|
||||
{file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97"},
|
||||
{file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9"},
|
||||
{file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52"},
|
||||
{file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941"},
|
||||
{file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a"},
|
||||
{file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c"},
|
||||
{file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2"},
|
||||
{file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556"},
|
||||
{file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49"},
|
||||
{file = "pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba"},
|
||||
{file = "pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9"},
|
||||
{file = "pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6"},
|
||||
{file = "pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b"},
|
||||
{file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a"},
|
||||
{file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8"},
|
||||
{file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e"},
|
||||
{file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1"},
|
||||
{file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b"},
|
||||
{file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b"},
|
||||
{file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284"},
|
||||
{file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594"},
|
||||
{file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e"},
|
||||
{file = "pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b"},
|
||||
{file = "pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe"},
|
||||
{file = "pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f"},
|
||||
{file = "pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7"},
|
||||
{file = "pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0"},
|
||||
{file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69"},
|
||||
{file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75"},
|
||||
{file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05"},
|
||||
{file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc"},
|
||||
{file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c"},
|
||||
{file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5"},
|
||||
{file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c"},
|
||||
{file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294"},
|
||||
{file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1"},
|
||||
{file = "pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d"},
|
||||
{file = "pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815"},
|
||||
{file = "pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3"},
|
||||
{file = "pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9"},
|
||||
{file = "pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34"},
|
||||
{file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0"},
|
||||
{file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33"},
|
||||
{file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e"},
|
||||
{file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2"},
|
||||
{file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586"},
|
||||
{file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d"},
|
||||
{file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740"},
|
||||
{file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e"},
|
||||
{file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858"},
|
||||
{file = "pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36"},
|
||||
{file = "pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11"},
|
||||
{file = "pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c"},
|
||||
{file = "pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008"},
|
||||
{file = "pydantic_core-2.41.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:8bfeaf8735be79f225f3fefab7f941c712aaca36f1128c9d7e2352ee1aa87bdf"},
|
||||
{file = "pydantic_core-2.41.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:346285d28e4c8017da95144c7f3acd42740d637ff41946af5ce6e5e420502dd5"},
|
||||
{file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a75dafbf87d6276ddc5b2bf6fae5254e3d0876b626eb24969a574fff9149ee5d"},
|
||||
{file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b93a4d08587e2b7e7882de461e82b6ed76d9026ce91ca7915e740ecc7855f60"},
|
||||
{file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8465ab91a4bd96d36dde3263f06caa6a8a6019e4113f24dc753d79a8b3a3f82"},
|
||||
{file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:299e0a22e7ae2b85c1a57f104538b2656e8ab1873511fd718a1c1c6f149b77b5"},
|
||||
{file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:707625ef0983fcfb461acfaf14de2067c5942c6bb0f3b4c99158bed6fedd3cf3"},
|
||||
{file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f41eb9797986d6ebac5e8edff36d5cef9de40def462311b3eb3eeded1431e425"},
|
||||
{file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0384e2e1021894b1ff5a786dbf94771e2986ebe2869533874d7e43bc79c6f504"},
|
||||
{file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:f0cd744688278965817fd0839c4a4116add48d23890d468bc436f78beb28abf5"},
|
||||
{file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:753e230374206729bf0a807954bcc6c150d3743928a73faffee51ac6557a03c3"},
|
||||
{file = "pydantic_core-2.41.5-cp39-cp39-win32.whl", hash = "sha256:873e0d5b4fb9b89ef7c2d2a963ea7d02879d9da0da8d9d4933dee8ee86a8b460"},
|
||||
{file = "pydantic_core-2.41.5-cp39-cp39-win_amd64.whl", hash = "sha256:e4f4a984405e91527a0d62649ee21138f8e3d0ef103be488c1dc11a80d7f184b"},
|
||||
{file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034"},
|
||||
{file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c"},
|
||||
{file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2"},
|
||||
{file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad"},
|
||||
{file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd"},
|
||||
{file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc"},
|
||||
{file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56"},
|
||||
{file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b"},
|
||||
{file = "pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8"},
|
||||
{file = "pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a"},
|
||||
{file = "pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b"},
|
||||
{file = "pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2"},
|
||||
{file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093"},
|
||||
{file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a"},
|
||||
{file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963"},
|
||||
{file = "pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a"},
|
||||
{file = "pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26"},
|
||||
{file = "pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808"},
|
||||
{file = "pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc"},
|
||||
{file = "pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1"},
|
||||
{file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84"},
|
||||
{file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770"},
|
||||
{file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f"},
|
||||
{file = "pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51"},
|
||||
{file = "pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
||||
typing-extensions = ">=4.14.1"
|
||||
|
||||
[[package]]
|
||||
name = "pyflakes"
|
||||
@@ -5874,6 +5897,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"},
|
||||
@@ -5882,6 +5906,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"},
|
||||
@@ -5890,6 +5915,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"},
|
||||
@@ -5898,6 +5924,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"},
|
||||
@@ -5906,6 +5933,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"},
|
||||
@@ -6298,14 +6326,14 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "typing-inspection"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
description = "Runtime typing introspection tools"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main", "dev"]
|
||||
files = [
|
||||
{file = "typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51"},
|
||||
{file = "typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28"},
|
||||
{file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"},
|
||||
{file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -6853,4 +6881,4 @@ files = [
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">3.9.1,<3.13"
|
||||
content-hash = "f9ff21ae57caa3ddcd27f3753c29c1b3be2966709baed52e1bbc24e7bdc33f3c"
|
||||
content-hash = "f1ac30f34fd838017ad24702043564e2c37afd1fdbf674cf5e5def79082463d5"
|
||||
|
||||
+62
-1
@@ -2,6 +2,64 @@
|
||||
|
||||
All notable changes to the **Prowler SDK** are documented in this file.
|
||||
|
||||
## [5.19.0] (Prowler UNRELEASED)
|
||||
|
||||
### 🚀 Added
|
||||
|
||||
- `organization_verified_badge` check for GitHub provider [(#10033)](https://github.com/prowler-cloud/prowler/pull/10033)
|
||||
- OpenStack provider `clouds_yaml_content` parameter for API integration [(#10003)](https://github.com/prowler-cloud/prowler/pull/10003)
|
||||
- `defender_safe_attachments_policy_enabled` check for M365 provider [(#9833)](https://github.com/prowler-cloud/prowler/pull/9833)
|
||||
- `defender_safelinks_policy_enabled` check for M365 provider [(#9832)](https://github.com/prowler-cloud/prowler/pull/9832)
|
||||
- AI Skills: Added a skill for creating new Attack Paths queries in openCypher, compatible with Neo4j and Neptune [(#9975)](https://github.com/prowler-cloud/prowler/pull/9975)
|
||||
- CSA CCM 4.0 for the AWS provider [(#10018)](https://github.com/prowler-cloud/prowler/pull/10018)
|
||||
- CSA CCM 4.0 for the GCP provider [(#10042)](https://github.com/prowler-cloud/prowler/pull/10042)
|
||||
- CSA CCM 4.0 for the Azure provider [(#10039)](https://github.com/prowler-cloud/prowler/pull/10039)
|
||||
- CSA CCM 4.0 for the Oracle Cloud provider [(#10057)](https://github.com/prowler-cloud/prowler/pull/10057)
|
||||
- OCI regions updater script and CI workflow [(#10020)](https://github.com/prowler-cloud/prowler/pull/10020)
|
||||
- `image` provider for container image scanning with Trivy integration [(#9984)](https://github.com/prowler-cloud/prowler/pull/9984)
|
||||
- CSA CCM 4.0 for the Alibaba Cloud provider [(#10061)](https://github.com/prowler-cloud/prowler/pull/10061)
|
||||
- ECS Exec (ECS-006) privilege escalation detection via `ecs:ExecuteCommand` + `ecs:DescribeTasks` [(#10066)](https://github.com/prowler-cloud/prowler/pull/10066)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
- Update Azure Monitor service metadata to new format [(#9622)](https://github.com/prowler-cloud/prowler/pull/9622)
|
||||
- Parallelize Cloudflare zone API calls with threading to improve scan performance [(#9982)](https://github.com/prowler-cloud/prowler/pull/9982)
|
||||
- Update GCP API Keys service metadata to new format [(#9637)](https://github.com/prowler-cloud/prowler/pull/9637)
|
||||
- Update GCP BigQuery service metadata to new format [(#9638)](https://github.com/prowler-cloud/prowler/pull/9638)
|
||||
- Update GCP Cloud SQL service metadata to new format [(#9639)](https://github.com/prowler-cloud/prowler/pull/9639)
|
||||
- Update GCP Cloud Storage service metadata to new format [(#9640)](https://github.com/prowler-cloud/prowler/pull/9640)
|
||||
- Update GCP Compute Engine service metadata to new format [(#9641)](https://github.com/prowler-cloud/prowler/pull/9641)
|
||||
- Update GCP Dataproc service metadata to new format [(#9642)](https://github.com/prowler-cloud/prowler/pull/9642)
|
||||
- Update GCP DNS service metadata to new format [(#9643)](https://github.com/prowler-cloud/prowler/pull/9643)
|
||||
- Update GCP GCR service metadata to new format [(#9644)](https://github.com/prowler-cloud/prowler/pull/9644)
|
||||
- Update GCP GKE service metadata to new format [(#9645)](https://github.com/prowler-cloud/prowler/pull/9645)
|
||||
- Update GCP IAM service metadata to new format [(#9646)](https://github.com/prowler-cloud/prowler/pull/9646)
|
||||
- Update GCP KMS service metadata to new format [(#9647)](https://github.com/prowler-cloud/prowler/pull/9647)
|
||||
- Update GCP Logging service metadata to new format [(#9648)](https://github.com/prowler-cloud/prowler/pull/9648)
|
||||
|
||||
### 🔐 Security
|
||||
|
||||
- Bumped `py-ocsf-models` to 0.8.1 and `cryptography` to 44.0.3 [(#10059)](https://github.com/prowler-cloud/prowler/pull/10059)
|
||||
|
||||
---
|
||||
|
||||
## [5.18.3] (Prowler UNRELEASED)
|
||||
|
||||
### 🐞 Fixed
|
||||
|
||||
- `pip install prowler` failing on systems without C compiler due to `netifaces` transitive dependency from `openstacksdk` [(#10055)](https://github.com/prowler-cloud/prowler/pull/10055)
|
||||
|
||||
---
|
||||
|
||||
## [5.18.2] (Prowler v5.18.2)
|
||||
|
||||
### 🐞 Fixed
|
||||
|
||||
- `--repository` and `--organization` flags combined interaction in GitHub provider, qualifying unqualified repository names with organization [(#10001)](https://github.com/prowler-cloud/prowler/pull/10001)
|
||||
- HPACK library logging tokens in debug mode for Azure, M365, and Cloudflare providers [(#10010)](https://github.com/prowler-cloud/prowler/pull/10010)
|
||||
|
||||
---
|
||||
|
||||
## [5.18.0] (Prowler v5.18.0)
|
||||
|
||||
### 🚀 Added
|
||||
@@ -9,6 +67,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- `defender_zap_for_teams_enabled` check for M365 provider [(#9838)](https://github.com/prowler-cloud/prowler/pull/9838)
|
||||
- `compute_instance_suspended_without_persistent_disks` check for GCP provider [(#9747)](https://github.com/prowler-cloud/prowler/pull/9747)
|
||||
- `codebuild_project_webhook_filters_use_anchored_patterns` check for AWS provider to detect CodeBreach vulnerability [(#9840)](https://github.com/prowler-cloud/prowler/pull/9840)
|
||||
- `defender_atp_safe_attachments_policy_enabled` check for M365 provider [(#9837)](https://github.com/prowler-cloud/prowler/pull/9837)
|
||||
- `exchange_shared_mailbox_sign_in_disabled` check for M365 provider [(#9828)](https://github.com/prowler-cloud/prowler/pull/9828)
|
||||
- CloudTrail Timeline abstraction for querying resource modification history [(#9101)](https://github.com/prowler-cloud/prowler/pull/9101)
|
||||
- Cloudflare `--account-id` filter argument [(#9894)](https://github.com/prowler-cloud/prowler/pull/9894)
|
||||
@@ -17,6 +76,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- `OpenStack` documentation for the support in the CLI [(#9848)](https://github.com/prowler-cloud/prowler/pull/9848)
|
||||
- Add HIPAA compliance framework for the Azure provider [(#9957)](https://github.com/prowler-cloud/prowler/pull/9957)
|
||||
- Cloudflare provider credentials as constructor parameters (`api_token`, `api_key`, `api_email`) [(#9907)](https://github.com/prowler-cloud/prowler/pull/9907)
|
||||
- CIS 3.1 for the Oracle Cloud provider [(#9971)](https://github.com/prowler-cloud/prowler/pull/9971)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
@@ -36,7 +96,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- Update Azure Network service metadata to new format [(#9624)](https://github.com/prowler-cloud/prowler/pull/9624)
|
||||
- Update Azure Storage service metadata to new format [(#9628)](https://github.com/prowler-cloud/prowler/pull/9628)
|
||||
|
||||
### 🐛 Fixed
|
||||
### 🐞 Fixed
|
||||
|
||||
- Duplicated findings in `entra_user_with_vm_access_has_mfa` check when user has multiple VM access roles [(#9914)](https://github.com/prowler-cloud/prowler/pull/9914)
|
||||
- Jira integration failing with `INVALID_INPUT` error when sending findings with long resource UIDs exceeding 255-character summary limit [(#9926)](https://github.com/prowler-cloud/prowler/pull/9926)
|
||||
@@ -104,6 +164,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- Update Azure AI Search service metadata to new format [(#9087)](https://github.com/prowler-cloud/prowler/pull/9087)
|
||||
- Update Azure AKS service metadata to new format [(#9611)](https://github.com/prowler-cloud/prowler/pull/9611)
|
||||
- Update Azure API Management service metadata to new format [(#9612)](https://github.com/prowler-cloud/prowler/pull/9612)
|
||||
- Enhance AWS IAM privilege escalation detection with patterns from pathfinding.cloud library [(#9922)](https://github.com/prowler-cloud/prowler/pull/9922)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
+81
-7
@@ -8,6 +8,7 @@ from colorama import Fore, Style
|
||||
from colorama import init as colorama_init
|
||||
|
||||
from prowler.config.config import (
|
||||
EXTERNAL_TOOL_PROVIDERS,
|
||||
csv_file_suffix,
|
||||
get_available_compliance_frameworks,
|
||||
html_file_suffix,
|
||||
@@ -65,6 +66,11 @@ from prowler.lib.outputs.compliance.cis.cis_kubernetes import KubernetesCIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_m365 import M365CIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_oraclecloud import OracleCloudCIS
|
||||
from prowler.lib.outputs.compliance.compliance import display_compliance_table
|
||||
from prowler.lib.outputs.compliance.csa.csa_alibabacloud import AlibabaCloudCSA
|
||||
from prowler.lib.outputs.compliance.csa.csa_aws import AWSCSA
|
||||
from prowler.lib.outputs.compliance.csa.csa_azure import AzureCSA
|
||||
from prowler.lib.outputs.compliance.csa.csa_gcp import GCPCSA
|
||||
from prowler.lib.outputs.compliance.csa.csa_oraclecloud import OracleCloudCSA
|
||||
from prowler.lib.outputs.compliance.ens.ens_aws import AWSENS
|
||||
from prowler.lib.outputs.compliance.ens.ens_azure import AzureENS
|
||||
from prowler.lib.outputs.compliance.ens.ens_gcp import GCPENS
|
||||
@@ -119,6 +125,8 @@ from prowler.providers.common.quick_inventory import run_provider_quick_inventor
|
||||
from prowler.providers.gcp.models import GCPOutputOptions
|
||||
from prowler.providers.github.models import GithubOutputOptions
|
||||
from prowler.providers.iac.models import IACOutputOptions
|
||||
from prowler.providers.image.exceptions.exceptions import ImageBaseException
|
||||
from prowler.providers.image.models import ImageOutputOptions
|
||||
from prowler.providers.kubernetes.models import KubernetesOutputOptions
|
||||
from prowler.providers.llm.models import LLMOutputOptions
|
||||
from prowler.providers.m365.models import M365OutputOptions
|
||||
@@ -206,8 +214,8 @@ def prowler():
|
||||
# Load compliance frameworks
|
||||
logger.debug("Loading compliance frameworks from .json files")
|
||||
|
||||
# Skip compliance frameworks for IAC and LLM providers
|
||||
if provider != "iac" and provider != "llm":
|
||||
# Skip compliance frameworks for external-tool providers
|
||||
if provider not in EXTERNAL_TOOL_PROVIDERS:
|
||||
bulk_compliance_frameworks = Compliance.get_bulk(provider)
|
||||
# Complete checks metadata with the compliance framework specification
|
||||
bulk_checks_metadata = update_checks_metadata_with_compliance(
|
||||
@@ -264,8 +272,8 @@ def prowler():
|
||||
if not args.only_logs:
|
||||
global_provider.print_credentials()
|
||||
|
||||
# Skip service and check loading for IAC and LLM providers
|
||||
if provider != "iac" and provider != "llm":
|
||||
# Skip service and check loading for external-tool providers
|
||||
if provider not in EXTERNAL_TOOL_PROVIDERS:
|
||||
# Import custom checks from folder
|
||||
if checks_folder:
|
||||
custom_checks = parse_checks_from_folder(global_provider, checks_folder)
|
||||
@@ -352,6 +360,8 @@ def prowler():
|
||||
)
|
||||
elif provider == "iac":
|
||||
output_options = IACOutputOptions(args, bulk_checks_metadata)
|
||||
elif provider == "image":
|
||||
output_options = ImageOutputOptions(args, bulk_checks_metadata)
|
||||
elif provider == "llm":
|
||||
output_options = LLMOutputOptions(args, bulk_checks_metadata)
|
||||
elif provider == "oraclecloud":
|
||||
@@ -375,8 +385,8 @@ def prowler():
|
||||
# Execute checks
|
||||
findings = []
|
||||
|
||||
if provider == "iac" or provider == "llm":
|
||||
# For IAC and LLM providers, run the scan directly
|
||||
if provider in EXTERNAL_TOOL_PROVIDERS:
|
||||
# For external-tool providers, run the scan directly
|
||||
if provider == "llm":
|
||||
|
||||
def streaming_callback(findings_batch):
|
||||
@@ -386,7 +396,11 @@ def prowler():
|
||||
findings = global_provider.run_scan(streaming_callback=streaming_callback)
|
||||
else:
|
||||
# Original behavior for IAC or non-verbose LLM
|
||||
findings = global_provider.run()
|
||||
try:
|
||||
findings = global_provider.run()
|
||||
except ImageBaseException as error:
|
||||
logger.critical(f"{error}")
|
||||
sys.exit(1)
|
||||
# Note: IaC doesn't support granular progress tracking since Trivy runs as a black box
|
||||
# and returns all findings at once. Progress tracking would just be 0% → 100%.
|
||||
|
||||
@@ -626,6 +640,18 @@ def prowler():
|
||||
)
|
||||
generated_outputs["compliance"].append(c5)
|
||||
c5.batch_write_data_to_file()
|
||||
elif compliance_name == "csa_ccm_4.0_aws":
|
||||
filename = (
|
||||
f"{output_options.output_directory}/compliance/"
|
||||
f"{output_options.output_filename}_{compliance_name}.csv"
|
||||
)
|
||||
csa_ccm_4_0_aws = AWSCSA(
|
||||
findings=finding_outputs,
|
||||
compliance=bulk_compliance_frameworks[compliance_name],
|
||||
file_path=filename,
|
||||
)
|
||||
generated_outputs["compliance"].append(csa_ccm_4_0_aws)
|
||||
csa_ccm_4_0_aws.batch_write_data_to_file()
|
||||
else:
|
||||
filename = (
|
||||
f"{output_options.output_directory}/compliance/"
|
||||
@@ -729,6 +755,18 @@ def prowler():
|
||||
)
|
||||
generated_outputs["compliance"].append(c5_azure)
|
||||
c5_azure.batch_write_data_to_file()
|
||||
elif compliance_name == "csa_ccm_4.0_azure":
|
||||
filename = (
|
||||
f"{output_options.output_directory}/compliance/"
|
||||
f"{output_options.output_filename}_{compliance_name}.csv"
|
||||
)
|
||||
csa_ccm_4_0_azure = AzureCSA(
|
||||
findings=finding_outputs,
|
||||
compliance=bulk_compliance_frameworks[compliance_name],
|
||||
file_path=filename,
|
||||
)
|
||||
generated_outputs["compliance"].append(csa_ccm_4_0_azure)
|
||||
csa_ccm_4_0_azure.batch_write_data_to_file()
|
||||
else:
|
||||
filename = (
|
||||
f"{output_options.output_directory}/compliance/"
|
||||
@@ -832,6 +870,18 @@ def prowler():
|
||||
)
|
||||
generated_outputs["compliance"].append(c5_gcp)
|
||||
c5_gcp.batch_write_data_to_file()
|
||||
elif compliance_name == "csa_ccm_4.0_gcp":
|
||||
filename = (
|
||||
f"{output_options.output_directory}/compliance/"
|
||||
f"{output_options.output_filename}_{compliance_name}.csv"
|
||||
)
|
||||
csa_ccm_4_0_gcp = GCPCSA(
|
||||
findings=finding_outputs,
|
||||
compliance=bulk_compliance_frameworks[compliance_name],
|
||||
file_path=filename,
|
||||
)
|
||||
generated_outputs["compliance"].append(csa_ccm_4_0_gcp)
|
||||
csa_ccm_4_0_gcp.batch_write_data_to_file()
|
||||
else:
|
||||
filename = (
|
||||
f"{output_options.output_directory}/compliance/"
|
||||
@@ -1024,6 +1074,18 @@ def prowler():
|
||||
)
|
||||
generated_outputs["compliance"].append(cis)
|
||||
cis.batch_write_data_to_file()
|
||||
elif compliance_name == "csa_ccm_4.0_oraclecloud":
|
||||
filename = (
|
||||
f"{output_options.output_directory}/compliance/"
|
||||
f"{output_options.output_filename}_{compliance_name}.csv"
|
||||
)
|
||||
csa_ccm_4_0_oraclecloud = OracleCloudCSA(
|
||||
findings=finding_outputs,
|
||||
compliance=bulk_compliance_frameworks[compliance_name],
|
||||
file_path=filename,
|
||||
)
|
||||
generated_outputs["compliance"].append(csa_ccm_4_0_oraclecloud)
|
||||
csa_ccm_4_0_oraclecloud.batch_write_data_to_file()
|
||||
else:
|
||||
filename = (
|
||||
f"{output_options.output_directory}/compliance/"
|
||||
@@ -1052,6 +1114,18 @@ def prowler():
|
||||
)
|
||||
generated_outputs["compliance"].append(cis)
|
||||
cis.batch_write_data_to_file()
|
||||
elif compliance_name == "csa_ccm_4.0_alibabacloud":
|
||||
filename = (
|
||||
f"{output_options.output_directory}/compliance/"
|
||||
f"{output_options.output_filename}_{compliance_name}.csv"
|
||||
)
|
||||
csa_ccm_4_0_alibabacloud = AlibabaCloudCSA(
|
||||
findings=finding_outputs,
|
||||
compliance=bulk_compliance_frameworks[compliance_name],
|
||||
file_path=filename,
|
||||
)
|
||||
generated_outputs["compliance"].append(csa_ccm_4_0_alibabacloud)
|
||||
csa_ccm_4_0_alibabacloud.batch_write_data_to_file()
|
||||
elif compliance_name == "prowler_threatscore_alibabacloud":
|
||||
filename = (
|
||||
f"{output_options.output_directory}/compliance/"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -778,7 +778,9 @@
|
||||
{
|
||||
"Id": "1.3.9",
|
||||
"Description": "Confirm the domains an organization owns with a \"Verified\" badge.",
|
||||
"Checks": [],
|
||||
"Checks": [
|
||||
"organization_verified_badge"
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "1 Source Code",
|
||||
|
||||
@@ -318,7 +318,9 @@
|
||||
{
|
||||
"Id": "2.1.1",
|
||||
"Description": "Enabling Safe Links policy for Office applications allows URL's that exist inside of Office documents and email applications opened by Office, Office Online and Office mobile to be processed against Defender for Office time-of-click verification and rewritten if required.**Note:** E5 Licensing includes a number of Built-in Protection policies. When auditing policies note which policy you are viewing, and keep in mind CIS recommendations often extend the Default or Build-in Policies provided by MS. In order to **Pass** the highest priority policy must match all settings recommended.",
|
||||
"Checks": [],
|
||||
"Checks": [
|
||||
"defender_safelinks_policy_enabled"
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "2 Microsoft 365 Defender",
|
||||
@@ -385,7 +387,9 @@
|
||||
{
|
||||
"Id": "2.1.4",
|
||||
"Description": "The Safe Attachments policy helps protect users from malware in email attachments by scanning attachments for viruses, malware, and other malicious content. When an email attachment is received by a user, Safe Attachments will scan the attachment in a secure environment and provide a verdict on whether the attachment is safe or not.",
|
||||
"Checks": [],
|
||||
"Checks": [
|
||||
"defender_safe_attachments_policy_enabled"
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "2 Microsoft 365 Defender",
|
||||
@@ -406,7 +410,9 @@
|
||||
{
|
||||
"Id": "2.1.5",
|
||||
"Description": "Safe Attachments for SharePoint, OneDrive, and Microsoft Teams scans these services for malicious files.",
|
||||
"Checks": [],
|
||||
"Checks": [
|
||||
"defender_atp_safe_attachments_and_docs_configured"
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "2 Microsoft 365 Defender",
|
||||
|
||||
@@ -339,7 +339,9 @@
|
||||
{
|
||||
"Id": "2.1.1",
|
||||
"Description": "Safe Links for Office Applications is a feature in Microsoft 365 that provides URL scanning and rewriting of inbound email messages in mail flow, and time-of-click verification of URLs and links in email messages, other Microsoft 365 applications such as Teams, and other locations such as SharePoint Online. It can help protect organizations from malicious links used in phishing and other attacks.",
|
||||
"Checks": [],
|
||||
"Checks": [
|
||||
"defender_safelinks_policy_enabled"
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "2 Microsoft 365 Defender",
|
||||
@@ -404,7 +406,9 @@
|
||||
{
|
||||
"Id": "2.1.4",
|
||||
"Description": "The Safe Attachments policy helps protect users from malware in email attachments by scanning attachments for viruses, malware, and other malicious content. When an email attachment is received by a user, Safe Attachments will scan the attachment in a secure environment and provide a verdict on whether the attachment is safe or not.",
|
||||
"Checks": [],
|
||||
"Checks": [
|
||||
"defender_safe_attachments_policy_enabled"
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "2 Microsoft 365 Defender",
|
||||
@@ -425,7 +429,9 @@
|
||||
{
|
||||
"Id": "2.1.5",
|
||||
"Description": "Safe Attachments for SharePoint, OneDrive, and Microsoft Teams scans these services for malicious files.",
|
||||
"Checks": [],
|
||||
"Checks": [
|
||||
"defender_atp_safe_attachments_and_docs_configured"
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "2 Microsoft 365 Defender",
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
"defender_antiphishing_policy_configured",
|
||||
"defender_antispam_outbound_policy_configured",
|
||||
"defender_malware_policy_notifications_internal_users_malware_enabled",
|
||||
"defender_safelinks_policy_enabled",
|
||||
"defender_zap_for_teams_enabled",
|
||||
"entra_admin_users_phishing_resistant_mfa_enabled",
|
||||
"entra_identity_protection_sign_in_risk_enabled",
|
||||
@@ -692,6 +693,8 @@
|
||||
"defender_malware_policy_common_attachments_filter_enabled",
|
||||
"defender_malware_policy_comprehensive_attachments_filter_applied",
|
||||
"defender_malware_policy_notifications_internal_users_malware_enabled",
|
||||
"defender_safe_attachments_policy_enabled",
|
||||
"defender_safelinks_policy_enabled",
|
||||
"defender_zap_for_teams_enabled",
|
||||
"teams_external_domains_restricted",
|
||||
"teams_external_users_cannot_start_conversations"
|
||||
@@ -729,6 +732,7 @@
|
||||
],
|
||||
"Checks": [
|
||||
"defender_antiphishing_policy_configured",
|
||||
"defender_safelinks_policy_enabled",
|
||||
"entra_admin_users_phishing_resistant_mfa_enabled"
|
||||
]
|
||||
},
|
||||
@@ -833,10 +837,11 @@
|
||||
}
|
||||
],
|
||||
"Checks": [
|
||||
"teams_external_domains_restricted",
|
||||
"teams_external_users_cannot_start_conversations",
|
||||
"defender_safelinks_policy_enabled",
|
||||
"sharepoint_external_sharing_managed",
|
||||
"sharepoint_external_sharing_restricted",
|
||||
"sharepoint_external_sharing_managed"
|
||||
"teams_external_domains_restricted",
|
||||
"teams_external_users_cannot_start_conversations"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -38,7 +38,7 @@ class _MutableTimestamp:
|
||||
|
||||
timestamp = _MutableTimestamp(datetime.today())
|
||||
timestamp_utc = _MutableTimestamp(datetime.now(timezone.utc))
|
||||
prowler_version = "5.18.0"
|
||||
prowler_version = "5.19.0"
|
||||
html_logo_url = "https://github.com/prowler-cloud/prowler/"
|
||||
square_logo_img = "https://raw.githubusercontent.com/prowler-cloud/prowler/dc7d2d5aeb92fdf12e8604f42ef6472cd3e8e889/docs/img/prowler-logo-black.png"
|
||||
aws_logo = "https://user-images.githubusercontent.com/38561120/235953920-3e3fba08-0795-41dc-b480-9bea57db9f2e.png"
|
||||
@@ -63,8 +63,13 @@ class Provider(str, Enum):
|
||||
ORACLECLOUD = "oraclecloud"
|
||||
ALIBABACLOUD = "alibabacloud"
|
||||
OPENSTACK = "openstack"
|
||||
IMAGE = "image"
|
||||
|
||||
|
||||
# Providers that delegate scanning to an external tool (e.g. Trivy, promptfoo)
|
||||
# and bypass standard check/service loading.
|
||||
EXTERNAL_TOOL_PROVIDERS = frozenset({"iac", "llm", "image"})
|
||||
|
||||
# Compliance
|
||||
actual_directory = pathlib.Path(os.path.dirname(os.path.realpath(__file__)))
|
||||
|
||||
@@ -75,7 +80,10 @@ def get_available_compliance_frameworks(provider=None):
|
||||
if provider:
|
||||
providers = [provider]
|
||||
for provider in providers:
|
||||
with os.scandir(f"{actual_directory}/../compliance/{provider}") as files:
|
||||
compliance_dir = f"{actual_directory}/../compliance/{provider}"
|
||||
if not os.path.isdir(compliance_dir):
|
||||
continue
|
||||
with os.scandir(compliance_dir) as files:
|
||||
for file in files:
|
||||
if file.is_file() and file.name.endswith(".json"):
|
||||
available_compliance_frameworks.append(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user