Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91b86777ce |
No files matched your search
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "prowler-plugins",
|
||||
"description": "Prowler Cloud security and compliance for Claude",
|
||||
"description": "Prowler Cloud Security for Claude Code",
|
||||
"owner": {
|
||||
"name": "Prowler",
|
||||
"email": "support@prowler.com"
|
||||
@@ -9,7 +9,7 @@
|
||||
{
|
||||
"name": "prowler",
|
||||
"source": "./claude_plugins/prowler",
|
||||
"description": "Connect Claude to Prowler Cloud through the Prowler MCP server. Reads providers, scans, findings, compliance results and resources for AWS, Azure, GCP, Kubernetes, Microsoft 365, GitHub and the other providers listed at https://registry.prowler.com, and returns remediation guidance for failed checks. Writes are limited to Prowler Cloud itself: triggering scans, finding triage, mute rules and the mutelist, providers and integrations. Your cloud resources are not changed by the connector.",
|
||||
"description": "Prowler Cloud security and compliance skills for Claude, powered by the Prowler MCP server. Triage compliance gaps and remediate findings on AWS, Azure, GCP, Kubernetes, Microsoft 365, GitHub and many more providers listed at https://registry.prowler.com, plus custom providers, until your account meets the framework you choose.",
|
||||
"category": "security",
|
||||
"homepage": "https://prowler.com"
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ SENTRY_RELEASE=local
|
||||
# REO_DEV_CLIENT_ID=
|
||||
|
||||
#### Prowler release version ####
|
||||
NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v5.48.0
|
||||
NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v5.46.0
|
||||
|
||||
# Social login credentials
|
||||
SOCIAL_GOOGLE_OAUTH_CALLBACK_URL="${AUTH_URL}/api/auth/callback/google"
|
||||
|
||||
@@ -139,6 +139,10 @@ jobs:
|
||||
if: steps.check-changes.outputs.any_changed == 'true'
|
||||
run: pnpm run healthcheck
|
||||
|
||||
- name: Check product-tour alignment
|
||||
if: steps.check-changes.outputs.any_changed == 'true'
|
||||
run: pnpm run tour:check
|
||||
|
||||
- name: Run pnpm audit
|
||||
if: steps.check-changes.outputs.any_changed == 'true'
|
||||
run: pnpm run audit
|
||||
|
||||
@@ -164,7 +164,6 @@ GEMINI.md
|
||||
# AI Skills symlinks (generated by skills/setup.sh)
|
||||
.claude/skills
|
||||
.codex/skills
|
||||
.agents/skills
|
||||
.github/skills
|
||||
.gemini/skills
|
||||
|
||||
|
||||
@@ -95,10 +95,3 @@ ignore:
|
||||
package:
|
||||
name: zlib
|
||||
version: 1.3.2-r0
|
||||
|
||||
# Documented in .trivyignore.yaml: go-jose 4.1.5 compiled into the Trivy binary (0.76.1,
|
||||
# the latest release). Pinned to 4.1.5 so it stops matching with the next Trivy bump.
|
||||
- vulnerability: CVE-2026-116587
|
||||
package:
|
||||
name: github.com/go-jose/go-jose/v4
|
||||
version: v4.1.5
|
||||
@@ -226,11 +226,3 @@ vulnerabilities:
|
||||
purls:
|
||||
- "pkg:nuget/System.Security.Cryptography.Pkcs@10.0.0"
|
||||
expired_at: 2026-12-15
|
||||
|
||||
# go-jose 4.1.5 is compiled into the Trivy binary (usr/local/bin/trivy). Trivy merged the
|
||||
# 4.1.6 bump upstream (aquasecurity/trivy#11488) but 0.76.1 is still the latest release.
|
||||
# Bump TRIVY_VERSION and drop this entry once a release ships it.
|
||||
- id: CVE-2026-116587
|
||||
purls:
|
||||
- "pkg:golang/github.com/go-jose/go-jose/v4@v4.1.5"
|
||||
expired_at: 2026-11-20
|
||||
@@ -24,7 +24,7 @@ Use these skills for detailed patterns on-demand:
|
||||
| `jsonapi` | Strict JSON:API v1.1 spec compliance | [SKILL.md](skills/jsonapi/SKILL.md) |
|
||||
| `zod-4` | New API (z.email(), z.uuid()) | [SKILL.md](skills/zod-4/SKILL.md) |
|
||||
| `zustand-5` | Persist, selectors, slices | [SKILL.md](skills/zustand-5/SKILL.md) |
|
||||
| `ai-sdk-5` | Vercel AI SDK 6 (UIMessage, streaming), Lighthouse v1 | [SKILL.md](skills/ai-sdk-5/SKILL.md) |
|
||||
| `ai-sdk-5` | UIMessage, streaming, LangChain | [SKILL.md](skills/ai-sdk-5/SKILL.md) |
|
||||
| `vitest` | Unit testing, React Testing Library | [SKILL.md](skills/vitest/SKILL.md) |
|
||||
| `tdd` | Test-Driven Development workflow | [SKILL.md](skills/tdd/SKILL.md) |
|
||||
|
||||
@@ -40,13 +40,10 @@ Use these skills for detailed patterns on-demand:
|
||||
| `prowler-test-sdk` | SDK testing (pytest + moto) | [SKILL.md](skills/prowler-test-sdk/SKILL.md) |
|
||||
| `prowler-test-api` | API testing (pytest-django + RLS) | [SKILL.md](skills/prowler-test-api/SKILL.md) |
|
||||
| `prowler-test-ui` | E2E testing (Playwright) | [SKILL.md](skills/prowler-test-ui/SKILL.md) |
|
||||
| `prowler-test-mcp` | MCP server testing (pytest + FastMCP Client) | [SKILL.md](skills/prowler-test-mcp/SKILL.md) |
|
||||
| `prowler-compliance` | Compliance framework structure | [SKILL.md](skills/prowler-compliance/SKILL.md) |
|
||||
| `prowler-compliance-review` | Review compliance framework PRs | [SKILL.md](skills/prowler-compliance-review/SKILL.md) |
|
||||
| `prowler-provider` | Add new cloud providers | [SKILL.md](skills/prowler-provider/SKILL.md) |
|
||||
| `prowler-registry-artifact` | Package checks, compliance and providers as plug-ins; publish to Prowler Registry | [SKILL.md](skills/prowler-registry-artifact/SKILL.md) |
|
||||
| `prowler-readme-table` | Sync README provider/check counts table | [SKILL.md](skills/prowler-readme-table/SKILL.md) |
|
||||
| `prowler-changelog` | Changelog fragments (towncrier, `changelog.d/`) | [SKILL.md](skills/prowler-changelog/SKILL.md) |
|
||||
| `prowler-changelog` | Changelog entries (keepachangelog.com) | [SKILL.md](skills/prowler-changelog/SKILL.md) |
|
||||
| `prowler-ci` | CI checks and PR gates (GitHub Actions) | [SKILL.md](skills/prowler-ci/SKILL.md) |
|
||||
| `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) |
|
||||
@@ -54,9 +51,9 @@ Use these skills for detailed patterns on-demand:
|
||||
| `django-migration-psql` | Django migration best practices for PostgreSQL | [SKILL.md](skills/django-migration-psql/SKILL.md) |
|
||||
| `postgresql-indexing` | PostgreSQL indexing, EXPLAIN, monitoring, maintenance | [SKILL.md](skills/postgresql-indexing/SKILL.md) |
|
||||
| `prowler-attack-paths-query` | Create Attack Paths openCypher queries | [SKILL.md](skills/prowler-attack-paths-query/SKILL.md) |
|
||||
| `prowler-tour` | Keep product-tour definitions aligned with the UI | [SKILL.md](skills/prowler-tour/SKILL.md) |
|
||||
| `gh-aw` | GitHub Agentic Workflows (gh-aw) | [SKILL.md](skills/gh-aw/SKILL.md) |
|
||||
| `skill-creator` | Create new AI agent skills | [SKILL.md](skills/skill-creator/SKILL.md) |
|
||||
| `skill-sync` | Sync skill metadata to AGENTS.md Auto-invoke tables | [SKILL.md](skills/skill-sync/SKILL.md) |
|
||||
|
||||
### Auto-invoke Skills
|
||||
|
||||
@@ -65,7 +62,6 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
| Action | Skill |
|
||||
|--------|-------|
|
||||
| Add changelog entry for a PR or feature | `prowler-changelog` |
|
||||
| Add or edit changelog fragments in <component>/changelog.d/ | `prowler-changelog` |
|
||||
| Adding ConfigRequirements guardrails to compliance requirements | `prowler-compliance` |
|
||||
| Adding DRF pagination or permissions | `django-drf` |
|
||||
| Adding a compliance output formatter (per-provider class + table dispatcher) | `prowler-compliance` |
|
||||
@@ -73,10 +69,12 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
| Adding new providers | `prowler-provider` |
|
||||
| Adding privilege escalation detection queries | `prowler-attack-paths-query` |
|
||||
| Adding services to existing providers | `prowler-provider` |
|
||||
| Adding, updating, or removing a tour definition (*.tour.ts) | `prowler-tour` |
|
||||
| After creating/modifying a skill | `skill-sync` |
|
||||
| App Router / Server Actions | `nextjs-16` |
|
||||
| Auditing check-to-requirement mappings as a cloud auditor | `prowler-compliance` |
|
||||
| Building AI chat features | `ai-sdk-5` |
|
||||
| Changing button labels or section headings on a tour-covered page | `prowler-tour` |
|
||||
| Committing changes | `prowler-commit` |
|
||||
| Configuring MCP servers in agentic workflows | `gh-aw` |
|
||||
| Create PR that requires changelog entry | `prowler-changelog` |
|
||||
@@ -96,6 +94,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
| Creating/updating compliance frameworks | `prowler-compliance` |
|
||||
| Debug why a GitHub Actions job is failing | `prowler-ci` |
|
||||
| Debugging gh-aw compilation errors | `gh-aw` |
|
||||
| Editing a UI file containing data-tour-id attributes | `prowler-tour` |
|
||||
| Fill .github/pull_request_template.md (Context/Description/Steps to review/Checklist) | `prowler-pr` |
|
||||
| Fixing bug | `tdd` |
|
||||
| Fixing compliance JSON bugs (duplicate IDs, empty Section, stale refs) | `prowler-compliance` |
|
||||
@@ -110,10 +109,10 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
| Modifying API responses | `jsonapi` |
|
||||
| Modifying component | `tdd` |
|
||||
| Modifying gh-aw workflow frontmatter or safe-outputs | `gh-aw` |
|
||||
| Packaging checks, compliance frameworks or providers as external packages | `prowler-registry-artifact` |
|
||||
| Publishing artifacts to Prowler Registry | `prowler-registry-artifact` |
|
||||
| Refactoring code | `tdd` |
|
||||
| Regenerate AGENTS.md Auto-invoke tables (sync.sh) | `skill-sync` |
|
||||
| Renaming or removing a data-tour-id attribute value | `prowler-tour` |
|
||||
| Restructuring routes or layouts covered by a tour | `prowler-tour` |
|
||||
| Review PR requirements: template, title conventions, changelog gate | `prowler-pr` |
|
||||
| Review changelog format and conventions | `prowler-changelog` |
|
||||
| Reviewing JSON:API compliance | `jsonapi` |
|
||||
@@ -121,7 +120,6 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
| Reviewing compliance framework PRs | `prowler-compliance-review` |
|
||||
| Running makemigrations or pgmakemigrations | `django-migration-psql` |
|
||||
| Syncing compliance framework with upstream catalog | `prowler-compliance` |
|
||||
| Testing MCP tools or models | `prowler-test-mcp` |
|
||||
| Testing RLS tenant isolation | `prowler-test-api` |
|
||||
| Testing hooks or utilities | `vitest` |
|
||||
| Troubleshoot why a skill is missing from AGENTS.md auto-invoke | `skill-sync` |
|
||||
@@ -129,6 +127,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
| Understand PR title conventional-commit validation | `prowler-ci` |
|
||||
| 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 README.md provider statistics table | `prowler-readme-table` |
|
||||
| Updating checks, services, compliance, or categories count in README.md | `prowler-readme-table` |
|
||||
| Updating existing Attack Paths queries | `prowler-attack-paths-query` |
|
||||
@@ -141,7 +140,6 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
| Working with Tailwind classes | `tailwind-4` |
|
||||
| Writing Playwright E2E tests | `playwright` |
|
||||
| Writing Prowler API tests | `prowler-test-api` |
|
||||
| Writing Prowler MCP server tests | `prowler-test-mcp` |
|
||||
| Writing Prowler SDK tests | `prowler-test-sdk` |
|
||||
| Writing Prowler UI E2E tests | `prowler-test-ui` |
|
||||
| Writing Python tests with pytest | `pytest` |
|
||||
@@ -159,6 +157,14 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
|
||||
Prowler is an open-source cloud security assessment tool supporting AWS, Azure, GCP, Kubernetes, GitHub, M365, and more.
|
||||
|
||||
| Component | Location | Tech Stack |
|
||||
|-----------|----------|------------|
|
||||
| SDK | `prowler/` | Python 3.10+, uv |
|
||||
| API | `api/` | Django 5.1, DRF, Celery |
|
||||
| UI | `ui/` | Next.js 16, React 19, Tailwind 4 |
|
||||
| MCP Server | `mcp_server/` | FastMCP, Python 3.12+ |
|
||||
| Dashboard | `dashboard/` | Dash, Plotly |
|
||||
|
||||
---
|
||||
|
||||
## Python Development
|
||||
@@ -180,7 +186,7 @@ uv run prek run --all-files
|
||||
|
||||
Follow conventional-commit style: `<type>[scope]: <description>`
|
||||
|
||||
**Types:** `feat`, `fix`, `docs`, `chore`, `perf`, `refactor`, `style`, `test`, `build`, `ci`, `revert` (add `!` for breaking changes)
|
||||
**Types:** `feat`, `fix`, `docs`, `chore`, `perf`, `refactor`, `style`, `test`
|
||||
|
||||
Before creating a PR:
|
||||
1. Complete checklist in `.github/pull_request_template.md`
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
FROM python:3.12.16-slim-trixie@sha256:8523d6abeb48ceae0b7240d30c5808fc26cb79c1a635bacdf19cf3baecfbec07 AS build
|
||||
FROM python:3.12.15-slim-trixie@sha256:05cda9777409a9c3ffddd94a4c476b79f0769a0b4857f0c7ed9226b6800b0d6f AS build
|
||||
|
||||
LABEL maintainer="https://github.com/prowler-cloud/prowler"
|
||||
LABEL org.opencontainers.image.source="https://github.com/prowler-cloud/prowler"
|
||||
|
||||
ARG POWERSHELL_VERSION=7.5.13
|
||||
ARG POWERSHELL_VERSION=7.5.12
|
||||
ENV POWERSHELL_VERSION=${POWERSHELL_VERSION}
|
||||
# Opt out of PowerShell telemetry (Application Insights -> dc.services.visualstudio.com)
|
||||
ENV POWERSHELL_TELEMETRY_OPTOUT=1
|
||||
@@ -17,8 +17,8 @@ ENV ZIZMOR_VERSION=${ZIZMOR_VERSION}
|
||||
# Pinned here, not fetched with the artefact: a compromised release ships its own checksum.
|
||||
ARG TRIVY_SHA256_AMD64=c7cbe3137fb8a48a17574bede3dd6beb16742d1e9772929940fc90082c39d9c0
|
||||
ARG TRIVY_SHA256_ARM64=e174dff2a6dba5e3ae41f8d0537a6324405bd08132497340304c6b20e0f16a1f
|
||||
ARG POWERSHELL_SHA256_AMD64=e9256bfc6ac98fcbec97270e8a986577a7346a587837cc80d30595eef3c2546b
|
||||
ARG POWERSHELL_SHA256_ARM64=6a556353ccfb0a414b80322334eac29a540a398537d3cf8dcc3ecec9cd8abd66
|
||||
ARG POWERSHELL_SHA256_AMD64=db85ae1f45005ffd20e456890585167257151fa99406ccd7ab344f7cf3a766fd
|
||||
ARG POWERSHELL_SHA256_ARM64=29eb382cd510e4bd246902650ff6cf9f3b56f959d1bd0be75e0a1e425177c831
|
||||
ARG ZIZMOR_SHA256_AMD64=a8000f3c683319a523d3b20df0e75457ba591f049cfcbfa98966631b56733c03
|
||||
ARG ZIZMOR_SHA256_ARM64=d66e37ef8a375fb07939c630ebf9709a6e0f20242bdc3faf672a7ed97e0b768d
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ Every AWS provider scan will enqueue an Attack Paths ingestion job automatically
|
||||
| M365 | 144 | 10 | 9 | 10 | Official | UI, API, CLI |
|
||||
| OCI | 52 | 14 | 5 | 10 | Official | UI, API, CLI |
|
||||
| Alibaba Cloud | 63 | 9 | 6 | 9 | Official | UI, API, CLI |
|
||||
| Cloudflare | 43 | 5 | 3 | 9 | Official | UI, API, CLI |
|
||||
| Cloudflare | 29 | 3 | 2 | 5 | Official | UI, API, 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 | 1 | 8 | Official | UI, API, CLI |
|
||||
| LLM | [See `promptfoo` docs.](https://www.promptfoo.dev/docs/red-team/plugins/) | N/A | N/A | N/A | Official | CLI |
|
||||
|
||||
@@ -17,7 +17,6 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
| Action | Skill |
|
||||
|--------|-------|
|
||||
| Add changelog entry for a PR or feature | `prowler-changelog` |
|
||||
| Add or edit changelog fragments in <component>/changelog.d/ | `prowler-changelog` |
|
||||
| Adding DRF pagination or permissions | `django-drf` |
|
||||
| Adding indexes or constraints to database tables | `django-migration-psql` |
|
||||
| Adding privilege escalation detection queries | `prowler-attack-paths-query` |
|
||||
@@ -43,6 +42,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
| Reviewing JSON:API compliance | `jsonapi` |
|
||||
| Running makemigrations or pgmakemigrations | `django-migration-psql` |
|
||||
| Testing RLS tenant isolation | `prowler-test-api` |
|
||||
| Update CHANGELOG.md in any component | `prowler-changelog` |
|
||||
| Updating existing Attack Paths queries | `prowler-attack-paths-query` |
|
||||
| Working on task | `tdd` |
|
||||
| Writing Prowler API tests | `prowler-test-api` |
|
||||
@@ -97,20 +97,43 @@ Needs retry → Celery task
|
||||
|
||||
---
|
||||
|
||||
## TECH STACK
|
||||
|
||||
Django 5.1.x | DRF 3.15.x | djangorestframework-jsonapi 7.x | Celery 5.4.x | PostgreSQL 16 | pytest 8.x
|
||||
|
||||
---
|
||||
|
||||
## PROJECT STRUCTURE
|
||||
|
||||
```text
|
||||
api/src/backend/
|
||||
├── api/ # Main Django app
|
||||
│ ├── v1/ # API version 1 (views, serializers, urls)
|
||||
│ ├── models.py # Django models
|
||||
│ ├── filters.py # FilterSet classes
|
||||
│ ├── base_views.py # Base ViewSet classes
|
||||
│ ├── rls.py # Row-Level Security
|
||||
│ └── tests/ # Unit tests
|
||||
├── config/ # Django configuration
|
||||
└── tasks/ # Celery tasks
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## COMMANDS
|
||||
|
||||
```bash
|
||||
# Development (from api/src/backend)
|
||||
uv run python manage.py runserver
|
||||
# Development
|
||||
uv run python src/backend/manage.py runserver
|
||||
uv run celery -A config.celery worker -l INFO
|
||||
|
||||
# Database (from api/src/backend)
|
||||
uv run python manage.py makemigrations
|
||||
uv run python manage.py migrate --database admin
|
||||
# Database
|
||||
uv run python src/backend/manage.py makemigrations
|
||||
uv run python src/backend/manage.py migrate
|
||||
|
||||
# Testing (from api/src/backend) & Linting (from the repo root)
|
||||
# Testing & Linting
|
||||
uv run pytest -x --tb=short
|
||||
make lint-api
|
||||
uv run make lint
|
||||
```
|
||||
|
||||
---
|
||||
@@ -118,7 +141,7 @@ make lint-api
|
||||
## QA CHECKLIST
|
||||
|
||||
- [ ] `uv run pytest` passes
|
||||
- [ ] `make lint-api` passes (from the repo root)
|
||||
- [ ] `uv run make lint` passes
|
||||
- [ ] Migrations created if models changed
|
||||
- [ ] New endpoints have `@extend_schema` decorators
|
||||
- [ ] RLS properly applied for tenant data
|
||||
|
||||
@@ -4,14 +4,6 @@ All notable changes to the **Prowler API** are documented in this file.
|
||||
|
||||
<!-- changelog: release notes start -->
|
||||
|
||||
## [1.48.0] (Prowler v5.47.0)
|
||||
|
||||
### 🔐 Security
|
||||
|
||||
- pymongo to 4.18.3, dnspython to 2.9.0 and oauthlib to 4.0.0 in the API container image, with django-allauth from 65.15.0 to 65.19.7 because earlier releases cap oauthlib below 4, patching the BSON decoding and DNS compression pointer denial of service advisories and the OAuth device flow token disclosure [(#13185)](https://github.com/prowler-cloud/prowler/pull/13185)
|
||||
|
||||
---
|
||||
|
||||
## [1.47.0] (Prowler v5.46.0)
|
||||
|
||||
### 🐞 Fixed
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
FROM python:3.12.16-slim-trixie@sha256:8523d6abeb48ceae0b7240d30c5808fc26cb79c1a635bacdf19cf3baecfbec07 AS build
|
||||
FROM python:3.12.15-slim-trixie@sha256:05cda9777409a9c3ffddd94a4c476b79f0769a0b4857f0c7ed9226b6800b0d6f AS build
|
||||
|
||||
LABEL maintainer="https://github.com/prowler-cloud/api"
|
||||
|
||||
ARG POWERSHELL_VERSION=7.5.13
|
||||
ARG POWERSHELL_VERSION=7.5.12
|
||||
ENV POWERSHELL_VERSION=${POWERSHELL_VERSION}
|
||||
# Opt out of PowerShell telemetry (Application Insights -> dc.services.visualstudio.com)
|
||||
ENV POWERSHELL_TELEMETRY_OPTOUT=1
|
||||
@@ -16,8 +16,8 @@ ENV ZIZMOR_VERSION=${ZIZMOR_VERSION}
|
||||
# Pinned here, not fetched with the artefact: a compromised release ships its own checksum.
|
||||
ARG TRIVY_SHA256_AMD64=c7cbe3137fb8a48a17574bede3dd6beb16742d1e9772929940fc90082c39d9c0
|
||||
ARG TRIVY_SHA256_ARM64=e174dff2a6dba5e3ae41f8d0537a6324405bd08132497340304c6b20e0f16a1f
|
||||
ARG POWERSHELL_SHA256_AMD64=e9256bfc6ac98fcbec97270e8a986577a7346a587837cc80d30595eef3c2546b
|
||||
ARG POWERSHELL_SHA256_ARM64=6a556353ccfb0a414b80322334eac29a540a398537d3cf8dcc3ecec9cd8abd66
|
||||
ARG POWERSHELL_SHA256_AMD64=db85ae1f45005ffd20e456890585167257151fa99406ccd7ab344f7cf3a766fd
|
||||
ARG POWERSHELL_SHA256_ARM64=29eb382cd510e4bd246902650ff6cf9f3b56f959d1bd0be75e0a1e425177c831
|
||||
ARG ZIZMOR_SHA256_AMD64=a8000f3c683319a523d3b20df0e75457ba591f049cfcbfa98966631b56733c03
|
||||
ARG ZIZMOR_SHA256_ARM64=d66e37ef8a375fb07939c630ebf9709a6e0f20242bdc3faf672a7ed97e0b768d
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
PowerShell from 7.5.12 to 7.5.13 in the API container image, bundling .NET runtime 9.0.22
|
||||
@@ -1 +0,0 @@
|
||||
Python base image from 3.12.15 to 3.12.16 in the API container image, patching CVE-2026-115557
|
||||
@@ -1 +0,0 @@
|
||||
h2 from 4.3.0 to 4.4.1 and werkzeug from 3.1.7 to 3.1.9, patching the duplicate Host header request smuggling and the Windows device name bypass in safe_join, plus pylint 4.0.9 and filelock 4.2.1 in the development dependencies
|
||||
@@ -1 +0,0 @@
|
||||
pyasn1 to 0.6.5, patching the ASN.1 decoding denial of service advisories
|
||||
@@ -4,10 +4,10 @@ dev = [
|
||||
"coverage==7.5.4",
|
||||
"django-silk==5.3.2",
|
||||
"docker==7.1.0",
|
||||
"filelock==4.2.1",
|
||||
"filelock==3.20.3",
|
||||
"freezegun==1.5.1",
|
||||
"mypy==1.10.1",
|
||||
"pylint==4.0.9",
|
||||
"pylint==3.2.5",
|
||||
"pytest==9.0.3",
|
||||
"pytest-cov==5.0.0",
|
||||
"pytest-django==4.8.0",
|
||||
@@ -26,7 +26,7 @@ dependencies = [
|
||||
"celery (==5.6.2)",
|
||||
"dj-rest-auth[with_social,jwt] (==7.0.1)",
|
||||
"django (==5.2.17)",
|
||||
"django-allauth[saml] (==65.19.7)",
|
||||
"django-allauth[saml] (==65.15.0)",
|
||||
"django-celery-beat (==2.9.0)",
|
||||
"django-celery-results (==2.6.0)",
|
||||
"django-cors-headers==4.4.0",
|
||||
@@ -45,14 +45,14 @@ dependencies = [
|
||||
"gunicorn==26.0.0",
|
||||
"uvloop==0.22.1",
|
||||
"lxml==6.1.0",
|
||||
"prowler @ git+https://github.com/prowler-cloud/prowler.git@master",
|
||||
"prowler @ git+https://github.com/prowler-cloud/prowler.git@v5.46",
|
||||
"psycopg2-binary==2.9.9",
|
||||
"pytest-celery[redis] (==1.3.0)",
|
||||
"sentry-sdk[django] (==2.56.0)",
|
||||
"uuid6==2024.7.10",
|
||||
"openai (==1.109.1)",
|
||||
"xmlsec==1.3.17",
|
||||
"h2 (==4.4.1)",
|
||||
"h2 (==4.3.0)",
|
||||
"markdown (==3.10.2)",
|
||||
"drf-simple-apikey (==2.2.1)",
|
||||
"matplotlib (==3.10.8)",
|
||||
@@ -60,7 +60,7 @@ dependencies = [
|
||||
"neo4j (==6.1.0)",
|
||||
"cartography (==0.138.1)",
|
||||
"gevent (==25.9.1)",
|
||||
"werkzeug (==3.1.9)",
|
||||
"werkzeug (==3.1.7)",
|
||||
"sqlparse (==0.6.0)",
|
||||
"fonttools (==4.62.1)",
|
||||
"uvicorn-worker (==0.4.0)"
|
||||
@@ -71,7 +71,7 @@ name = "prowler-api"
|
||||
package-mode = false
|
||||
# Needed for the SDK compatibility
|
||||
requires-python = ">=3.11,<3.13"
|
||||
version = "1.49.0"
|
||||
version = "1.47.0"
|
||||
|
||||
# Shared ruff baseline (kept in sync with mcp_server/pyproject.toml).
|
||||
# target-version tracks this project's lowest supported Python.
|
||||
@@ -142,7 +142,7 @@ constraint-dependencies = [
|
||||
"apscheduler==3.11.2",
|
||||
"argcomplete==3.5.3",
|
||||
"asgiref==3.11.0",
|
||||
"astroid==4.0.4",
|
||||
"astroid==3.2.4",
|
||||
"async-timeout==5.0.1",
|
||||
"attrs==25.4.0",
|
||||
"authlib==1.6.12",
|
||||
@@ -223,7 +223,7 @@ constraint-dependencies = [
|
||||
"distro==1.9.0",
|
||||
"dj-rest-auth==7.0.1",
|
||||
"django==5.2.17",
|
||||
"django-allauth==65.19.7",
|
||||
"django-allauth==65.15.0",
|
||||
"django-celery-beat==2.9.0",
|
||||
"django-celery-results==2.6.0",
|
||||
"django-cors-headers==4.4.0",
|
||||
@@ -237,7 +237,7 @@ constraint-dependencies = [
|
||||
"djangorestframework==3.18.3",
|
||||
"djangorestframework-jsonapi==7.0.2",
|
||||
"djangorestframework-simplejwt==5.5.1",
|
||||
"dnspython==2.9.0",
|
||||
"dnspython==2.8.0",
|
||||
"docker==7.1.0",
|
||||
"dogpile-cache==1.5.0",
|
||||
"dparse==0.6.4",
|
||||
@@ -251,7 +251,7 @@ constraint-dependencies = [
|
||||
"durationpy==0.10",
|
||||
"email-validator==2.2.0",
|
||||
"execnet==2.1.2",
|
||||
"filelock==4.2.1",
|
||||
"filelock==3.20.3",
|
||||
"flask==3.1.3",
|
||||
"fonttools==4.62.1",
|
||||
"freezegun==1.5.1",
|
||||
@@ -275,8 +275,8 @@ constraint-dependencies = [
|
||||
"grpcio-status==1.76.0",
|
||||
"gunicorn==26.0.0",
|
||||
"h11==0.16.0",
|
||||
"h2==4.4.1",
|
||||
"hpack==4.2.0",
|
||||
"h2==4.3.0",
|
||||
"hpack==4.1.0",
|
||||
"httpcore==1.0.9",
|
||||
"httplib2==0.32.0",
|
||||
"httpx==0.28.1",
|
||||
@@ -337,7 +337,7 @@ constraint-dependencies = [
|
||||
"nest-asyncio==1.6.0",
|
||||
"nltk==3.9.4",
|
||||
"numpy==2.2.6",
|
||||
"oauthlib==4.0.0",
|
||||
"oauthlib==3.3.1",
|
||||
"oci==2.184.1",
|
||||
"openai==1.109.1",
|
||||
"openstacksdk==4.2.0",
|
||||
@@ -367,7 +367,7 @@ constraint-dependencies = [
|
||||
"py-deviceid==0.1.1",
|
||||
"py-iam-expand==0.3.0",
|
||||
"py-ocsf-models==0.10.0",
|
||||
"pyasn1==0.6.5",
|
||||
"pyasn1==0.6.4",
|
||||
"pyasn1-modules==0.4.2",
|
||||
"pycodestyle==2.14.0",
|
||||
"pycparser==3.0",
|
||||
@@ -376,7 +376,7 @@ constraint-dependencies = [
|
||||
"pygithub==2.8.0",
|
||||
"pygments==2.20.0",
|
||||
"pyjwt==2.14.0",
|
||||
"pylint==4.0.9",
|
||||
"pylint==3.2.5",
|
||||
"pymsalruntime==0.18.1",
|
||||
"pynacl==1.6.2",
|
||||
"pyopenssl==26.4.0",
|
||||
@@ -447,7 +447,7 @@ constraint-dependencies = [
|
||||
"vulture==2.14",
|
||||
"wcwidth==0.5.3",
|
||||
"websocket-client==1.9.0",
|
||||
"werkzeug==3.1.9",
|
||||
"werkzeug==3.1.7",
|
||||
"workos==8.3.0",
|
||||
"wrapt==1.17.3",
|
||||
"xlsxwriter==3.2.9",
|
||||
@@ -485,7 +485,7 @@ override-dependencies = [
|
||||
"okta==3.4.2",
|
||||
# huaweicloudsdkcore (via prowler) pins pymongo==4.15.1 exactly; CVE-2026-96748 and
|
||||
# CVE-2026-96749 are fixed in 4.18.2. Only bson types are used, so the override is safe.
|
||||
"pymongo==4.18.3",
|
||||
"pymongo==4.18.2",
|
||||
# prowler requires cryptography==50.0.0. Two api-only dependencies still cap it below
|
||||
# 49 and cannot move yet: msal, pinned exactly by azure-cli-core (2.83.0 -> 1.35.0b1,
|
||||
# 2.89.1 -> 1.36.0, both <49; cartography needs azure-cli-core), and workos 8.3.0
|
||||
@@ -502,7 +502,5 @@ override-dependencies = [
|
||||
"microsoft-kiota-serialization-multipart==1.9.10",
|
||||
"microsoft-kiota-serialization-text==1.9.10",
|
||||
"dulwich==1.2.9",
|
||||
# Same trailing-rev case as dulwich: h2 4.4.1 patches GHSA-6hr6-w5qg-qmwg.
|
||||
"h2==4.4.1",
|
||||
"pyjwt[crypto]==2.14.0"
|
||||
]
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Prowler API
|
||||
version: 1.49.0
|
||||
version: 1.47.0
|
||||
description: |-
|
||||
Prowler API specification.
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ constraints = [
|
||||
{ name = "apscheduler", specifier = "==3.11.2" },
|
||||
{ name = "argcomplete", specifier = "==3.5.3" },
|
||||
{ name = "asgiref", specifier = "==3.11.0" },
|
||||
{ name = "astroid", specifier = "==4.0.4" },
|
||||
{ name = "astroid", specifier = "==3.2.4" },
|
||||
{ name = "async-timeout", specifier = "==5.0.1" },
|
||||
{ name = "attrs", specifier = "==25.4.0" },
|
||||
{ name = "authlib", specifier = "==1.6.12" },
|
||||
@@ -139,7 +139,7 @@ constraints = [
|
||||
{ name = "distro", specifier = "==1.9.0" },
|
||||
{ name = "dj-rest-auth", specifier = "==7.0.1" },
|
||||
{ name = "django", specifier = "==5.2.17" },
|
||||
{ name = "django-allauth", specifier = "==65.19.7" },
|
||||
{ name = "django-allauth", specifier = "==65.15.0" },
|
||||
{ name = "django-celery-beat", specifier = "==2.9.0" },
|
||||
{ name = "django-celery-results", specifier = "==2.6.0" },
|
||||
{ name = "django-cors-headers", specifier = "==4.4.0" },
|
||||
@@ -153,7 +153,7 @@ constraints = [
|
||||
{ name = "djangorestframework", specifier = "==3.18.3" },
|
||||
{ name = "djangorestframework-jsonapi", specifier = "==7.0.2" },
|
||||
{ name = "djangorestframework-simplejwt", specifier = "==5.5.1" },
|
||||
{ name = "dnspython", specifier = "==2.9.0" },
|
||||
{ name = "dnspython", specifier = "==2.8.0" },
|
||||
{ name = "docker", specifier = "==7.1.0" },
|
||||
{ name = "dogpile-cache", specifier = "==1.5.0" },
|
||||
{ name = "dparse", specifier = "==0.6.4" },
|
||||
@@ -167,7 +167,7 @@ constraints = [
|
||||
{ name = "durationpy", specifier = "==0.10" },
|
||||
{ name = "email-validator", specifier = "==2.2.0" },
|
||||
{ name = "execnet", specifier = "==2.1.2" },
|
||||
{ name = "filelock", specifier = "==4.2.1" },
|
||||
{ name = "filelock", specifier = "==3.20.3" },
|
||||
{ name = "flask", specifier = "==3.1.3" },
|
||||
{ name = "fonttools", specifier = "==4.62.1" },
|
||||
{ name = "freezegun", specifier = "==1.5.1" },
|
||||
@@ -191,8 +191,8 @@ constraints = [
|
||||
{ name = "grpcio-status", specifier = "==1.76.0" },
|
||||
{ name = "gunicorn", specifier = "==26.0.0" },
|
||||
{ name = "h11", specifier = "==0.16.0" },
|
||||
{ name = "h2", specifier = "==4.4.1" },
|
||||
{ name = "hpack", specifier = "==4.2.0" },
|
||||
{ name = "h2", specifier = "==4.3.0" },
|
||||
{ name = "hpack", specifier = "==4.1.0" },
|
||||
{ name = "httpcore", specifier = "==1.0.9" },
|
||||
{ name = "httplib2", specifier = "==0.32.0" },
|
||||
{ name = "httpx", specifier = "==0.28.1" },
|
||||
@@ -253,7 +253,7 @@ constraints = [
|
||||
{ name = "nest-asyncio", specifier = "==1.6.0" },
|
||||
{ name = "nltk", specifier = "==3.9.4" },
|
||||
{ name = "numpy", specifier = "==2.2.6" },
|
||||
{ name = "oauthlib", specifier = "==4.0.0" },
|
||||
{ name = "oauthlib", specifier = "==3.3.1" },
|
||||
{ name = "oci", specifier = "==2.184.1" },
|
||||
{ name = "openai", specifier = "==1.109.1" },
|
||||
{ name = "openstacksdk", specifier = "==4.2.0" },
|
||||
@@ -283,7 +283,7 @@ constraints = [
|
||||
{ name = "py-deviceid", specifier = "==0.1.1" },
|
||||
{ name = "py-iam-expand", specifier = "==0.3.0" },
|
||||
{ name = "py-ocsf-models", specifier = "==0.10.0" },
|
||||
{ name = "pyasn1", specifier = "==0.6.5" },
|
||||
{ name = "pyasn1", specifier = "==0.6.4" },
|
||||
{ name = "pyasn1-modules", specifier = "==0.4.2" },
|
||||
{ name = "pycodestyle", specifier = "==2.14.0" },
|
||||
{ name = "pycparser", specifier = "==3.0" },
|
||||
@@ -292,7 +292,7 @@ constraints = [
|
||||
{ name = "pygithub", specifier = "==2.8.0" },
|
||||
{ name = "pygments", specifier = "==2.20.0" },
|
||||
{ name = "pyjwt", specifier = "==2.14.0" },
|
||||
{ name = "pylint", specifier = "==4.0.9" },
|
||||
{ name = "pylint", specifier = "==3.2.5" },
|
||||
{ name = "pymsalruntime", specifier = "==0.18.1" },
|
||||
{ name = "pynacl", specifier = "==1.6.2" },
|
||||
{ name = "pyopenssl", specifier = "==26.4.0" },
|
||||
@@ -363,7 +363,7 @@ constraints = [
|
||||
{ name = "vulture", specifier = "==2.14" },
|
||||
{ name = "wcwidth", specifier = "==0.5.3" },
|
||||
{ name = "websocket-client", specifier = "==1.9.0" },
|
||||
{ name = "werkzeug", specifier = "==3.1.9" },
|
||||
{ name = "werkzeug", specifier = "==3.1.7" },
|
||||
{ name = "workos", specifier = "==8.3.0" },
|
||||
{ name = "wrapt", specifier = "==1.17.3" },
|
||||
{ name = "xlsxwriter", specifier = "==3.2.9" },
|
||||
@@ -379,7 +379,6 @@ overrides = [
|
||||
{ name = "azure-mgmt-containerservice", specifier = "==34.1.0" },
|
||||
{ name = "cryptography", specifier = "==50.0.0" },
|
||||
{ name = "dulwich", specifier = "==1.2.9" },
|
||||
{ name = "h2", specifier = "==4.4.1" },
|
||||
{ name = "microsoft-kiota-abstractions", specifier = "==1.9.10" },
|
||||
{ name = "microsoft-kiota-authentication-azure", specifier = "==1.9.10" },
|
||||
{ name = "microsoft-kiota-http", specifier = "==1.9.10" },
|
||||
@@ -389,7 +388,7 @@ overrides = [
|
||||
{ name = "microsoft-kiota-serialization-text", specifier = "==1.9.10" },
|
||||
{ name = "okta", specifier = "==3.4.2" },
|
||||
{ name = "pyjwt", extras = ["crypto"], specifier = "==2.14.0" },
|
||||
{ name = "pymongo", specifier = "==4.18.3" },
|
||||
{ name = "pymongo", specifier = "==4.18.2" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1024,11 +1023,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "astroid"
|
||||
version = "4.0.4"
|
||||
version = "3.2.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/07/63/0adf26577da5eff6eb7a177876c1cfa213856be9926a000f65c4add9692b/astroid-4.0.4.tar.gz", hash = "sha256:986fed8bcf79fb82c78b18a53352a0b287a73817d6dbcfba3162da36667c49a0", size = 406358, upload-time = "2026-02-07T23:35:07.509Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9e/53/1067e1113ecaf58312357f2cd93063674924119d80d173adc3f6f2387aa2/astroid-3.2.4.tar.gz", hash = "sha256:0e14202810b30da1b735827f78f5157be2bbd4a7a59b7707ca0bfc2fb4c0063a", size = 397576, upload-time = "2024-07-20T12:57:43.26Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/cf/1c5f42b110e57bc5502eb80dbc3b03d256926062519224835ef08134f1f9/astroid-4.0.4-py3-none-any.whl", hash = "sha256:52f39653876c7dec3e3afd4c2696920e05c83832b9737afc21928f2d2eb7a753", size = 276445, upload-time = "2026-02-07T23:35:05.344Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/96/b32bbbb46170a1c8b8b1f28c794202e25cfe743565e9d3469b8eb1e0cc05/astroid-3.2.4-py3-none-any.whl", hash = "sha256:413658a61eeca6202a59231abb473f932038fbcbf1666587f66d482083413a25", size = 276348, upload-time = "2024-07-20T12:57:40.886Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1230,6 +1229,20 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/32/b3/8ec1268082f4d20cc8bf723a1a8e6b9e330bcc338a4dbcee9c7737e9dc1c/azure_mgmt_authorization-4.0.0-py3-none-any.whl", hash = "sha256:d8feeb3842e6ddf1a370963ca4f61fb6edc124e8997b807dd025bc9b2379cd1a", size = 1072620, upload-time = "2023-07-25T04:47:49.26Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "azure-mgmt-cognitiveservices"
|
||||
version = "14.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "azure-mgmt-core" },
|
||||
{ name = "msrest" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/fa/8e/9fcfdd507413a2536c5458b40942705ea8d74fe4e17f05fd1c32bb0225a9/azure_mgmt_cognitiveservices-14.1.0.tar.gz", hash = "sha256:915191374d0adb443863c20aaea2c9f3b9d558a849ac2b78f152249262fdcaf8", size = 184444, upload-time = "2025-10-24T07:28:14.229Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/25/ed6bbc01a03991255dd22aa41091360d225f1be20c88710af0f4a6c27459/azure_mgmt_cognitiveservices-14.1.0-py3-none-any.whl", hash = "sha256:3c0eecc00d183842a11d754f4f5c3328ff86f2d6c0a2b81b28dd7e073680258e", size = 290096, upload-time = "2025-10-24T07:28:15.766Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "azure-mgmt-compute"
|
||||
version = "34.0.0"
|
||||
@@ -2346,15 +2359,15 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "django-allauth"
|
||||
version = "65.19.7"
|
||||
version = "65.15.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "asgiref" },
|
||||
{ name = "django" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c4/33/7c8f8fc85f4ee644ee3acb20c1fe4d04516298ab5903f812e1556b65f947/django_allauth-65.19.7.tar.gz", hash = "sha256:c7749551b659ca954e483f6f634cd0c262d65dd8144f5219b3a31cba0426e981", size = 2296178, upload-time = "2026-10-01T12:35:24.152Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/84/c1/d3385f4c3169c1d6eea3c63aed0f36af51478c1d72e46db12bb1a08f8034/django_allauth-65.15.0.tar.gz", hash = "sha256:b404d48cf0c3ee14dacc834c541f30adedba2ff1c433980ecc494d6cb0b395a8", size = 2215709, upload-time = "2026-03-09T13:51:28.675Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/30/c4/a42cc4439b18b8d2767f8c54999e011b9f620a478806ed265baed7c3dc01/django_allauth-65.19.7-py3-none-any.whl", hash = "sha256:8899377f38afabf10445c9ee2f808a730304ca8aecc540657d51a8b3928283d6", size = 2076429, upload-time = "2026-10-01T12:35:20.844Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/b8/c8411339171bd8bc075c09ef190fb42195e9a2149e5c5026e094fe62fce0/django_allauth-65.15.0-py3-none-any.whl", hash = "sha256:ad9fc49c49a9368eaa5bb95456b76e2a4f377b3c6862ee8443507816578c098d", size = 2022994, upload-time = "2026-03-09T13:51:19.711Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
@@ -2551,11 +2564,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "dnspython"
|
||||
version = "2.9.0"
|
||||
version = "2.8.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ef/4a/50822184bd67cc6493f0fb6a880749158fcd31ab3fa07409acfd91f9fc85/dnspython-2.9.0.tar.gz", hash = "sha256:b44dc6b18f07a8b1c56676a19fbfdb5209415b046a9cece286baafa87ff3f7f1", size = 423560, upload-time = "2026-10-09T00:07:24.352Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/10/02/cdcc9b7c051786a103c3b09e1003a82fa0c66bcb91ffbdabcfbf7b4163b9/dnspython-2.9.0-py3-none-any.whl", hash = "sha256:9a4aedb833c3c1b49214d04d44d3032ab7a9135f7c1d29a549b4ff78fd82fda9", size = 354822, upload-time = "2026-10-09T00:07:22.622Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2738,11 +2751,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "filelock"
|
||||
version = "4.2.1"
|
||||
version = "3.20.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d5/98/771d8ca889f220d7d7e352addf500666368f0fd081c6080a83767580c6e4/filelock-4.2.1.tar.gz", hash = "sha256:c4c937ccac2a813cee448e662a56366cfb374c0f8702e75f295c412cc1c5d5a3", size = 650997, upload-time = "2026-10-17T16:48:14.435Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload-time = "2026-01-09T17:55:05.421Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/28/00/db89d339bc4ecdc8087fa7b8607ba22ffc27bf96286f340c9620bea428b3/filelock-4.2.1-py3-none-any.whl", hash = "sha256:7be2662e9e826b9bba28afc0f843a123280d799a2ea44bb5d35ccec67905ae44", size = 162455, upload-time = "2026-10-17T16:48:12.937Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload-time = "2026-01-09T17:55:04.334Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3333,24 +3346,24 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "4.4.1"
|
||||
version = "4.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "hpack" },
|
||||
{ name = "hyperframe" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e7/85/7c366e69d84c17bb778fe41419e1fbcce3033d5b7ce29bbffff0a98b859f/h2-4.4.1.tar.gz", hash = "sha256:4e866ffb1a869ae14dd9b5e6beb5c24a13da0495ad72b65925ded182521c1516", size = 2157281, upload-time = "2026-08-03T11:45:09.509Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1d/17/afa56379f94ad0fe8defd37d6eb3f89a25404ffc71d4d848893d270325fc/h2-4.3.0.tar.gz", hash = "sha256:6c59efe4323fa18b47a632221a1888bd7fde6249819beda254aeca909f221bf1", size = 2152026, upload-time = "2025-08-23T18:12:19.778Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl", hash = "sha256:0e25f1462b23c9cb82d9eb02e28bc706dac2a68cb457c6a0d74d63c8a2a5d0e6", size = 62636, upload-time = "2026-08-03T11:44:59.164Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl", hash = "sha256:c438f029a25f7945c69e0ccf0fb951dc3f73a5f6412981daee861431b70e2bdd", size = 61779, upload-time = "2025-08-23T18:12:17.779Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hpack"
|
||||
version = "4.2.0"
|
||||
version = "4.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/26/5b/fcabf6028144a8723726318b07a32c2f3314acdff6265743cf08a344b18e/hpack-4.2.0.tar.gz", hash = "sha256:0895cfa3b5531fc65fe439c05eb65144f123bf7a394fcaa56aa423548d8e45c0", size = 51300, upload-time = "2026-06-23T18:34:46.667Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/2c/48/71de9ed269fdae9c8057e5a4c0aa7402e8bb16f2c6e90b3aa53327b113f8/hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca", size = 51276, upload-time = "2025-01-22T21:44:58.347Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl", hash = "sha256:858ac0b02280fa582b5080d68db0899c62a80375e0e5413a74970c5e518b6986", size = 34246, upload-time = "2026-06-23T18:34:45.472Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357, upload-time = "2025-01-22T21:44:56.92Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3504,6 +3517,17 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/18/7d/721f162c46e3de604a73674223bf6c6bc6cf7ade25b3751a71288f4dd122/huaweicloudsdkrds-3.1.204-py3-none-any.whl", hash = "sha256:a790b5b3c457a608e5679c101f463b4d037dd9a8a66f6e46144a9e5a4b37780f", size = 1626906, upload-time = "2026-07-09T09:04:06.936Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "huaweicloudsdksmn"
|
||||
version = "3.1.204"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "huaweicloudsdkcore" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/5d/c0de47d011f1932c9c0ddf669c238d9fad01653d438d38203703526799d7/huaweicloudsdksmn-3.1.204-py3-none-any.whl", hash = "sha256:b0818ea9293e27458c8fa1d2da021c98006cbf9ce01cf17a0f1df598c4da3a6c", size = 323674, upload-time = "2026-07-09T09:04:24.804Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "huaweicloudsdkvpc"
|
||||
version = "3.1.204"
|
||||
@@ -4420,11 +4444,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "oauthlib"
|
||||
version = "4.0.0"
|
||||
version = "3.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7a/d8/a1bcc8ba112a627f8ffbdc212a78ce18d3ac07e91a5ca65d27918eee25a1/oauthlib-4.0.0.tar.gz", hash = "sha256:efb274799819440f95b4ab3b818869f1ce9ae26c5beacba0201d1a1b76b54f86", size = 187232, upload-time = "2026-09-28T06:01:18.77Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918, upload-time = "2025-06-19T22:48:08.269Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/f4/78229a1066068ca14fc60fb26cf7381cabe4382261392b90e5f9552722d4/oauthlib-4.0.0-py3-none-any.whl", hash = "sha256:624c28c13a0a59cabf9747dfa52af63be3e512a7f2714df16e91b5b3a145e6cd", size = 159715, upload-time = "2026-09-28T06:01:17.008Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4843,8 +4867,8 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "prowler"
|
||||
version = "5.41.0"
|
||||
source = { git = "https://github.com/prowler-cloud/prowler.git?rev=master#f05a490cd74a2c0f11a5d66d8ce29d03fa5c64a2" }
|
||||
version = "5.46.0"
|
||||
source = { git = "https://github.com/prowler-cloud/prowler.git?rev=v5.46#fdb1bd619345b6f92bd6a7f8906fa5e6684a90a4" }
|
||||
dependencies = [
|
||||
{ name = "alibabacloud-actiontrail20200706" },
|
||||
{ name = "alibabacloud-credentials" },
|
||||
@@ -4865,6 +4889,7 @@ dependencies = [
|
||||
{ name = "azure-mgmt-apimanagement" },
|
||||
{ name = "azure-mgmt-applicationinsights" },
|
||||
{ name = "azure-mgmt-authorization" },
|
||||
{ name = "azure-mgmt-cognitiveservices" },
|
||||
{ name = "azure-mgmt-compute" },
|
||||
{ name = "azure-mgmt-containerregistry" },
|
||||
{ name = "azure-mgmt-containerservice" },
|
||||
@@ -4908,6 +4933,7 @@ dependencies = [
|
||||
{ name = "huaweicloudsdkkms" },
|
||||
{ name = "huaweicloudsdkobs" },
|
||||
{ name = "huaweicloudsdkrds" },
|
||||
{ name = "huaweicloudsdksmn" },
|
||||
{ name = "huaweicloudsdkvpc" },
|
||||
{ name = "huaweicloudsdkwaf" },
|
||||
{ name = "jsonschema" },
|
||||
@@ -4946,7 +4972,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "prowler-api"
|
||||
version = "1.49.0"
|
||||
version = "1.47.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "cartography" },
|
||||
@@ -5021,7 +5047,7 @@ requires-dist = [
|
||||
{ name = "defusedxml", specifier = "==0.7.1" },
|
||||
{ name = "dj-rest-auth", extras = ["with-social", "jwt"], specifier = "==7.0.1" },
|
||||
{ name = "django", specifier = "==5.2.17" },
|
||||
{ name = "django-allauth", extras = ["saml"], specifier = "==65.19.7" },
|
||||
{ name = "django-allauth", extras = ["saml"], specifier = "==65.15.0" },
|
||||
{ name = "django-celery-beat", specifier = "==2.9.0" },
|
||||
{ name = "django-celery-results", specifier = "==2.6.0" },
|
||||
{ name = "django-cors-headers", specifier = "==4.4.0" },
|
||||
@@ -5040,13 +5066,13 @@ requires-dist = [
|
||||
{ name = "fonttools", specifier = "==4.62.1" },
|
||||
{ name = "gevent", specifier = "==25.9.1" },
|
||||
{ name = "gunicorn", specifier = "==26.0.0" },
|
||||
{ name = "h2", specifier = "==4.4.1" },
|
||||
{ name = "h2", specifier = "==4.3.0" },
|
||||
{ name = "lxml", specifier = "==6.1.0" },
|
||||
{ name = "markdown", specifier = "==3.10.2" },
|
||||
{ name = "matplotlib", specifier = "==3.10.8" },
|
||||
{ name = "neo4j", specifier = "==6.1.0" },
|
||||
{ name = "openai", specifier = "==1.109.1" },
|
||||
{ name = "prowler", git = "https://github.com/prowler-cloud/prowler.git?rev=master" },
|
||||
{ name = "prowler", git = "https://github.com/prowler-cloud/prowler.git?rev=v5.46" },
|
||||
{ name = "psycopg2-binary", specifier = "==2.9.9" },
|
||||
{ name = "pytest-celery", extras = ["redis"], specifier = "==1.3.0" },
|
||||
{ name = "reportlab", specifier = "==4.4.10" },
|
||||
@@ -5055,7 +5081,7 @@ requires-dist = [
|
||||
{ name = "uuid6", specifier = "==2024.7.10" },
|
||||
{ name = "uvicorn-worker", specifier = "==0.4.0" },
|
||||
{ name = "uvloop", specifier = "==0.22.1" },
|
||||
{ name = "werkzeug", specifier = "==3.1.9" },
|
||||
{ name = "werkzeug", specifier = "==3.1.7" },
|
||||
{ name = "xmlsec", specifier = "==1.3.17" },
|
||||
]
|
||||
|
||||
@@ -5065,11 +5091,11 @@ dev = [
|
||||
{ name = "coverage", specifier = "==7.5.4" },
|
||||
{ name = "django-silk", specifier = "==5.3.2" },
|
||||
{ name = "docker", specifier = "==7.1.0" },
|
||||
{ name = "filelock", specifier = "==4.2.1" },
|
||||
{ name = "filelock", specifier = "==3.20.3" },
|
||||
{ name = "freezegun", specifier = "==1.5.1" },
|
||||
{ name = "mypy", specifier = "==1.10.1" },
|
||||
{ name = "prek", specifier = "==0.3.9" },
|
||||
{ name = "pylint", specifier = "==4.0.9" },
|
||||
{ name = "pylint", specifier = "==3.2.5" },
|
||||
{ name = "pytest", specifier = "==9.0.3" },
|
||||
{ name = "pytest-cov", specifier = "==5.0.0" },
|
||||
{ name = "pytest-django", specifier = "==4.8.0" },
|
||||
@@ -5175,11 +5201,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "pyasn1"
|
||||
version = "0.6.5"
|
||||
version = "0.6.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/88/7e/3c0da41061a2021cac7cd524fd57092adbe5b515e8bf9005702e366802e2/pyasn1-0.6.5.tar.gz", hash = "sha256:6b11616a6bcf3a40e635f082bb232fa57b5e0dd7f517bd7ddd69ec3794508a47", size = 155152, upload-time = "2026-10-27T06:32:49.125Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a4/9a/23310166d960def5897e91fe20e5b724601b02a22e84ba1f94232c0b7f67/pyasn1-0.6.4.tar.gz", hash = "sha256:9c447d8431c947fe4c8febc4ed9e760bc29011a5b01e5c74b67025bd9fb8ce81", size = 151262, upload-time = "2026-07-09T01:12:33.988Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/19/1f/3eefd5c84c35cae44549ce1c7f7e58f7945b34f5a6bce07a135438522073/pyasn1-0.6.5-py3-none-any.whl", hash = "sha256:4017b0fce125096b8573b39c989fdb1a4b19cf761e683398184550fea0e66587", size = 84807, upload-time = "2026-10-27T06:32:48.045Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl", hash = "sha256:deda9277cfd454080ec40b207fb6df82206a3a2688735233cdcd8d3d565f088b", size = 84410, upload-time = "2026-07-09T01:12:32.92Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5354,7 +5380,7 @@ crypto = [
|
||||
|
||||
[[package]]
|
||||
name = "pylint"
|
||||
version = "4.0.9"
|
||||
version = "3.2.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "astroid" },
|
||||
@@ -5365,40 +5391,40 @@ dependencies = [
|
||||
{ name = "platformdirs" },
|
||||
{ name = "tomlkit" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e0/5e/d5ec2c861010cf8577a3e5baaf2405fdf1004f1657d9245c4efb006c1dfd/pylint-4.0.9.tar.gz", hash = "sha256:6f1305780229ae720e89b8aff2b3ff857cbb268fbab98c8b586960267667ad34", size = 1604187, upload-time = "2026-09-23T15:26:43.144Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/df/f3/e552877a02574b7919855a8d1f372591e67d276ea880c079968e7b3ba353/pylint-3.2.5.tar.gz", hash = "sha256:e9b7171e242dcc6ebd0aaa7540481d1a72860748a0a7816b8fe6cf6c80a6fe7e", size = 1508793, upload-time = "2024-06-28T13:10:26.915Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/66/46/12e94ae1f9db89152223bdb17920b12c79e94ac51e19dce1da9fb63627b0/pylint-4.0.9-py3-none-any.whl", hash = "sha256:c4ba5bbaf1e70ecf05f08cd7d6091ea04824b79a2b2d9f5b10dc25fc34cb1124", size = 542068, upload-time = "2026-09-23T15:26:41.626Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/ff/7f52c1461d8ceaefa989d2700a027f84427879bb7571145bbffdec5d5f4a/pylint-3.2.5-py3-none-any.whl", hash = "sha256:32cd6c042b5004b8e857d727708720c54a676d1e22917cf1a2df9b4d4868abd6", size = 519603, upload-time = "2024-06-28T13:10:23.526Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pymongo"
|
||||
version = "4.18.3"
|
||||
version = "4.18.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "dnspython" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/42/d8/2421a5ae0d6dcdaad2a0fb75d4071eaede9f764e73b829c62b6185c3ee6b/pymongo-4.18.3.tar.gz", hash = "sha256:5dd6e659b6014288a1c53458929402a58f44a032e6f29bcef44e7477c5268e48", size = 2747872, upload-time = "2026-10-08T19:44:08.343Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/dc/04/455039b475bb8afa5af9b8c363fb773a45d898016f04ee40c1c75003a3f9/pymongo-4.18.2.tar.gz", hash = "sha256:1bd4321cc63c06954953eae9eb8fb5d9075296b96c0e3ed34ccb91a0dcce31a5", size = 2746691, upload-time = "2026-09-24T16:59:59.472Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/58/a6/63bdeb527d98998b8ea2c667eca00d48f22dd42af281e9a2d7090632d54d/pymongo-4.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f00cb357d7cc7f2798116e2377732a409c43a6dc882f0241eafed7ffed50655", size = 818805, upload-time = "2026-10-08T19:42:09.125Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/e9/35602972d9fa98b894d1e5feef4db2f5d275298430e99b54b39f01125efa/pymongo-4.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3fe2ef9c6eb6b75689e10b20a3d8119da87302481b0a7029f9399b35142adfd8", size = 819303, upload-time = "2026-10-08T19:42:10.749Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/e1/468f2c69b32565c93a56623535f248b091cf52e83c3509fa4b791427889f/pymongo-4.18.3-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ba6090d4bed582c97e38fa818c0a2b7443f203cb28882900b433ff713465f158", size = 1023754, upload-time = "2026-10-08T19:42:12.683Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/24/8af75e8af2427a47cfcc996444df934990ac4890d855f2ec064409d8b94b/pymongo-4.18.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f9903d0a089317422f52bbc25f5827e6656f0c42c43ed7d799bd02748e79a1", size = 1031920, upload-time = "2026-10-08T19:42:14.443Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/78/d0/96fa79fb7cb47e6f09e58ccbe1a726330b5d052f395b65d57e286849ed43/pymongo-4.18.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ac9bf2304c2b092ccf04261ab0cddb7fd65df1cc1ae0fa57312b03396c00d28c", size = 1053859, upload-time = "2026-10-08T19:42:16.315Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/99/1b3f48bd3580c53e4a0e89bdc8cd8c15af94ca944f9de96582cb3ebfa5d0/pymongo-4.18.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5f37095428af3042f6bb1ebe269fedcbb645d9e0642b274e1cff026d3979500b", size = 1047418, upload-time = "2026-10-08T19:42:18.023Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/1e/ab9148b15dcefd3d02852a65e4ac3a1df86248c227dd532dc53b41f33697/pymongo-4.18.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:16ade5053ab6c712fd25d3f878e38441b169d607d1326d708844a131911d029f", size = 1033358, upload-time = "2026-10-08T19:42:19.746Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/39/93/bbbd0edfa33b10e7a86c864478dbb12163c946c142fd1e7b1bd0b6490353/pymongo-4.18.3-cp311-cp311-win32.whl", hash = "sha256:463c09e2cc208a65d35a1af3c613360cff6d58c8aef652273da07250bb214dba", size = 814425, upload-time = "2026-10-08T19:42:21.501Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/13/7515f91ed9e80968cc5dc9321ac97fafde07afb75123adb9e294f50c8a10/pymongo-4.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:1d7d0474012def6113c224b167aae661b926ac3b788219426830013ea25acd33", size = 821387, upload-time = "2026-10-08T19:42:23.349Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/59/f54d5ee7d95ec4ed1f31bff014a0f61caa3e888d7a89a0585f3eb4be164b/pymongo-4.18.3-cp311-cp311-win_arm64.whl", hash = "sha256:83dff65baa6f2423857598ffc371d7412fa4d2a07c618bdc8d5053ade65de664", size = 817697, upload-time = "2026-10-08T19:42:25.128Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/d5/4775a2891396ad125545e23b3024adae4bfac9553b70c924f1f372269dbf/pymongo-4.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ea78719dd05de3a919a52b94bec790c0d0cb7d07d2f7271711832664502a0782", size = 819374, upload-time = "2026-10-08T19:42:26.931Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/0b/89ad56f43c3da6cbde100699f6b99528e78eba3c6740d8dad4ea2516aa45/pymongo-4.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6029d14761ba7243e6c5e464592013b519ad4dd3e4cfb75ddec39f4b5910711b", size = 819694, upload-time = "2026-10-08T19:42:28.76Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/b4/b68ffc205441b0a6d36d6299e35e063a5d0d3264fd685428920e1f82b634/pymongo-4.18.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9536fb3820f721290f03ad07472ec2266d8f364f91de628679a7146c9c1dbe35", size = 1040136, upload-time = "2026-10-08T19:42:30.852Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/40/e779ff3d9165316c35a2f9742a42b9c3e3a678e9e2a9f6fe4128b7c551eb/pymongo-4.18.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e461bfca4861057929efa4215730b28b93b2adb4d07828d0b65475755bbf63f5", size = 1051430, upload-time = "2026-10-08T19:42:32.533Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/9b/443ee038a739cc65a75f2078c9ef725c1cb4881545d2e9d7941c46f64a6c/pymongo-4.18.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1fef248623ed5e7406902a68d49dc0b1db434f19489f8d2fc9fe512c3c08bb1", size = 1075464, upload-time = "2026-10-08T19:42:34.325Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/4b/d80518f675cd4c1215b770444bb83002454574dae0e69760af10703ed1e8/pymongo-4.18.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:213eaed8fc4f2b0f9c84323a229dea699e01e18b8fb39723f430123b6ee77813", size = 1069046, upload-time = "2026-10-08T19:42:36.105Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/77/f2e9648c62e423c3b9dab1e16491a6c33250487c819e5c75784b35d16047/pymongo-4.18.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa6f363ff648bf061335d2190dd580cbf465b1308a7e6acb992d128d6a16a3bd", size = 1050321, upload-time = "2026-10-08T19:42:38.052Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/e4/3236e3a87b29fc4c502ad7dd1521c20d4a29faf1db6fde6ae94d05c5ec27/pymongo-4.18.3-cp312-cp312-win32.whl", hash = "sha256:28ba8cae86ea02d7ffdf0eea81be69be80d35d6a4a3eba4dc436d3194341805a", size = 815300, upload-time = "2026-10-08T19:42:40.062Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/18/3fa9d86ba32386c02ea991f10875a6a066dd5e5d80790243be3c141b0e73/pymongo-4.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:dc8ccf72b76c99a6b9fd05f8b89fe4a693128c5cfdba70f70e5792a6a563f6b0", size = 822079, upload-time = "2026-10-08T19:42:42.089Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/50/65a7cefd3891b77994841992b2c5b59394667df64ef21377b8ac7ecdef47/pymongo-4.18.3-cp312-cp312-win_arm64.whl", hash = "sha256:4a1f7c7dc1d554449a1695d897eb42b6080a2f1e9ccd81385dfa00204979c54d", size = 817935, upload-time = "2026-10-08T19:42:43.98Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/01/e8358c562ce4e3255035f16eed43a6f77669b0779f3aa918362c670e869f/pymongo-4.18.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257519b59d8509a950b21c4a626e5295b3ad4397c12ec47e6e93353c49236145", size = 818562, upload-time = "2026-09-24T16:58:20.602Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/18/48a9e7f44a35560284b36bba24622a959ec1dd940e7c4f7cd308cfdba756/pymongo-4.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:845b890622e7a2f031140f9cb1c0f266c1baa876ea359f7e51d0c38112cb3c6e", size = 819081, upload-time = "2026-09-24T16:58:22.043Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/24/2d9c0bb5649f262257f507b03f84419ac1254e94894cd493bda87fb935e1/pymongo-4.18.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a746f7e183c6d48aba6152d9f333e3bae2e8b6b00fac7abe69d4bdb3d10915c8", size = 1023284, upload-time = "2026-09-24T16:58:23.437Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/40/af888435ce8e3ae1e1a201b87fb397aa91e3ce115bb1bb3999197f2b9b72/pymongo-4.18.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf9d13d812e55d406080b8ec3d5b9ef8eb2279bac32529e4f7b41cfefd5340e2", size = 1031549, upload-time = "2026-09-24T16:58:24.869Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/66/f5053862cbeddf37b3184870fa179a3e9d9e27e668c720bb7ab28b65b753/pymongo-4.18.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:930e8bcdf781a73d3df05976f5eaca1193102571cb91726e30009d64878ef8ce", size = 1054025, upload-time = "2026-09-24T16:58:26.229Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/29/4d7c9d7cb718ea7bbac56465de3aea5f79d1266683c16bdcd40e77746530/pymongo-4.18.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a695bd34d1e942eca93a186e679be196e288370f1a203e383b2187c06349e348", size = 1046337, upload-time = "2026-09-24T16:58:27.822Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/aa/c18c564883c5b2616744d1ee7ab073a3b4045aaa4bbbd524105448d4f630/pymongo-4.18.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d95e339e94b82950bfd62ec9ff8fea9bc8dfd9db0940e9134d1647d366560df5", size = 1032845, upload-time = "2026-09-24T16:58:29.518Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/16/f8a1cb7ac3f1c2c45649f18b7cb398779b4b45e1954bbfcb9317c74c744d/pymongo-4.18.2-cp311-cp311-win32.whl", hash = "sha256:2e2a3b816270c493f6645a168150ecbfb19a0bd0d9d3b56be728a847954da717", size = 814203, upload-time = "2026-09-24T16:58:30.924Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/53/e9d6350ea753b7a72d0346fb2c8e0c589e0eb443b5041989f3b4ea52ce55/pymongo-4.18.2-cp311-cp311-win_amd64.whl", hash = "sha256:812b4ad5fe577f829cdb4e39a5601025b9cd7f2e3f8cd373cd5ab64ce78b0fb0", size = 821265, upload-time = "2026-09-24T16:58:32.479Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/2a/be9693eca04bb6f53f3bdb027220a210bd429c7bf902b79538471849297e/pymongo-4.18.2-cp311-cp311-win_arm64.whl", hash = "sha256:c36cadbc3a7712575900c6f50cdf24ebe2b376b6ad643cb5df1b3dce93447eae", size = 815444, upload-time = "2026-09-24T16:58:34.212Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/eb/995ec978741cfc56a29223ec0806976218b95d79a516d9b719c984ead130/pymongo-4.18.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:78a3b324407ba7228a57f207e175efc40341c1312d1e7df2d4ad8141ff6d8e00", size = 819057, upload-time = "2026-09-24T16:58:35.844Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/e4/5a166bbac7f6e620cfb75b0640e793dd3ce69423a1f89cf6a0bfc588c107/pymongo-4.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:498187b5171d5efa87291b30e4cbf1e9849929c02bc436e95a3d01ff19e49f42", size = 819448, upload-time = "2026-09-24T16:58:37.221Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/c8/82194d9a1387a56cac996901f92ea6a25ae817622ee32d15c986638b263f/pymongo-4.18.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2c003646d3fa5db4e835483fc29018eb06d8c637cf69f676ffbb3f0734005220", size = 1039602, upload-time = "2026-09-24T16:58:38.821Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/06/628f93f15f269d8a1ea20a024083e67871f722876a33992aec5525a6c6c4/pymongo-4.18.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c743347143298252948e038f768ea6f71b71ef8a85b7cf0dc13b734e072f74da", size = 1050746, upload-time = "2026-09-24T16:58:40.322Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/93/58ea76803128651ec9c732b59b8c1eb73d511c085c2e5786da3289d4015c/pymongo-4.18.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:09e6afa68001433c42925a258b57f2ceccb95c73fe8920452e147a82d90c1ae9", size = 1075681, upload-time = "2026-09-24T16:58:41.722Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/6d/702ee4593420e2a8ceb169ece6394f0bb9fc2e8e8d8101e99f2468ed6d0d/pymongo-4.18.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8d3445caeeb47dc64bf416dc03e0b3bfcf3b60a109dec355a563aa62c135cb33", size = 1068235, upload-time = "2026-09-24T16:58:43.228Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/92/a02a4108ca4faf05bca394d65dcebc7b84b0248cff23aa89927c81a0d5dd/pymongo-4.18.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecde9e735e1f86559e0a71a5bbec671e59a35549bfd8c60968d9f032b05013de", size = 1049896, upload-time = "2026-09-24T16:58:44.914Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6e/93/65ef17eecdd86c153f7907b2d490d85eb655d3a5eb35a8494e7e09376353/pymongo-4.18.2-cp312-cp312-win32.whl", hash = "sha256:a463c3fc072655b7fe9e9ded4601876bef7f1df98f6f3faeed07fa7f11309fff", size = 815124, upload-time = "2026-09-24T16:58:46.39Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/cc/fd66aa9d8956e8269ea63b2977a7fd38fbec45795d38b8067bfafc98992f/pymongo-4.18.2-cp312-cp312-win_amd64.whl", hash = "sha256:cbb67901ba9b6334fa94643d66587a30ffe5be05061af287364e6b5f7d239dc5", size = 821996, upload-time = "2026-09-24T16:58:47.769Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/21/983d340cfe226c987014f1caf9568b176cbd7f25dd87536379a609e6371e/pymongo-4.18.2-cp312-cp312-win_arm64.whl", hash = "sha256:94c5e0fe9af4c05f382ae7c4addd0255a8ddcc91b3d2a6bc09b34230cb28290b", size = 815707, upload-time = "2026-09-24T16:58:49.493Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6472,14 +6498,14 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "werkzeug"
|
||||
version = "3.1.9"
|
||||
version = "3.1.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markupsafe" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a4/34/4dd12fc8bb7d61c91467ec3efe415ffa7d5456f799954b40c5bbaeae470e/werkzeug-3.1.9.tar.gz", hash = "sha256:55ca7c70a75689be937aa27f8ff4b018f06ff4838fc73045560bf0f5a1291060", size = 940188, upload-time = "2026-09-27T18:33:41.637Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b5/43/76ded108b296a49f52de6bac5192ca1c4be84e886f9b5c9ba8427d9694fd/werkzeug-3.1.7.tar.gz", hash = "sha256:fb8c01fe6ab13b9b7cdb46892b99b1d66754e1d7ab8e542e865ec13f526b5351", size = 875700, upload-time = "2026-03-24T01:08:07.687Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/38/df03f564f43cec2684823f3cccae1a652ee7face1cbaa76fb223096e64d7/werkzeug-3.1.9-py3-none-any.whl", hash = "sha256:6392e50c78460ba618e5b21f08a71f59c99ce99cdc6cf6e3dd7e6ccca8754fab", size = 228700, upload-time = "2026-09-27T18:33:39.685Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/b2/0bba9bbb4596d2d2f285a16c2ab04118f6b957d8441566e1abb892e6a6b2/werkzeug-3.1.7-py3-none-any.whl", hash = "sha256:4b314d81163a3e1a169b6a0be2a000a0e204e8873c5de6586f453c55688d422f", size = 226295, upload-time = "2026-03-24T01:08:06.133Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
"name": "prowler",
|
||||
"displayName": "Prowler Cloud",
|
||||
"version": "0.1.0",
|
||||
"description": "Connect Claude to Prowler Cloud through the Prowler MCP server. Reads providers, scans, findings, compliance results and resources for AWS, Azure, GCP, Kubernetes, Microsoft 365, GitHub and the other providers listed at https://registry.prowler.com, and returns remediation guidance for failed checks. Writes are limited to Prowler Cloud itself: triggering scans, finding triage, mute rules and the mutelist, providers and integrations. Your cloud resources are not changed by the connector.",
|
||||
"description": "Prowler Cloud security and compliance skills for Claude, powered by the Prowler MCP server. Triage compliance gaps and remediate findings on AWS, Azure, GCP, Kubernetes, Microsoft 365, GitHub and many more providers listed at https://registry.prowler.com, plus custom providers, until your account meets the framework you choose.",
|
||||
"author": {
|
||||
"name": "Prowler",
|
||||
"email": "support@prowler.com",
|
||||
"url": "https://prowler.com"
|
||||
},
|
||||
"homepage": "https://docs.prowler.com/user-guide/ai-agents",
|
||||
"homepage": "https://docs.prowler.com",
|
||||
"repository": "https://github.com/prowler-cloud/prowler",
|
||||
"license": "Apache-2.0",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Prowler Cloud
|
||||
# Prowler for Claude Code
|
||||
|
||||
Cloud security and compliance in Claude, powered by the [Prowler MCP server](https://docs.prowler.com/projects/prowler-mcp/). Claude reads your Prowler Cloud providers, scans, findings and compliance results, returns Prowler's remediation guidance for each failed check, and manages triage and mute state. The connector never changes your cloud resources: any fix is applied with your own tools (Terraform, a cloud CLI or the console), and only after you approve it.
|
||||
End-to-end cloud security and compliance from inside [Claude Code](https://www.claude.com/product/claude-code), powered by the [Prowler MCP server](https://docs.prowler.com/projects/prowler-mcp/). The plugin lets Claude walk a Prowler Cloud-connected account through a compliance assessment and remediate findings until the chosen security or industry framework is compliant.
|
||||
|
||||
> **Preview**: this plugin is under active development. Report issues at <https://github.com/prowler-cloud/prowler/issues> or join the [Slack community](https://goto.prowler.com/slack).
|
||||
|
||||
@@ -70,7 +70,7 @@ Claude tracks progress in a markdown report under `.prowler/` at your project ro
|
||||
|
||||
## Data and privacy
|
||||
|
||||
The plugin stores nothing itself. It connects to the Prowler MCP server at `https://mcp.prowler.com/mcp`, authenticating with the API key you provide (kept in your system keychain and sent only as a bearer token to that server). Through it, Claude reads your Prowler Cloud providers, scans, findings, compliance results and resource metadata. It can also write to Prowler Cloud: trigger scans, set finding triage, create mute rules, replace the mutelist, and add or remove providers and integrations. Mutes and deletions are marked as destructive, so your client can ask before running them. It also queries the public Prowler Hub and Prowler documentation. The remediation report is written locally under `.prowler/` in your project. Nothing is sent to any other service. See the [Prowler privacy policy](https://prowler.com/privacy-policy) for how Prowler Cloud handles account data.
|
||||
The plugin stores nothing itself. It connects to the Prowler MCP server at `https://mcp.prowler.com/mcp`, authenticating with the API key you provide (kept in your system keychain and sent only as a bearer token to that server). Through it, Claude reads your Prowler Cloud providers, scans, findings, compliance results and resource metadata, and can trigger scans. It also queries the public Prowler Hub and Prowler documentation. The remediation report is written locally under `.prowler/` in your project. Nothing is sent to any other service. See the [Prowler privacy policy](https://prowler.com/privacy-policy) for how Prowler Cloud handles account data.
|
||||
|
||||
## Uninstalling
|
||||
|
||||
|
||||
@@ -1,41 +1,28 @@
|
||||
# Importing Packages
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
import click
|
||||
import dash
|
||||
import dash_bootstrap_components as dbc
|
||||
from colorama import init as colorama_init
|
||||
from colorama import Fore, Style
|
||||
from dash import dcc, html
|
||||
from dash.dependencies import Input, Output
|
||||
|
||||
from dashboard.config import folder_path_overview
|
||||
from dashboard.lib.startup import (
|
||||
install_server_ready_hook,
|
||||
silence_dash_running_line,
|
||||
)
|
||||
from prowler.lib.banner import (
|
||||
print_dashboard_banner,
|
||||
print_dashboard_loading,
|
||||
print_dashboard_promotion,
|
||||
)
|
||||
from prowler.config.config import orange_color
|
||||
from prowler.lib.banner import print_banner
|
||||
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
# Honour the NO_COLOR convention: the dashboard parser has no --no-color flag.
|
||||
if os.environ.get("NO_COLOR"):
|
||||
colorama_init(strip=True)
|
||||
|
||||
# Compact startup output: identity, one hand-off block and the CSV directory.
|
||||
# The local URL is printed by ``install_server_ready_hook`` once the server is
|
||||
# actually listening, so nothing claims to be ready before it is. S3 download
|
||||
# instructions live in the dashboard documentation instead of every startup.
|
||||
cli = sys.modules["flask.cli"]
|
||||
print_dashboard_banner()
|
||||
print_dashboard_promotion()
|
||||
print_dashboard_loading(folder_path_overview)
|
||||
cli.show_server_banner = lambda *_: None
|
||||
install_server_ready_hook()
|
||||
print_banner()
|
||||
print(
|
||||
f"{Fore.GREEN}Loading all CSV files from the folder {folder_path_overview} ...\n{Style.RESET_ALL}"
|
||||
)
|
||||
cli.show_server_banner = lambda *_: click.echo(
|
||||
f"{Fore.YELLOW}NOTE:{Style.RESET_ALL} If you are using {Fore.GREEN}{Style.BRIGHT}Prowler Cloud{Style.RESET_ALL} with the S3 integration or that integration \nfrom {Fore.CYAN}{Style.BRIGHT}Prowler CLI{Style.RESET_ALL} and you want to use your data from your S3 bucket,\nrun: `{orange_color}aws s3 cp s3://<your-bucket>/output/csv ./output --recursive{Style.RESET_ALL}`\nand then run `prowler dashboard` again to load the new files."
|
||||
)
|
||||
|
||||
# Initialize the app - incorporate css
|
||||
dashboard = dash.Dash(
|
||||
@@ -43,10 +30,8 @@ dashboard = dash.Dash(
|
||||
external_stylesheets=[dbc.themes.FLATLY],
|
||||
use_pages=True,
|
||||
suppress_callback_exceptions=True,
|
||||
title="Prowler Local Dashboard",
|
||||
title="Prowler Dashboard",
|
||||
)
|
||||
# The ready block already announces the URL; drop Dash's pre-bind duplicate.
|
||||
silence_dash_running_line(dashboard)
|
||||
|
||||
# ``use_pages`` above already imported dashboard/pages/cloud.py and registered
|
||||
# every /cloud/* route. Import its metadata now (after app instantiation) so
|
||||
@@ -85,10 +70,7 @@ DASHBOARD_ITEMS = [
|
||||
# Gated navigation groups reference the shared feature metadata by slug so the
|
||||
# sidebar and the informational pages never drift apart.
|
||||
GATED_GROUPS = [
|
||||
(
|
||||
"Upgrade to Prowler Cloud",
|
||||
["findings", "exploitable-issues", "lighthouse-ai", "mcp", "attack-paths"],
|
||||
),
|
||||
("Upgrade to Prowler Cloud", ["lighthouse-ai", "attack-paths", "findings"]),
|
||||
("Configuration", ["alerts", "mutelist", "integrations"]),
|
||||
("Workspace", ["organization"]),
|
||||
]
|
||||
|
||||
@@ -300,18 +300,6 @@
|
||||
margin: 0 0 26px;
|
||||
}
|
||||
|
||||
/* Prowler Cloud screenshot shown on each gated page. */
|
||||
.pc-shot {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 760px;
|
||||
height: auto;
|
||||
border: 1px solid var(--pc-border);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 30px rgba(2, 6, 23, 0.08);
|
||||
margin: 0 0 28px;
|
||||
}
|
||||
|
||||
.pc-benefits {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
@@ -362,111 +350,6 @@
|
||||
background: var(--pc-btn-press);
|
||||
}
|
||||
|
||||
/* ------------------------------------------- Findings hand-off additions */
|
||||
|
||||
/* Secondary "how to" block rendered between the message and the CTA. */
|
||||
.pc-steps {
|
||||
width: 100%;
|
||||
max-width: 560px;
|
||||
text-align: left;
|
||||
background: #f8fafc;
|
||||
border: 1px solid var(--pc-border);
|
||||
border-radius: 12px;
|
||||
padding: 18px 20px;
|
||||
margin: 0 0 26px;
|
||||
}
|
||||
|
||||
.pc-steps-title {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: var(--pc-text);
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.pc-steps-list {
|
||||
/* Tailwind's preflight strips list markers; restore the numbering. */
|
||||
list-style: decimal outside;
|
||||
margin: 0 0 12px;
|
||||
padding-left: 22px;
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
color: var(--pc-text-2);
|
||||
}
|
||||
|
||||
.pc-steps-note {
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
color: #52525b;
|
||||
margin: 0 0 6px;
|
||||
}
|
||||
|
||||
.pc-steps-note:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.pc-cta-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px 20px;
|
||||
}
|
||||
|
||||
.pc-link-secondary {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--pc-text);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
|
||||
.pc-link-secondary:hover {
|
||||
color: var(--pc-btn-press);
|
||||
}
|
||||
|
||||
.pc-note {
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
color: #52525b;
|
||||
margin: 14px 0 0;
|
||||
}
|
||||
|
||||
/* Compact hand-off card used at the end of the Compliance page. */
|
||||
.pc-handoff {
|
||||
min-width: 0;
|
||||
background: #ffffff;
|
||||
border: 1px solid var(--pc-border);
|
||||
border-radius: 14px;
|
||||
padding: 24px 28px;
|
||||
}
|
||||
|
||||
.pc-handoff .pc-avail {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.pc-handoff-title {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: var(--pc-text);
|
||||
margin: 0 0 8px;
|
||||
}
|
||||
|
||||
.pc-handoff-desc {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.pc-handoff-benefits {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.pc-handoff .pc-cta-row {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.pc-handoff .pc-note {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------- Responsive collapse */
|
||||
|
||||
@media (max-width: 900px) {
|
||||
|
||||
|
Before Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 171 KiB |
|
Before Width: | Height: | Size: 225 KiB |
|
Before Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 216 KiB |
|
Before Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 78 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="22" x2="18" y1="12" y2="12"/><line x1="6" x2="2" y1="12" y2="12"/><line x1="12" x2="12" y1="6" y2="2"/><line x1="12" x2="12" y1="22" y2="18"/></svg>
|
||||
|
Before Width: | Height: | Size: 341 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><path d="M12 22v-5"/><path d="M9 8V2"/><path d="M15 8V2"/><path d="M18 8v5a6 6 0 0 1-12 0V8z"/></svg>
|
||||
|
Before Width: | Height: | Size: 252 B |
@@ -1,7 +1,5 @@
|
||||
from dash import dcc, html
|
||||
|
||||
from dashboard.pages.cloud import build_compliance_handoff_card
|
||||
|
||||
|
||||
def create_layout_overview(
|
||||
account_dropdown: html.Div,
|
||||
@@ -196,7 +194,6 @@ def create_layout_compliance(
|
||||
className="text-prowler-stone-900 text-lg font-bold",
|
||||
),
|
||||
html.Div(className="flex flex-wrap", id="output"),
|
||||
build_compliance_handoff_card(),
|
||||
],
|
||||
className="grid gap-x-8 gap-y-8 2xl:container mx-auto",
|
||||
)
|
||||
@@ -1,112 +0,0 @@
|
||||
"""Startup output helpers for `prowler dashboard`.
|
||||
|
||||
The local URL is announced only once the HTTP server is listening. Werkzeug
|
||||
calls ``BaseWSGIServer.log_startup`` right after it binds the socket, so a
|
||||
thin wrapper around that method reads the effective host and port from the
|
||||
bound server and prints the ready message. Dash silences the Werkzeug logger
|
||||
below ERROR while in debug mode, so hooking the method (not the log) is what
|
||||
makes the announcement reliable. Werkzeug's own behaviour is untouched: the
|
||||
original method still runs and no logger is reconfigured.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import socket
|
||||
|
||||
from colorama import Fore, Style
|
||||
from werkzeug.serving import BaseWSGIServer, get_interface_ip
|
||||
|
||||
from prowler.config.config import banner_color
|
||||
|
||||
_WILDCARD_HOSTS = {"0.0.0.0": "127.0.0.1", "::": "[::1]"}
|
||||
|
||||
|
||||
def server_urls(host, port, scheme="http"):
|
||||
"""Return the browser URL and the other reachable URLs for a bound server.
|
||||
|
||||
A wildcard host (``0.0.0.0`` or ``::``) is never presented as a browser
|
||||
destination: the loopback address is used instead and the interface
|
||||
address is listed as also reachable.
|
||||
"""
|
||||
if host in _WILDCARD_HOSTS:
|
||||
primary = f"{scheme}://{_WILDCARD_HOSTS[host]}:{port}/"
|
||||
family = socket.AF_INET if host == "0.0.0.0" else socket.AF_INET6
|
||||
try:
|
||||
interface_ip = get_interface_ip(family)
|
||||
except OSError:
|
||||
interface_ip = None
|
||||
others = []
|
||||
if interface_ip:
|
||||
if ":" in interface_ip:
|
||||
interface_ip = f"[{interface_ip}]"
|
||||
others.append(f"{scheme}://{interface_ip}:{port}/")
|
||||
return primary, others
|
||||
display_host = f"[{host}]" if ":" in host and not host.startswith("[") else host
|
||||
return f"{scheme}://{display_host}:{port}/", []
|
||||
|
||||
|
||||
def format_ready_message(host, port, scheme="http"):
|
||||
"""Render the ready block, styled like the CLI banner, for a listening server."""
|
||||
primary, others = server_urls(host, port, scheme)
|
||||
bar = f"{banner_color}│{Style.RESET_ALL}"
|
||||
check = f"{Fore.GREEN}✓{Style.RESET_ALL}"
|
||||
lines = [
|
||||
f"{bar} {check} {Style.BRIGHT}Prowler Local Dashboard now is running on{Style.RESET_ALL} "
|
||||
f"{banner_color}{primary}{Style.RESET_ALL}"
|
||||
]
|
||||
if host in _WILDCARD_HOSTS:
|
||||
lines.append(f"{bar} Listening on all interfaces ({host}).")
|
||||
if others:
|
||||
lines.append(f"{bar} Also reachable at: " + ", ".join(others))
|
||||
lines.append(f"{bar} Press Ctrl+C to stop.")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
class DashRunningLineFilter(logging.Filter):
|
||||
"""Drop Dash's own ``Dash is running on ...`` line from the app logger.
|
||||
|
||||
The ready block printed by ``install_server_ready_hook`` already states the
|
||||
effective URL once the server is listening, so Dash's pre-bind line would
|
||||
only repeat it. Every other record on the logger still passes.
|
||||
"""
|
||||
|
||||
def filter(self, record):
|
||||
return not record.getMessage().startswith("Dash is running on")
|
||||
|
||||
|
||||
def silence_dash_running_line(app):
|
||||
"""Attach ``DashRunningLineFilter`` to a Dash app's logger once."""
|
||||
if not any(isinstance(f, DashRunningLineFilter) for f in app.logger.filters):
|
||||
app.logger.addFilter(DashRunningLineFilter())
|
||||
|
||||
|
||||
def _print_now(message):
|
||||
"""Print and flush so the ready message shows even when stdout is piped."""
|
||||
print(message, flush=True)
|
||||
|
||||
|
||||
def install_server_ready_hook(announce=_print_now):
|
||||
"""Announce the effective address right after Werkzeug binds the socket.
|
||||
|
||||
Wraps ``BaseWSGIServer.log_startup`` once per process. The wrapper calls
|
||||
the original method first, so Werkzeug's own startup output is unchanged,
|
||||
then prints the ready block a single time. A failed bind never reaches
|
||||
``log_startup``, so a startup error is never announced as ready.
|
||||
"""
|
||||
if getattr(BaseWSGIServer.log_startup, "_prowler_ready_hook", False):
|
||||
return BaseWSGIServer.log_startup
|
||||
|
||||
original = BaseWSGIServer.log_startup
|
||||
state = {"announced": False}
|
||||
|
||||
def log_startup(self):
|
||||
original(self)
|
||||
if state["announced"]:
|
||||
return
|
||||
state["announced"] = True
|
||||
scheme = "http" if self.ssl_context is None else "https"
|
||||
announce("\n" + format_ready_message(self.host, self.port, scheme) + "\n")
|
||||
|
||||
log_startup._prowler_ready_hook = True
|
||||
log_startup._prowler_original = original
|
||||
BaseWSGIServer.log_startup = log_startup
|
||||
return log_startup
|
||||
@@ -21,58 +21,12 @@ CLOUD_CTA_BASE = (
|
||||
# Path to the recolorable checkmark mask used for benefit bullets.
|
||||
CHECK_ICON = "/assets/images/icons/cloud/check.svg"
|
||||
|
||||
# Prowler Cloud screenshots shown on each gated page. They come from the
|
||||
# product documentation (docs/images) and are downscaled for the dashboard.
|
||||
SCREENSHOT_DIR = "/assets/images/cloud/screenshots"
|
||||
|
||||
# Prowler Cloud pricing page used by the "Compare editions" secondary link.
|
||||
CLOUD_PRICING_URL = "https://prowler.com/pricing"
|
||||
|
||||
# Findings hand-off CTA. Shares the ``report-handoff`` campaign and ``oss``
|
||||
# medium with the OSS HTML report CTA; ``utm_source`` identifies this entry
|
||||
# point and ``intent`` expresses the user's goal. The URL is static: no
|
||||
# assessment data (accounts, resources, findings, paths) is ever appended.
|
||||
FINDINGS_HANDOFF_CTA_URL = (
|
||||
"https://cloud.prowler.com/sign-up"
|
||||
"?utm_source=prowler-local-dashboard&utm_medium=oss"
|
||||
"&utm_campaign=report-handoff&utm_content=findings&intent=import-findings"
|
||||
)
|
||||
|
||||
# Same hand-off for the Compliance page; only ``utm_content`` differs.
|
||||
COMPLIANCE_HANDOFF_CTA_URL = (
|
||||
"https://cloud.prowler.com/sign-up"
|
||||
"?utm_source=prowler-local-dashboard&utm_medium=oss"
|
||||
"&utm_campaign=report-handoff&utm_content=compliance&intent=import-findings"
|
||||
)
|
||||
|
||||
# Shared hand-off copy (identical to the OSS HTML report CTA).
|
||||
HANDOFF_TITLE = "Keep scanning locally. Bring your findings to Prowler Cloud."
|
||||
HANDOFF_DESCRIPTION = (
|
||||
"Import your accompanying OCSF report to explore managed security workflows."
|
||||
)
|
||||
HANDOFF_CTA_LABEL = "Explore Prowler Cloud"
|
||||
HANDOFF_SECONDARY_LABEL = "Compare editions"
|
||||
HANDOFF_NOTE = "Nothing is uploaded automatically."
|
||||
|
||||
# What Prowler Cloud adds on top of the local compliance view, as documented in
|
||||
# the Compliance, Cross-Provider Compliance and Cross-Provider Type Compliance
|
||||
# tutorials. Keep these verifiable; do not add unreleased capabilities.
|
||||
COMPLIANCE_HANDOFF_BENEFITS = [
|
||||
"Compliance Watchlist to pin the frameworks you track",
|
||||
"Cross-account and cross-provider roll-ups of a framework, with a per-provider breakdown",
|
||||
"Downloadable CSV and PDF compliance reports",
|
||||
]
|
||||
|
||||
|
||||
# Normative feature definitions. ``icon`` points to a local mask asset so no
|
||||
# external requests are needed and the glyph recolors per context.
|
||||
CLOUD_FEATURES = [
|
||||
{
|
||||
"slug": "lighthouse-ai",
|
||||
"screenshot": {
|
||||
"file": "lighthouse-ai.jpg",
|
||||
"alt": "Lighthouse AI chat in Prowler Cloud",
|
||||
},
|
||||
"route": "/cloud/lighthouse-ai",
|
||||
"nav_label": "Lighthouse AI",
|
||||
"page_title": "Lighthouse AI",
|
||||
@@ -89,64 +43,8 @@ CLOUD_FEATURES = [
|
||||
"utm_content": "lighthouse-ai",
|
||||
"icon": "/assets/images/icons/cloud/lighthouse-ai.svg",
|
||||
},
|
||||
{
|
||||
# Wording mirrors the Prowler Cloud issues model: an issue folds the
|
||||
# findings of one attack path and carries a verdict, legs and a fix.
|
||||
"slug": "exploitable-issues",
|
||||
"route": "/cloud/exploitable-issues",
|
||||
"nav_label": "Exploitable Issues",
|
||||
"page_title": "Exploitable Issues",
|
||||
"card_title": "Unlock Exploitable Issues",
|
||||
"description": (
|
||||
"See which findings combine into an exploitable attack path, from "
|
||||
"where a threat actor starts to what they would gain, so the toxic "
|
||||
"combinations get fixed first."
|
||||
),
|
||||
"benefits": [
|
||||
"Each issue folds the related findings of one attack path into a single verdict: exploitable, likely, conditional or not exploitable",
|
||||
"Reachability, access, target, controls and verification are assessed separately, with the evidence behind each",
|
||||
"Outcome and starting point are spelled out, from the internet to a leaked credential, together with the fix and a triage status",
|
||||
],
|
||||
"utm_content": "exploitable-issues",
|
||||
"icon": "/assets/images/icons/cloud/exploitable-issues.svg",
|
||||
"note": "Exploitable Issues is rolling out to Prowler Cloud tenants.",
|
||||
},
|
||||
{
|
||||
# Capabilities below mirror the Prowler MCP documentation (Overview and
|
||||
# Cloud MCP Server configuration). The hosted server is in preview.
|
||||
"slug": "mcp",
|
||||
"screenshot": {
|
||||
"file": "mcp.jpg",
|
||||
"alt": "Claude Code querying Prowler through the Prowler MCP Server",
|
||||
},
|
||||
"route": "/cloud/mcp",
|
||||
"nav_label": "MCP Server",
|
||||
"page_title": "Prowler MCP",
|
||||
"card_title": "Unlock Prowler MCP",
|
||||
"description": (
|
||||
"Connect your AI assistant to Prowler through the hosted MCP Server "
|
||||
"at mcp.prowler.com, with no installation, using a Prowler Cloud "
|
||||
"API key."
|
||||
),
|
||||
"benefits": [
|
||||
"Ask about findings, resources and compliance in natural language from Claude Code, Cursor, VS Code or Codex",
|
||||
"Trigger scans and manage providers, mute rules and integrations from your AI agent",
|
||||
"Cloud-only tools for findings triage, scan scheduling, scan configurations and alerts",
|
||||
],
|
||||
"utm_content": "mcp",
|
||||
"icon": "/assets/images/icons/cloud/mcp.svg",
|
||||
"secondary_link": {
|
||||
"label": "Connect your AI agent",
|
||||
"href": "https://docs.prowler.com/user-guide/ai-agents/",
|
||||
},
|
||||
"note": "Prowler MCP Server is currently a preview feature.",
|
||||
},
|
||||
{
|
||||
"slug": "attack-paths",
|
||||
"screenshot": {
|
||||
"file": "attack-paths.jpg",
|
||||
"alt": "Attack path graph in Prowler Cloud",
|
||||
},
|
||||
"route": "/cloud/attack-paths",
|
||||
"nav_label": "Attack Paths",
|
||||
"page_title": "Attack Paths",
|
||||
@@ -164,53 +62,25 @@ CLOUD_FEATURES = [
|
||||
"icon": "/assets/images/icons/cloud/attack-paths.svg",
|
||||
},
|
||||
{
|
||||
# Findings is a voluntary hand-off, not an upsell: the dashboard keeps
|
||||
# showing findings from CSV, and this page explains how to bring the
|
||||
# OCSF report to Prowler Cloud. Copy is shared with the OSS HTML report.
|
||||
"slug": "findings",
|
||||
"screenshot": {
|
||||
"file": "findings.jpg",
|
||||
"alt": "Findings table with triage in Prowler Cloud",
|
||||
},
|
||||
"route": "/cloud/findings",
|
||||
"nav_label": "Findings",
|
||||
"page_title": "Findings",
|
||||
"card_title": "Keep scanning locally. Bring your findings to Prowler Cloud.",
|
||||
"card_title": "Unlock Findings",
|
||||
"description": (
|
||||
"Import your accompanying OCSF report to explore managed security "
|
||||
"workflows."
|
||||
"Filter, investigate, and prioritize security findings across "
|
||||
"providers and scans from one workspace."
|
||||
),
|
||||
"benefits": [],
|
||||
"benefits": [
|
||||
"Search and filter findings across all connected accounts",
|
||||
"Track status, severity, ownership, and remediation context",
|
||||
"Triage findings and share a consistent source of truth with your security team",
|
||||
],
|
||||
"utm_content": "findings",
|
||||
"icon": "/assets/images/icons/cloud/findings.svg",
|
||||
"cta_label": "Explore Prowler Cloud",
|
||||
"cta_url": FINDINGS_HANDOFF_CTA_URL,
|
||||
"secondary_link": {"label": "Compare editions", "href": CLOUD_PRICING_URL},
|
||||
"note": "Nothing is uploaded automatically.",
|
||||
"steps": {
|
||||
"title": "How to bring your results",
|
||||
"items": [
|
||||
"Create or sign in to your Prowler Cloud account.",
|
||||
"In Prowler Cloud, open Scans \u2192 Import Findings.",
|
||||
"Select the accompanying .ocsf.json report and start the import.",
|
||||
],
|
||||
"notes": [
|
||||
"This dashboard reads CSV files. Cloud import requires the OCSF "
|
||||
"JSON report, not the CSV or HTML report.",
|
||||
"If you did not generate an OCSF report, include json-ocsf in "
|
||||
"your output formats on your next scan.",
|
||||
"Import Findings is available to roles with the Manage Ingestions "
|
||||
"permission on an active Prowler Cloud subscription; each cloud "
|
||||
"account in the report counts as a provider.",
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"slug": "alerts",
|
||||
"screenshot": {
|
||||
"file": "alerts.jpg",
|
||||
"alt": "Alert rules list in Prowler Cloud",
|
||||
},
|
||||
"route": "/cloud/alerts",
|
||||
"nav_label": "Alerts",
|
||||
"page_title": "Alerts",
|
||||
@@ -229,10 +99,6 @@ CLOUD_FEATURES = [
|
||||
},
|
||||
{
|
||||
"slug": "mutelist",
|
||||
"screenshot": {
|
||||
"file": "mutelist.jpg",
|
||||
"alt": "Mutelist configuration in Prowler Cloud",
|
||||
},
|
||||
"route": "/cloud/mutelist",
|
||||
"nav_label": "Mutelist",
|
||||
"page_title": "Mutelist",
|
||||
@@ -251,10 +117,6 @@ CLOUD_FEATURES = [
|
||||
},
|
||||
{
|
||||
"slug": "integrations",
|
||||
"screenshot": {
|
||||
"file": "integrations.jpg",
|
||||
"alt": "Integrations page in Prowler Cloud",
|
||||
},
|
||||
"route": "/cloud/integrations",
|
||||
"nav_label": "Integrations",
|
||||
"page_title": "Integrations",
|
||||
@@ -273,10 +135,6 @@ CLOUD_FEATURES = [
|
||||
},
|
||||
{
|
||||
"slug": "organization",
|
||||
"screenshot": {
|
||||
"file": "organization.jpg",
|
||||
"alt": "Organization users page in Prowler Cloud",
|
||||
},
|
||||
"route": "/cloud/organization",
|
||||
"nav_label": "Organization",
|
||||
"page_title": "Organization",
|
||||
@@ -320,114 +178,9 @@ def _benefit_item(text):
|
||||
)
|
||||
|
||||
|
||||
def _handoff_links(cta_url):
|
||||
"""Return the primary CTA and the "Compare editions" link for a hand-off."""
|
||||
return html.Div(
|
||||
[
|
||||
html.A(
|
||||
HANDOFF_CTA_LABEL,
|
||||
href=cta_url,
|
||||
target="_blank",
|
||||
rel="noopener noreferrer",
|
||||
className="pc-cta",
|
||||
),
|
||||
html.A(
|
||||
HANDOFF_SECONDARY_LABEL,
|
||||
href=CLOUD_PRICING_URL,
|
||||
target="_blank",
|
||||
rel="noopener noreferrer",
|
||||
className="pc-link-secondary",
|
||||
),
|
||||
],
|
||||
className="pc-cta-row",
|
||||
)
|
||||
|
||||
|
||||
def build_compliance_handoff_card():
|
||||
"""Build the compact hand-off card shown at the end of the Compliance page.
|
||||
|
||||
The local compliance view keeps working from CSV; this card only explains
|
||||
what Prowler Cloud adds for compliance reporting. Static links only: no
|
||||
upload control, no request, no assessment data in URLs.
|
||||
"""
|
||||
return html.Div(
|
||||
[
|
||||
html.Div("Available in Prowler Cloud", className="pc-avail"),
|
||||
html.H2(HANDOFF_TITLE, className="pc-handoff-title"),
|
||||
html.P(HANDOFF_DESCRIPTION, className="pc-card-desc pc-handoff-desc"),
|
||||
html.Ul(
|
||||
[_benefit_item(benefit) for benefit in COMPLIANCE_HANDOFF_BENEFITS],
|
||||
className="pc-benefits pc-handoff-benefits",
|
||||
),
|
||||
_handoff_links(COMPLIANCE_HANDOFF_CTA_URL),
|
||||
html.P(HANDOFF_NOTE, className="pc-note"),
|
||||
],
|
||||
className="pc-handoff pc-font",
|
||||
role="complementary",
|
||||
)
|
||||
|
||||
|
||||
def _screenshot(screenshot):
|
||||
"""Render the Prowler Cloud screenshot that shows the gated feature."""
|
||||
return html.Img(
|
||||
src=f"{SCREENSHOT_DIR}/{screenshot['file']}",
|
||||
alt=screenshot["alt"],
|
||||
className="pc-shot",
|
||||
)
|
||||
|
||||
|
||||
def _steps_block(steps):
|
||||
"""Build the optional secondary "how to" block rendered below the message.
|
||||
|
||||
It is plain text and links only: no file selector, upload control or
|
||||
request is introduced, since the browser cannot read local report files.
|
||||
"""
|
||||
return html.Div(
|
||||
[
|
||||
html.H3(steps["title"], className="pc-steps-title"),
|
||||
html.Ol(
|
||||
[html.Li(item) for item in steps["items"]],
|
||||
className="pc-steps-list",
|
||||
),
|
||||
*[html.P(note, className="pc-steps-note") for note in steps["notes"]],
|
||||
],
|
||||
className="pc-steps",
|
||||
)
|
||||
|
||||
|
||||
def build_cloud_layout(feature):
|
||||
"""Build the reusable gated informational page for a single feature.
|
||||
|
||||
Features may override the CTA (``cta_label``/``cta_url``) and add an
|
||||
optional ``screenshot``, ``steps`` block, ``secondary_link`` and ``note``.
|
||||
Features that do not set them render exactly as before.
|
||||
"""
|
||||
cta_url = feature.get("cta_url") or f"{CLOUD_CTA_BASE}{feature['utm_content']}"
|
||||
cta_label = feature.get("cta_label", "Upgrade to Prowler Cloud")
|
||||
steps = feature.get("steps")
|
||||
screenshot = feature.get("screenshot")
|
||||
secondary_link = feature.get("secondary_link")
|
||||
note = feature.get("note")
|
||||
|
||||
cta_links = [
|
||||
html.A(
|
||||
cta_label,
|
||||
href=cta_url,
|
||||
target="_blank",
|
||||
rel="noopener noreferrer",
|
||||
className="pc-cta",
|
||||
)
|
||||
]
|
||||
if secondary_link:
|
||||
cta_links.append(
|
||||
html.A(
|
||||
secondary_link["label"],
|
||||
href=secondary_link["href"],
|
||||
target="_blank",
|
||||
rel="noopener noreferrer",
|
||||
className="pc-link-secondary",
|
||||
)
|
||||
)
|
||||
"""Build the reusable gated informational page for a single feature."""
|
||||
cta_url = f"{CLOUD_CTA_BASE}{feature['utm_content']}"
|
||||
|
||||
return html.Div(
|
||||
html.Div(
|
||||
@@ -474,7 +227,6 @@ def build_cloud_layout(feature):
|
||||
feature["description"],
|
||||
className="pc-card-desc",
|
||||
),
|
||||
*([_screenshot(screenshot)] if screenshot else []),
|
||||
html.Ul(
|
||||
[
|
||||
_benefit_item(benefit)
|
||||
@@ -482,13 +234,13 @@ def build_cloud_layout(feature):
|
||||
],
|
||||
className="pc-benefits",
|
||||
),
|
||||
*([_steps_block(steps)] if steps else []),
|
||||
*(
|
||||
[html.Div(cta_links, className="pc-cta-row")]
|
||||
if secondary_link
|
||||
else cta_links
|
||||
html.A(
|
||||
"Upgrade to Prowler Cloud",
|
||||
href=cta_url,
|
||||
target="_blank",
|
||||
rel="noopener noreferrer",
|
||||
className="pc-cta",
|
||||
),
|
||||
*([html.P(note, className="pc-note")] if note else []),
|
||||
],
|
||||
className="pc-card-body",
|
||||
),
|
||||
@@ -508,6 +260,6 @@ for _feature in CLOUD_FEATURES:
|
||||
f"cloud_{_feature['slug'].replace('-', '_')}",
|
||||
path=_feature["route"],
|
||||
name=_feature["nav_label"],
|
||||
title=f"Prowler Local Dashboard - {_feature['page_title']}",
|
||||
title=f"Prowler Dashboard - {_feature['page_title']}",
|
||||
layout=build_cloud_layout(_feature),
|
||||
)
|
||||
@@ -80,8 +80,6 @@ Prowler Features are considered proper nouns. They are to be referenced without
|
||||
|
||||
Prowler ships two product families. Use these names exactly; the former names Prowler App (now Prowler Local Server) and Prowler Enterprise (now Prowler Private Cloud) must not appear in new writing. The only allowed former-name notes are on the Prowler Product Families page (`getting-started/products/index.mdx`) and in the site-wide banner, which document the mapping.
|
||||
|
||||
Web UI guides are written for Prowler Cloud. Steps that open the application link to `https://cloud.prowler.com/sign-in`, and the scope is stated once at the top of the section with the AppliesTo banner (see [AppliesTo Banner for Product Scope](#appliesto-banner-for-product-scope)). Do not offer Prowler Local Server as an inline alternative in a step list ("Go to Prowler Cloud or launch Prowler Local Server"). Mention Prowler Local Server inline only where its behavior differs, for example a feature that is not available or an environment variable that must be set.
|
||||
|
||||
Prowler Products:
|
||||
|
||||
* **Prowler Cloud**
|
||||
@@ -575,7 +573,7 @@ The default covers Prowler Cloud, Prowler Private Cloud, and Prowler Local Serve
|
||||
<AppliesTo products={["Prowler Cloud", "Prowler Private Cloud"]} />
|
||||
```
|
||||
|
||||
Place it on its own line below the Version Badge when one is present, otherwise directly after the imports. On a page that also covers Prowler CLI, such as the provider getting-started guides, place it under the `## Prowler Cloud` heading instead, so it scopes only the web UI section.
|
||||
Place it on its own line below the Version Badge when one is present, otherwise directly after the imports.
|
||||
|
||||
### Cloud Marker for Subscription Content
|
||||
|
||||
|
||||
@@ -4,149 +4,6 @@ description: "New features and improvements in each Prowler release"
|
||||
rss: true
|
||||
---
|
||||
|
||||
<Update label="v5.47.0" description="October 29, 2026">
|
||||
### 🧭 Add Provider — One Step to Connect Any Provider
|
||||
|
||||
The add-provider wizard follows the same model for every provider: one connect step, then the launch step. Adding an Azure subscription used to take six screens; now the account, its alias and its credentials are one form, and a single submit registers the account, stores the secret and tests the connection.
|
||||
|
||||
- A failed connection test shows inline, keeps the values and turns the action into **Retry connection** without registering the account twice.
|
||||
- Access methods show as cards on the same step for AWS, GCP, Microsoft 365, GitHub, Alibaba Cloud and Cloudflare, and AWS, Azure and GCP switch to their organization flow through tabs.
|
||||
- Users with the Manage Account permission can invite a teammate to finish the connection for every provider, not only AWS.
|
||||
- **Ask Lighthouse AI** opens beside the wizard without closing it. It guides the connection from the Prowler docs by default and, when asked, connects the provider itself after confirming the provider, UID and credential field names, never echoing a secret back.
|
||||
- Product tours and the guided onboarding sequence are removed; new tenants still land on the add-provider wizard.
|
||||
|
||||
### 🎯 Issues — Verdicts Explained in the List
|
||||
|
||||
<Note>
|
||||
This feature is available exclusively in **Prowler Cloud** and **Prowler Private Cloud** with a [subscription](https://prowler.com/pricing).
|
||||
</Note>
|
||||
|
||||
- The issue list leads with the verdict, shows the attack path under each title and adds a **Why** column with the five evidence legs, so the reason for a verdict reads without opening the issue. The summary tiles become one line with the folded findings and the findings already covered by a control.
|
||||
- A row opens in the side panel, next to Lighthouse AI, with the verdict, legs, remediation, triage and an **Attack path** tab with the issue graph, instead of expanding the issue inline.
|
||||
- The menu entry is renamed to **Exploitability issues**.
|
||||
|
||||
### ☁️ Azure and AWS Checks
|
||||
|
||||
- `network_application_gateway_waf_enabled` and `network_application_gateway_http2_enabled` cover Azure Application Gateways and their WAF policies, mapped to CIS 5.0 and 6.0. Contributed by @BabafemiB. Thank you!
|
||||
- `iam_subscription_owners_between_2_and_3` verifies that each Azure subscription has between two and three Owners, counting owners inherited from management groups, mapped to CIS 5.0 and 6.0. Contributed by @BabafemiB. Thank you!
|
||||
- The AWS security group internet exposure checks treat CIDRs in one ingress rule that together cover `0.0.0.0/0` or `::/0`, such as `0.0.0.0/1` plus `128.0.0.0/1`, as open to the internet; such a rule used to pass `ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22` and its siblings. Contributed by @harshrajdebug. Thank you!
|
||||
|
||||
Explore all checks at [Prowler Hub](https://hub.prowler.com/check).
|
||||
|
||||
### 🛠️ Improvements and Fixes
|
||||
|
||||
- Every MCP Server tool declares `readOnlyHint` and `destructiveHint`, so clients can tell a listing from a write when deciding whether to ask the user. Mutelist and mute rule writes are marked destructive because they hide findings for good.
|
||||
- The cross-provider compliance tab keeps the frameworks that loaded, with a warning, when one catalog page or framework fails, instead of going blank.
|
||||
- The NATO D32 compliance framework has its own icon on the compliance cards.
|
||||
- Lighthouse AI replies no longer blink when the response finishes streaming, and the user avatar no longer requests the current page as an image, which rendered every page twice.
|
||||
- The Invitations page uses **Status** instead of **State**, and the Invitations and Roles filters show capitalized options.
|
||||
- **Prowler Cloud:** actions refused because the tenant is over its plan's usage limit, such as launching a scan, saving a schedule, adding a provider or triaging a finding, now link to the plans page.
|
||||
- **Prowler Cloud:** creating API keys is a Prowler Cloud feature; on Local Server the button opens the upgrade dialog, and existing keys can still be edited and revoked.
|
||||
- **Prowler Cloud:** issue evaluation after a scan reads the scan's findings through their indexes instead of a server-side cursor that took hours on large scans, so the evaluations no longer queue up behind each other.
|
||||
- **Prowler Private Cloud:** Lighthouse AI can use Amazon Bedrock with only a region, relying on the installation's own AWS role, when the API allows it.
|
||||
|
||||
### 🔐 Security Updates
|
||||
|
||||
- `pymongo` upgraded to 4.18.3, `dnspython` to 2.9.0 and `oauthlib` to 4.0.0 in the SDK and the API container image, patching the BSON decoding and DNS compression pointer denial of service advisories and the OAuth device flow token disclosure. The API also moves `django-allauth` to 65.19.7, since earlier releases cap `oauthlib` below 4.
|
||||
- `Authlib` upgraded to 1.9.1 and `dnspython` to 2.9.0 in the MCP Server container image, patching CVE-2026-96760 (critical), CVE-2026-114615, CVE-2026-114616 and CVE-2026-114605.
|
||||
|
||||
### 🙌 External Contributors
|
||||
|
||||
Thank you to our community contributors for this release!
|
||||
|
||||
- @BabafemiB: Azure `network_application_gateway_waf_enabled`, `network_application_gateway_http2_enabled` and `iam_subscription_owners_between_2_and_3` checks ([#13160](https://github.com/prowler-cloud/prowler/pull/13160), [#13145](https://github.com/prowler-cloud/prowler/pull/13145))
|
||||
- @harshrajdebug: AWS security group internet exposure fix for split CIDRs ([#13191](https://github.com/prowler-cloud/prowler/pull/13191))
|
||||
|
||||
See the [full release notes on GitHub](https://github.com/prowler-cloud/prowler/releases/tag/5.47.0) for the complete list of changes.
|
||||
</Update>
|
||||
|
||||
<Update label="v5.46.0" description="October 26, 2026">
|
||||
### 🎯 Issues — Attack Paths with an Exploitability Verdict
|
||||
|
||||
<Note>
|
||||
This feature is available exclusively in **Prowler Cloud** and **Prowler Private Cloud** with a [subscription](https://prowler.com/pricing).
|
||||
</Note>
|
||||
|
||||
A scan returns a list of failed checks, and most of them are one problem seen from several angles. The new **Issues** page folds the failed findings of each account into attack paths and gives each one a verdict: `exploitable`, `likely`, `conditional`, `not_exploitable` or `unknown`. The verdict is drawn from five legs of evidence (reachability, access, target, controls and verification), each naming the checks and resources it was read from, so a reader can disagree with it instead of having to trust it. A control in force moves a verdict one rung down and the issue says which control did it; a check that did not run reads as `unknown`, never as safe.
|
||||
|
||||
- Patterns cover AWS, Azure, GCP and Microsoft 365 and are keyed on Prowler check IDs, so detection is never reimplemented. Six more AWS paths ship in this release: Lambda functions anyone can invoke, snapshots shared with every AWS account, instances that can leak their role's credentials, database ports open to the internet, stale or weakly protected IAM user credentials, and roles another AWS account can use.
|
||||
- Each issue says what the path buys an attacker and where the attacker has to start, lists the compliance frameworks its findings put at risk, and can be sent to Jira as one grouped ticket.
|
||||
- An attack path can be triaged with a status and notes from its detail. The decision is kept per account and pattern, so it survives the next scan, which marks it resolved when the path is gone and reopened when it comes back.
|
||||
- The issue list opens with summary tiles and names the account of each issue, so two accounts with the same misconfiguration no longer read as one row. Each issue shows its risk factors, the triage status of every folded finding and an issue graph that starts internet-facing paths at the Internet node, drawn only where a reachability check failed on the resource, and has a page of its own to share.
|
||||
- The Overview shows a verdict share card and the top issues with their risk factors, with counts scoped to the latest completed scan of each provider.
|
||||
- **API:** `GET /api/v1/issues`, `GET /api/v1/issues/{id}` and `GET /api/v1/issues/overview`, with `filter[outcome__in]`, `filter[attacker_start__in]` and `filter[triage_status__in]`; triage lives at `/api/v1/issues/{id}/triage` and `/api/v1/issues/{id}/triage/notes`.
|
||||
|
||||
### 🐘 PHP — Coverage After the October Security Release
|
||||
|
||||
The PHP project shipped an emergency release on October 21 fixing two unauthenticated remote code execution flaws (CVE-2026-109618, CVE-2026-109619), with no fix for 8.1 and older branches. Four new checks cover how each cloud exposes the runtime, and the Azure runtime checks no longer fail every version newer than the configured one.
|
||||
|
||||
- **AWS:** `elasticbeanstalk_environment_php_platform_updated` flags PHP environments on branches without security fixes or on platform versions older than the one bundling the fixed release, `lightsail_instance_php_blueprint_updated` reports instances created from PHP blueprints for manual verification, and `wafv2_webacl_managed_rule_groups_enabled` verifies that a Web ACL references at least one managed rule group.
|
||||
- **GCP:** new `appengine` service and `appengine_version_php_runtime_supported` check, flagging App Engine serving versions on PHP runtimes without security fixes.
|
||||
- **Azure:** `app_ensure_php_version_is_latest`, `app_ensure_python_version_is_latest` and `app_ensure_java_version_is_latest` now pass any runtime at or above the configured minimum, and the default `php_latest_version` is raised from `8.2` to `8.5` in the SDK and in the scan configuration template of Prowler App.
|
||||
|
||||
The version thresholds are configurable; see the [configuration file documentation](https://docs.prowler.com/user-guide/cli/tutorials/configuration_file).
|
||||
|
||||
### 🧠 GCP — Vertex AI Workbench Coverage
|
||||
|
||||
A new Vertex AI service audits Workbench instances with five checks, all contributed by @rajeshnadiminti. Thank you!
|
||||
|
||||
- `vertexai_workbench_instance_public_ip_disabled` and `vertexai_workbench_instance_root_access_disabled`, mapped to PCI DSS 4.0.
|
||||
- `vertexai_workbench_instance_terminal_access_disabled`, `vertexai_workbench_instance_file_download_disabled` and `vertexai_workbench_instance_auto_upgrade_enabled`, with the Workbench checks mapped to the CCC MLDE requirements.
|
||||
|
||||
### 🤖 AWS — Bedrock and Cognito Checks
|
||||
|
||||
- `bedrock_guardrail_sensitive_information_filter_enforced` flags guardrails whose PII entities or custom regexes take no action on the output path, so a detected match is reported in the trace and still delivered to the caller. Contributed by @tamg-aws. Thank you!
|
||||
- `bedrock_model_invocation_logging_text_data_enabled` verifies that model invocation logging delivers prompt and response text rather than naming a destination while excluding request and response bodies. Contributed by @tamg-aws. Thank you!
|
||||
- `cognito_user_pool_account_recovery_sms_not_preferred` verifies that user pools do not rank SMS first for account recovery. Contributed by @UTKARSH698. Thank you!
|
||||
- `bedrock_api_key_no_long_term_credentials` now reports long-term API keys that never expire; IAM only returns `ExpirationDate` for keys created with an expiration period, so keys created without one produced no finding at all. Also contributed by @tamg-aws.
|
||||
|
||||
Explore all checks at [Prowler Hub](https://hub.prowler.com/check).
|
||||
|
||||
### 📬 Google Workspace — Policy Precedence and Edition Context
|
||||
|
||||
- Checks now read the policy Google applies (the greatest `sortOrder`) instead of the last policy the Cloud Identity Policy API lists, which reported default values over admin-configured ones.
|
||||
- Checks for Chat, Drive, Gmail, Calendar and Groups pass with the reason stated when the app is turned off for everyone and no organizational unit or group turns it back on. Drive sharing settings and the settings of existing groups keep being evaluated, because existing shares and groups stay reachable.
|
||||
- Findings state when a feature is not sold on the tenant edition, such as Drive DLP rules, Google session control and the shared drive sharing settings on Business Starter. Reading editions needs the optional `apps.licensing` scope; see the [authentication documentation](https://docs.prowler.com/user-guide/providers/googleworkspace/authentication).
|
||||
- The Gmail spoofing checks read each protection action from its own Policy API field: the inbound domain spoofing check could never pass and the similar domain names check reported the inbound action.
|
||||
- `drive_publishing_files_disabled` passes when sharing outside the organization is limited to allowlisted domains or off, and `drive_desktop_access_disabled` remediation points to the Google Drive for desktop card in the Admin console.
|
||||
|
||||
### 🛠️ Improvements and Fixes
|
||||
|
||||
- Scan report generation parses each resource's metadata once per batch, sanitizes it once per finding and releases each batch before building the next one, so providers with very large resource metadata no longer exhaust the worker memory.
|
||||
- Scan ingestion compares the serialized resource metadata with the stored value and serializes sets in a stable order, so unchanged resources no longer get their metadata, details and `updated_at` rewritten on every scan.
|
||||
- The compliance report PDF cover table wraps every value, so long account IDs such as OCI tenancy OCIDs no longer overflow their cell.
|
||||
- **Launch an initial scan now** is ticked by default on the provider and organization setup launch steps, so saving a schedule also runs a first scan unless the box is unticked.
|
||||
- The SAML SSO integration card on the profile page is shown to roles with the Manage Account permission, matching the API requirement.
|
||||
- **Prowler Cloud:** the scan-reports worker replaces each Celery child process after one report, so the memory a large report needs is returned instead of pushing the task towards an out-of-memory kill, and a container health check replaces a worker that stops consuming instead of leaving it in steady state.
|
||||
- **Prowler Cloud:** persistent report, compliance and overview workers no longer shut themselves down when a task named like a scan hits its time limit or is revoked; the one-shot shutdown only applies to the ephemeral workers of the `scans` queue.
|
||||
|
||||
### 🔐 Security Updates
|
||||
|
||||
- Resource metadata attached to findings no longer carries the values that secrets checks scan (CloudFormation outputs, Lambda environment variables, EC2 user data and similar fields); they are replaced with `REDACTED` before reaching the Evidence tab, the API and the output files.
|
||||
- SAML SSO configuration endpoints require the `manage_account` permission instead of `manage_integrations`, since the configured IdP controls who signs in and which role they receive.
|
||||
- Attack Paths custom queries strip block comments before the blocked-operation check and drop APOC virtual nodes and relationships from results, so `LOAD CSV` can no longer be split with a comment nor its response returned under a forged provider label.
|
||||
- `GET /resources/metadata`, `GET /resources/metadata/latest`, `GET /findings/metadata` and `GET /findings/metadata/latest` honour the provider groups of the caller role instead of aggregating every provider in the tenant.
|
||||
- OpenStack `auth_url` values resolving to loopback, private or otherwise non-public hosts are rejected before the SDK connects, on both the connection test and the scan.
|
||||
- `djangorestframework` upgraded to 3.18.3 in the API, patching the JSON parser charset and Accept header denial of service and the TokenProxy revocation bypass.
|
||||
- `Pillow` upgraded to 13.0.0 in the API, patching a JPEG decoder heap overflow.
|
||||
- `certifi` upgraded to 2026.10.19 in the SDK, the API and the MCP Server, dropping the emSign root CAs whose intermediate keys were compromised, and `uv` to 0.13.4 in the SDK and API images for the same reason.
|
||||
- `aiohttp` upgraded to 3.14.5 with `yarl` 1.25.1 in the SDK and the API, patching the aiohttp resource exhaustion advisories.
|
||||
- `black` upgraded to 26.10.1 and `graphql-core` to 3.2.12 in the SDK, patching CVE-2026-114134, CVE-2026-75507 and CVE-2026-75508, and `libbrotli1` to 1.1.0-2+deb13u1 in its container image, patching CVE-2026-111497.
|
||||
- Trivy upgraded to 0.76.1 in the SDK and API images, patching the HTTP/2, TLS and Go 1.27.2 stdlib CVEs bundled in Trivy 0.75.0, and the SDK and API images no longer ship the MicrosoftTeams build SBOM that Trivy read as installed `zod` and `body-parser`.
|
||||
- `next` upgraded to 16.4.1 in the UI, patching two unauthenticated remote code executions (Image Optimization with SVG files, GHSA-2464-fhr4-w9xw; `use cache` functions returning typed arrays, GHSA-673q-mjm6-r5xr), `@sentry/nextjs` to 10.75.2 for the middleware bypass through the tunnel route (GHSA-mchm-gjx6-7h55) and DOMPurify to 3.4.17 for the `SAFE_FOR_TEMPLATES` bypass (GHSA-cg2g-xh64-v4q7).
|
||||
- Node.js upgraded to 24.22.1 LTS in the UI container image, patching the eight CVEs of the October 2026 security release that affect the 24.x line, including the Brotli decoder remote code execution (CVE-2026-111497); the base image moves to Alpine 3.24.
|
||||
|
||||
### 🙌 External Contributors
|
||||
|
||||
Thank you to our community contributors for this release!
|
||||
|
||||
- @rajeshnadiminti: GCP Vertex AI service and its Workbench checks ([#13062](https://github.com/prowler-cloud/prowler/pull/13062), [#13077](https://github.com/prowler-cloud/prowler/pull/13077))
|
||||
- @tamg-aws: AWS `bedrock_guardrail_sensitive_information_filter_enforced` and `bedrock_model_invocation_logging_text_data_enabled` checks and the `bedrock_api_key_no_long_term_credentials` fix ([#12663](https://github.com/prowler-cloud/prowler/pull/12663))
|
||||
- @UTKARSH698: AWS `cognito_user_pool_account_recovery_sms_not_preferred` check ([#12251](https://github.com/prowler-cloud/prowler/pull/12251))
|
||||
|
||||
See the [full release notes on GitHub](https://github.com/prowler-cloud/prowler/releases/tag/5.46.0) for the complete list of changes.
|
||||
</Update>
|
||||
|
||||
<Update label="v5.45.0" description="October 15, 2026">
|
||||
### 🤖 Azure — AI Services Coverage
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ The script creates symlinks so each tool finds the skills in its expected locati
|
||||
|------|------------------|
|
||||
| Claude Code | `.claude/skills/` symlink and `CLAUDE.md` |
|
||||
| Gemini CLI | `.gemini/skills/` symlink and `GEMINI.md` |
|
||||
| Codex (OpenAI) | `.agents/skills/` symlink, plus the legacy `.codex/skills/` (uses `AGENTS.md` natively) |
|
||||
| Codex (OpenAI) | `.codex/skills/` symlink (uses `AGENTS.md` natively) |
|
||||
| GitHub Copilot | `.github/copilot-instructions.md` symlink to `AGENTS.md` |
|
||||
|
||||
After running the setup, restart the AI coding assistant to load the skills.
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
"getting-started/goto/prowler-api-reference"
|
||||
]
|
||||
},
|
||||
"getting-started/products/prowler-private-cloud-aws-marketplace",
|
||||
{
|
||||
"group": "Prowler Lighthouse AI",
|
||||
"pages": [
|
||||
|
||||
@@ -2,15 +2,11 @@
|
||||
title: "Installation"
|
||||
---
|
||||
|
||||
<Tip>
|
||||
[Prowler Cloud](https://cloud.prowler.com/sign-up) runs the same application with no installation or maintenance. Follow the [Prowler Cloud guide](/user-guide/tutorials/prowler-app) to start scanning right away.
|
||||
</Tip>
|
||||
|
||||
### Installation
|
||||
|
||||
Prowler Local Server offers flexible installation methods tailored to various environments.
|
||||
|
||||
Refer to the [Prowler Cloud guide](/user-guide/tutorials/prowler-app) for detailed usage instructions, which apply to Prowler Local Server as well.
|
||||
Refer to the [Prowler Cloud guide](/user-guide/tutorials/prowler-app) for detailed usage instructions.
|
||||
|
||||
<Warning>
|
||||
Prowler configuration is based on `.env` files. Every version of Prowler can have differences on that file, so, please, use the file that corresponds with that version or repository branch or tag.
|
||||
@@ -132,8 +128,8 @@ To update the environment file:
|
||||
Edit the `.env` file and change version values:
|
||||
|
||||
```env
|
||||
PROWLER_UI_VERSION="5.47.0"
|
||||
PROWLER_API_VERSION="5.47.0"
|
||||
PROWLER_UI_VERSION="5.45.0"
|
||||
PROWLER_API_VERSION="5.45.0"
|
||||
```
|
||||
|
||||
<Note>
|
||||
|
||||
@@ -15,7 +15,7 @@ Read the [public announcement of the Prowler product families](https://prowler-w
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| [Prowler Cloud](/getting-started/products/prowler-cloud) | Managed cloud security platform operated by the Prowler team. See [pricing](https://prowler.com/pricing). |
|
||||
| Prowler Private Cloud | Prowler Cloud deployed in your own environment. Formerly Prowler Enterprise. Available [on AWS Marketplace](/getting-started/products/prowler-private-cloud-aws-marketplace). See [pricing](https://prowler.com/pricing). |
|
||||
| Prowler Private Cloud | Prowler Cloud deployed in your own environment. Formerly Prowler Enterprise. See [pricing](https://prowler.com/pricing). |
|
||||
| [Prowler Hub](https://hub.prowler.com) | Free public library of versioned checks, cloud service artifacts, and compliance frameworks. |
|
||||
| [Prowler Lighthouse AI](/getting-started/products/prowler-cloud-lighthouse) | AI security analyst capabilities within Prowler Cloud and Prowler Private Cloud. |
|
||||
| [Prowler MCP](/getting-started/products/prowler-mcp) | MCP server that connects AI assistants and agents to Prowler, including IDE plugins such as [Prowler for Claude Code](/user-guide/ai-agents/claude-code). |
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: 'Overview'
|
||||
---
|
||||
|
||||
Prowler Local Server is a self-hosted web application that simplifies running Prowler. It is the open source counterpart of [Prowler Cloud](/getting-started/products/prowler-cloud), which runs the same application as a managed service. It provides:
|
||||
Prowler Local Server is a self-hosted web application that simplifies running Prowler. It provides:
|
||||
|
||||
- **User-friendly interface** for configuring and executing scans
|
||||
- Dashboard to **view results** and manage **security findings**
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
---
|
||||
title: "Prowler Private Cloud"
|
||||
sidebarTitle: "Prowler Private Cloud"
|
||||
description: "Choose a plan, install Prowler Private Cloud in your own AWS account from AWS Marketplace, and understand billing and infrastructure cost."
|
||||
---
|
||||
|
||||
import { AwsMarketplaceBanner } from "/snippets/aws-marketplace-banner.mdx"
|
||||
|
||||
<AwsMarketplaceBanner />
|
||||
|
||||
Prowler Private Cloud is the full Prowler platform, installed in the customer's own AWS account from AWS Marketplace and billed on the AWS bill. Findings, resource data and Lighthouse AI prompts stay in that account and Region.
|
||||
|
||||
<Note>
|
||||
For AWS GovCloud (US), an air-gapped environment, an on-premises data center, or a different bundle size or contract term, [contact us](https://prowler.com/contact) for a private offer.
|
||||
</Note>
|
||||
|
||||
## Choose a Plan
|
||||
|
||||
Each plan is its own AWS Marketplace listing. All three install the same product and differ only in how many cloud accounts the price covers:
|
||||
|
||||
* **Paid accounts:** AWS accounts, Azure subscriptions and Microsoft 365 tenants.
|
||||
* **Other accounts:** everything else Prowler scans, such as Google Cloud projects, Kubernetes clusters, GitHub and Okta.
|
||||
|
||||
| Plan | Price | Included every month | Extra accounts |
|
||||
| --- | --- | --- | --- |
|
||||
| [Pay as You Go](https://aws.amazon.com/marketplace/pp/prodview-cpfki233rkskw) | 125 USD per paid account per month, no minimum | 1 other account per paid account | 125 USD each per month |
|
||||
| [10-Account Bundle](https://aws.amazon.com/marketplace/pp/prodview-2pgvyyakt34go) | 1,000 USD per month, or 9,600 USD for 12 months upfront | 10 paid and 15 other accounts | 125 USD each per month |
|
||||
| [25-Account Bundle](https://aws.amazon.com/marketplace/pp/prodview-ugxkxhdxfrhse) | 2,000 USD per month, or 19,200 USD for 12 months upfront | 25 paid and 40 other accounts | 125 USD each per month |
|
||||
|
||||
### Example: Pay as You Go
|
||||
|
||||
A month with 4 AWS accounts and 6 Google Cloud projects scanned:
|
||||
|
||||
| Charge | Quantity × price | Subtotal |
|
||||
| --- | --- | --- |
|
||||
| Paid accounts (the 4 AWS accounts) | 4 × 125 USD | 500 USD |
|
||||
| Included other accounts (4 Google Cloud projects, 1 per paid account) | 4 × 0 USD | 0 USD |
|
||||
| Extra accounts (the other 2 Google Cloud projects) | 2 × 125 USD | 250 USD |
|
||||
| **Total** | | **750 USD** |
|
||||
|
||||
### Infrastructure Cost
|
||||
|
||||
AWS bills the infrastructure the installation runs on separately, at AWS prices. With the default size in us-east-1, it costs about 360 USD a month before scans.
|
||||
|
||||
Scans add to that: each scan runs as its own task at about 0.12 USD for every hour it runs, and the database grows while scans run. A scan of one AWS account usually takes:
|
||||
|
||||
* **Up to 2,000 resources:** about 10 minutes.
|
||||
* **2,000 to 10,000 resources:** about 25 minutes.
|
||||
* **Over 10,000 resources:** about an hour.
|
||||
|
||||
For example, 10 AWS accounts scanned once a day, at about 20 minutes each:
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Scans per month | 10 accounts × 30 days = 300 scans |
|
||||
| Scan time per month | 300 scans × 1/3 hour = 100 hours |
|
||||
| **Scan cost per month** | **100 hours × 0.12 USD = about 12 USD** |
|
||||
|
||||
Other Regions cost more than us-east-1. Amazon Bedrock is billed per use, only when Lighthouse AI is on.
|
||||
|
||||
<Note>
|
||||
These figures are estimates based on AWS public list prices. AWS bills the infrastructure directly to your account, and the final amount depends on your Region, usage and any discounts you have with AWS. Prowler does not set or charge these costs.
|
||||
</Note>
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Infrastructure cost breakdown">
|
||||
About 360 USD a month for the default size in us-east-1, at AWS list prices, before scans:
|
||||
|
||||
| Resource | About, per month |
|
||||
| --- | --- |
|
||||
| Amazon Elastic Container Service (ECS) on AWS Fargate (Prowler services) | 177 USD |
|
||||
| Amazon Aurora PostgreSQL | 47 USD |
|
||||
| Amazon ElastiCache | 37 USD |
|
||||
| Network address translation (NAT) gateway | 37 USD |
|
||||
| Application Load Balancer and AWS Web Application Firewall (WAF) | 28 USD |
|
||||
| Amazon CloudWatch | 22 USD |
|
||||
| Other AWS services | 10 USD |
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## How It Works
|
||||
|
||||
The installation runs in the customer's AWS account, in the chosen Region. Users reach it through an Amazon CloudFront address, or a [custom domain](#updates-and-settings). Everything else runs in private subnets that cannot be reached from the internet. Scans use read-only access to the connected cloud accounts, and Prowler has no access to the installation.
|
||||
|
||||
<Frame>
|
||||
<img className="block dark:hidden" src="/images/products/architecture/prowler-private-cloud-aws-architecture-light.svg" alt="Prowler Private Cloud on AWS: users reach Amazon CloudFront, which connects to an internal load balancer in a private network; the Prowler services run on Amazon ECS, with Amazon Aurora and Amazon ElastiCache for data and other AWS services in the same account; scans reach the connected accounts with read-only access" />
|
||||
<img className="hidden dark:block" src="/images/products/architecture/prowler-private-cloud-aws-architecture-dark.svg" alt="Prowler Private Cloud on AWS: users reach Amazon CloudFront, which connects to an internal load balancer in a private network; the Prowler services run on Amazon ECS, with Amazon Aurora and Amazon ElastiCache for data and other AWS services in the same account; scans reach the connected accounts with read-only access" />
|
||||
</Frame>
|
||||
|
||||
## Install Prowler Private Cloud
|
||||
|
||||
<Steps>
|
||||
<Step title="Subscribe on AWS Marketplace">
|
||||
Open the plan's listing on AWS Marketplace (links in [Choose a Plan](#choose-a-plan)), click **View purchase options**, and subscribe. Then continue to the configuration and to launch. The launch page has a link that opens the AWS CloudFormation console with the Prowler template already loaded.
|
||||
</Step>
|
||||
|
||||
<Step title="Choose a Supported Region">
|
||||
Before creating the stack, switch the console to a supported Region at the top right. The template refuses the others.
|
||||
|
||||
<Accordion title="Supported Regions">
|
||||
| Region code | Region name | Lighthouse AI |
|
||||
| --- | --- | --- |
|
||||
| us-east-1 | US East (N. Virginia) | Available |
|
||||
| us-east-2 | US East (Ohio) | Available |
|
||||
| us-west-1 | US West (N. California) | Not available |
|
||||
| us-west-2 | US West (Oregon) | Available |
|
||||
| ca-central-1 | Canada (Central) | Not available |
|
||||
| sa-east-1 | South America (São Paulo) | Available |
|
||||
| eu-west-1 | Europe (Ireland) | Available |
|
||||
| eu-west-2 | Europe (London) | Available |
|
||||
| eu-west-3 | Europe (Paris) | Not available |
|
||||
| eu-central-1 | Europe (Frankfurt) | Available |
|
||||
| eu-north-1 | Europe (Stockholm) | Available |
|
||||
| ap-east-1 | Asia Pacific (Hong Kong) | Not available |
|
||||
| ap-south-1 | Asia Pacific (Mumbai) | Available |
|
||||
| ap-southeast-1 | Asia Pacific (Singapore) | Available |
|
||||
| ap-southeast-2 | Asia Pacific (Sydney) | Available |
|
||||
| ap-northeast-1 | Asia Pacific (Tokyo) | Available |
|
||||
| ap-northeast-2 | Asia Pacific (Seoul) | Available |
|
||||
</Accordion>
|
||||
</Step>
|
||||
|
||||
<Step title="Fill In the Required Section">
|
||||
Enter:
|
||||
|
||||
* **Admin password:** the password for the built-in account `admin@prowler.local`.
|
||||
* **Notification email:** the address that receives update, alarm and subscription notices.
|
||||
* **Lighthouse AI:** whether to turn it on. Leave it off in the Regions where it is not available.
|
||||
* **Portal access:** who can open the portal, from anywhere or only from an IP range.
|
||||
|
||||
Leave the optional fields and the version as they are, acknowledge the Identity and Access Management (IAM) capabilities, and create the stack. The installation takes about 35 minutes.
|
||||
</Step>
|
||||
|
||||
<Step title="Confirm the Notification Email">
|
||||
AWS sends a subscription confirmation to the notification address. Confirm it: without it, no update, alarm or subscription notices arrive.
|
||||
</Step>
|
||||
|
||||
<Step title="Sign In">
|
||||
Open the address in the stack's **Outputs** tab (`UiUrl`), an Amazon CloudFront address until a [custom domain](#updates-and-settings) is set up, and sign in as `admin@prowler.local` with the admin password set in step 3. The AWS account Prowler is installed in is already connected: start its first scan from **Scans**, and invite the team from **Users**.
|
||||
</Step>
|
||||
|
||||
<Step title="Add Cloud Accounts">
|
||||
From **Cloud Providers** in the portal, add single AWS accounts, a whole AWS Organization, or other providers.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## How Billing Works
|
||||
|
||||
* **Monthly count:** each cloud account Prowler scans in a calendar month (UTC) counts once that month, however many scans it has.
|
||||
* **AWS bill:** the subscription appears on the AWS bill, line by line, including the accounts the plan includes at 0.00 USD.
|
||||
* **Monthly statement:** at the start of each month, the installation emails last month's usage.
|
||||
|
||||
If the subscription ends, Prowler keeps working for 7 days and a daily email counts the days down. After that, new scans and premium features pause, but findings, history and reports stay. Subscribing again resumes everything within the hour.
|
||||
|
||||
## Updates and Settings
|
||||
|
||||
New Prowler releases install automatically every night. Settings chosen at launch can be changed later with a stack update:
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Use a Custom Domain">
|
||||
Without a custom domain, Prowler runs on its Amazon CloudFront address.
|
||||
|
||||
1. Choose a subdomain that starts with `prowler`, such as `prowler.example.com`.
|
||||
2. Request an AWS Certificate Manager certificate for `cloud.prowler.example.com`, `api.cloud.prowler.example.com` and `mcp.prowler.example.com` in us-east-1. Request a second one in the installation's Region, unless the domain is an Amazon Route 53 hosted zone in the same account.
|
||||
3. Open the AWS CloudFormation console in the installation's Region, go to **Stacks**, select the Prowler stack, and click **Update**, then **Make a direct update**.
|
||||
4. Choose **Use existing template** and click **Next**.
|
||||
5. Fill in the **Your own domain** fields with the domain and the certificates, and leave every other parameter as it is. Click **Next** until the review page.
|
||||
6. Acknowledge the IAM capabilities and click **Submit**.
|
||||
</Accordion>
|
||||
<Accordion title="Turn Lighthouse AI On or Off">
|
||||
To turn Lighthouse AI on:
|
||||
|
||||
1. Open the AWS CloudFormation console in the installation's Region, go to **Stacks**, select the Prowler stack, and click **Update**, then **Make a direct update**.
|
||||
2. Choose **Use existing template** and click **Next**.
|
||||
3. Set **Lighthouse AI** to **Enabled**, and leave every other parameter as it is. Click **Next** until the review page.
|
||||
4. Acknowledge the IAM capabilities and click **Submit**. Lighthouse AI is ready within minutes and needs no keys.
|
||||
|
||||
To turn it off, delete its provider in the portal's Lighthouse AI settings.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Uninstall
|
||||
|
||||
Contact [support@prowler.com](mailto:support@prowler.com) for the uninstall steps: the installation protects its data against accidental deletion, so deleting the stack on its own stops partway. Uninstalling does not cancel the subscription; cancel it in the AWS Marketplace console, under **Manage subscriptions**.
|
||||
|
||||
## Get Support
|
||||
|
||||
Write to [support@prowler.com](mailto:support@prowler.com), with the AWS account ID, the Region and the stack name.
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1460 790" font-family="'Inter Diagram', Inter, 'Segoe UI', system-ui, -apple-system, sans-serif" role="img" aria-label="Prowler Private Cloud on AWS architecture"><title>Prowler Private Cloud on AWS architecture</title><defs><style>@font-face{font-family:"Inter Diagram";font-weight:400 700;src:url(data:font/woff2;base64,d09GMgABAAAAAL0wABQAAAAB4AgAALy3AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoZeG4KyRBzVcD9IVkFSi2k/TVZBUl4GYD9TVEFUgU4nJgCFNi9sEQgKgbtAgaEUC4gOADCCnD4BNgIkA5AYBCAFhi4HoQRbbM1xJ9pEvFeIqaVsuokIsO22SVU1fQk3aHa/1VxA501dSsJn5lSwbRr1bgcRJN0fNvv////PTSpjaFO2tAUBUdXp/H+hZmYeWbxMkksUg6gSjR4sJp1OluyFAZzHknNZFfcOC/jkm4TBTvWYFyAlzqJGm4RoBKtiTp9mkyGfCzYwC/BDbocpQqUSQIhMa7ygZvA0U75Y4LFTHnT/aGZJWR6pLqVniIDetGuXwgUe8/POsOsP1Q9VUiWTp72izbt5tKtLgWhoWrfh09M7RFpXf5QIFuBDxYUkcftGuBj4EcUodLrLBqOES28ulU2C4bvURfopCwxHk8sX8DGo2D5LQadmFhKB7no9F66EECKF6kb1LqY15mIYK93FNtnkyduuV/xNv9PH6x75G9MA70vGml6p8vX9jTf8AlMyEzuyoIG97E5cYX23aa9Hhfa/gh+rhMr0p6hG3V/wUX/4bg8BtusHxJhISTNsDu+T58G6+P7cJFXdA5Grx9UI3uHDWFqdI9Ktmb2SSyGEEKqU0AMiIERQ9DXQRVFERKTZsDREnyYqQuzAK/KWiqiIvCLvK49+s1SK7ysqomJ9xU6RIlJyVj8G+727t4KYRiKJ6Uw3iRAa2bRlQiZEItHsW/vD03T+u+jlcsnF5JJcVJs03iStI4UWK6LFbFo+M0LKTNmHjYkoait4BVakjq+l1KiQpkOgZ1ejQ422tKUtSiXWioidPSUhIkaCIEQiJCIRxIrZgS6Umqtf2qKtjv1Px/y9+msMz2/q/7lAgHjTWFWm1u39lwuknXfinuWlXXeFXDRAULlcJHiACBaVSpLG6zrP9pfj382aQdsZgpTumfvX7RNCulCnLRXfvMwJ+YXfUxXkTPjnn/182+cl+UV2VSRMdTuAwgDh8lHDRrIjMIL8qBEeMNcHvm3fH+/WjbYKuzHASXJESqJioBVY17svf6PqbzuK4d/N6iGtj+iaWFkz/5I7p6zJuXQ61p1ScwoePIQQgkYhEBIIwQMEAPR8+/VWPTOJIpIZnRPLCgkX7n+LqGKXJDBIYOoauuaHLayoaOIjGdjlV6MOfAKzjwhVNzQG8uRBYAVG2G770u2fvmQSp6bxI+T7xENyB+QBe8AeoEcZuQ+kAeuBNUAPWC5Q9GWfx1lOJY/yDoxbtnO9DPRjm33JS4DgNZ9ZFz3tVZR+Oa2onNy/uJXaQAMEgOdzqn9JzlyoZbnAjsVZJcsFBJQRPR7+3U9T2ylSxF9XdraQNyIXPyBJZMSM6/E1btLkwv/za5LnfprgMqmiIj2Tlm3ZuArXd/NTJInsditVbStcBuZmuh2o+5q/Le+s6Wn6HRGdCSs788v5/j+BxKuXa14CfoTIRDS2lRoVt+HWDIa+ViyxC8jxO7gBW/OIoGiLnaEaCsXU2aW+WOJz2VEo+nvGlPjd/j3RNKHmv5gaD0KBXUYZRsEehmEIuDF2TFNM/H2pWtf/Gh9kA5phEeCu2FpPaNrLnY+JkCacQbXkCSnd99xAEwa6AVINiJIBUAGkU4Myxx8UaYPksMwGFGjSKVLakO2sTfkDlGpalDzVJhVAOVGaqPJtYqA3hHCL8bS1p91biOe9nUK+7Snkw+m+x93rZXn+//fmbO5s6ij+etAlEhlh/sKqKS05REF/DrprzauscSBjvAD+v5+m+OmM5rkr2p9WEdv5sgNIAA7ga3fN3Y1SuiawdVQqlAsK8gQgT1AHpHVcAQpjISAAx/+cllRPT77x/4su6bQ1zlclIxd5i51a0HpTCwsK4UFHYADC+WmtX/2Le4iQCUnMG41QmMfyvu0XQ8yiv5WbO/8ijmop1ELNs4MdJLETVBI8H960wDp7QLiL8kmCA8CPYRj2l6qfLR6BNyR/5kVeCKEozyFWJ3cVsIvVYrFYEUzzQYI8pUskpR8yJQetwH8GeSGGyjFQF0LsfOXVrly5c1V6ehdFFXLfmIf+l+/s3iS0stDloIiOcN+q3Ucdhtaqa0U4MBYhP8Jx8ECgLqa7fnPxCKfgAxOkGc4hlEASFBLH+3xTZ9v8XOc6hmIrhE8c8ssqm9XruP+Qa2oewlIXHDK9wBLCOBOecPNd7o+pilS1stzLEdZ9OtYygqAgwlXJwr/bC6/nhumPhSelkyKhBBdk7HPWxMpSrcMGsGGGxQgzCCOEEI1ohBA6YRzfxPl9y2RNdvv3faPQ77zZeW6nHCQEEREJEkQknX0IdYqXva4nCasWr+lFjEq5Tuwb6+8dY7Yf8GuX1ae/5AEBBTmWNsEitkz2kJfKUKpQ4/X//dLPi8Gk3T2+ZZaNLIdSawnBKxJFQgjHOvM1lqqKI1Neth/ZVFpz6cNukFF/QZG7/ffQd4HvIswRhVCRs1CVR9Bjz6GX+qBBOhiCBDA0MoCRoAQwUtQHjHUEjEMGmOAIMOHRYQqrh9mTHmZ/RpiDWWBO5Yc5XQjm79IwF2uDqWkEldauwHTUgUp33SiIAKsDi0NsahpsqOGu1Q1hbkNQbkWDshFwCnAIsDI9iEDggQXOPtm7vQDyP9G7f7Y+9Uco+35f/hvvxaeBOeAe8BVQIAKkd761/u0pr4EC5AXBef4Jv3BX5YMrdv/fntv3rzjw+FMrbkKPvnKL8+Ss2yrvXH5X5d3L7x1/7/J7V967+t619y9/wFzrrI0/uPxhZX30kvNS5WOOf8ufeLisvQxMT3+SceW8K5VPLnly+VOO64broevxZ21NrqaspmBT5fO+oNGKHwAzshFCBHGhdDGLTbIkqN+rVUtPnanehoztbX4LDnwYRsg7nJ7e3O5O97OLD6X00c9wSAOP4vjSkvmmO/3zkzm43GqWP6fTWR0xUuSYKIYBa86TTyEiarHkbGOExU976TuJWFQmOdOY+BzOl0cycktZhDqgD46jsLEgZEEYhRYehAy2sjksbIUO+7URjkhEI5ahclSowhWtwk5PzjXn//QTtXTZ1kFMbNzlbxBNZ3pTSr99G7pYktK+O5qgBtbtcGNhHofHE+ydhAVbBIk4MqWyXWnKUu7JZKJUmtjOvegIivXu6zsL3wGPAwAEoE24SCKtUzsbQpFUh8Vm9/j8cBjDE8k0STFslsvxhdJgwvN5KGJMorKq6YZlZwViBaHRGsxWRyhcINEa7aFsDhAgHQYdFQRgbxoQYFERitD738bp4f14iY/B5WneH4XLC+5sAuZoQOcNUFAm1Cg7xs0ue5JPYOSkqf6Vi1C+GI3v2hwIJjg2ercBtaG5gnHXJxpf5uewRmhJsWSQCMIlSsXzzuJCgqHhwZExCaok7FnpBR+uQxWG6SBafD6UPwfUfNiMH3ni8C5UivfKiBb3hgy2AKpvJjiC/7WCaVABDXhcuSU8D0fg4hdIkmMcFh0GZ6/4Nx//0NL/Xgvdl/o/fPtXfAS+9ri+Oiv5yz/M4Z/3YVOo7H1x2cPOd9ZbLrnI2U/bComrutjZTqugctwTnkMe5bE9FGFX/sfFF9rlmTOue7U1n9iqja3nMt+DQZNpZStM37ahV14eNqdTW8WOpiRGfInEHq0zI42y2/K/TWbYIc7yifFGF0EQDrb9bPk6tzrgfOXrtltrqdTdwLeD3zXbRCNsqqD0sFkdS1ZO13RB+cpYQcqNSytCVSqQqFizFS+PTJIIZnopMHqFFnlsoMG0u83Q6RM0QotZQzlTmNZrOJlIwmkwm7EgL1ZZgpHoryUL19xpef5XpYpVq+qG6qiq4jqqq8wFSZ0uzQblYfjE45lscxbjjTWy8PN9C5rxfvRh7CjtSco3lsiCkD5z4ga0a9Su2BojujTIuVGO1aSioUr9emM1TEaEAnNAyLcAatm0GSMCYqu5ZIhYBZ0Yg4BEinZJlRlGUrIK4agtQinyvBsACEeSpeqAztqyiNe24NAk6E39qzMefI9uaAVcVbTyv9DevGWz/kU3hK0nNstO7Z+FwrRJWWLW9zLpWcR4Crd9E15Xz+OhLZ+9KVXx74Y2nOQMUF71midvXjG807SupKyoEX2RM2S43m3CkbgV8131NbICl2yOfDhPVePOWXFLFhn3Xza9foOTJzgQKjOcTZhWDYGp86oAef2Rp68ex54tWo7GuAdTr++81yZwExUeu0b7UOqZwCa+aWayiWrXLvwJf7uhEG30URWB+3bwRRkbDbvvaMvl4Ja1mtqZD3OI7J2DcIGh/SkX/MuaGYHD/bIvl2OzZSx6L+QlngLk1VeGNPOs7eYZlkr6enPTOaVYX246qNY5hIvuMNvMe7Xp/MY/PdufDHWu7DNZifO0Py8e7GdvMpHnFmMQCss4oiRcsmPT5PgitkzQP9ebG4+/UpPxh78OoYHMk6uy8BFZsNHm/4Q/GcJyfjhfo72Yx88Ds3DApGaFzw4mLOGro34kNfhwiLweyV4GloOmDWkLShB29CMIeF4SklM1HdexIkRC9h8jacvLa7bnRe3VEo+L1n7qOCFIGloxb258jez5Line truncated
|
||||
|
Before Width: | Height: | Size: 106 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1460 790" font-family="'Inter Diagram', Inter, 'Segoe UI', system-ui, -apple-system, sans-serif" role="img" aria-label="Prowler Private Cloud on AWS architecture"><title>Prowler Private Cloud on AWS architecture</title><defs><style>@font-face{font-family:"Inter Diagram";font-weight:400 700;src:url(data:font/woff2;base64,d09GMgABAAAAAL0wABQAAAAB4AgAALy3AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoZeG4KyRBzVcD9IVkFSi2k/TVZBUl4GYD9TVEFUgU4nJgCFNi9sEQgKgbtAgaEUC4gOADCCnD4BNgIkA5AYBCAFhi4HoQRbbM1xJ9pEvFeIqaVsuokIsO22SVU1fQk3aHa/1VxA501dSsJn5lSwbRr1bgcRJN0fNvv////PTSpjaFO2tAUBUdXp/H+hZmYeWbxMkksUg6gSjR4sJp1OluyFAZzHknNZFfcOC/jkm4TBTvWYFyAlzqJGm4RoBKtiTp9mkyGfCzYwC/BDbocpQqUSQIhMa7ygZvA0U75Y4LFTHnT/aGZJWR6pLqVniIDetGuXwgUe8/POsOsP1Q9VUiWTp72izbt5tKtLgWhoWrfh09M7RFpXf5QIFuBDxYUkcftGuBj4EcUodLrLBqOES28ulU2C4bvURfopCwxHk8sX8DGo2D5LQadmFhKB7no9F66EECKF6kb1LqY15mIYK93FNtnkyduuV/xNv9PH6x75G9MA70vGml6p8vX9jTf8AlMyEzuyoIG97E5cYX23aa9Hhfa/gh+rhMr0p6hG3V/wUX/4bg8BtusHxJhISTNsDu+T58G6+P7cJFXdA5Grx9UI3uHDWFqdI9Ktmb2SSyGEEKqU0AMiIERQ9DXQRVFERKTZsDREnyYqQuzAK/KWiqiIvCLvK49+s1SK7ysqomJ9xU6RIlJyVj8G+727t4KYRiKJ6Uw3iRAa2bRlQiZEItHsW/vD03T+u+jlcsnF5JJcVJs03iStI4UWK6LFbFo+M0LKTNmHjYkoait4BVakjq+l1KiQpkOgZ1ejQ422tKUtSiXWioidPSUhIkaCIEQiJCIRxIrZgS6Umqtf2qKtjv1Px/y9+msMz2/q/7lAgHjTWFWm1u39lwuknXfinuWlXXeFXDRAULlcJHiACBaVSpLG6zrP9pfj382aQdsZgpTumfvX7RNCulCnLRXfvMwJ+YXfUxXkTPjnn/182+cl+UV2VSRMdTuAwgDh8lHDRrIjMIL8qBEeMNcHvm3fH+/WjbYKuzHASXJESqJioBVY17svf6PqbzuK4d/N6iGtj+iaWFkz/5I7p6zJuXQ61p1ScwoePIQQgkYhEBIIwQMEAPR8+/VWPTOJIpIZnRPLCgkX7n+LqGKXJDBIYOoauuaHLayoaOIjGdjlV6MOfAKzjwhVNzQG8uRBYAVG2G770u2fvmQSp6bxI+T7xENyB+QBe8AeoEcZuQ+kAeuBNUAPWC5Q9GWfx1lOJY/yDoxbtnO9DPRjm33JS4DgNZ9ZFz3tVZR+Oa2onNy/uJXaQAMEgOdzqn9JzlyoZbnAjsVZJcsFBJQRPR7+3U9T2ylSxF9XdraQNyIXPyBJZMSM6/E1btLkwv/za5LnfprgMqmiIj2Tlm3ZuArXd/NTJInsditVbStcBuZmuh2o+5q/Le+s6Wn6HRGdCSs788v5/j+BxKuXa14CfoTIRDS2lRoVt+HWDIa+ViyxC8jxO7gBW/OIoGiLnaEaCsXU2aW+WOJz2VEo+nvGlPjd/j3RNKHmv5gaD0KBXUYZRsEehmEIuDF2TFNM/H2pWtf/Gh9kA5phEeCu2FpPaNrLnY+JkCacQbXkCSnd99xAEwa6AVINiJIBUAGkU4Myxx8UaYPksMwGFGjSKVLakO2sTfkDlGpalDzVJhVAOVGaqPJtYqA3hHCL8bS1p91biOe9nUK+7Snkw+m+x93rZXn+//fmbO5s6ij+etAlEhlh/sKqKS05REF/DrprzauscSBjvAD+v5+m+OmM5rkr2p9WEdv5sgNIAA7ga3fN3Y1SuiawdVQqlAsK8gQgT1AHpHVcAQpjISAAx/+cllRPT77x/4su6bQ1zlclIxd5i51a0HpTCwsK4UFHYADC+WmtX/2Le4iQCUnMG41QmMfyvu0XQ8yiv5WbO/8ijmop1ELNs4MdJLETVBI8H960wDp7QLiL8kmCA8CPYRj2l6qfLR6BNyR/5kVeCKEozyFWJ3cVsIvVYrFYEUzzQYI8pUskpR8yJQetwH8GeSGGyjFQF0LsfOXVrly5c1V6ehdFFXLfmIf+l+/s3iS0stDloIiOcN+q3Ucdhtaqa0U4MBYhP8Jx8ECgLqa7fnPxCKfgAxOkGc4hlEASFBLH+3xTZ9v8XOc6hmIrhE8c8ssqm9XruP+Qa2oewlIXHDK9wBLCOBOecPNd7o+pilS1stzLEdZ9OtYygqAgwlXJwr/bC6/nhumPhSelkyKhBBdk7HPWxMpSrcMGsGGGxQgzCCOEEI1ohBA6YRzfxPl9y2RNdvv3faPQ77zZeW6nHCQEEREJEkQknX0IdYqXva4nCasWr+lFjEq5Tuwb6+8dY7Yf8GuX1ae/5AEBBTmWNsEitkz2kJfKUKpQ4/X//dLPi8Gk3T2+ZZaNLIdSawnBKxJFQgjHOvM1lqqKI1Neth/ZVFpz6cNukFF/QZG7/ffQd4HvIswRhVCRs1CVR9Bjz6GX+qBBOhiCBDA0MoCRoAQwUtQHjHUEjEMGmOAIMOHRYQqrh9mTHmZ/RpiDWWBO5Yc5XQjm79IwF2uDqWkEldauwHTUgUp33SiIAKsDi0NsahpsqOGu1Q1hbkNQbkWDshFwCnAIsDI9iEDggQXOPtm7vQDyP9G7f7Y+9Uco+35f/hvvxaeBOeAe8BVQIAKkd761/u0pr4EC5AXBef4Jv3BX5YMrdv/fntv3rzjw+FMrbkKPvnKL8+Ss2yrvXH5X5d3L7x1/7/J7V967+t619y9/wFzrrI0/uPxhZX30kvNS5WOOf8ufeLisvQxMT3+SceW8K5VPLnly+VOO64broevxZ21NrqaspmBT5fO+oNGKHwAzshFCBHGhdDGLTbIkqN+rVUtPnanehoztbX4LDnwYRsg7nJ7e3O5O97OLD6X00c9wSAOP4vjSkvmmO/3zkzm43GqWP6fTWR0xUuSYKIYBa86TTyEiarHkbGOExU976TuJWFQmOdOY+BzOl0cycktZhDqgD46jsLEgZEEYhRYehAy2sjksbIUO+7URjkhEI5ahclSowhWtwk5PzjXn//QTtXTZ1kFMbNzlbxBNZ3pTSr99G7pYktK+O5qgBtbtcGNhHofHE+ydhAVbBIk4MqWyXWnKUu7JZKJUmtjOvegIivXu6zsL3wGPAwAEoE24SCKtUzsbQpFUh8Vm9/j8cBjDE8k0STFslsvxhdJgwvN5KGJMorKq6YZlZwViBaHRGsxWRyhcINEa7aFsDhAgHQYdFQRgbxoQYFERitD738bp4f14iY/B5WneH4XLC+5sAuZoQOcNUFAm1Cg7xs0ue5JPYOSkqf6Vi1C+GI3v2hwIJjg2ercBtaG5gnHXJxpf5uewRmhJsWSQCMIlSsXzzuJCgqHhwZExCaok7FnpBR+uQxWG6SBafD6UPwfUfNiMH3ni8C5UivfKiBb3hgy2AKpvJjiC/7WCaVABDXhcuSU8D0fg4hdIkmMcFh0GZ6/4Nx//0NL/Xgvdl/o/fPtXfAS+9ri+Oiv5yz/M4Z/3YVOo7H1x2cPOd9ZbLrnI2U/bComrutjZTqugctwTnkMe5bE9FGFX/sfFF9rlmTOue7U1n9iqja3nMt+DQZNpZStM37ahV14eNqdTW8WOpiRGfInEHq0zI42y2/K/TWbYIc7yifFGF0EQDrb9bPk6tzrgfOXrtltrqdTdwLeD3zXbRCNsqqD0sFkdS1ZO13RB+cpYQcqNSytCVSqQqFizFS+PTJIIZnopMHqFFnlsoMG0u83Q6RM0QotZQzlTmNZrOJlIwmkwm7EgL1ZZgpHoryUL19xpef5XpYpVq+qG6qiq4jqqq8wFSZ0uzQblYfjE45lscxbjjTWy8PN9C5rxfvRh7CjtSco3lsiCkD5z4ga0a9Su2BojujTIuVGO1aSioUr9emM1TEaEAnNAyLcAatm0GSMCYqu5ZIhYBZ0Yg4BEinZJlRlGUrIK4agtQinyvBsACEeSpeqAztqyiNe24NAk6E39qzMefI9uaAVcVbTyv9DevGWz/kU3hK0nNstO7Z+FwrRJWWLW9zLpWcR4Crd9E15Xz+OhLZ+9KVXx74Y2nOQMUF71midvXjG807SupKyoEX2RM2S43m3CkbgV8131NbICl2yOfDhPVePOWXFLFhn3Xza9foOTJzgQKjOcTZhWDYGp86oAef2Rp68ex54tWo7GuAdTr++81yZwExUeu0b7UOqZwCa+aWayiWrXLvwJf7uhEG30URWB+3bwRRkbDbvvaMvl4Ja1mtqZD3OI7J2DcIGh/SkX/MuaGYHD/bIvl2OzZSx6L+QlngLk1VeGNPOs7eYZlkr6enPTOaVYX246qNY5hIvuMNvMe7Xp/MY/PdufDHWu7DNZifO0Py8e7GdvMpHnFmMQCss4oiRcsmPT5PgitkzQP9ebG4+/UpPxh78OoYHMk6uy8BFZsNHm/4Q/GcJyfjhfo72Yx88Ds3DApGaFzw4mLOGro34kNfhwiLweyV4GloOmDWkLShB29CMIeF4SklM1HdexIkRC9h8jacvLa7bnRe3VEo+L1n7qOCFIGloxb258jez5Line truncated
|
||||
|
Before Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 210 KiB |
@@ -4,10 +4,6 @@
|
||||
|
||||

|
||||
|
||||
<Card title="Get started with Prowler Cloud" icon="cloud" href="https://cloud.prowler.com/sign-up">
|
||||
The fastest way to run Prowler: create an account, connect a provider, and get findings without installing anything. No billing details are required during the trial period.
|
||||
</Card>
|
||||
|
||||
Prowler ships two product families: Prowler Products, operated or licensed by the Prowler team, and Open Source projects, free to run and extend. See [Prowler product families](/getting-started/products) for every official name, including former names.
|
||||
|
||||
### Prowler Products
|
||||
@@ -29,8 +25,6 @@ Prowler ships two product families: Prowler Products, operated or licensed by th
|
||||
|
||||
### Open Source
|
||||
|
||||
Free to run and extend. Prefer the Open Source projects to run Prowler from a terminal, in CI/CD, or on infrastructure you operate yourself.
|
||||
|
||||
<Columns cols={2}>
|
||||
<Card title="Prowler CLI" icon="terminal" href="/getting-started/products/prowler-cli">
|
||||
Command line tool to run security scans across all supported providers.
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
export const AwsMarketplaceBanner = () => {
|
||||
return (
|
||||
<Info>
|
||||
<b>Now available on AWS Marketplace.</b> Install Prowler Private Cloud in your own AWS account and pay on your AWS bill, with three plans: Pay as You Go, 10-Account Bundle and 25-Account Bundle. <a href="#choose-a-plan">Choose a plan</a>.
|
||||
</Info>
|
||||
);
|
||||
};
|
||||
@@ -80,7 +80,6 @@
|
||||
nested spans of a tag pill such as Coming Soon.
|
||||
Icon source: /images/icons/cloud-bold.svg. See AGENTS.md "Cloud Marker" convention. */
|
||||
li[data-title="Prowler Cloud"] > button span:first-child::after,
|
||||
li[id="/getting-started/products/prowler-private-cloud-aws-marketplace"] a > div > div > span:first-child::after,
|
||||
li[data-title="Prowler Lighthouse AI"] > button span:first-child::after,
|
||||
li[data-title="Providers"] > button span:first-child::after,
|
||||
li[data-title="Scans"] > button span:first-child::after,
|
||||
|
||||
@@ -292,8 +292,6 @@ The following list includes all the Vercel checks with configurable variables th
|
||||
| `deployment_production_uses_stable_target` | `stable_branches` | List of Strings | `["main", "master"]` |
|
||||
| `domain_ssl_certificate_valid` | `days_to_expire_threshold` | Integer | `7` |
|
||||
| `project_environment_no_secrets_in_plain_type` | `secret_suffixes` | List of Strings | `["_KEY", "_SECRET", "_TOKEN", "_PASSWORD", "_API_KEY", "_PRIVATE_KEY"]` |
|
||||
| `project_environment_no_secrets_with_public_prefix` | `secret_suffixes` | List of Strings | `["_KEY", "_SECRET", "_TOKEN", "_PASSWORD", "_API_KEY", "_PRIVATE_KEY"]` |
|
||||
| `project_environment_no_secrets_with_public_prefix` | `public_env_prefixes` | List of Strings | `["NEXT_PUBLIC_", "NUXT_PUBLIC_", "VITE_", "REACT_APP_", "VUE_APP_", "GATSBY_", "EXPO_PUBLIC_", "PUBLIC_"]` |
|
||||
| `team_member_role_least_privilege` | `max_owner_percentage` | Integer | `20` |
|
||||
| `team_member_role_least_privilege` | `max_owners` | Integer | `3` |
|
||||
| `team_no_stale_invitations` | `stale_invitation_threshold_days` | Integer | `30` |
|
||||
@@ -907,7 +905,7 @@ vercel:
|
||||
# vercel.team_member_role_least_privilege
|
||||
max_owner_percentage: 20
|
||||
max_owners: 3
|
||||
# vercel.project_environment_no_secrets_in_plain_type & vercel.project_environment_no_secrets_with_public_prefix
|
||||
# vercel.project_environment_no_secrets_in_plain_type
|
||||
secret_suffixes:
|
||||
- "_KEY"
|
||||
- "_SECRET"
|
||||
@@ -915,16 +913,6 @@ vercel:
|
||||
- "_PASSWORD"
|
||||
- "_API_KEY"
|
||||
- "_PRIVATE_KEY"
|
||||
# vercel.project_environment_no_secrets_with_public_prefix
|
||||
public_env_prefixes:
|
||||
- "NEXT_PUBLIC_"
|
||||
- "NUXT_PUBLIC_"
|
||||
- "VITE_"
|
||||
- "REACT_APP_"
|
||||
- "VUE_APP_"
|
||||
- "GATSBY_"
|
||||
- "EXPO_PUBLIC_"
|
||||
- "PUBLIC_"
|
||||
|
||||
|
||||
```
|
||||
@@ -24,13 +24,7 @@ Make sure you update the `/your/local/dir/prowler-output` to match the path that
|
||||
**Remember that the `dashboard` server is not authenticated. If you expose it to the Internet, do it at your own risk.**
|
||||
|
||||
</Note>
|
||||
The console shows the dashboard version, the directory the CSV files are loaded from, the local URL once the server is listening, and a short note about bringing your findings to Prowler Cloud. Set `PROWLER_NO_PROMOTIONS=1` to omit that note:
|
||||
|
||||
```sh
|
||||
PROWLER_NO_PROMOTIONS=1 prowler dashboard
|
||||
```
|
||||
|
||||
Set `NO_COLOR=1` to print the startup output without colors.
|
||||
The banner and additional info about the dashboard will be shown on your console: <img src="/images/cli/dashboard/dashboard-banner.png" />
|
||||
|
||||
## Overview Page
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: 'Compliance'
|
||||
sidebarTitle: 'Overview'
|
||||
description: 'Run security checks against compliance frameworks, review posture across providers, use Compliance Watchlist to pin frameworks, and download CSV or PDF reports from Prowler Cloud, or CSV reports from Prowler CLI.'
|
||||
description: 'Run security checks against compliance frameworks, review posture across providers, use Compliance Watchlist to pin frameworks, and download CSV or PDF reports from Prowler Cloud and Prowler Local Server, or CSV reports from Prowler CLI.'
|
||||
---
|
||||
|
||||
import { SubscriptionBanner } from "/snippets/subscription-banner.mdx"
|
||||
@@ -24,15 +24,15 @@ For the unified compliance score methodology used across frameworks, see [Prowle
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Prowler Cloud
|
||||
## Prowler Cloud and Prowler Local Server
|
||||
|
||||
The Compliance section in Prowler Cloud centralizes compliance posture across every connected provider. It aggregates scan results, surfaces Prowler ThreatScore, and exposes detailed requirement-level evidence for each supported framework.
|
||||
The Compliance section in Prowler Cloud and Prowler Local Server centralizes compliance posture across every connected provider. It aggregates scan results, surfaces Prowler ThreatScore, and exposes detailed requirement-level evidence for each supported framework.
|
||||
|
||||
### Accessing the Compliance Section
|
||||
|
||||
To open the compliance overview, follow these steps:
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in).
|
||||
1. Sign in to Prowler Cloud at [cloud.prowler.com](https://cloud.prowler.com/sign-in) or to a Prowler Local Server instance.
|
||||
2. Select **Compliance** from the left navigation.
|
||||
|
||||
The Compliance page is organized into two tabs:
|
||||
@@ -42,10 +42,10 @@ The Compliance page is organized into two tabs:
|
||||
|
||||
<SubscriptionBanner label="Multiple Scans tab" />
|
||||
|
||||
<img src="/images/compliance/prowler-app-compliance-overview.png" alt="Compliance overview page in Prowler Cloud showing filters, the Prowler ThreatScore card, and the framework grid" width="900" />
|
||||
<img src="/images/compliance/prowler-app-compliance-overview.png" alt="Compliance overview page in Prowler Cloud and Prowler Local Server showing filters, the Prowler ThreatScore card, and the framework grid" width="900" />
|
||||
|
||||
<Note>
|
||||
Compliance results require at least one completed scan. If no scan has finished yet, Prowler Cloud displays a notice prompting to launch or wait for a scan to complete.
|
||||
Compliance results require at least one completed scan. If no scan has finished yet, Prowler Cloud and Prowler Local Server display a notice prompting to launch or wait for a scan to complete.
|
||||
</Note>
|
||||
|
||||
### Filtering Compliance Results
|
||||
@@ -196,7 +196,7 @@ Frameworks without a custom layout fall back to the generic details panel, which
|
||||
|
||||
### Downloading Compliance Reports
|
||||
|
||||
Prowler Cloud exposes two formats:
|
||||
Prowler Cloud and Prowler Local Server expose two formats:
|
||||
|
||||
* **CSV report:** Every requirement, every check, and every finding for the selected scan and filters. Available for all supported frameworks.
|
||||
* **PDF report:** Curated executive-style report. Currently supported for Prowler ThreatScore, ENS RD2022, NIS2, and CSA CCM. Additional PDF reports are added in subsequent Prowler releases.
|
||||
@@ -234,7 +234,7 @@ Use the API to integrate compliance evidence into ticketing systems, executive d
|
||||
|
||||
## Prowler CLI
|
||||
|
||||
Prowler CLI evaluates the same compliance frameworks as Prowler Cloud, and produces detailed CSV outputs alongside the standard scan results. By default, it runs every supported framework and prints a status summary at the end of the scan:
|
||||
Prowler CLI evaluates the same compliance frameworks as Prowler Cloud and Prowler Local Server, and produces detailed CSV outputs alongside the standard scan results. By default, it runs every supported framework and prints a status summary at the end of the scan:
|
||||
|
||||
<img src="/images/cli/compliance/compliance.png" />
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ title: 'Getting Started With Alibaba Cloud on Prowler'
|
||||
---
|
||||
|
||||
import { VersionBadge } from "/snippets/version-badge.mdx"
|
||||
import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
Prowler supports Alibaba Cloud both from the CLI and from Prowler Cloud. This guide walks you through the requirements, how to connect the provider in the UI, and how to run scans from the command line.
|
||||
|
||||
@@ -30,8 +29,6 @@ Before you begin, make sure you have:
|
||||
|
||||
<VersionBadge version="5.18.0" />
|
||||
|
||||
<AppliesTo />
|
||||
|
||||
### Step 1: Get Your Alibaba Cloud Account ID
|
||||
|
||||
1. Log in to the [Alibaba Cloud Console](https://home.console.alibabacloud.com/)
|
||||
@@ -42,7 +39,7 @@ Before you begin, make sure you have:
|
||||
|
||||
### Step 2: Access Prowler Cloud
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in) or [create an account](https://cloud.prowler.com/sign-up)
|
||||
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler Local Server](/user-guide/tutorials/prowler-app)
|
||||
2. Go to "Configuration" > "Providers"
|
||||
|
||||

|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
title: 'Getting Started With AWS on Prowler'
|
||||
---
|
||||
|
||||
import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
## Prowler Cloud
|
||||
|
||||
<AppliesTo />
|
||||
|
||||
<iframe width="560" height="380" src="https://www.youtube-nocookie.com/embed/RPgIWOCERzY" title="Prowler Cloud Onboarding AWS" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="1"></iframe>
|
||||
|
||||
> Walkthrough video onboarding an AWS Account using Assumed Role.
|
||||
@@ -22,7 +18,7 @@ import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
### Step 2: Access Prowler Cloud
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in) or [create an account](https://cloud.prowler.com/sign-up)
|
||||
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler Local Server](/user-guide/tutorials/prowler-app)
|
||||
2. Go to "Configuration" > "Providers"
|
||||
|
||||

|
||||
@@ -79,7 +75,7 @@ For detailed instructions on how to create the role, see [Authentication > Assum
|
||||
|
||||

|
||||
|
||||
9. Paste the ARN into the corresponding field in Prowler Cloud
|
||||
9. Paste the ARN into the corresponding field in Prowler Cloud or Prowler Local Server
|
||||
|
||||

|
||||
|
||||
@@ -114,7 +110,7 @@ AWS accounts can also be configured using static credentials (not recommended fo
|
||||
|
||||
For detailed instructions on how to create the credentials, see [Authentication > Credentials](/user-guide/providers/aws/authentication#credentials).
|
||||
|
||||
1. Complete the form in Prowler Cloud and click "Next"
|
||||
1. Complete the form in Prowler Cloud or Prowler Local Server and click "Next"
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
title: 'Getting Started With Azure on Prowler'
|
||||
---
|
||||
|
||||
import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
## Prowler Cloud
|
||||
|
||||
<AppliesTo />
|
||||
|
||||
<iframe width="560" height="380" src="https://www.youtube-nocookie.com/embed/v1as8vTFlMg" title="Prowler Cloud Onboarding Azure" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="1"></iframe>
|
||||
> Walkthrough video onboarding an Azure Subscription using Service Principal.
|
||||
|
||||
@@ -38,7 +34,7 @@ For detailed instructions on how to create the Service Principal and configure p
|
||||
|
||||
### Step 2: Access Prowler Cloud
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in) or [create an account](https://cloud.prowler.com/sign-up)
|
||||
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler Local Server](/user-guide/tutorials/prowler-app)
|
||||
2. Navigate to `Configuration` > `Providers`
|
||||
|
||||

|
||||
|
||||
@@ -17,15 +17,11 @@ Prowler for Cloudflare supports two authentication methods, both available in Pr
|
||||
|
||||
## Required Permissions
|
||||
|
||||
Prowler requires read-only access to Cloudflare accounts, zones, and developer platform resources. The following permissions must be configured when creating the API Token:
|
||||
Prowler requires read-only access to Cloudflare zones and their settings. The following permissions must be configured when creating the API Token:
|
||||
|
||||
| Resource | Permission | Access | Description |
|
||||
|----------|------------|--------|-------------|
|
||||
| `Account` | `Account Settings` | `Read` | Required to list accounts, verify user identity, and read account members and 2FA enforcement |
|
||||
| `Account` | `Account API Tokens` | `Read` | Required to read account-owned API tokens (expiration, IP filtering, last use) |
|
||||
| `Account` | `Workers Scripts` | `Read` | Required to read Workers scripts, their settings, bindings, and `workers.dev` exposure |
|
||||
| `Account` | `Workers R2 Storage` | `Read` | Required to read R2 buckets, public `r2.dev` access, custom domains, and CORS policies |
|
||||
| `User` | `API Tokens` | `Read` | Optional. Required to read the authenticated user's own API tokens |
|
||||
| `Account` | `Account Settings` | `Read` | Required to list accounts and verify user identity |
|
||||
| `Zone` | `Zone` | `Read` | Required to list zones |
|
||||
| `Zone` | `Zone Settings` | `Read` | Required to read zone security settings (SSL/TLS mode, TLS versions, HSTS, Always Use HTTPS, WAF, etc.) |
|
||||
| `Zone` | `DNS` | `Read` | Required to read DNS records (SPF, DMARC, DKIM, CAA) and DNSSEC status |
|
||||
@@ -37,10 +33,6 @@ Prowler requires read-only access to Cloudflare accounts, zones, and developer p
|
||||
Ensure the API Token has access to all zones targeted for scanning. Missing permissions may cause some checks to fail or return incomplete results.
|
||||
</Warning>
|
||||
|
||||
<Note>
|
||||
Account-owned API tokens can only be listed by tokens created by a Super Administrator. When a permission is missing, the affected checks report one `MANUAL` finding per account naming the missing permission, and the rest of the scan continues. User-owned tokens are still evaluated when the optional `API Tokens Read` user permission is granted.
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
## API Token (Recommended)
|
||||
@@ -55,10 +47,10 @@ User API Tokens are the recommended authentication method because they:
|
||||
Create a **User API Token**, not an Account API Token. User API Tokens are created from the profile settings and offer finer permission control.
|
||||
</Note>
|
||||
|
||||
**Quick Setup:** Use these pre-configured links to open the Cloudflare Dashboard with most of the required permissions already selected. Add the `Account API Tokens`, `Workers Scripts`, and `Workers R2 Storage` read permissions manually before creating the token:
|
||||
**Quick Setup:** Use these pre-configured links to open the Cloudflare Dashboard with the required permissions already selected:
|
||||
|
||||
- [Create User API Token](https://dash.cloudflare.com/profile/api-tokens?permissionGroupKeys=%5B%7B%22key%22%3A%22account_settings%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone_settings%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22dns%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22ssl_and_certificates%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22bot_management%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone_waf%22%2C%22type%22%3A%22read%22%7D%5D&accountId=%2A&zoneId=all&name=Prowler%20Security%20Scanner) — creates a **User API Token** (recommended). Opens the **Create Custom Token** form prefilled with the seven required read-only scopes (`Account Settings`, `Zone`, `Zone Settings`, `DNS`, `SSL and Certificates`, `Bot Management`, `Zone WAF`) and the name `Prowler Security Scanner`. Then add the `Account API Tokens`, `Workers Scripts`, and `Workers R2 Storage` read permissions (and optionally the user `API Tokens` read permission) manually. Adjust **Account Resources** and **Zone Resources** to match the accounts and zones you want to scan, then click **Create Token**.
|
||||
- [Create Account-Owned API Token](https://dash.cloudflare.com/?to=/:account/api-tokens&permissionGroupKeys=%5B%7B%22key%22%3A%22account_settings%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone_settings%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22dns%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22ssl_and_certificates%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22bot_management%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone_waf%22%2C%22type%22%3A%22read%22%7D%5D&name=Prowler%20Security%20Scanner) — creates an [account-owned token](https://developers.cloudflare.com/fundamentals/api/how-to/account-owned-token-template/) instead. Use this for automation or CI/CD where the token should not depend on a specific user account remaining active. Requires the **Super Administrator** or **Administrator** role on the account. As with the user token link, add the `Account API Tokens`, `Workers Scripts`, and `Workers R2 Storage` read permissions manually.
|
||||
- [Create User API Token](https://dash.cloudflare.com/profile/api-tokens?permissionGroupKeys=%5B%7B%22key%22%3A%22account_settings%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone_settings%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22dns%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22ssl_and_certificates%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22bot_management%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone_waf%22%2C%22type%22%3A%22read%22%7D%5D&accountId=%2A&zoneId=all&name=Prowler%20Security%20Scanner) — creates a **User API Token** (recommended). Opens the **Create Custom Token** form prefilled with the seven required read-only scopes (`Account Settings`, `Zone`, `Zone Settings`, `DNS`, `SSL and Certificates`, `Bot Management`, `Zone WAF`) and the name `Prowler Security Scanner`. Adjust **Account Resources** and **Zone Resources** to match the accounts and zones you want to scan, then click **Create Token**.
|
||||
- [Create Account-Owned API Token](https://dash.cloudflare.com/?to=/:account/api-tokens&permissionGroupKeys=%5B%7B%22key%22%3A%22account_settings%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone_settings%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22dns%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22ssl_and_certificates%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22bot_management%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone_waf%22%2C%22type%22%3A%22read%22%7D%5D&name=Prowler%20Security%20Scanner) — creates an [account-owned token](https://developers.cloudflare.com/fundamentals/api/how-to/account-owned-token-template/) instead. Use this for automation or CI/CD where the token should not depend on a specific user account remaining active. Requires the **Super Administrator** or **Administrator** role on the account.
|
||||
|
||||
<Note>
|
||||
Template URLs only pre-fill the token creation form. Review the permissions, configure resources, and click **Create Token** to complete the process.
|
||||
@@ -74,10 +66,6 @@ Template URLs only pre-fill the token creation form. Review the permissions, con
|
||||
- **Token name:** A descriptive name (e.g., "Prowler Security Scanner")
|
||||
- **Permissions:**
|
||||
- `Account` — `Account Settings` — `Read`
|
||||
- `Account` — `Account API Tokens` — `Read`
|
||||
- `Account` — `Workers Scripts` — `Read`
|
||||
- `Account` — `Workers R2 Storage` — `Read`
|
||||
- `User` — `API Tokens` — `Read` (optional, for user token checks)
|
||||
- `Zone` — `Zone` — `Read`
|
||||
- `Zone` — `Zone Settings` — `Read`
|
||||
- `Zone` — `DNS` — `Read`
|
||||
|
||||
@@ -3,7 +3,6 @@ title: 'Getting Started With Cloudflare on Prowler'
|
||||
---
|
||||
|
||||
import { VersionBadge } from "/snippets/version-badge.mdx"
|
||||
import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
Prowler for Cloudflare scans zones for security misconfigurations, including SSL/TLS settings, DNSSEC, HSTS, WAF rules, DNS records, and more.
|
||||
|
||||
@@ -12,16 +11,16 @@ Prowler for Cloudflare scans zones for security misconfigurations, including SSL
|
||||
Set up authentication for Cloudflare with the [Cloudflare Authentication](/user-guide/providers/cloudflare/authentication) guide before starting either path:
|
||||
|
||||
- Create a Cloudflare User API Token (recommended) or locate the Global API Key
|
||||
- Grant the required read-only permissions (`Account Settings:Read`, `Account API Tokens:Read`, `Workers Scripts:Read`, `Workers R2 Storage:Read`, `Zone:Read`, `Zone Settings:Read`, `DNS:Read`, `SSL and Certificates:Read`, `Bot Management:Read`, `Zone WAF:Read`)
|
||||
- Grant the required read-only permissions (`Account Settings:Read`, `Zone:Read`, `Zone Settings:Read`, `DNS:Read`, `SSL and Certificates:Read`, `Bot Management:Read`, `Zone WAF:Read`)
|
||||
- Identify the Cloudflare Account ID to use as the provider identifier
|
||||
|
||||
<Note>
|
||||
**Quick Setup:** Use these pre-configured links to create a token with most of the required permissions already selected:
|
||||
**Quick Setup:** Use these pre-configured links to create a token with the required permissions already selected:
|
||||
|
||||
- [Create User API Token](https://dash.cloudflare.com/profile/api-tokens?permissionGroupKeys=%5B%7B%22key%22%3A%22account_settings%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone_settings%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22dns%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22ssl_and_certificates%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22bot_management%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone_waf%22%2C%22type%22%3A%22read%22%7D%5D&accountId=%2A&zoneId=all&name=Prowler%20Security%20Scanner) — creates a User API Token (recommended).
|
||||
- [Create Account-Owned API Token](https://dash.cloudflare.com/?to=/:account/api-tokens&permissionGroupKeys=%5B%7B%22key%22%3A%22account_settings%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone_settings%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22dns%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22ssl_and_certificates%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22bot_management%22%2C%22type%22%3A%22read%22%7D%2C%7B%22key%22%3A%22zone_waf%22%2C%22type%22%3A%22read%22%7D%5D&name=Prowler%20Security%20Scanner) — creates an [account-owned token](https://developers.cloudflare.com/fundamentals/api/how-to/account-owned-token-template/), better suited for automation and CI/CD.
|
||||
|
||||
Both links open the Cloudflare Dashboard with the seven required read-only scopes (`Account Settings`, `Zone`, `Zone Settings`, `DNS`, `SSL and Certificates`, `Bot Management`, `Zone WAF`) and the name `Prowler Security Scanner` prefilled. Add the `Account API Tokens`, `Workers Scripts`, and `Workers R2 Storage` read permissions manually before creating the token. See [Cloudflare Authentication](/user-guide/providers/cloudflare/authentication#api-token-recommended) for the equivalent manual steps.
|
||||
Both links open the Cloudflare Dashboard with the seven required read-only scopes (`Account Settings`, `Zone`, `Zone Settings`, `DNS`, `SSL and Certificates`, `Bot Management`, `Zone WAF`) and the name `Prowler Security Scanner` prefilled. See [Cloudflare Authentication](/user-guide/providers/cloudflare/authentication#api-token-recommended) for the equivalent manual steps.
|
||||
</Note>
|
||||
|
||||
<CardGroup cols={2}>
|
||||
@@ -37,8 +36,6 @@ Both links open the Cloudflare Dashboard with the seven required read-only scope
|
||||
|
||||
<VersionBadge version="5.19.0" />
|
||||
|
||||
<AppliesTo />
|
||||
|
||||
### Step 1: Locate the Account ID
|
||||
|
||||
1. Log into the [Cloudflare Dashboard](https://dash.cloudflare.com).
|
||||
@@ -53,7 +50,7 @@ The Account ID is a 32-character hexadecimal string (e.g., `372e67954025e0ba6aaa
|
||||
|
||||
### Step 2: Open Prowler Cloud
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in) or [create an account](https://cloud.prowler.com/sign-up).
|
||||
1. Go to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler Local Server](/user-guide/tutorials/prowler-app).
|
||||
2. Navigate to "Configuration" > "Providers".
|
||||
|
||||

|
||||
|
||||
@@ -89,7 +89,7 @@ This method uses the Google Cloud CLI to authenticate and is suitable for develo
|
||||
|
||||

|
||||
|
||||
8. Extract the following values for Prowler Cloud:
|
||||
8. Extract the following values for Prowler Cloud or Prowler Local Server:
|
||||
|
||||
- `client_id`
|
||||
- `client_secret`
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
title: 'Getting Started With GCP on Prowler'
|
||||
---
|
||||
|
||||
import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
## Prowler Cloud
|
||||
|
||||
<AppliesTo />
|
||||
|
||||
### Step 1: Get the GCP Project ID
|
||||
|
||||
1. Go to the [GCP Console](https://console.cloud.google.com/)
|
||||
@@ -17,7 +13,7 @@ import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
### Step 2: Access Prowler Cloud
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in) or [create an account](https://cloud.prowler.com/sign-up)
|
||||
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler Local Server](/user-guide/tutorials/prowler-app)
|
||||
2. Go to "Configuration" > "Providers"
|
||||
|
||||

|
||||
|
||||
@@ -272,7 +272,7 @@ Store the `.pem` private key securely. Anyone with this key can authenticate as
|
||||
|
||||
## Prowler Cloud Authentication
|
||||
|
||||
For step-by-step setup instructions for Prowler Cloud, see the [Getting Started Guide](/user-guide/providers/github/getting-started-github#prowler-cloud).
|
||||
For step-by-step setup instructions for Prowler Cloud, see the [Getting Started Guide](/user-guide/providers/github/getting-started-github#prowler-cloud-and-prowler-local-server).
|
||||
|
||||
### Using Personal Access Token
|
||||
|
||||
@@ -302,7 +302,7 @@ For step-by-step setup instructions for Prowler Cloud, see the [Getting Started
|
||||
|
||||
3. Enter your GitHub App ID and upload the private key (`.pem` file).
|
||||
|
||||
For complete step-by-step instructions, see the [Getting Started Guide](/user-guide/providers/github/getting-started-github#prowler-cloud).
|
||||
For complete step-by-step instructions, see the [Getting Started Guide](/user-guide/providers/github/getting-started-github#prowler-cloud-and-prowler-local-server).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
title: 'Getting Started with GitHub'
|
||||
---
|
||||
|
||||
import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
This guide covers setting up GitHub security scanning with Prowler. Choose a preferred interface below:
|
||||
|
||||
<Note>
|
||||
@@ -18,7 +16,7 @@ Prowler can scan either:
|
||||
</Note>
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Prowler Cloud" icon="cloud" href="#prowler-cloud">
|
||||
<Card title="Prowler Cloud & Local Server" icon="cloud" href="#prowler-cloud-and-prowler-local-server">
|
||||
Web-based interface with centralized management
|
||||
</Card>
|
||||
<Card title="Prowler CLI" icon="terminal" href="#prowler-cli">
|
||||
@@ -28,9 +26,7 @@ Prowler can scan either:
|
||||
|
||||
---
|
||||
|
||||
## Prowler Cloud
|
||||
|
||||
<AppliesTo />
|
||||
## Prowler Cloud and Prowler Local Server
|
||||
|
||||
<iframe width="560" height="380" src="https://www.youtube-nocookie.com/embed/9ETI84Xpu2g" title="Prowler Cloud Onboarding Github" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="1"></iframe>
|
||||
|
||||
@@ -38,7 +34,7 @@ Prowler can scan either:
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before adding GitHub to Prowler Cloud, ensure you have:
|
||||
Before adding GitHub to Prowler Cloud or Prowler Local Server, ensure you have:
|
||||
|
||||
1. **GitHub Account Access**
|
||||
- Personal GitHub account, OR
|
||||
@@ -50,9 +46,9 @@ Before adding GitHub to Prowler Cloud, ensure you have:
|
||||
- OAuth App Token
|
||||
- GitHub App Credentials (Not Recommended - limited data access)
|
||||
|
||||
### Step 1: Access Prowler Cloud
|
||||
### Step 1: Access Prowler Cloud or Prowler Local Server
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in) or [create an account](https://cloud.prowler.com/sign-up)
|
||||
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler Local Server](/user-guide/tutorials/prowler-app)
|
||||
2. Go to **Configuration** → **Providers**
|
||||
|
||||

|
||||
|
||||
@@ -3,7 +3,6 @@ title: 'Getting Started With Google Workspace on Prowler'
|
||||
---
|
||||
|
||||
import { VersionBadge } from "/snippets/version-badge.mdx"
|
||||
import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
Prowler for Google Workspace audits the organization's Google Workspace environment for security misconfigurations, including super administrator account hygiene, domain settings, and more.
|
||||
|
||||
@@ -29,8 +28,6 @@ Set up authentication for Google Workspace with the [Google Workspace Authentica
|
||||
|
||||
<VersionBadge version="5.21.0" />
|
||||
|
||||
<AppliesTo />
|
||||
|
||||
### Step 1: Locate the Customer ID
|
||||
|
||||
1. Log into the [Google Workspace Admin Console](https://admin.google.com).
|
||||
@@ -45,7 +42,7 @@ The Customer ID starts with the letter "C" followed by alphanumeric characters (
|
||||
|
||||
### Step 2: Open Prowler Cloud
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in) or [create an account](https://cloud.prowler.com/sign-up).
|
||||
1. Go to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler Local Server](/user-guide/tutorials/prowler-app).
|
||||
2. Navigate to "Configuration" > "Providers".
|
||||
|
||||

|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
title: "Getting Started with the IaC Provider"
|
||||
---
|
||||
import { VersionBadge } from "/snippets/version-badge.mdx"
|
||||
import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
Prowler's Infrastructure as Code (IaC) provider enables scanning of local or remote infrastructure code for security and compliance issues using [Trivy](https://trivy.dev/). This provider supports a wide range of IaC frameworks, allowing assessment of code before deployment.
|
||||
|
||||
@@ -36,15 +35,13 @@ Prowler IaC provider scans the following Infrastructure as Code configurations f
|
||||
|
||||
<VersionBadge version="5.14.0" />
|
||||
|
||||
<AppliesTo />
|
||||
|
||||
### Supported Scanners
|
||||
|
||||
Scanner selection is not configurable in Prowler Cloud. Default scanners, misconfig and secret, run automatically during each scan.
|
||||
|
||||
### Step 1: Access Prowler Cloud
|
||||
### Step 1: Access Prowler Cloud or Prowler Local Server
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in) or [create an account](https://cloud.prowler.com/sign-up)
|
||||
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler Local Server](/user-guide/tutorials/prowler-app)
|
||||
2. Go to "Configuration" > "Providers"
|
||||
|
||||

|
||||
|
||||
@@ -3,7 +3,6 @@ title: "Getting Started with the Image Provider"
|
||||
---
|
||||
|
||||
import { VersionBadge } from "/snippets/version-badge.mdx"
|
||||
import { AppliesTo } from "/snippets/applies-to.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.
|
||||
|
||||
@@ -28,15 +27,13 @@ Prowler's Image provider enables comprehensive container image security scanning
|
||||
|
||||
<VersionBadge version="5.21.0" />
|
||||
|
||||
<AppliesTo />
|
||||
|
||||
### Supported Scanners
|
||||
|
||||
Prowler Cloud does not support scanner selection. The vulnerability, secret, and misconfiguration scanners run automatically during each scan.
|
||||
|
||||
### Step 1: Access Prowler Cloud
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in) or [create an account](https://cloud.prowler.com/sign-up)
|
||||
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler Local Server](/user-guide/tutorials/prowler-app)
|
||||
2. Navigate to "Configuration" > "Providers"
|
||||
|
||||

|
||||
|
||||
@@ -2,15 +2,11 @@
|
||||
title: 'Getting Started with Kubernetes'
|
||||
---
|
||||
|
||||
import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
## Prowler Cloud
|
||||
|
||||
<AppliesTo />
|
||||
### Step 1: Access Prowler Cloud or Prowler Local Server
|
||||
|
||||
### Step 1: Access Prowler Cloud
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in) or [create an account](https://cloud.prowler.com/sign-up)
|
||||
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler Local Server](/user-guide/tutorials/prowler-app)
|
||||
2. Go to "Configuration" > "Providers"
|
||||
|
||||

|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
title: 'Getting Started With Microsoft 365 on Prowler'
|
||||
---
|
||||
|
||||
import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
<Note>
|
||||
**Government Cloud Support**
|
||||
|
||||
@@ -31,8 +29,6 @@ Set up authentication for Microsoft 365 with the [Microsoft 365 Authentication](
|
||||
|
||||
## Prowler Cloud
|
||||
|
||||
<AppliesTo />
|
||||
|
||||
### Step 1: Locate the Domain ID
|
||||
|
||||
1. Open the Entra ID portal, then search for "Domain" or go to Identity > Settings > Domain Names.
|
||||
@@ -45,7 +41,7 @@ Set up authentication for Microsoft 365 with the [Microsoft 365 Authentication](
|
||||
|
||||
### Step 2: Open Prowler Cloud
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in) or [create an account](https://cloud.prowler.com/sign-up).
|
||||
1. Go to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler Local Server](/user-guide/tutorials/prowler-app).
|
||||
2. Navigate to "Configuration" > "Providers".
|
||||
|
||||

|
||||
|
||||
@@ -15,7 +15,7 @@ Before you begin, make sure you have:
|
||||
3. An **API Key pair** (public and private keys) with appropriate permissions:
|
||||
- **Organization Read Only**: Provides read-only access to everything in the organization, including all projects in the organization. This permission is sufficient for most security checks.
|
||||
- **Organization Owner**: Required to audit the [Auditing configuration](https://www.mongodb.com/docs/api/doc/atlas-admin-api-v2/group/endpoint-auditing) for projects. Database auditing tracks database operations and security events, including authentication attempts, data definition language (DDL) changes, user and role modifications, and privilege grants. This configuration is essential for security monitoring, forensics, and compliance. Without **Organization Owner** permission, the `projects_auditing_enabled` check cannot retrieve the audit configuration status.
|
||||
4. A [Prowler Cloud](https://cloud.prowler.com/sign-up) account, or Prowler CLI (`pip install prowler`).
|
||||
4. Access to Prowler Cloud or Prowler Local Server, or Prowler CLI (`pip install prowler`).
|
||||
|
||||
For detailed instructions on creating API keys, see the [MongoDB Atlas authentication guide](./authentication.mdx).
|
||||
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
title: 'Getting Started with Oracle Cloud Infrastructure (OCI)'
|
||||
---
|
||||
|
||||
import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
Prowler supports security scanning of Oracle Cloud Infrastructure (OCI) environments. This guide will help you get started with using Prowler to audit your OCI tenancy.
|
||||
|
||||
## Prowler Cloud
|
||||
|
||||
<AppliesTo />
|
||||
The following steps apply to Prowler Cloud and Prowler Local Server.
|
||||
|
||||
### Step 1: Collect OCI Identifiers
|
||||
1. Sign in to the [OCI Console](https://cloud.oracle.com/) and open **Tenancy Details** to copy the Tenancy OCID.
|
||||
@@ -17,7 +15,7 @@ Prowler supports security scanning of Oracle Cloud Infrastructure (OCI) environm
|
||||
4. In **Tenancy Details**, note the **Home Region** identifier (for example, `me-abudhabi-1`). Any other region the tenancy is subscribed to also works.
|
||||
|
||||
### Step 2: Access Prowler Cloud
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in) or [create an account](https://cloud.prowler.com/sign-up).
|
||||
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler Local Server](/user-guide/tutorials/prowler-app).
|
||||
2. Go to **Configuration** → **Providers** and click **Add Provider**.
|
||||

|
||||
3. Select **Oracle Cloud** and enter the **Tenancy OCID** and an optional alias, then choose **Next**.
|
||||
@@ -344,7 +342,7 @@ prowler oci \
|
||||
|
||||
**Error: "OCI credential validation failed" with `401 NotAuthenticated` on `get_tenancy`**
|
||||
- The tenancy is not subscribed to the region used for validation (by default `us-ashburn-1`)
|
||||
- In Prowler Cloud, update the provider credentials and select the tenancy home region
|
||||
- In Prowler Cloud or Prowler Local Server, update the provider credentials and select the tenancy home region
|
||||
- In Prowler CLI, set `region` in `~/.oci/config` to the home region. All subscribed regions are still scanned; `--region` also works but limits the scan to that region
|
||||
|
||||
**Error: "Invalid region"**
|
||||
|
||||
@@ -3,7 +3,6 @@ title: 'Getting Started With Okta on Prowler'
|
||||
---
|
||||
|
||||
import { VersionBadge } from "/snippets/version-badge.mdx"
|
||||
import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
Prowler for Okta scans an Okta organization for identity and session-management misconfigurations. The provider authenticates as a service application using **OAuth 2.0 with a private-key JWT** (Client Credentials grant) — no end-user login, read-only by scope.
|
||||
|
||||
@@ -29,11 +28,9 @@ Set up authentication for Okta with the [Okta Authentication](/user-guide/provid
|
||||
|
||||
<VersionBadge version="5.28.0" />
|
||||
|
||||
<AppliesTo />
|
||||
|
||||
### Step 1: Add the Provider
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in) or [create an account](https://cloud.prowler.com/sign-up).
|
||||
1. Go to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler Local Server](/user-guide/tutorials/prowler-app).
|
||||
2. Navigate to "Configuration" > "Providers".
|
||||
|
||||

|
||||
|
||||
@@ -3,7 +3,6 @@ title: "Getting Started With Vercel on Prowler"
|
||||
---
|
||||
|
||||
import { VersionBadge } from "/snippets/version-badge.mdx"
|
||||
import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
Prowler for Vercel scans teams and projects for security misconfigurations, including deployment protection, environment variable exposure, WAF rules, domain configuration, team access controls, and more.
|
||||
|
||||
@@ -27,11 +26,9 @@ Set up authentication for Vercel with the [Vercel Authentication](/user-guide/pr
|
||||
|
||||
<VersionBadge version="5.23.0" />
|
||||
|
||||
<AppliesTo />
|
||||
|
||||
### Step 1: Add the Provider
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in) or [create an account](https://cloud.prowler.com/sign-up).
|
||||
1. Go to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler Local Server](/user-guide/tutorials/prowler-app).
|
||||
2. Navigate to "Configuration" > "Providers".
|
||||
|
||||

|
||||
|
||||
@@ -99,7 +99,7 @@ export PROWLER_API_KEY="pk_example-api-key"
|
||||
|
||||
To create an API key:
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in)
|
||||
1. Log in to Prowler Cloud or Prowler Local Server
|
||||
2. Click **Profile** → **Account**
|
||||
3. Click **Create API Key**
|
||||
4. Provide a descriptive name and optionally set an expiration date
|
||||
|
||||
@@ -51,7 +51,7 @@ export PROWLER_API_KEY="pk_example-api-key"
|
||||
|
||||
To create an API key:
|
||||
|
||||
1. Sign in to [Prowler Cloud](https://cloud.prowler.com/sign-in)
|
||||
1. Log in to Prowler Cloud or Prowler Local Server
|
||||
2. Click **Profile** → **Account**
|
||||
3. Click **Create API Key**
|
||||
4. Provide a descriptive name and optionally set an expiration date
|
||||
|
||||
@@ -4,15 +4,22 @@ sidebarTitle: 'Getting Started'
|
||||
---
|
||||
|
||||
import { ProviderCards } from "/snippets/provider-cards.mdx"
|
||||
import { AppliesTo } from "/snippets/applies-to.mdx"
|
||||
|
||||
<AppliesTo />
|
||||
|
||||
**Prowler Cloud** is a web application that simplifies running Prowler. This tutorial will guide you through setting up and using it.
|
||||
|
||||
**Prowler Local Server** is the self-hosted version of **Prowler Cloud**. See [Prowler product families](/getting-started/products) for every official product name.
|
||||
|
||||
## Accessing Prowler Cloud and API Documentation
|
||||
|
||||
Sign in at [cloud.prowler.com](https://cloud.prowler.com/sign-in). The API documentation is available at [https://api.prowler.com/api/v1/docs](https://api.prowler.com/api/v1/docs).
|
||||
If you are a [Prowler Cloud](https://cloud.prowler.com/sign-in) user, you can access API docs at [https://api.prowler.com/api/v1/docs](https://api.prowler.com/api/v1/docs)
|
||||
|
||||
<Note>
|
||||
**For Prowler Local Server users**
|
||||
|
||||
After [installing](/getting-started/installation/prowler-app) **Prowler Local Server**, access it at [http://localhost:3000](http://localhost:3000).
|
||||
|
||||
To view the auto-generated **Prowler API** documentation, navigate to [http://localhost:8080/api/v1/docs](http://localhost:8080/api/v1/docs). This documentation provides details on available endpoints, parameters, and responses.
|
||||
</Note>
|
||||
|
||||
## Step 1: Sign Up
|
||||
### Sign Up with Email
|
||||
@@ -78,14 +85,20 @@ For detailed instructions on configuring credentials for each provider, refer to
|
||||
<ProviderCards />
|
||||
|
||||
## Step 5: Test Connection
|
||||
To verify the credentials, click the connect action at the bottom of the same step (for example, "Connect account", "Connect subscription" or "Connect project"). Prowler saves the provider and its credentials and tests the connection in that single action. When the test succeeds, the wizard moves straight to launching the scan. When it fails, the reason appears above the form and the values stay in place: click "Retry connection" to test again, or correct a field, which brings back the connect action, and click it. Neither adds the provider twice.
|
||||
After adding your cloud account credentials, click the `Check connection` button to verify that Prowler can successfully connect to your provider:
|
||||
|
||||
<img src="/images/test-connection-button.png" alt="Test Connection" width="700" />
|
||||
|
||||
<Note>
|
||||
To delegate the connection, select "I don't have access, invite a teammate" on the same step when you cannot create the credentials yourself. The option is available for every provider to users who can manage the account. Prowler Local Server adds the invitation to the tenant and shows the link to share. Prowler Cloud also emails it.
|
||||
For a single AWS account, Prowler tests the connection as part of the `Connect account` step, so the wizard moves straight to launching the scan.
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
To delegate the AWS connection, select `I don't have access, invite a teammate` on the same step when you cannot create the IAM role or do not have the account credentials. Prowler App sends the invitation to the tenant and shows the link to share. Prowler Cloud also emails it. This option is available to users who can manage the account.
|
||||
</Note>
|
||||
|
||||
## Step 6: Scan Started
|
||||
Once the connection test succeeds, the wizard moves to the launch step, since the provider is already saved. To start the first scan, click "Launch scan", or "Save and launch scan" when scanning on a schedule. The `Scans` section shows the scan in progress:
|
||||
After the connection check succeeds, save the provider and start your first scan with the `Launch Scan` button. The `Scans` section shows the scan in progress:
|
||||
|
||||
<img src="/images/provider-added.png" alt="Start Now" width="700" />
|
||||
|
||||
@@ -164,9 +177,3 @@ Once your scan has finished, you don’t need to grab the entire ZIP—just pull
|
||||
To fetch a single compliance report via API, see the Retrieve compliance report as CSV endpoint in the Prowler API Reference. [Prowler API Reference - Retrieve compliance report as CSV](https://api.prowler.com/api/v1/docs#tag/Scan/operation/scans_compliance_retrieve)
|
||||
|
||||
</Note>
|
||||
|
||||
## Running the Same Steps on Prowler Local Server
|
||||
|
||||
**Prowler Local Server** is the self-hosted version of **Prowler Cloud**, and every step in this guide works the same way on it. See [Prowler product families](/getting-started/products) for every official product name.
|
||||
|
||||
After [installing](/getting-started/installation/prowler-app) **Prowler Local Server**, access it at [http://localhost:3000](http://localhost:3000) and the auto-generated **Prowler API** documentation at [http://localhost:8080/api/v1/docs](http://localhost:8080/api/v1/docs).
|
||||
@@ -9,14 +9,13 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
| Action | Skill |
|
||||
|--------|-------|
|
||||
| Add changelog entry for a PR or feature | `prowler-changelog` |
|
||||
| Add or edit changelog fragments in <component>/changelog.d/ | `prowler-changelog` |
|
||||
| Committing changes | `prowler-commit` |
|
||||
| Create PR that requires changelog entry | `prowler-changelog` |
|
||||
| Creating a git commit | `prowler-commit` |
|
||||
| Review changelog format and conventions | `prowler-changelog` |
|
||||
| Testing MCP tools or models | `prowler-test-mcp` |
|
||||
| Update CHANGELOG.md in any component | `prowler-changelog` |
|
||||
| Working on MCP server tools | `prowler-mcp` |
|
||||
| Writing Prowler MCP server tests | `prowler-test-mcp` |
|
||||
| Writing tests for the MCP server | `prowler-test-mcp` |
|
||||
|
||||
## Project Overview
|
||||
|
||||
@@ -28,7 +27,7 @@ The Prowler MCP Server provides AI agents access to the Prowler ecosystem throug
|
||||
|
||||
### Tool Implementation
|
||||
- ALWAYS: Extend `BaseTool` ABC for Prowler tools (auto-registration)
|
||||
- ALWAYS: Use `@hub_mcp_server.tool(annotations={...})` (or the docs server equivalent) for Hub/Docs tools
|
||||
- ALWAYS: Use `@mcp.tool()` decorator for Hub/Docs tools
|
||||
- NEVER: Manually register BaseTool subclasses
|
||||
- NEVER: Import tools directly in server.py
|
||||
|
||||
@@ -64,7 +63,7 @@ prowler_mcp_server.mount(docs_mcp_server, namespace="prowler_docs")
|
||||
|
||||
## TECH STACK
|
||||
|
||||
Python 3.12+ | FastMCP 3.4.5 | httpx (async) | Pydantic | uv | pytest
|
||||
Python 3.12+ | FastMCP 3.4.4 | httpx (async) | Pydantic | uv | pytest
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -4,18 +4,6 @@ All notable changes to the **Prowler MCP Server** are documented in this file.
|
||||
|
||||
<!-- changelog: release notes start -->
|
||||
|
||||
## [0.13.0] (Prowler v5.47.0)
|
||||
|
||||
### 🚀 Added
|
||||
|
||||
- `readOnlyHint` and `destructiveHint` annotations on every MCP tool, with mute rule and mutelist writes marked destructive [(#13196)](https://github.com/prowler-cloud/prowler/pull/13196)
|
||||
|
||||
### 🔐 Security
|
||||
|
||||
- Authlib from 1.7.2 to 1.9.1 and dnspython from 2.8.0 to 2.9.0 in the MCP Server container image, patching CVE-2026-96760 (critical), CVE-2026-114615, CVE-2026-114616 and CVE-2026-114605 [(#13186)](https://github.com/prowler-cloud/prowler/pull/13186)
|
||||
|
||||
---
|
||||
|
||||
## [0.12.4] (Prowler v5.46.0)
|
||||
|
||||
### 🔐 Security
|
||||
|
||||
@@ -25,7 +25,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
|
||||
# =============================================================================
|
||||
# Final stage - Minimal runtime environment
|
||||
# =============================================================================
|
||||
FROM python:3.13.18-alpine3.23@sha256:e4aeaca9081549f19bd5bc8605ed5ab257ba34f97e0471f8e09161f45b4b08b8
|
||||
FROM python:3.13.16-alpine3.23@sha256:07b20c774a247152e74f622034c1482495d299e070eec620ddff13e01264290b
|
||||
|
||||
LABEL maintainer="https://github.com/prowler-cloud"
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
joserfc to 1.7.5, patching the JWE decryption denial of service advisory
|
||||
@@ -1 +0,0 @@
|
||||
Python base image from 3.13.16 to 3.13.18 in the MCP Server container image, patching CVE-2026-115557
|
||||
@@ -30,8 +30,6 @@ class AttackPathsTools(BaseTool):
|
||||
- prowler_run_attack_paths_query: Execute query and analyze attack paths
|
||||
"""
|
||||
|
||||
read_only_tools = frozenset({"run_attack_paths_query"})
|
||||
|
||||
async def list_attack_paths_scans(
|
||||
self,
|
||||
provider_id: list[str] = Field(
|
||||
|
||||
@@ -2,16 +2,12 @@ import inspect
|
||||
from abc import ABC
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from mcp.types import ToolAnnotations
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from fastmcp import FastMCP
|
||||
|
||||
from prowler_mcp_server.lib.logger import logger
|
||||
from prowler_mcp_server.prowler_app.utils.api_client import ProwlerAPIClient
|
||||
|
||||
READ_ONLY_PREFIXES = ("get_", "list_", "search_")
|
||||
|
||||
|
||||
class BaseTool(ABC):
|
||||
"""Abstract base class for all MCP tools.
|
||||
@@ -28,10 +24,6 @@ class BaseTool(ABC):
|
||||
Attributes:
|
||||
_api_client: Singleton instance of ProwlerAPIClient for API requests
|
||||
_logger: Logger instance for structured logging
|
||||
read_only_tools: Tools that change nothing although their name does not
|
||||
start with one of READ_ONLY_PREFIXES
|
||||
destructive_tools: Tools that remove, replace or hide data although their
|
||||
name does not start with "delete_"
|
||||
|
||||
Example:
|
||||
class FindingsTools(BaseTool):
|
||||
@@ -45,9 +37,6 @@ class BaseTool(ABC):
|
||||
return response
|
||||
"""
|
||||
|
||||
read_only_tools: frozenset[str] = frozenset()
|
||||
destructive_tools: frozenset[str] = frozenset()
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the tool.
|
||||
|
||||
@@ -104,24 +93,10 @@ class BaseTool(ABC):
|
||||
|
||||
# Check if the method is a coroutine function (async)
|
||||
if inspect.iscoroutinefunction(method):
|
||||
mcp.tool(method, annotations=self._annotations_for(name))
|
||||
mcp.tool(method)
|
||||
registered_count += 1
|
||||
self.logger.debug(f"Auto-registered tool: {name}")
|
||||
|
||||
self.logger.info(
|
||||
f"Auto-registered {registered_count} tools from {self.__class__.__name__}"
|
||||
)
|
||||
|
||||
def _annotations_for(self, name: str) -> ToolAnnotations:
|
||||
"""Return the MCP hints a client reads to decide whether to ask the user.
|
||||
|
||||
Every tool states both hints: left out, the MCP spec treats a tool as
|
||||
destructive, so a client could not tell a listing from a deletion.
|
||||
"""
|
||||
if name.startswith(READ_ONLY_PREFIXES) or name in self.read_only_tools:
|
||||
return ToolAnnotations(readOnlyHint=True, destructiveHint=False)
|
||||
return ToolAnnotations(
|
||||
readOnlyHint=False,
|
||||
destructiveHint=name.startswith("delete_")
|
||||
or name in self.destructive_tools,
|
||||
)
|
||||
@@ -29,12 +29,6 @@ class MutingTools(BaseTool):
|
||||
- Managing mute rules (finding-specific muting)
|
||||
"""
|
||||
|
||||
# A wrong mute hides findings silently and for good, so it is flagged like a deletion.
|
||||
# update_mute_rule is included because re-enabling a rule mutes its findings again.
|
||||
destructive_tools = frozenset(
|
||||
{"set_mutelist", "create_mute_rule", "update_mute_rule"}
|
||||
)
|
||||
|
||||
# ===== MUTELIST TOOLS =====
|
||||
|
||||
async def _get_mutelist_raw(self) -> dict[str, Any] | None:
|
||||
|
||||
@@ -34,8 +34,6 @@ class RolesTools(BaseTool):
|
||||
- prowler_set_user_role: Set the role a user holds (idempotent)
|
||||
"""
|
||||
|
||||
destructive_tools = frozenset({"set_user_role"})
|
||||
|
||||
async def list_roles(
|
||||
self,
|
||||
page_size: int = Field(
|
||||
|
||||
@@ -14,7 +14,7 @@ docs_mcp_server = FastMCP("prowler-docs", mask_error_details=True)
|
||||
prowler_docs_search_engine = ProwlerDocsSearchEngine()
|
||||
|
||||
|
||||
@docs_mcp_server.tool(annotations={"readOnlyHint": True, "destructiveHint": False})
|
||||
@docs_mcp_server.tool()
|
||||
def search(
|
||||
term: NonBlankStr = Field(
|
||||
description="The term to search for in the documentation"
|
||||
@@ -41,7 +41,7 @@ def search(
|
||||
return prowler_docs_search_engine.search(term, page_size) # type: ignore In the hint we cannot put SearchResult type because JSON API MCP Generator cannot handle Pydantic models yet
|
||||
|
||||
|
||||
@docs_mcp_server.tool(annotations={"readOnlyHint": True, "destructiveHint": False})
|
||||
@docs_mcp_server.tool()
|
||||
def get_document(
|
||||
doc_path: NonBlankStr = Field(
|
||||
description="Path to the documentation file to retrieve. It is the same as the 'path' field of the search results. Use `prowler_docs_search` to find the path first."
|
||||
|
||||
@@ -167,7 +167,7 @@ def _explain_missing_check_file(
|
||||
|
||||
|
||||
# Security Check Tools
|
||||
@hub_mcp_server.tool(annotations={"readOnlyHint": True, "destructiveHint": False})
|
||||
@hub_mcp_server.tool()
|
||||
async def list_checks(
|
||||
providers: list[str] = Field(
|
||||
default=[],
|
||||
@@ -251,7 +251,7 @@ async def list_checks(
|
||||
return {"count": len(checks), "checks": checks_list}
|
||||
|
||||
|
||||
@hub_mcp_server.tool(annotations={"readOnlyHint": True, "destructiveHint": False})
|
||||
@hub_mcp_server.tool()
|
||||
async def semantic_search_checks(
|
||||
term: NonBlankStr = Field(
|
||||
description="Search term. Examples: 'public access', 'encryption', 'MFA', 'logging'.",
|
||||
@@ -303,7 +303,7 @@ async def semantic_search_checks(
|
||||
return {"count": len(checks), "checks": checks_list}
|
||||
|
||||
|
||||
@hub_mcp_server.tool(annotations={"readOnlyHint": True, "destructiveHint": False})
|
||||
@hub_mcp_server.tool()
|
||||
async def get_check_details(
|
||||
check_id: NonBlankStr = Field(
|
||||
description="The check ID to retrieve details for. Example: 's3_bucket_level_public_access_block'"
|
||||
@@ -441,7 +441,7 @@ async def get_check_details(
|
||||
return result
|
||||
|
||||
|
||||
@hub_mcp_server.tool(annotations={"readOnlyHint": True, "destructiveHint": False})
|
||||
@hub_mcp_server.tool()
|
||||
async def get_check_code(
|
||||
provider_id: NonBlankStr = Field(
|
||||
description="Prowler Provider ID. Example: 'aws', 'azure', 'gcp', 'kubernetes'. Use `prowler_hub_list_providers` to get available provider IDs.",
|
||||
@@ -494,7 +494,7 @@ async def get_check_code(
|
||||
}
|
||||
|
||||
|
||||
@hub_mcp_server.tool(annotations={"readOnlyHint": True, "destructiveHint": False})
|
||||
@hub_mcp_server.tool()
|
||||
async def get_check_fixer(
|
||||
provider_id: NonBlankStr = Field(
|
||||
description="Prowler Provider ID. Example: 'aws', 'azure', 'gcp', 'kubernetes'. Use `prowler_hub_list_providers` to get available provider IDs.",
|
||||
@@ -550,7 +550,7 @@ async def get_check_fixer(
|
||||
|
||||
|
||||
# Compliance Framework Tools
|
||||
@hub_mcp_server.tool(annotations={"readOnlyHint": True, "destructiveHint": False})
|
||||
@hub_mcp_server.tool()
|
||||
async def list_compliances(
|
||||
provider: list[str] = Field(
|
||||
default=[],
|
||||
@@ -610,7 +610,7 @@ async def list_compliances(
|
||||
return {"count": len(compliances), "compliances": compliances_list}
|
||||
|
||||
|
||||
@hub_mcp_server.tool(annotations={"readOnlyHint": True, "destructiveHint": False})
|
||||
@hub_mcp_server.tool()
|
||||
async def semantic_search_compliances(
|
||||
term: NonBlankStr = Field(
|
||||
description="Search term. Examples: 'CIS', 'HIPAA', 'PCI', 'GDPR', 'SOC2', 'NIST'.",
|
||||
@@ -654,7 +654,7 @@ async def semantic_search_compliances(
|
||||
return {"count": len(compliances), "compliances": compliances_list}
|
||||
|
||||
|
||||
@hub_mcp_server.tool(annotations={"readOnlyHint": True, "destructiveHint": False})
|
||||
@hub_mcp_server.tool()
|
||||
async def get_compliance_details(
|
||||
compliance_id: NonBlankStr = Field(
|
||||
description="The compliance framework ID to retrieve details for. Example: 'cis_4.0_aws'. Use `prowler_hub_list_compliances` or `prowler_hub_semantic_search_compliances` to find available compliance IDs.",
|
||||
@@ -743,7 +743,7 @@ async def get_compliance_details(
|
||||
|
||||
|
||||
# Provider Tools
|
||||
@hub_mcp_server.tool(annotations={"readOnlyHint": True, "destructiveHint": False})
|
||||
@hub_mcp_server.tool()
|
||||
async def list_providers() -> dict:
|
||||
"""List all providers supported by Prowler.
|
||||
|
||||
@@ -784,7 +784,7 @@ async def list_providers() -> dict:
|
||||
return {"count": len(providers), "providers": providers_list}
|
||||
|
||||
|
||||
@hub_mcp_server.tool(annotations={"readOnlyHint": True, "destructiveHint": False})
|
||||
@hub_mcp_server.tool()
|
||||
async def get_provider_services(
|
||||
provider_id: NonBlankStr = Field(
|
||||
description="The provider ID to get services for. Example: 'aws', 'azure', 'gcp', 'kubernetes'. Use `prowler_hub_list_providers` to get available provider IDs.",
|
||||
|
||||
@@ -74,14 +74,13 @@ extend-select = [
|
||||
]
|
||||
|
||||
[tool.uv]
|
||||
package = true
|
||||
|
||||
# Transitive pins fastmcp does not raise on its own; each carries a known HIGH.
|
||||
constraint-dependencies = [
|
||||
"authlib==1.9.1",
|
||||
"cryptography==50.0.0",
|
||||
"dnspython==2.9.0",
|
||||
"joserfc==1.7.5",
|
||||
"joserfc==1.6.8",
|
||||
"mcp==1.28.1",
|
||||
"pyjwt==2.14.0",
|
||||
"python-multipart==0.0.30"
|
||||
]
|
||||
package = true
|
||||
@@ -49,36 +49,3 @@ async def test_every_tool_and_parameter_is_described(mcp_root_server):
|
||||
|
||||
for tool in tools:
|
||||
assert_tool_contract(tool)
|
||||
|
||||
|
||||
async def test_every_tool_says_whether_it_is_read_only_or_destructive(mcp_root_server):
|
||||
"""Clients decide whether to ask the user from these hints.
|
||||
|
||||
Left unset, the MCP spec treats a tool as destructive, so a listing would look
|
||||
exactly like a deletion.
|
||||
"""
|
||||
async with Client(mcp_root_server) as client:
|
||||
tools = {tool.name: tool.annotations for tool in await client.list_tools()}
|
||||
|
||||
for name, annotations in tools.items():
|
||||
assert annotations is not None, f"{name} has no annotations"
|
||||
assert annotations.readOnlyHint is not None, f"{name} has no readOnlyHint"
|
||||
assert annotations.destructiveHint is not None, f"{name} has no destructiveHint"
|
||||
|
||||
destructive = {name for name, a in tools.items() if a.destructiveHint}
|
||||
assert destructive == {
|
||||
"prowler_create_mute_rule",
|
||||
"prowler_update_mute_rule",
|
||||
"prowler_set_mutelist",
|
||||
"prowler_delete_mutelist",
|
||||
"prowler_delete_mute_rule",
|
||||
"prowler_delete_provider",
|
||||
"prowler_delete_integration",
|
||||
"prowler_set_user_role",
|
||||
}
|
||||
assert tools["prowler_run_attack_paths_query"].readOnlyHint
|
||||
assert tools["prowler_hub_list_checks"].readOnlyHint
|
||||
assert tools["prowler_docs_search"].readOnlyHint
|
||||
assert tools["prowler_get_mutelist"].readOnlyHint
|
||||
assert tools["prowler_hub_get_check_code"].readOnlyHint
|
||||
assert not tools["prowler_trigger_scan"].readOnlyHint
|
||||
@@ -1,5 +1,5 @@
|
||||
version = 1
|
||||
revision = 5
|
||||
revision = 2
|
||||
requires-python = ">=3.12"
|
||||
resolution-markers = [
|
||||
"python_full_version >= '3.14' and sys_platform == 'win32'",
|
||||
@@ -10,10 +10,8 @@ resolution-markers = [
|
||||
|
||||
[manifest]
|
||||
constraints = [
|
||||
{ name = "authlib", specifier = "==1.9.1" },
|
||||
{ name = "cryptography", specifier = "==50.0.0" },
|
||||
{ name = "dnspython", specifier = "==2.9.0" },
|
||||
{ name = "joserfc", specifier = "==1.7.5" },
|
||||
{ name = "joserfc", specifier = "==1.6.8" },
|
||||
{ name = "mcp", specifier = "==1.28.1" },
|
||||
{ name = "pyjwt", specifier = "==2.14.0" },
|
||||
{ name = "python-multipart", specifier = "==0.0.30" },
|
||||
@@ -64,15 +62,15 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "authlib"
|
||||
version = "1.9.1"
|
||||
version = "1.7.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cryptography" },
|
||||
{ name = "joserfc" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c9/dc/087c08741a98d234c9b98beef8a28d3c309f814d14b6156422c5815bf6d6/authlib-1.9.1.tar.gz", hash = "sha256:5c7d9848f47cac340f060f76ae0bc09b59f5c8e89cc1bb032d4370a0c55b5974", size = 182700, upload-time = "2026-10-14T14:17:52.307Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/36/98/7d93f30d029643c0275dbc0bd6d5a6f670661ee6c9a94d93af7ab4887600/authlib-1.7.2.tar.gz", hash = "sha256:2cea25fefcd4e7173bdf1372c0afc265c8034b23a8cd5dcb6a9164b826c64231", size = 176511, upload-time = "2026-05-06T08:10:23.116Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/39/44/a46089266de32a0d809023b6bf31b80a1f26a46954446a7ce695a565cbea/authlib-1.9.1-py2.py3-none-any.whl", hash = "sha256:8b9be8b1e5174dcbf5520e984f1a22dc2edae5b6e40a61d4cedbf86b97e9e69b", size = 266042, upload-time = "2026-10-14T14:17:50.695Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/95/adcb68e20c34162e9135f370d6e31737719c2b6f94bc953fe7ed1f10fe21/authlib-1.7.2-py2.py3-none-any.whl", hash = "sha256:3e1faedc9d87e7d56a164eca3ccb6ace0d61b94abe83e92242f8dc8bba9b4a9f", size = 259548, upload-time = "2026-05-06T08:10:21.436Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -352,11 +350,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "dnspython"
|
||||
version = "2.9.0"
|
||||
version = "2.8.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ef/4a/50822184bd67cc6493f0fb6a880749158fcd31ab3fa07409acfd91f9fc85/dnspython-2.9.0.tar.gz", hash = "sha256:b44dc6b18f07a8b1c56676a19fbfdb5209415b046a9cece286baafa87ff3f7f1", size = 423560, upload-time = "2026-10-09T00:07:24.352Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/10/02/cdcc9b7c051786a103c3b09e1003a82fa0c66bcb91ffbdabcfbf7b4163b9/dnspython-2.9.0-py3-none-any.whl", hash = "sha256:9a4aedb833c3c1b49214d04d44d3032ab7a9135f7c1d29a549b4ff78fd82fda9", size = 354822, upload-time = "2026-10-09T00:07:22.622Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -594,14 +592,14 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "joserfc"
|
||||
version = "1.7.5"
|
||||
version = "1.6.8"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cryptography" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/19/94/80fea1514b7c6d7d37804d3fe9ca81455f633347fc98731bd71ffe1faa17/joserfc-1.7.5.tar.gz", hash = "sha256:d5ff536e658e17664f8c1b1ab60dc4aa62aa973fcef1edd33cc44bda45d6f5ea", size = 234990, upload-time = "2026-08-29T13:05:42.057Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5d/ac/d4fd5b30f82900eac60d765f179f0ba005825ac462cc8ced6e13ec685ab3/joserfc-1.6.8.tar.gz", hash = "sha256:878620c553a6ebdd76ccdc356782fee3f735f21a356d079a546b42a4670ace5f", size = 232930, upload-time = "2026-05-27T03:22:37.819Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl", hash = "sha256:add2c2c84e8373b084d526a8b53daba5d7a513a118cd2dcd9fc9f979d0922159", size = 71269, upload-time = "2026-08-29T13:05:40.718Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/98/8c/5cdce2cf3ce8155849baf9a5e2ce77e89dc87ec3bdb38259e5d85fbc45bd/joserfc-1.6.8-py3-none-any.whl", hash = "sha256:22fb31a69094a5e6f44632002a9df2c30c941fc6c8ce1b037e92c03de954cf9f", size = 70927, upload-time = "2026-05-27T03:22:35.796Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1295,8 +1293,8 @@ name = "secretstorage"
|
||||
version = "3.5.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cryptography" },
|
||||
{ name = "jeepney" },
|
||||
{ name = "cryptography", marker = "sys_platform != 'win32'" },
|
||||
{ name = "jeepney", marker = "sys_platform != 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1c/03/e834bcd866f2f8a49a85eaff47340affa3bfa391ee9912a952a1faa68c7b/secretstorage-3.5.0.tar.gz", hash = "sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be", size = 19884, upload-time = "2025-11-23T19:02:53.191Z" }
|
||||
wheels = [
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
AWSTemplateFormatVersion: "2010-09-09"
|
||||
|
||||
Description: |
|
||||
Prowler Realtime Detection and Remediation real-time feed. EventBridge forwards risky AWS API calls recorded by CloudTrail to an SQS queue,
|
||||
and Prowler Cloud reads the queue with the ProwlerScan role. Without this stack Prowler Realtime still works, using CloudTrail
|
||||
LookupEvents with a delay of a few minutes. Delete the stack to remove everything it creates.
|
||||
Deploy it in one region: Prowler Realtime reads one queue per account. Global-service events (IAM, S3 account settings)
|
||||
arrive in us-east-1.
|
||||
|
||||
Parameters:
|
||||
ProwlerScanRoleName:
|
||||
Description: Name of the ProwlerScan role Prowler Cloud already uses for this account. It receives read access to this queue only.
|
||||
Type: String
|
||||
Default: ProwlerScan
|
||||
MinLength: 1
|
||||
|
||||
Resources:
|
||||
Queue:
|
||||
Type: AWS::SQS::Queue
|
||||
Properties:
|
||||
QueueName: prowler-realtime-events
|
||||
MessageRetentionPeriod: 3600
|
||||
ReceiveMessageWaitTimeSeconds: 20
|
||||
SqsManagedSseEnabled: true
|
||||
Tags:
|
||||
- { Key: prowler, Value: realtime-feed }
|
||||
|
||||
Rule:
|
||||
Type: AWS::Events::Rule
|
||||
Properties:
|
||||
Name: prowler-realtime-risky-api-calls
|
||||
Description: Risky changes that can break compliance checks, forwarded to Prowler Realtime Detection and Remediation
|
||||
State: ENABLED
|
||||
EventPattern:
|
||||
detail-type: ["AWS API Call via CloudTrail", "AWS Console Sign In via CloudTrail"]
|
||||
detail:
|
||||
eventName:
|
||||
- AuthorizeSecurityGroupIngress
|
||||
- PutBucketPublicAccessBlock
|
||||
- DeleteBucketPublicAccessBlock
|
||||
- PutAccountPublicAccessBlock
|
||||
- DeletePublicAccessBlock
|
||||
- PutBucketPolicy
|
||||
- StopLogging
|
||||
- DeleteTrail
|
||||
- UpdateTrail
|
||||
- StopConfigurationRecorder
|
||||
- DeleteConfigurationRecorder
|
||||
- DeleteFlowLogs
|
||||
- ScheduleKeyDeletion
|
||||
- DisableKey
|
||||
- DisableEbsEncryptionByDefault
|
||||
- CreateVolume
|
||||
- RunInstances
|
||||
- CreateDBInstance
|
||||
- ModifyDBInstance
|
||||
- AttachUserPolicy
|
||||
- AttachRolePolicy
|
||||
- AttachGroupPolicy
|
||||
- CreateAccessKey
|
||||
- ConsoleLogin
|
||||
Targets:
|
||||
- { Id: prowler-realtime-queue, Arn: !GetAtt Queue.Arn }
|
||||
|
||||
QueuePolicy:
|
||||
Type: AWS::SQS::QueuePolicy
|
||||
Properties:
|
||||
Queues: [!Ref Queue]
|
||||
PolicyDocument:
|
||||
Version: "2012-10-17"
|
||||
Statement:
|
||||
- Sid: AllowEventBridge
|
||||
Effect: Allow
|
||||
Principal: { Service: events.amazonaws.com }
|
||||
Action: sqs:SendMessage
|
||||
Resource: !GetAtt Queue.Arn
|
||||
Condition:
|
||||
ArnEquals: { "aws:SourceArn": !GetAtt Rule.Arn }
|
||||
|
||||
ReadFeedPolicy:
|
||||
Type: AWS::IAM::RolePolicy
|
||||
Properties:
|
||||
RoleName: !Ref ProwlerScanRoleName
|
||||
PolicyName: ProwlerRealtimeFeed
|
||||
PolicyDocument:
|
||||
Version: "2012-10-17"
|
||||
Statement:
|
||||
- Sid: ReadRealtimeQueue
|
||||
Effect: Allow
|
||||
Action: [sqs:ReceiveMessage, sqs:DeleteMessage, sqs:GetQueueAttributes]
|
||||
Resource: !GetAtt Queue.Arn
|
||||
|
||||
Outputs:
|
||||
QueueUrl:
|
||||
Description: Paste this URL in Prowler Cloud, Prowler Realtime, Real-time feed.
|
||||
Value: !Ref Queue
|
||||
@@ -1,91 +0,0 @@
|
||||
AWSTemplateFormatVersion: "2010-09-09"
|
||||
|
||||
Description: |
|
||||
Optional. Creates the ProwlerRemediation IAM role that lets Prowler Realtime Detection and Remediation fix a small, fixed set of misconfigurations
|
||||
automatically (and undo them). It is separate from the read-only ProwlerScan role: without it Prowler Realtime can only alert
|
||||
and propose pull requests. Every action below is one a listed fix or its undo needs; the resource comes from the event,
|
||||
so most statements cannot name it in advance. Delete the stack to revoke.
|
||||
If you are deploying this template to be used in Prowler Cloud please do not edit the AccountId and IAMPrincipal parameters.
|
||||
|
||||
What Prowler can do at runtime through this role, and nothing else:
|
||||
- Close internet-open ports (22, 3389, all) on the security group named in an event, revoking only 0.0.0.0/0 and ::/0 rules (undo recorded)
|
||||
- Turn on the four public access block settings of the S3 bucket named in an event (undo recorded)
|
||||
- Turn on the account-wide S3 public access block (undo recorded; can affect buckets that are public on purpose)
|
||||
- Start CloudTrail logging again on trails that were stopped (not revertible)
|
||||
- Enable EBS encryption by default in the region; existing volumes are not changed (undo recorded)
|
||||
- Set PubliclyAccessible to false on the RDS database named in an event (undo recorded)
|
||||
|
||||
Parameters:
|
||||
ExternalId:
|
||||
Description: The External ID Prowler Realtime Detection and Remediation uses to assume this role. Use the same value you enter in Prowler Cloud.
|
||||
Type: String
|
||||
MinLength: 8
|
||||
AllowedPattern: ".+"
|
||||
ConstraintDescription: "ExternalId must be at least 8 characters."
|
||||
|
||||
AccountId:
|
||||
Description: AWS account ID that assumes the role. If you are deploying this template to be used in Prowler Cloud please do not edit this.
|
||||
Type: String
|
||||
Default: "232136659152"
|
||||
MinLength: 12
|
||||
MaxLength: 12
|
||||
AllowedPattern: "[0-9]{12}"
|
||||
|
||||
IAMPrincipal:
|
||||
Description: IAM principal allowed to assume the role. If you are deploying this template to be used in Prowler Cloud please do not edit this.
|
||||
Type: String
|
||||
Default: role/prowler*
|
||||
|
||||
Resources:
|
||||
ProwlerRemediation:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
RoleName: ProwlerRemediation
|
||||
MaxSessionDuration: 3600
|
||||
AssumeRolePolicyDocument:
|
||||
Version: "2012-10-17"
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal: { AWS: !Sub "arn:${AWS::Partition}:iam::${AccountId}:root" }
|
||||
Action: sts:AssumeRole
|
||||
Condition:
|
||||
StringEquals: { "sts:ExternalId": !Ref ExternalId }
|
||||
StringLike: { "aws:PrincipalArn": !Sub "arn:${AWS::Partition}:iam::${AccountId}:${IAMPrincipal}" }
|
||||
Policies:
|
||||
- PolicyName: ProwlerRealtimeFixes
|
||||
PolicyDocument:
|
||||
Version: "2012-10-17"
|
||||
Statement:
|
||||
- Sid: SecurityGroupIngress
|
||||
Effect: Allow
|
||||
Action: [ec2:DescribeSecurityGroups, ec2:RevokeSecurityGroupIngress, ec2:AuthorizeSecurityGroupIngress]
|
||||
Resource: "*"
|
||||
- Sid: EbsDefaultEncryption
|
||||
Effect: Allow
|
||||
Action: [ec2:GetEbsEncryptionByDefault, ec2:EnableEbsEncryptionByDefault, ec2:DisableEbsEncryptionByDefault]
|
||||
Resource: "*"
|
||||
- Sid: BucketPublicAccessBlock
|
||||
Effect: Allow
|
||||
Action: [s3:GetBucketPublicAccessBlock, s3:PutBucketPublicAccessBlock]
|
||||
Resource: !Sub "arn:${AWS::Partition}:s3:::*"
|
||||
- Sid: AccountPublicAccessBlock
|
||||
Effect: Allow
|
||||
Action: [s3:GetAccountPublicAccessBlock, s3:PutAccountPublicAccessBlock]
|
||||
Resource: "*"
|
||||
- Sid: CloudTrailLogging
|
||||
Effect: Allow
|
||||
Action: [cloudtrail:DescribeTrails, cloudtrail:GetTrailStatus, cloudtrail:StartLogging]
|
||||
Resource: "*"
|
||||
- Sid: RdsPrivate
|
||||
Effect: Allow
|
||||
Action: [rds:DescribeDBInstances, rds:ModifyDBInstance]
|
||||
Resource: !Sub "arn:${AWS::Partition}:rds:*:${AWS::AccountId}:db:*"
|
||||
- Sid: WhoAmI
|
||||
Effect: Allow
|
||||
Action: sts:GetCallerIdentity
|
||||
Resource: "*"
|
||||
|
||||
Outputs:
|
||||
RoleArn:
|
||||
Description: Paste this ARN in Prowler Cloud, Prowler Realtime, Auto-fix.
|
||||
Value: !GetAtt ProwlerRemediation.Arn
|
||||
@@ -1,85 +0,0 @@
|
||||
# Prowler Realtime Detection and Remediation: real-time feed.
|
||||
#
|
||||
# EventBridge forwards risky AWS API calls recorded by CloudTrail to an SQS queue, and Prowler Cloud reads the queue with
|
||||
# the ProwlerScan role. Without it Prowler still works, using CloudTrail LookupEvents with a delay of a few minutes.
|
||||
# Apply it in one region: Prowler Realtime reads one queue per account. Global-service events (IAM, S3 account settings)
|
||||
# arrive in us-east-1.
|
||||
|
||||
terraform {
|
||||
required_version = ">= 1.5"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 5.83"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
event_names = [
|
||||
"AuthorizeSecurityGroupIngress", "PutBucketPublicAccessBlock", "DeleteBucketPublicAccessBlock",
|
||||
"PutAccountPublicAccessBlock", "DeletePublicAccessBlock", "PutBucketPolicy", "StopLogging", "DeleteTrail",
|
||||
"UpdateTrail", "StopConfigurationRecorder", "DeleteConfigurationRecorder", "DeleteFlowLogs", "ScheduleKeyDeletion",
|
||||
"DisableKey", "DisableEbsEncryptionByDefault", "CreateVolume", "RunInstances", "CreateDBInstance",
|
||||
"ModifyDBInstance", "AttachUserPolicy", "AttachRolePolicy", "AttachGroupPolicy", "CreateAccessKey", "ConsoleLogin",
|
||||
]
|
||||
}
|
||||
|
||||
resource "aws_sqs_queue" "events" {
|
||||
name = "prowler-realtime-events"
|
||||
message_retention_seconds = 3600
|
||||
receive_wait_time_seconds = 20
|
||||
sqs_managed_sse_enabled = true
|
||||
tags = { prowler = "realtime-feed" }
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_event_rule" "risky_api_calls" {
|
||||
name = "prowler-realtime-risky-api-calls"
|
||||
description = "Risky changes that can break compliance checks, forwarded to Prowler Realtime"
|
||||
event_pattern = jsonencode({
|
||||
"detail-type" = ["AWS API Call via CloudTrail", "AWS Console Sign In via CloudTrail"]
|
||||
detail = { eventName = local.event_names }
|
||||
})
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_event_target" "queue" {
|
||||
rule = aws_cloudwatch_event_rule.risky_api_calls.name
|
||||
target_id = "prowler-realtime-queue"
|
||||
arn = aws_sqs_queue.events.arn
|
||||
}
|
||||
|
||||
data "aws_iam_policy_document" "queue" {
|
||||
statement {
|
||||
sid = "AllowEventBridge"
|
||||
actions = ["sqs:SendMessage"]
|
||||
resources = [aws_sqs_queue.events.arn]
|
||||
principals {
|
||||
type = "Service"
|
||||
identifiers = ["events.amazonaws.com"]
|
||||
}
|
||||
condition {
|
||||
test = "ArnEquals"
|
||||
variable = "aws:SourceArn"
|
||||
values = [aws_cloudwatch_event_rule.risky_api_calls.arn]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_sqs_queue_policy" "events" {
|
||||
queue_url = aws_sqs_queue.events.id
|
||||
policy = data.aws_iam_policy_document.queue.json
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "read_feed" {
|
||||
name = "ProwlerRealtimeFeed"
|
||||
role = var.prowler_scan_role_name
|
||||
policy = jsonencode({
|
||||
Version = "2012-10-17"
|
||||
Statement = [{
|
||||
Sid = "ReadRealtimeQueue"
|
||||
Effect = "Allow"
|
||||
Action = ["sqs:ReceiveMessage", "sqs:DeleteMessage", "sqs:GetQueueAttributes"]
|
||||
Resource = aws_sqs_queue.events.arn
|
||||
}]
|
||||
})
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
output "queue_url" {
|
||||
description = "Paste this URL in Prowler Cloud, Realtime, Real-time feed."
|
||||
value = aws_sqs_queue.events.url
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
variable "prowler_scan_role_name" {
|
||||
type = string
|
||||
description = "Name of the ProwlerScan role Prowler Cloud already uses for this account. It receives read access to this queue only."
|
||||
default = "ProwlerScan"
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
# Prowler Realtime Detection and Remediation: remediation-only IAM role (optional).
|
||||
#
|
||||
# Lets Prowler fix a small, fixed set of misconfigurations automatically (and undo them). It is separate from the
|
||||
# read-only ProwlerScan role: without it Prowler can only alert and propose pull requests. Every action is one a listed
|
||||
# fix or its undo needs; the resource comes from the event, so most statements cannot name it in advance. Destroy the
|
||||
# stack to revoke.
|
||||
#
|
||||
# If you deploy this to be used in Prowler Cloud, do not edit account_id and iam_principal.
|
||||
#
|
||||
# What Prowler can do at runtime through this role, and nothing else:
|
||||
# - Close internet-open ports (22, 3389, all) on the security group named in an event, revoking only 0.0.0.0/0 and ::/0 rules (undo recorded)
|
||||
# - Turn on the four public access block settings of the S3 bucket named in an event (undo recorded)
|
||||
# - Turn on the account-wide S3 public access block (undo recorded; can affect buckets that are public on purpose)
|
||||
# - Start CloudTrail logging again on trails that were stopped (not revertible)
|
||||
# - Enable EBS encryption by default in the region; existing volumes are not changed (undo recorded)
|
||||
# - Set PubliclyAccessible to false on the RDS database named in an event (undo recorded)
|
||||
|
||||
terraform {
|
||||
required_version = ">= 1.5"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 5.83"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data "aws_partition" "current" {}
|
||||
data "aws_caller_identity" "current" {}
|
||||
|
||||
data "aws_iam_policy_document" "assume_role" {
|
||||
statement {
|
||||
actions = ["sts:AssumeRole"]
|
||||
principals {
|
||||
type = "AWS"
|
||||
identifiers = ["arn:${data.aws_partition.current.partition}:iam::${var.account_id}:root"]
|
||||
}
|
||||
condition {
|
||||
test = "StringEquals"
|
||||
variable = "sts:ExternalId"
|
||||
values = [var.external_id]
|
||||
}
|
||||
condition {
|
||||
test = "StringLike"
|
||||
variable = "aws:PrincipalArn"
|
||||
values = ["arn:${data.aws_partition.current.partition}:iam::${var.account_id}:${var.iam_principal}"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data "aws_iam_policy_document" "fixes" {
|
||||
statement {
|
||||
sid = "SecurityGroupIngress"
|
||||
actions = ["ec2:DescribeSecurityGroups", "ec2:RevokeSecurityGroupIngress", "ec2:AuthorizeSecurityGroupIngress"]
|
||||
resources = ["*"]
|
||||
}
|
||||
statement {
|
||||
sid = "EbsDefaultEncryption"
|
||||
actions = ["ec2:GetEbsEncryptionByDefault", "ec2:EnableEbsEncryptionByDefault", "ec2:DisableEbsEncryptionByDefault"]
|
||||
resources = ["*"]
|
||||
}
|
||||
statement {
|
||||
sid = "BucketPublicAccessBlock"
|
||||
actions = ["s3:GetBucketPublicAccessBlock", "s3:PutBucketPublicAccessBlock"]
|
||||
resources = ["arn:${data.aws_partition.current.partition}:s3:::*"]
|
||||
}
|
||||
statement {
|
||||
sid = "AccountPublicAccessBlock"
|
||||
actions = ["s3:GetAccountPublicAccessBlock", "s3:PutAccountPublicAccessBlock"]
|
||||
resources = ["*"]
|
||||
}
|
||||
statement {
|
||||
sid = "CloudTrailLogging"
|
||||
actions = ["cloudtrail:DescribeTrails", "cloudtrail:GetTrailStatus", "cloudtrail:StartLogging"]
|
||||
resources = ["*"]
|
||||
}
|
||||
statement {
|
||||
sid = "RdsPrivate"
|
||||
actions = ["rds:DescribeDBInstances", "rds:ModifyDBInstance"]
|
||||
resources = ["arn:${data.aws_partition.current.partition}:rds:*:${data.aws_caller_identity.current.account_id}:db:*"]
|
||||
}
|
||||
statement {
|
||||
sid = "WhoAmI"
|
||||
actions = ["sts:GetCallerIdentity"]
|
||||
resources = ["*"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "prowler_remediation" {
|
||||
name = "ProwlerRemediation"
|
||||
max_session_duration = 3600
|
||||
assume_role_policy = data.aws_iam_policy_document.assume_role.json
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "fixes" {
|
||||
name = "ProwlerRealtimeFixes"
|
||||
role = aws_iam_role.prowler_remediation.id
|
||||
policy = data.aws_iam_policy_document.fixes.json
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
output "role_arn" {
|
||||
description = "Paste this ARN in Prowler Cloud, Realtime, Credentials for remediation only."
|
||||
value = aws_iam_role.prowler_remediation.arn
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
variable "external_id" {
|
||||
type = string
|
||||
description = "The External ID Prowler uses to assume this role. Use the same value you enter in Prowler Cloud."
|
||||
|
||||
validation {
|
||||
condition = length(var.external_id) >= 8
|
||||
error_message = "external_id must be at least 8 characters."
|
||||
}
|
||||
}
|
||||
|
||||
variable "account_id" {
|
||||
type = string
|
||||
description = "AWS account ID that assumes the role. If you deploy this to be used in Prowler Cloud, do not edit this."
|
||||
default = "232136659152"
|
||||
|
||||
validation {
|
||||
condition = can(regex("^[0-9]{12}$", var.account_id))
|
||||
error_message = "account_id must be a valid AWS account ID."
|
||||
}
|
||||
}
|
||||
|
||||
variable "iam_principal" {
|
||||
type = string
|
||||
description = "IAM principal allowed to assume the role. If you deploy this to be used in Prowler Cloud, do not edit this."
|
||||
default = "role/prowler*"
|
||||
}
|
||||
@@ -14,32 +14,21 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
|
||||
| Action | Skill |
|
||||
|--------|-------|
|
||||
| Add changelog entry for a PR or feature | `prowler-changelog` |
|
||||
| Add or edit changelog fragments in <component>/changelog.d/ | `prowler-changelog` |
|
||||
| Adding ConfigRequirements guardrails to compliance requirements | `prowler-compliance` |
|
||||
| Adding a compliance output formatter (per-provider class + table dispatcher) | `prowler-compliance` |
|
||||
| Adding new providers | `prowler-provider` |
|
||||
| Adding services to existing providers | `prowler-provider` |
|
||||
| Auditing check-to-requirement mappings as a cloud auditor | `prowler-compliance` |
|
||||
| Committing changes | `prowler-commit` |
|
||||
| Create PR that requires changelog entry | `prowler-changelog` |
|
||||
| Creating a git commit | `prowler-commit` |
|
||||
| Creating a universal (multi-provider) compliance framework | `prowler-compliance` |
|
||||
| Creating new checks | `prowler-sdk-check` |
|
||||
| Creating/updating compliance frameworks | `prowler-compliance` |
|
||||
| Fixing bug | `tdd` |
|
||||
| Fixing compliance JSON bugs (duplicate IDs, empty Section, stale refs) | `prowler-compliance` |
|
||||
| Implementing feature | `tdd` |
|
||||
| Mapping checks to compliance controls | `prowler-compliance` |
|
||||
| Mocking AWS with moto in tests | `prowler-test-sdk` |
|
||||
| Modifying component | `tdd` |
|
||||
| Packaging checks, compliance frameworks or providers as external packages | `prowler-registry-artifact` |
|
||||
| Publishing artifacts to Prowler Registry | `prowler-registry-artifact` |
|
||||
| Refactoring code | `tdd` |
|
||||
| Review changelog format and conventions | `prowler-changelog` |
|
||||
| Reviewing compliance framework PRs | `prowler-compliance-review` |
|
||||
| Syncing compliance framework with upstream catalog | `prowler-compliance` |
|
||||
| Update CHANGELOG.md in any component | `prowler-changelog` |
|
||||
| Updating existing checks and metadata | `prowler-sdk-check` |
|
||||
| Working on task | `tdd` |
|
||||
| Writing Prowler SDK tests | `prowler-test-sdk` |
|
||||
| Writing Python tests with pytest | `pytest` |
|
||||
|
||||
|
||||
@@ -4,23 +4,6 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
|
||||
<!-- changelog: release notes start -->
|
||||
|
||||
## [5.47.0] (Prowler v5.47.0)
|
||||
|
||||
### 🚀 Added
|
||||
|
||||
- `iam_subscription_owners_between_2_and_3` check for Azure provider, verifying each subscription has between 2 and 3 principals with the Owner role, including owners inherited from management groups, mapped to CIS 5.0 and 6.0 [(#13145)](https://github.com/prowler-cloud/prowler/pull/13145)
|
||||
- `network_application_gateway_waf_enabled` and `network_application_gateway_http2_enabled` checks for Azure provider, with Application Gateway and WAF policy collection in the network service, mapped to CIS 5.0 and 6.0 [(#13160)](https://github.com/prowler-cloud/prowler/pull/13160)
|
||||
|
||||
### 🐞 Fixed
|
||||
|
||||
- Security group internet exposure checks now treat CIDRs in one ingress rule that together cover 0.0.0.0/0 or ::/0 as open to the internet [(#13191)](https://github.com/prowler-cloud/prowler/pull/13191)
|
||||
|
||||
### 🔐 Security
|
||||
|
||||
- pymongo to 4.18.3, dnspython to 2.9.0 and oauthlib to 4.0.0 in the SDK, patching the BSON decoding and DNS compression pointer denial of service advisories and the OAuth device flow token disclosure; dnspython stays on 2.8.0 for Python 3.10, which 2.9.0 no longer supports [(#13185)](https://github.com/prowler-cloud/prowler/pull/13185)
|
||||
|
||||
---
|
||||
|
||||
## [5.46.0] (Prowler v5.46.0)
|
||||
|
||||
### 🚀 Added
|
||||
|
||||
@@ -698,8 +698,6 @@ def prowler():
|
||||
html_output = HTML(
|
||||
findings=finding_outputs,
|
||||
file_path=f"{filename}{html_file_suffix}",
|
||||
# Only the OSS CLI shows the Prowler Cloud hand-off block
|
||||
show_cloud_cta=True,
|
||||
)
|
||||
generated_outputs["regular"].append(html_output)
|
||||
html_output.batch_write_data_to_file(
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
`gen-ai` category for `guardduty_ai_protection_enabled` and `iam_user_access_not_stale_to_sagemaker` AWS checks
|
||||