Compare commits

...

6 Commits

Author SHA1 Message Date
Pablo F.G 4ca5a9a942 ci(docs): use pnpm_config_ignore_scripts env (dlx rejects the flag)
`pnpm dlx --ignore-scripts ...` errors with "Unknown option: 'ignore-
scripts'" — pnpm only honors the flag on `pnpm install`. Set the same
behavior via the `pnpm_config_ignore_scripts=true` env var, which pnpm
reads at runtime. Preserves the postinstall-blocking guarantee against
malicious transitives without changing the command name.
2026-05-19 11:08:52 +02:00
Pablo F.G 482cb39ad3 ci(docs): allow release-assets.githubusercontent.com for Node download
Node 24.13.0 (pinned via ui/.nvmrc) is not in the runner toolcache, so
actions/setup-node fetches it from the actions/node-versions release
assets at release-assets.githubusercontent.com — which harden-runner
was blocking. Mirrors the allowlist used by ui-tests.yml, which hits
the same path.
2026-05-19 11:03:49 +02:00
Pablo F.G 03f731f34c ci(docs): drop tj-actions/changed-files gate from markdown lint
Lint-all is fast (~5s on the tree) and the full job (~30s) saves so
little when skipped that the gate doesn't pay for itself the way it
does in api-/sdk-code-quality (where Python toolchain setup costs
60-90s). Removing the gate also drops a third-party action with a
documented 2025 supply-chain incident (still pinned by SHA here, but
fewer external dependencies is a win when the cost is this small).
2026-05-19 10:34:01 +02:00
Pablo F.G 0855534d59 docs: lint full repo and clean pre-existing markdownlint violations
- Switch CI to lint **/*.md instead of the changed-file subset, aligning
  with the api/sdk code-quality gating pattern (gate via changed-files,
  lint the full scope).
- Replace `npm install --global` with `pnpm dlx --ignore-scripts` and
  pin Node via ui/.nvmrc for consistency with the UI workspace.
- Fix the violations surfaced by the wider scope: MD040 fenced-code
  language across skills/ and project READMEs; MD036 emphasis-as-
  heading in tdd/docs/mcp_server; MD025 multi-h1 cascade in
  api/README.md; MD001 increment in *AGENTS.md; MD024 duplicate heading
  in skill-creator/SKILL.md. Formatting-only — no copy or code changes.
2026-05-19 10:03:04 +02:00
Pablo F.G a4db8d98ed ci(docs): wire markdownlint into CI and clean up touched files
Add a GitHub Actions workflow that runs the same markdownlint-cli v0.45.0
pinned in .pre-commit-config.yaml, so prek and CI behave identically.
The workflow uses tj-actions/changed-files to lint only .md files in the
PR (matching the sdk/api-code-quality pattern), which lets existing
violations be cleaned up incrementally without blocking unrelated work.

- .github/workflows/markdown-lint.yml: harden-runner + changed-files +
  npm install markdownlint-cli@0.45.0 + lint changed files only.
- .markdownlintignore: ignore **/CHANGELOG.md — auto-generated by the
  prowler-changelog skill (keepachangelog format legitimately repeats
  "### Fixed"/"### Added" across versions); revisit with the team.
- Apply markdownlint --fix across the repo (whitespace, list markers,
  trailing punctuation, blanks around tables) — 17 files affected.
- Promote bold-as-heading callouts to real headings in README.md and
  CONTRIBUTING.md so MD036/MD025 stop firing on touched files.
- Add alt text to README badges (MD045) and replace the "[here]" link
  text with descriptive copy (MD059).
- Tag fenced code blocks with the `text` language in skills/ and
  ui/docs/code-review docs (MD040).

Refs: WebstormProjects-qua

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 20:52:46 +02:00
Pablo F.G 16f8e071c2 chore: add markdownlint foundation config
Add markdownlint to the project to enable consistent Markdown formatting
across ~112 markdown files. This is the foundation; auto-fixable issues
will be addressed in a follow-up PR.

- .markdownlint.json: extends markdownlint/style/prettier with
  line-length and no-bare-urls disabled (conservative defaults)
- .markdownlintignore: excludes node_modules/, .venv/, build outputs, contrib/
- .pre-commit-config.yaml: add igorshubovych/markdownlint-cli hook (priority 30)
- Makefile: add lint-markdown and format-markdown targets

Refs: WebstormProjects-qua

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 20:52:46 +02:00
56 changed files with 418 additions and 313 deletions
+60
View File
@@ -0,0 +1,60 @@
name: 'Docs: Markdown Lint'
on:
push:
branches:
- 'master'
- 'v5.*'
pull_request:
branches:
- 'master'
- 'v5.*'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions: {}
jobs:
markdown-lint:
if: github.repository == 'prowler-cloud/prowler'
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
steps:
- name: Harden Runner
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
with:
egress-policy: block
allowed-endpoints: >
api.github.com:443
github.com:443
registry.npmjs.org:443
release-assets.githubusercontent.com:443
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: ui/.nvmrc
- name: Setup pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
with:
package_json_file: ui/package.json
run_install: false
- name: Run markdownlint
# Pin must match .pre-commit-config.yaml so prek and CI behave identically.
# pnpm dlx doesn't accept --ignore-scripts as a flag; the env var
# disables postinstall scripts on transitives the same way.
env:
pnpm_config_ignore_scripts: 'true'
run: pnpm dlx markdownlint-cli@0.45.0 '**/*.md'
+10
View File
@@ -0,0 +1,10 @@
{
"extends": "markdownlint/style/prettier",
"first-line-h1": false,
"no-duplicate-heading": {
"siblings_only": true
},
"no-inline-html": false,
"line-length": false,
"no-bare-urls": false
}
+16
View File
@@ -0,0 +1,16 @@
node_modules/
ui/node_modules/
.git/
.venv/
**/.venv/
dist/
build/
htmlcov/
.next/
ui/.next/
ui/out/
contrib/
# Auto-generated content (keepachangelog format legitimately repeats section headings).
# Revisit with the team — see beads task on markdownlint rule triage.
**/CHANGELOG.md
+7
View File
@@ -125,6 +125,13 @@ repos:
pass_filenames: false
priority: 50
## MARKDOWN
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.45.0
hooks:
- id: markdownlint
priority: 30
## CONTAINERS
- repo: https://github.com/hadolint/hadolint
rev: v2.14.0
+2
View File
@@ -11,6 +11,7 @@
Use these skills for detailed patterns on-demand:
### Generic Skills (Any Project)
| Skill | Description | URL |
|-------|-------------|-----|
| `typescript` | Const types, flat interfaces, utility types | [SKILL.md](skills/typescript/SKILL.md) |
@@ -28,6 +29,7 @@ Use these skills for detailed patterns on-demand:
| `tdd` | Test-Driven Development workflow | [SKILL.md](skills/tdd/SKILL.md) |
### Prowler-Specific Skills
| Skill | Description | URL |
|-------|-------------|-----|
| `prowler` | Project overview, component navigation | [SKILL.md](skills/prowler/SKILL.md) |
+4 -3
View File
@@ -1,4 +1,4 @@
# Do you want to learn on how to...
# Do you want to learn on how to
- [Contribute with your code or fixes to Prowler](https://docs.prowler.com/developer-guide/introduction)
- [Create a new provider](https://docs.prowler.com/developer-guide/provider)
@@ -32,5 +32,6 @@ Provider-specific developer notes:
Want some swag as appreciation for your contribution?
# Prowler Developer Guide
https://goto.prowler.com/devguide
## Prowler Developer Guide
<https://goto.prowler.com/devguide>
+21 -21
View File
@@ -1,6 +1,6 @@
<p align="center">
<img align="center" src="https://github.com/prowler-cloud/prowler/blob/master/docs/img/prowler-logo-black.png#gh-light-mode-only" width="50%" height="50%">
<img align="center" src="https://github.com/prowler-cloud/prowler/blob/master/docs/img/prowler-logo-white.png#gh-dark-mode-only" width="50%" height="50%">
<img align="center" alt="Prowler logo" src="https://github.com/prowler-cloud/prowler/blob/master/docs/img/prowler-logo-black.png#gh-light-mode-only" width="50%" height="50%">
<img align="center" alt="Prowler logo" src="https://github.com/prowler-cloud/prowler/blob/master/docs/img/prowler-logo-white.png#gh-dark-mode-only" width="50%" height="50%">
</p>
<p align="center">
<b><i>Prowler</b> is the Open Cloud Security Platform trusted by thousands to automate security and compliance in any cloud environment. With hundreds of ready-to-use checks and compliance frameworks, Prowler delivers real-time, customizable monitoring and seamless integrations, making cloud security simple, scalable, and cost-effective for organizations of any size.
@@ -22,8 +22,8 @@
<a href="https://pypistats.org/packages/prowler"><img alt="PyPI Downloads" src="https://img.shields.io/pypi/dw/prowler.svg?label=downloads"></a>
<a href="https://hub.docker.com/r/toniblyx/prowler"><img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/toniblyx/prowler"></a>
<a href="https://gallery.ecr.aws/prowler-cloud/prowler"><img width="120" height=19" alt="AWS ECR Gallery" src="https://user-images.githubusercontent.com/3985464/151531396-b6535a68-c907-44eb-95a1-a09508178616.png"></a>
<a href="https://codecov.io/gh/prowler-cloud/prowler"><img src="https://codecov.io/gh/prowler-cloud/prowler/graph/badge.svg?token=OflBGsdpDl"/></a>
<a href="https://insights.linuxfoundation.org/project/prowler-cloud-prowler"><img src="https://insights.linuxfoundation.org/api/badge/health-score?project=prowler-cloud-prowler"/></a>
<a href="https://codecov.io/gh/prowler-cloud/prowler"><img alt="Codecov coverage" src="https://codecov.io/gh/prowler-cloud/prowler/graph/badge.svg?token=OflBGsdpDl"/></a>
<a href="https://insights.linuxfoundation.org/project/prowler-cloud-prowler"><img alt="Linux Foundation insights health score" src="https://insights.linuxfoundation.org/api/badge/health-score?project=prowler-cloud-prowler"/></a>
</p>
<p align="center">
<a href="https://github.com/prowler-cloud/prowler/releases"><img alt="Version" src="https://img.shields.io/github/v/release/prowler-cloud/prowler"></a>
@@ -36,7 +36,7 @@
</p>
<hr>
<p align="center">
<img align="center" src="/docs/img/prowler-cloud.gif" width="100%" height="100%">
<img align="center" alt="Prowler Cloud demo" src="/docs/img/prowler-cloud.gif" width="100%" height="100%">
</p>
# Description
@@ -146,11 +146,11 @@ Prowler App offers flexible installation methods tailored to various environment
### Docker Compose
**Requirements**
#### Requirements
* `Docker Compose` installed: https://docs.docker.com/compose/install/.
- `Docker Compose` installed: https://docs.docker.com/compose/install/.
**Commands**
#### Commands
``` console
VERSION=$(curl -s https://api.github.com/repos/prowler-cloud/prowler/releases/latest | jq -r .tag_name)
@@ -175,14 +175,14 @@ You can find more information in the [Troubleshooting](./docs/troubleshooting.md
### From GitHub
**Requirements**
#### Requirements
* `git` installed.
* `uv` installed: [uv installation](https://docs.astral.sh/uv/getting-started/installation/).
* `pnpm` installed: [pnpm installation](https://pnpm.io/installation).
* `Docker Compose` installed: https://docs.docker.com/compose/install/.
- `git` installed.
- `uv` installed: [uv installation](https://docs.astral.sh/uv/getting-started/installation/).
- `pnpm` installed: [pnpm installation](https://pnpm.io/installation).
- `Docker Compose` installed: https://docs.docker.com/compose/install/.
**Commands to run the API**
#### Commands to run the API
``` console
git clone https://github.com/prowler-cloud/prowler
@@ -199,7 +199,7 @@ gunicorn -c config/guniconf.py config.wsgi:application
> After completing the setup, access the API documentation at http://localhost:8080/api/v1/docs.
**Commands to run the API Worker**
#### Commands to run the API Worker
``` console
git clone https://github.com/prowler-cloud/prowler
@@ -212,7 +212,7 @@ cd src/backend
python -m celery -A config.celery worker -l info -E
```
**Commands to run the API Scheduler**
#### Commands to run the API Scheduler
``` console
git clone https://github.com/prowler-cloud/prowler
@@ -225,7 +225,7 @@ cd src/backend
python -m celery -A config.celery beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
```
**Commands to run the UI**
#### Commands to run the UI
``` console
git clone https://github.com/prowler-cloud/prowler
@@ -237,7 +237,7 @@ pnpm start
> Once configured, access the Prowler App at http://localhost:3000. Sign up using your email and password to get started.
**Pre-commit Hooks Setup**
#### Pre-commit Hooks Setup
Some pre-commit hooks require tools installed on your system:
@@ -257,14 +257,14 @@ prowler -v
### Containers
**Available Versions of Prowler CLI**
#### Available Versions of Prowler CLI
The following versions of Prowler CLI are available, depending on your requirements:
- `latest`: Synchronizes with the `master` branch. Note that this version is not stable.
- `v4-latest`: Synchronizes with the `v4` branch. Note that this version is not stable.
- `v3-latest`: Synchronizes with the `v3` branch. Note that this version is not stable.
- `<x.y.z>` (release): Stable releases corresponding to specific versions. You can find the complete list of releases [here](https://github.com/prowler-cloud/prowler/releases).
- `<x.y.z>` (release): Stable releases corresponding to specific versions. See the [complete list of Prowler releases](https://github.com/prowler-cloud/prowler/releases).
- `stable`: Always points to the latest release.
- `v4-stable`: Always points to the latest release for v4.
- `v3-stable`: Always points to the latest release for v3.
@@ -338,7 +338,7 @@ Full configuration, per-provider authentication, and SARIF examples: [Prowler Gi
## Prowler CLI
**Running Prowler**
### Running Prowler
Prowler can be executed across various environments, offering flexibility to meet your needs. It can be run from:
+4 -4
View File
@@ -10,7 +10,7 @@
> - [`jsonapi`](../skills/jsonapi/SKILL.md) - Strict JSON:API v1.1 spec compliance
> - [`pytest`](../skills/pytest/SKILL.md) - Generic pytest patterns
### Auto-invoke Skills
## Auto-invoke Skills
When performing these actions, ALWAYS invoke the corresponding skill FIRST:
@@ -81,7 +81,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
## DECISION TREES
### Serializer Selection
```
```text
Read → <Model>Serializer
Create → <Model>CreateSerializer
Update → <Model>UpdateSerializer
@@ -89,7 +89,7 @@ Nested read → <Model>IncludeSerializer
```
### Task vs View
```
```text
< 100ms → View
> 100ms or external API → Celery task
Needs retry → Celery task
@@ -105,7 +105,7 @@ Django 5.1.x | DRF 3.15.x | djangorestframework-jsonapi 7.x | Celery 5.4.x | Pos
## PROJECT STRUCTURE
```
```text
api/src/backend/
├── api/ # Main Django app
│ ├── v1/ # API version 1 (views, serializers, urls)
+29 -29
View File
@@ -2,7 +2,7 @@
This repository contains the JSON API and Task Runner components for Prowler, which facilitate a complete backend that interacts with the Prowler SDK and is used by the Prowler UI.
# Components
## Components
The Prowler API is composed of the following components:
- The JSON API, which is an API built with Django Rest Framework.
@@ -10,13 +10,13 @@ The Prowler API is composed of the following components:
- The PostgreSQL database, which is used to store the data.
- The Valkey database, which is an in-memory database which is used as a message broker for the Celery workers.
## Note about Valkey
### Note about Valkey
[Valkey](https://valkey.io/) is an open source (BSD) high performance key/value datastore.
Valkey exposes a Redis 7.2 compliant API. Any service that exposes the Redis API can be used with Prowler API.
# Modify environment variables
## Modify environment variables
Under the root path of the project, you can find a file called `.env`. This file shows all the environment variables that the project uses. You should review it and set the values for the variables you want to change.
@@ -24,7 +24,7 @@ If you dont set `DJANGO_TOKEN_SIGNING_KEY` or `DJANGO_TOKEN_VERIFYING_KEY`, t
**Important note**: Every Prowler version (or repository branches and tags) could have different variables set in its `.env` file. Please use the `.env` file that corresponds with each version.
## Local deployment
### Local deployment
Keep in mind if you export the `.env` file to use it with local deployment that you will have to do it within the context of the virtual environment, not before. Otherwise, variables will not be loaded properly.
To do this, you can run:
@@ -34,12 +34,12 @@ set -a
source .env
```
# 🚀 Production deployment
## Docker deployment
## 🚀 Production deployment
### Docker deployment
This method requires `docker` and `docker compose`.
### Clone the repository
#### Clone the repository
```console
# HTTPS
@@ -50,13 +50,13 @@ git clone git@github.com:prowler-cloud/api.git
```
### Build the base image
#### Build the base image
```console
docker compose --profile prod build
```
### Run the production service
#### Run the production service
This command will start the Django production server and the Celery worker and also the Valkey and PostgreSQL databases.
@@ -68,7 +68,7 @@ You can access the server in `http://localhost:8080`.
> **NOTE:** notice how the port is different. When developing using docker, the port will be `8080` to prevent conflicts.
### View the Production Server Logs
#### View the Production Server Logs
To view the logs for any component (e.g., Django, Celery worker), you can use the following command with a wildcard. This command will follow logs for any container that matches the specified pattern:
@@ -133,13 +133,13 @@ gunicorn -c config/guniconf.py config.wsgi:application
> By default, the Gunicorn server will try to use as many workers as your machine can handle. You can manually change that in the `src/backend/config/guniconf.py` file.
# 🧪 Development guide
## 🧪 Development guide
## Local deployment
### Local deployment
To use this method, you'll need to set up a Python virtual environment (version ">=3.11,<3.13") and keep dependencies updated. Additionally, ensure that `uv` and `docker compose` are installed.
### Clone the repository
#### Clone the repository
```console
# HTTPS
@@ -150,7 +150,7 @@ git clone git@github.com:prowler-cloud/api.git
```
### Start the PostgreSQL Database and Valkey
#### Start the PostgreSQL Database and Valkey
The PostgreSQL database (version 16.3) and Valkey (version 7) are required for the development environment. To make development easier, we have provided a `docker-compose` file that will start these components for you.
@@ -161,7 +161,7 @@ The PostgreSQL database (version 16.3) and Valkey (version 7) are required for t
docker compose up postgres valkey -d
```
### Install the Python dependencies
#### Install the Python dependencies
> You must have uv installed
@@ -169,7 +169,7 @@ docker compose up postgres valkey -d
uv sync
```
### Apply migrations
#### Apply migrations
For migrations, you need to force the `admin` database router. Assuming you have the correct environment variables and Python virtual environment, run:
@@ -178,7 +178,7 @@ cd src/backend
python manage.py migrate --database admin
```
### Run the Django development server
#### Run the Django development server
```console
cd src/backend
@@ -188,7 +188,7 @@ python manage.py runserver
You can access the server in `http://localhost:8000`.
All changes in the code will be automatically reloaded in the server.
### Run the Celery worker
#### Run the Celery worker
```console
python -m celery -A config.celery worker -l info -E
@@ -196,11 +196,11 @@ python -m celery -A config.celery worker -l info -E
The Celery worker does not detect and reload changes in the code, so you need to restart it manually when you make changes.
## Docker deployment
### Docker deployment
This method requires `docker` and `docker compose`.
### Clone the repository
#### Clone the repository
```console
# HTTPS
@@ -211,13 +211,13 @@ git clone git@github.com:prowler-cloud/api.git
```
### Build the base image
#### Build the base image
```console
docker compose --profile dev build
```
### Run the development service
#### Run the development service
This command will start the Django development server and the Celery worker and also the Valkey and PostgreSQL databases.
@@ -230,7 +230,7 @@ All changes in the code will be automatically reloaded in the server.
> **NOTE:** notice how the port is different. When developing using docker, the port will be `8080` to prevent conflicts.
### View the development server logs
#### View the development server logs
To view the logs for any component (e.g., Django, Celery worker), you can use the following command with a wildcard. This command will follow logs for any container that matches the specified pattern:
@@ -238,7 +238,7 @@ To view the logs for any component (e.g., Django, Celery worker), you can use th
docker logs -f $(docker ps --format "{{.Names}}" | grep 'api-')
```
## Applying migrations
### Applying migrations
For migrations, you need to force the `admin` database router. Assuming you have the correct environment variables and Python virtual environment, run:
@@ -247,7 +247,7 @@ cd src/backend
uv run python manage.py migrate --database admin
```
## Apply fixtures
### Apply fixtures
Fixtures are used to populate the database with initial development data.
@@ -258,7 +258,7 @@ uv run python manage.py loaddata api/fixtures/0_dev_users.json --database admin
> The default credentials are `dev@prowler.com:Thisisapassword123@` or `dev2@prowler.com:Thisisapassword123@`
## Run tests
### Run tests
Note that the tests will fail if you use the same `.env` file as the development environment.
@@ -269,7 +269,7 @@ cd src/backend
uv run pytest
```
# Custom commands
## Custom commands
Django provides a way to create custom commands that can be run from the command line.
@@ -281,7 +281,7 @@ To run a custom command, you need to be in the `prowler/api/src/backend` directo
uv run python manage.py <command_name>
```
## Generate dummy data
### Generate dummy data
```console
python manage.py findings --tenant
@@ -298,7 +298,7 @@ This command creates, for a given tenant, a provider, scan and a set of findings
>
> The last step is required to access the findings details, since the UI needs that to print all the information.
### Example
#### Example
```console
~/backend $ uv run python manage.py findings --tenant
+2 -2
View File
@@ -134,7 +134,7 @@ Example 1 is vague and even potentially ambiguous. Verbs state your purpose and
Explicit use of second-person pronouns (you) and possessives (your) should be minimized whenever possible. Those constructions are best reserved for cases when instructions are directly given in an imperative form:
**Example of Improvement Through Avoiding Second Person Pronouns**
### Example of Improvement Through Avoiding Second Person Pronouns
**Original:**
Prowler App can be installed in different ways, depending on your environment:
@@ -236,7 +236,7 @@ The use of bullet points is highly recommended when:
* Information can be logically divided into multiple categories, each sharing characteristics, features, or other relevant classifications.
* Items are significant enough as standalone concepts to deserve their own bullet point.
**Example of Improvement Through Bullet Points**
#### Example of Improvement Through Bullet Points
**Original:**
It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, FedRAMS, PCI-DSS, GDPR, HIPAA, FFIEC, SOC2, GXP, AWS Well-Architected Framework Security Pillar, AWS Foundational Technical Review (FTR), ENS (Spanish National Security Scheme), and your custom security frameworks.
+2 -2
View File
@@ -2,7 +2,7 @@
> **Skills Reference**: See [`prowler-mcp`](../skills/prowler-mcp/SKILL.md)
### Auto-invoke Skills
## Auto-invoke Skills
When performing these actions, ALWAYS invoke the corresponding skill FIRST:
@@ -68,7 +68,7 @@ Python 3.12+ | FastMCP 2.13.1 | httpx (async) | Pydantic | uv
## PROJECT STRUCTURE
```
```text
mcp_server/prowler_mcp_server/
├── server.py # Main orchestration
├── prowler_hub/server.py # Hub tools (no auth)
+9 -6
View File
@@ -83,14 +83,14 @@ npm install --save-exact mcp-remote@0.1.38
### 2. Local STDIO Mode
**Run the server locally on your machine**
Run the server locally on your machine:
- Runs as a subprocess of your MCP client
- Requires Python 3.12+ or Docker
### 3. Self-Hosted HTTP Mode
**Deploy your own remote MCP server**
Deploy your own remote MCP server:
- Full control over deployment
- Requires Python 3.12+ or Docker
@@ -132,7 +132,7 @@ All tools follow a consistent naming pattern with prefixes:
## Architecture
```
```text
prowler_mcp_server/
├── server.py # Main orchestrator (imports sub-servers with prefixes)
├── main.py # CLI entry point
@@ -154,17 +154,20 @@ prowler_mcp_server/
The Prowler MCP Server enables powerful workflows through AI assistants:
**Security Operations**
### Security Operations
- "Show me all critical findings from my AWS production accounts"
- "Register my new AWS account in Prowler and run a scheduled scan every day"
- "List all muted findings and detect what findgings are muted by a not enough good reason in relation to their severity"
**Security Research**
### Security Research
- "Explain what the S3 bucket public access Prowler check does"
- "Find all Prowler checks related to encryption at rest"
- "What is the latest version of the CIS that Prowler is covering per provider?"
**Documentation & Learning**
### Documentation & Learning
- "How do I configure Prowler to scan my GCP organization?"
- "What authentication methods does Prowler support for Azure?"
- "How can I contribute with a new security check to Prowler?"
+4 -4
View File
@@ -28,12 +28,12 @@ This Terraform configuration creates the necessary IAM role and policies to allo
### Usage Examples
#### Basic deployment (without S3 integration):
#### Basic deployment (without S3 integration)
```bash
terraform apply -var="external_id=your-external-id-here"
```
#### With S3 integration enabled:
#### With S3 integration enabled
```bash
terraform apply \
-var="external_id=your-external-id-here" \
@@ -42,14 +42,14 @@ terraform apply \
-var="s3_integration_bucket_account_id=123456789012"
```
#### Using terraform.tfvars file (Recommended):
#### Using terraform.tfvars file (Recommended)
```bash
cp terraform.tfvars.example terraform.tfvars
# Edit the file with your values
terraform apply
```
#### Command line variables (Alternative):
#### Command line variables (Alternative)
```bash
terraform apply -var="external_id=your-external-id-here"
```
+3 -3
View File
@@ -7,7 +7,7 @@
> - [`prowler-compliance`](../skills/prowler-compliance/SKILL.md) - Compliance framework structure
> - [`pytest`](../skills/pytest/SKILL.md) - Generic pytest patterns
### Auto-invoke Skills
## Auto-invoke Skills
When performing these actions, ALWAYS invoke the corresponding skill FIRST:
@@ -44,7 +44,7 @@ The Prowler SDK is the core Python engine powering cloud security assessments ac
### Provider Architecture
```
```text
prowler/providers/{provider}/
├── {provider}_provider.py # Main provider class
├── models.py # Provider-specific models
@@ -91,7 +91,7 @@ Python 3.10+ | uv | pytest | moto (AWS mocking) | Pre-commit hooks (black, flake
## PROJECT STRUCTURE
```
```text
prowler/
├── __main__.py # CLI entry point
├── config/ # Global configuration
+3 -3
View File
@@ -36,7 +36,7 @@ After running setup, restart your AI coding assistant to load the skills.
Skills are automatically discovered by the AI agent. To manually load a skill during a session:
```
```text
Read skills/{skill-name}/SKILL.md
```
@@ -90,7 +90,7 @@ Patterns tailored for Prowler development:
## Directory Structure
```
```text
skills/
├── {skill-name}/
│ ├── SKILL.md # Required - main instrunsction and metadata
@@ -118,7 +118,7 @@ This reads `metadata.scope` and `metadata.auto_invoke` from each `SKILL.md` and
Use the `skill-creator` skill for guidance:
```
```text
Read skills/skill-creator/SKILL.md
```
+6 -6
View File
@@ -54,7 +54,7 @@ When implementing a new endpoint, review these patterns in order:
## Decision Trees
### Which Serializer?
```
```text
GET list/retrieve → <Model>Serializer
POST create → <Model>CreateSerializer
PATCH update → <Model>UpdateSerializer
@@ -62,7 +62,7 @@ PATCH update → <Model>UpdateSerializer
```
### Which Base Serializer?
```
```text
Read-only serializer → BaseModelSerializerV1
Create with tenant_id → RLSSerializer + BaseWriteSerializer (auto-injects tenant_id on create)
Update with validation → BaseWriteSerializer (tenant_id already exists on object)
@@ -70,14 +70,14 @@ Non-model data → BaseSerializerV1
```
### Which Filter Base?
```
```text
Direct FK to Provider → BaseProviderFilter
FK via Scan → BaseScanProviderFilter
No provider relation → FilterSet
```
### Which Base ViewSet?
```
```text
RLS-protected model → BaseRLSViewSet (most common)
Tenant operations → BaseTenantViewset
User operations → BaseUserViewset
@@ -85,7 +85,7 @@ No RLS required → BaseViewSet (rare)
```
### Resource Name Format?
```
```text
Single word model → plural lowercase (Provider → providers)
Multi-word model → plural lowercase kebab (ProviderGroup → provider-groups)
Through/join model → parent-child pattern (UserRoleRelationship → user-roles)
@@ -490,7 +490,7 @@ When implementing or debugging, query these libraries via `mcp_context7_query-do
| **drf-spectacular** | `/tfranzel/drf-spectacular` | OpenAPI schema, `@extend_schema` |
**Example queries:**
```
```text
mcp_context7_query-docs(libraryId="/websites/django-rest-framework", query="ViewSet get_queryset best practices")
mcp_context7_query-docs(libraryId="/tfranzel/drf-spectacular", query="extend_schema examples for custom actions")
mcp_context7_query-docs(libraryId="/websites/djangoproject_en_5_2", query="model constraints and indexes")
@@ -16,7 +16,7 @@
## ViewSet Hierarchy
```
```text
BaseViewSet (minimal - no RLS/auth)
├── BaseRLSViewSet (+ tenant filtering, RLS-protected models)
@@ -31,7 +31,7 @@ BaseViewSet (minimal - no RLS/auth)
## Serializer Hierarchy
```
```text
BaseModelSerializerV1 (JSON:API defaults, read_only_fields)
├── RLSSerializer (auto-injects tenant_id from request)
@@ -47,7 +47,7 @@ BaseModelSerializerV1 (JSON:API defaults, read_only_fields)
## Filter Hierarchy
```
```text
FilterSet (django-filter)
├── CommonFindingFilters (mixin for date ranges, delta, status)
@@ -2,7 +2,7 @@
## Content Type
```
```http
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json
```
+2 -2
View File
@@ -364,7 +364,7 @@ Batch utilities: `api/db_utils.py` (`batch_delete`, `create_objects_in_batches`,
## Decision tree
```
```text
Auto-generated migration?
├── Yes → Split it following the rules below
└── No → Review it against the rules below
@@ -420,7 +420,7 @@ When implementing or debugging migration patterns, query these libraries via `mc
| django-postgres-extra | `/SectorLabs/django-postgres-extra` | Partitioned models, `PostgresPartitionedModel`, partition management |
**Example queries:**
```
```text
mcp_context7_query-docs(libraryId="/websites/djangoproject_en_5_1", query="migration operations AddIndex RunPython atomic")
mcp_context7_query-docs(libraryId="/websites/djangoproject_en_5_1", query="database indexes Meta class concurrently")
mcp_context7_query-docs(libraryId="/websites/postgresql_org_docs_current", query="CREATE INDEX CONCURRENTLY partitioned table")
+2 -2
View File
@@ -30,7 +30,7 @@ allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch
## File Layout
```
```text
.github/
├── workflows/
│ ├── {name}.md # Frontmatter + thin context dispatcher
@@ -308,7 +308,7 @@ After modifying any `.github/workflows/*.md`:
Add to repo root so lock files auto-resolve on merge:
```
```text
.github/workflows/*.lock.yml linguist-generated=true merge=ours
```
+2 -2
View File
@@ -35,7 +35,7 @@ This skill focuses on **spec compliance**. For **implementation patterns** (View
If Context7 MCP is available, query the JSON:API spec directly:
```
```text
mcp_context7_resolve-library-id(query="jsonapi specification")
mcp_context7_query-docs(libraryId="<resolved-id>", query="[specific topic: relationships, errors, etc.]")
```
@@ -44,7 +44,7 @@ mcp_context7_query-docs(libraryId="<resolved-id>", query="[specific topic: relat
If Context7 is not available, fetch from the official spec:
```
```text
WebFetch(url="https://jsonapi.org/format/", prompt="Extract rules for [specific topic]")
```
+1 -1
View File
@@ -14,7 +14,7 @@ allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task
## App Router File Conventions
```
```text
app/
├── layout.tsx # Root layout (required)
├── page.tsx # Home page (/)
+3 -3
View File
@@ -36,7 +36,7 @@ allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task
## File Structure
```
```text
tests/
├── base-page.ts # Parent class for ALL pages
├── helpers.ts # Shared utilities
@@ -182,14 +182,14 @@ export class SignUpPage extends BasePage {
## Refactoring Guidelines
### Move to `BasePage` when:
### Move to `BasePage` when
- ✅ Navigation helpers used by multiple pages (`waitForPageLoad()`, `getCurrentUrl()`)
- ✅ Common UI interactions (notifications, modals, theme toggles)
- ✅ Verification patterns repeated across pages (`isVisible()`, `waitForVisible()`)
- ✅ Error handling that applies to all pages
- ✅ Screenshot utilities for debugging
### Move to `helpers.ts` when:
### Move to `helpers.ts` when
- ✅ Test data generation (`generateUniqueEmail()`, `generateTestUser()`)
- ✅ Setup/teardown utilities (`createTestUser()`, `cleanupTestData()`)
- ✅ Custom assertions (`expectNotificationToContain()`)
+3 -2
View File
@@ -225,7 +225,7 @@ Rebuild invalid indexes without locking writes:
REINDEX INDEX CONCURRENTLY index_name;
```
### Understanding _ccnew and _ccold artifacts
### Understanding _ccnew and_ccold artifacts
When `CREATE INDEX CONCURRENTLY` or `REINDEX INDEX CONCURRENTLY` is interrupted, temporary indexes may remain:
@@ -377,7 +377,8 @@ VACUUM (ANALYZE) table_name;
| PostgreSQL | `/websites/postgresql_org_docs_current` | Index types, EXPLAIN, partitioned table indexing, REINDEX |
**Example queries:**
```
```text
mcp_context7_query-docs(libraryId="/websites/postgresql_org_docs_current", query="CREATE INDEX CONCURRENTLY partitioned table")
mcp_context7_query-docs(libraryId="/websites/postgresql_org_docs_current", query="EXPLAIN ANALYZE BUFFERS query plan")
mcp_context7_query-docs(libraryId="/websites/postgresql_org_docs_current", query="partial index WHERE clause")
+6 -6
View File
@@ -61,7 +61,7 @@ Provider.objects.filter(connected=True) # Requires rls_transaction context
### RLS Transaction Flow
```
```text
Request → Authentication → BaseRLSViewSet.initial()
├─ Extract tenant_id from JWT
@@ -92,7 +92,7 @@ When implementing Prowler-specific API features:
## Decision Trees
### Which Base Model?
```
```text
Tenant-scoped data → RowLevelSecurityProtectedModel
Global/shared data → models.Model + BaseSecurityConstraint (rare)
Partitioned time-series → PostgresPartitionedModel + RowLevelSecurityProtectedModel
@@ -100,14 +100,14 @@ Soft-deletable → Add is_deleted + ActiveProviderManager
```
### Which Manager?
```
```text
Normal queries → Model.objects (excludes deleted)
Include deleted records → Model.all_objects
Celery task context → Must use rls_transaction() first
```
### Which Database?
```
```text
Standard API queries → default (automatic via ViewSet)
Read-only operations → replica (automatic for GET in BaseRLSViewSet)
Auth/admin operations → MainRouter.admin_db
@@ -115,7 +115,7 @@ Cross-tenant lookups → MainRouter.admin_db (use sparingly!)
```
### Celery Task Decorator Order?
```
```python
@shared_task(base=RLSTask, name="...", queue="...")
@set_tenant # First: sets tenant context
@handle_provider_deletion # Second: handles deleted providers
@@ -496,7 +496,7 @@ When implementing or debugging Prowler-specific patterns, query these libraries
| **Django** | `/websites/djangoproject_en_5_2` | Models, ORM, constraints, indexes |
**Example queries:**
```
```text
mcp_context7_query-docs(libraryId="/websites/celeryq_dev_en_stable", query="shared_task decorator retry patterns")
mcp_context7_query-docs(libraryId="/celery/django-celery-beat", query="periodic task database scheduler")
mcp_context7_query-docs(libraryId="/websites/djangoproject_en_5_2", query="model constraints CheckConstraint UniqueConstraint")
@@ -2,7 +2,7 @@
## Settings File Structure
```
```text
api/src/backend/config/
├── django/
│ ├── base.py # Base settings (all environments)
@@ -247,7 +247,7 @@ class JSONAPIMeta:
## Decision Tree: New Model
```
```text
Is it tenant-scoped data?
├── Yes → Inherit RowLevelSecurityProtectedModel
│ Add RowLevelSecurityConstraint
+4 -4
View File
@@ -228,7 +228,7 @@ AWS_QUERIES: list[AttackPathsQueryDefinition] = [
**FIRST**, read all files in the queries module to understand the structure, type definitions, registration, and existing style:
```
```text
api/src/backend/api/attack_paths/queries/
├── __init__.py # Module exports
├── types.py # AttackPathsQueryDefinition, AttackPathsQueryParameterDefinition
@@ -250,7 +250,7 @@ grep cartography api/pyproject.toml
Build the schema URL (ALWAYS use the specific tag, not master/main):
```
```text
# Git dependency (prowler-cloud/cartography@0.126.1):
https://raw.githubusercontent.com/prowler-cloud/cartography/refs/tags/0.126.1/docs/root/modules/{provider}/schema.md
@@ -283,7 +283,7 @@ Add the constant to the `{PROVIDER}_QUERIES` list.
### Query ID
```
```text
{provider}-{category}-{description}
```
@@ -291,7 +291,7 @@ Examples: `aws-ec2-privesc-passrole-iam`, `aws-ec2-instances-internet-exposed`
### Query constant name
```
```text
{PROVIDER}_{CATEGORY}_{DESCRIPTION}
```
+4 -4
View File
@@ -28,7 +28,7 @@ metadata:
## Commit Format
```
```text
type(scope): concise description
- Key change 1
@@ -68,7 +68,7 @@ type(scope): concise description
### Title Line
```
```text
# GOOD - Concise and clear
feat(api): add provider connection retry logic
fix(ui): resolve dashboard loading state
@@ -83,7 +83,7 @@ fix(ui): fix the bug in dashboard component on line 45
### Body (Bullet Points)
```
```text
# GOOD - High-level changes
- Add retry mechanism for failed connections
- Document task composition patterns
@@ -132,7 +132,7 @@ fix(ui): fix the bug in dashboard component on line 45
## Decision Tree
```
```text
Single file changed?
├─ Yes → May omit body, title only
└─ No → Include body with key changes
+1 -1
View File
@@ -53,7 +53,7 @@ diff dashboard/compliance/{new_framework}.py \
## Decision Tree
```
```text
JSON Valid?
├── No → FAIL: Fix JSON syntax errors
└── Yes ↓
+8 -4
View File
@@ -59,7 +59,7 @@ See "Compliance Framework Location" and "Framework-Specific Attribute Structures
**Every framework directory follows this exact convention** — do not deviate:
```
```text
{framework}/
├── __init__.py
├── {framework}.py # ONLY get_{framework}_table() — NO function docstring
@@ -85,7 +85,7 @@ See "Compliance Framework Location" and "Framework-Specific Attribute Structures
### The CLI Pipeline (end-to-end)
```
```text
prowler aws --compliance ccc_aws
Compliance.get_bulk("aws") → parses prowler/compliance/aws/*.json
@@ -483,6 +483,7 @@ Prowler ThreatScore is a custom security scoring framework developed by Prowler
## Available Compliance Frameworks
### AWS (41 frameworks)
| Framework | File Name |
|-----------|-----------|
| CIS 1.4, 1.5, 2.0, 3.0, 4.0, 5.0 | `cis_{version}_aws.json` |
@@ -508,6 +509,7 @@ Prowler ThreatScore is a custom security scoring framework developed by Prowler
| NIS2 | `nis2_aws.json` |
### Azure (15+ frameworks)
| Framework | File Name |
|-----------|-----------|
| CIS 2.0, 2.1, 3.0, 4.0 | `cis_{version}_azure.json` |
@@ -518,6 +520,7 @@ Prowler ThreatScore is a custom security scoring framework developed by Prowler
| NIST CSF 2.0 | `nist_csf_2.0_azure.json` |
### GCP (15+ frameworks)
| Framework | File Name |
|-----------|-----------|
| CIS 2.0, 3.0, 4.0 | `cis_{version}_gcp.json` |
@@ -528,6 +531,7 @@ Prowler ThreatScore is a custom security scoring framework developed by Prowler
| NIST CSF 2.0 | `nist_csf_2.0_gcp.json` |
### Kubernetes (6 frameworks)
| Framework | File Name |
|-----------|-----------|
| CIS 1.8, 1.10, 1.11 | `cis_{version}_kubernetes.json` |
@@ -561,7 +565,7 @@ done
The sync tooling is split into three layers so adding a new framework only takes a YAML config (and optionally a new parser module for an unfamiliar upstream format):
```
```text
skills/prowler-compliance/assets/
├── sync_framework.py # generic runner — works for any framework
├── configs/
@@ -902,7 +906,7 @@ Add fixtures to `tests/lib/outputs/compliance/fixtures.py`: one `Compliance` obj
**The table dispatcher file (`{framework}.py`) MUST NOT import `Finding`** (directly or transitively). The cycle is:
```
```text
compliance.compliance imports get_{framework}_table
→ {framework}.py imports ComplianceOutput
→ compliance_output imports Finding
@@ -46,7 +46,7 @@ Each framework type has a specific Pydantic model in `compliance_models.py`:
## File Naming Convention
```
```text
{framework}_{version}_{provider}.json
```
+1 -1
View File
@@ -104,7 +104,7 @@ Reference without articles:
## Documentation Structure
```
```text
docs/
├── getting-started/
├── tutorials/
+1 -1
View File
@@ -25,7 +25,7 @@ Use this skill when:
Every provider MUST follow this structure:
```
```text
prowler/providers/{provider}/
├── __init__.py
├── {provider}_provider.py # Main provider class
+1 -1
View File
@@ -34,7 +34,7 @@ python3 prowler-cli.py <provider> --list-<metric>
The CLI output ends with a summary line like:
```
```text
There are 572 available checks.
There is 1 available Compliance Framework.
```
+2 -2
View File
@@ -16,7 +16,7 @@ allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task
## Check Structure
```
```text
prowler/providers/{provider}/services/{service}/{check_name}/
├── __init__.py
├── {check_name}.py
@@ -90,7 +90,7 @@ See `prowler-test-sdk` skill for test patterns (PASS, FAIL, no resources, error
## Check Naming Convention
```
```text
{service}_{resource}_{security_control}
```
+1 -1
View File
@@ -28,7 +28,7 @@ allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task
## 1. Fixture Dependency Chain
```
```text
create_test_user (session) ─► tenants_fixture (function) ─► authenticated_client
└─► providers_fixture ─► scans_fixture ─► findings_fixture
@@ -14,7 +14,7 @@
## Fixture Dependency Graph
```
```text
create_test_user (session)
└─► tenants_fixture (function)
+1 -1
View File
@@ -265,7 +265,7 @@ from tests.providers.kubernetes.kubernetes_fixtures import set_mocked_kubernetes
## Test File Structure
```
```text
tests/providers/{provider}/services/{service}/
├── {service}_service_test.py # Service tests
└── {check_name}/
+6 -5
View File
@@ -19,7 +19,7 @@ allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task
## Prowler UI Test Structure
```
```text
ui/tests/
├── base-page.ts # Prowler-specific base page
├── helpers.ts # Prowler test utilities
@@ -35,13 +35,13 @@ ui/tests/
**⚠️ ALWAYS verify BEFORE completing any E2E task:**
### When CREATING new tests:
### When CREATING new tests
- [ ] `{page-name}-page.ts` - Page Object created/updated
- [ ] `{page-name}.spec.ts` - Tests added with correct tags (@TEST-ID)
- [ ] `{page-name}.md` - Documentation created with ALL test cases
- [ ] Test IDs in `.md` match tags in `.spec.ts`
### When MODIFYING existing tests:
### When MODIFYING existing tests
- [ ] `{page-name}.md` MUST be updated if:
- Test cases were added/removed
- Test flow changed (steps)
@@ -49,7 +49,7 @@ ui/tests/
- Tags or priorities changed
- [ ] Test IDs synchronized between `.md` and `.spec.ts`
### Quick validation:
### Quick validation
```bash
# Verify .md exists for each test folder
ls ui/tests/{feature}/{feature}.md
@@ -59,7 +59,8 @@ grep -o "@[A-Z]*-E2E-[0-9]*" ui/tests/{feature}/{feature}.spec.ts | sort -u
grep -o "\`[A-Z]*-E2E-[0-9]*\`" ui/tests/{feature}/{feature}.md | sort -u
```
**❌ An E2E change is NOT considered complete without updating the corresponding .md file**
> [!IMPORTANT]
> ❌ An E2E change is NOT considered complete without updating the corresponding `.md` file.
---
+5 -5
View File
@@ -27,7 +27,7 @@ allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task
## Tech Stack (Versions)
```
```text
Next.js 16.2.3 | React 19.2.5 | Tailwind 4.1.18 | shadcn/ui
Zod 4.1.11 | React Hook Form 7.62.0 | Zustand 5.0.8
NextAuth 5.0.0-beta.30 | Recharts 2.15.4
@@ -43,7 +43,7 @@ HeroUI 2.8.4 (LEGACY - do not add new components)
### Component Placement
```
```text
New feature UI? → shadcn/ui + Tailwind
Existing HeroUI feature? → Keep HeroUI (don't mix)
Used 1 feature? → features/{feature}/components/
@@ -54,7 +54,7 @@ Server component? → No directive needed
### Code Location
```
```text
Server action → actions/{feature}/{feature}.ts
Data transform → actions/{feature}/{feature}.adapter.ts
Types (shared 2+) → types/{domain}.ts
@@ -69,7 +69,7 @@ HeroUI components → components/ui/ (LEGACY)
### Styling Decision
```
```text
Tailwind class exists? → className
Dynamic value? → style prop
Conditional styles? → cn()
@@ -85,7 +85,7 @@ Recharts/library? → CHART_COLORS constant + var()
## Project Structure
```
```text
ui/
├── app/
│ ├── (auth)/ # Auth pages (login, signup)
+5 -5
View File
@@ -29,7 +29,7 @@ Create a skill when:
## Skill Structure
```
```text
skills/{skill-name}/
├── SKILL.md # Required - main skill file
├── assets/ # Optional - templates, schemas, examples
@@ -43,7 +43,7 @@ skills/{skill-name}/
## SKILL.md Template
```markdown
````markdown
---
name: {skill-name}
description: >
@@ -77,7 +77,7 @@ metadata:
- **Templates**: See [assets/](assets/) for {description}
- **Documentation**: See [references/](references/) for local docs
```
````
---
@@ -94,7 +94,7 @@ metadata:
## Decision: assets/ vs references/
```
```text
Need code templates? → assets/
Need JSON schemas? → assets/
Need example configs? → assets/
@@ -108,7 +108,7 @@ Link to external guides? → references/ (with local path)
## Decision: Prowler-Specific vs Generic
```
```text
Patterns apply to ANY project? → Generic skill (e.g., pytest, typescript)
Patterns are Prowler-specific? → prowler-{name} skill
Generic skill needs Prowler info? → Add references/ pointing to Prowler docs
@@ -38,7 +38,7 @@ Use this skill when:
## Decision Tree
```
```text
{Question 1}? → {Action A}
{Question 2}? → {Action B}
Otherwise → {Default action}
+1 -1
View File
@@ -14,7 +14,7 @@ allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task
## Styling Decision Tree
```
```text
Tailwind class exists? → className="..."
Dynamic value? → style={{ width: `${x}%` }}
Conditional styles? → cn("base", condition && "variant")
+12 -12
View File
@@ -20,7 +20,7 @@ allowed-tools: Read, Edit, Write, Glob, Grep, Bash, Task
## TDD Cycle (MANDATORY)
```
```text
+-----------------------------------------+
| RED -> GREEN -> REFACTOR |
| ^ | |
@@ -28,7 +28,7 @@ allowed-tools: Read, Edit, Write, Glob, Grep, Bash, Task
+-----------------------------------------+
```
**The question is NOT "should I write tests?" but "what tests do I need?"**
The question is NOT "should I write tests?" but "what tests do I need?"
---
@@ -94,7 +94,7 @@ uv run pytest api/src/backend/api/tests/test_models.py -v
### Decision Tree (All Stacks)
```
```text
+------------------------------------------+
| Does test file exist for this code? |
+----------+-----------------------+-------+
@@ -122,7 +122,7 @@ uv run pytest api/src/backend/api/tests/test_models.py -v
### For NEW Functionality
**UI (Vitest)**
#### UI (Vitest)
```typescript
describe("PriceCalculator", () => {
@@ -139,7 +139,7 @@ describe("PriceCalculator", () => {
});
```
**SDK (pytest)**
#### SDK (pytest)
```python
class Test_ec2_ami_public:
@@ -159,7 +159,7 @@ class Test_ec2_ami_public:
assert len(result) == 0
```
**API (pytest-django)**
#### API (pytest-django)
```python
@pytest.mark.django_db
@@ -192,18 +192,18 @@ Write a test that **reproduces the bug** first:
**API:** `assert response.status_code == 403 # Currently returns 200`
**Run -> Should FAIL (reproducing the bug)**
Run -> Should FAIL (reproducing the bug).
### For REFACTORING
Capture ALL current behavior BEFORE refactoring:
```
```text
# Any stack: run ALL existing tests, they should PASS
# This is your safety net - if any fail after refactoring, you broke something
```
**Run -> All should PASS (baseline)**
Run -> All should PASS (baseline).
---
@@ -288,13 +288,13 @@ Tests GREEN -> Improve code quality WITHOUT changing behavior.
- Add types/validation
- Reduce duplication
**Run tests after EACH change -> Must stay GREEN**
Run tests after EACH change -> Must stay GREEN.
---
## Quick Reference
```
```text
+------------------------------------------------+
| TDD WORKFLOW |
+------------------------------------------------+
@@ -320,7 +320,7 @@ Tests GREEN -> Improve code quality WITHOUT changing behavior.
## Anti-Patterns (NEVER DO)
```
```python
# ANY language:
# 1. Code first, tests after
+1 -1
View File
@@ -181,7 +181,7 @@ expect(screen.getByRole("button")).toBeDisabled();
## File Organization
```
```text
components/
├── Button/
│ ├── Button.tsx
+4 -4
View File
@@ -15,7 +15,7 @@
> - [`vitest`](../skills/vitest/SKILL.md) - Unit testing with React Testing Library
> - [`tdd`](../skills/tdd/SKILL.md) - TDD workflow (MANDATORY for UI tasks)
### Auto-invoke Skills
## Auto-invoke Skills
When performing these actions, ALWAYS invoke the corresponding skill FIRST:
@@ -89,7 +89,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST:
### Component Placement
```
```text
New/Existing UI? → shadcn/ui + Tailwind (NEVER HeroUI for new code)
Used 1 feature? → features/{feature}/components | Used 2+? → components/{domain}/
Needs state/hooks? → "use client" | Server component? → No directive
@@ -97,7 +97,7 @@ Needs state/hooks? → "use client" | Server component? → No directive
### Code Location
```
```text
Server action → actions/{feature}/{feature}.ts
Data transform → actions/{feature}/{feature}.adapter.ts
Types (shared 2+) → types/{domain}.ts | Types (local 1) → {feature}/types.ts
@@ -193,7 +193,7 @@ Zod 4.1.11 | React Hook Form 7.62.0 | Zustand 5.0.8 | NextAuth 5.0.0-beta.30 | R
## PROJECT STRUCTURE
```
```text
ui/
├── app/(auth)/ # Auth pages
├── app/(prowler)/ # Main app: compliance, findings, providers, scans
+1 -1
View File
@@ -6,7 +6,7 @@ This directory contains all shadcn/ui based components for the Prowler applicati
Example of a custom component:
```
```text
shadcn/
├── card/
│ ├── base-card/
+18 -18
View File
@@ -21,7 +21,7 @@
- Application is running.
- No active session (cookies cleared).
### Flow Steps:
### Flow Steps
1. Clear all cookies.
2. Navigate to /sign-in.
@@ -29,7 +29,7 @@
4. Navigate to /sign-up.
5. Verify page loads.
### Expected Result:
### Expected Result
- Public routes are accessible without authentication.
@@ -50,7 +50,7 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Log in with valid credentials.
2. Navigate to a protected route.
@@ -58,7 +58,7 @@
4. Navigate to another protected route.
5. Verify redirect to sign-in.
### Expected Result:
### Expected Result
- Invalid session results in redirect to sign-in.
@@ -79,13 +79,13 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to /sign-in with error=RefreshAccessTokenError query parameter.
2. Check for toast notification.
3. Verify form elements are still visible.
### Expected Result:
### Expected Result
- Toast shows "Session Expired" message with "Please sign in again".
- Sign-in form is displayed and functional.
@@ -107,13 +107,13 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to /sign-in with error=MissingRefreshToken query parameter.
2. Check for toast notification.
3. Verify email input is visible.
### Expected Result:
### Expected Result
- Toast shows "Session Error" message.
- Sign-in form is displayed.
@@ -135,12 +135,12 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to /sign-in with error=UnknownError query parameter.
2. Check for toast notification.
### Expected Result:
### Expected Result
- Toast shows "Authentication Error" message with "Please sign in again".
@@ -162,7 +162,7 @@
- Application is running.
- Valid test user credentials.
### Flow Steps:
### Flow Steps
1. Log in with valid credentials.
2. Navigate to a protected route (/scans).
@@ -171,7 +171,7 @@
5. Navigate to another protected route (/providers) using fresh navigation.
6. Verify redirect to sign-in includes callbackUrl parameter.
### Expected Result:
### Expected Result
- URL contains callbackUrl=/providers parameter.
- User can sign in and be redirected back to the original destination.
@@ -194,7 +194,7 @@
- Application is running.
- Valid test user credentials.
### Flow Steps:
### Flow Steps
1. Log in with valid credentials.
2. Verify home page is loaded.
@@ -202,7 +202,7 @@
4. Reload the page.
5. Verify session is still valid with same user data.
### Expected Result:
### Expected Result
- Session persists after reload.
- User email, userId, and tenantId remain the same.
@@ -225,14 +225,14 @@
- Application is running.
- Valid test user credentials.
### Flow Steps:
### Flow Steps
1. Log in with valid credentials.
2. Capture initial session with permissions.
3. Reload the page.
4. Verify permissions match initial session.
### Expected Result:
### Expected Result
- User permissions are identical before and after refresh.
- User profile data (email, name, companyName) is preserved.
@@ -255,14 +255,14 @@
- Application is running.
- Valid test user credentials.
### Flow Steps:
### Flow Steps
1. Log in with valid credentials.
2. Verify session is valid.
3. Clear all cookies.
4. Check session status.
### Expected Result:
### Expected Result
- Session returns null after cookies are cleared.
- User is effectively logged out.
+10 -10
View File
@@ -24,7 +24,7 @@ redirects to `/sign-in` with a `callbackUrl` that preserves the invitation token
- Application is running.
- No active session (cookies cleared).
### Flow Steps:
### Flow Steps
1. Clear all cookies.
2. Navigate to `/invitation/accept?invitation_token=test-token`.
@@ -32,7 +32,7 @@ redirects to `/sign-in` with a `callbackUrl` that preserves the invitation token
4. Click the "I have an account — Sign in" button.
5. Verify the redirect target and `callbackUrl` query param.
### Expected Result:
### Expected Result
- Heading "You've Been Invited" is visible.
- Description text "invited to join a tenant" is visible.
@@ -41,7 +41,7 @@ redirects to `/sign-in` with a `callbackUrl` that preserves the invitation token
- Decoded `callbackUrl` equals `/invitation/accept?invitation_token=test-token`.
- Decoded `callbackUrl` contains `invitation_token=test-token`.
### Key verification points:
### Key verification points
- `callbackUrl` preserves the original invitation path with token.
@@ -65,7 +65,7 @@ form actually renders (no redirect loop back to `/invitation/accept`).
- Application is running.
- No active session (cookies cleared).
### Flow Steps:
### Flow Steps
1. Clear all cookies.
2. Navigate to `/invitation/accept?invitation_token=test-token`.
@@ -73,17 +73,17 @@ form actually renders (no redirect loop back to `/invitation/accept`).
4. Click the button.
5. Verify the resulting URL and that the sign-up form is rendered.
### Expected Result:
### Expected Result
- URL pathname is `/sign-up`.
- Query param `invitation_token` equals `test-token`.
- Sign-up form is rendered (email input and submit button visible).
### Key verification points:
### Key verification points
- No redirect back to `/invitation/accept` (smart router does not loop).
### Notes:
### Notes
- The legacy `action=signup` param is no longer emitted: the backward-compat
redirect from `/sign-up?invitation_token=...` to `/invitation/accept` was
@@ -111,7 +111,7 @@ that the "Go to Sign In" link redirects to `/sign-in`.
- Application is running.
- No active session (cookies cleared).
### Flow Steps:
### Flow Steps
1. Clear all cookies.
2. Navigate to `/invitation/accept` (no query params).
@@ -119,13 +119,13 @@ that the "Go to Sign In" link redirects to `/sign-in`.
4. Click the "Go to Sign In" link.
5. Verify redirect to `/sign-in`.
### Expected Result:
### Expected Result
- Heading "Invalid Invitation Link" is visible.
- Description "No invitation token was provided" is visible.
- "Go to Sign In" link is visible and clickable.
- After click, URL matches `/sign-in`.
### Key verification points:
### Key verification points
- Client-side render only: no API calls involved.
+4 -4
View File
@@ -25,7 +25,7 @@
- `E2E_ORGANIZATION_ID` (expected organization for membership verification)
- Application running with accessible UI/API endpoints
### Flow Steps:
### Flow Steps
1. Navigate to invitations page
2. Click "Send Invitation" button
@@ -40,7 +40,7 @@
11. Verify successful login
12. Navigate to user profile and verify `organizationId` matches `E2E_ORGANIZATION_ID`
### Expected Result:
### Expected Result
- Invitation is created and a valid share URL is provided
- Invited user can sign up successfully using the invitation link
@@ -48,7 +48,7 @@
- Login succeeds with the new credentials
- User profile shows membership in the expected organization
### Key verification points:
### Key verification points
- Invitations page loads and displays the heading
- Send Invitation form is visible (email + role select)
@@ -58,7 +58,7 @@
- Login with the new account succeeds
- Profile page shows the expected organization id
### Notes:
### Notes
- Test uses a fresh browser context for the invitee to avoid admin session leakage
- Email should be unique per run (the test uses a random suffix)
+68 -68
View File
@@ -24,7 +24,7 @@
- Remove any existing provider with the same Account ID before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Account ID not to be already registered beforehand.
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -36,14 +36,14 @@
8. Verify redirect to Scans page
9. Verify scheduled scan status in Scans table (provider exists and scan name is "scheduled scan")
### Expected Result:
### Expected Result
- AWS provider successfully added with static credentials
- Initial scan launched successfully
- User redirected to Scans page
- Scheduled scan appears in Scans table with correct provider and scan name
### Key verification points:
### Key verification points
- Provider page loads correctly
- Connect account page displays AWS option
@@ -53,7 +53,7 @@
- Provider exists in Scans table (verified by account ID)
- Scan name field contains "scheduled scan"
### Notes:
### Notes
- Test uses environment variables for AWS credentials
- Provider cleanup performed before each test to ensure clean state
@@ -80,7 +80,7 @@
- Remove any existing provider with the same Account ID before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Account ID not to be already registered beforehand.
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -92,14 +92,14 @@
8. Verify redirect to Scans page
9. Verify scheduled scan status in Scans table (provider exists and scan name is "scheduled scan")
### Expected Result:
### Expected Result
- AWS provider successfully added with role credentials
- Initial scan launched successfully
- User redirected to Scans page
- Scheduled scan appears in Scans table with correct provider and scan name
### Key verification points:
### Key verification points
- Provider page loads correctly
- Connect account page displays AWS option
@@ -109,7 +109,7 @@
- Provider exists in Scans table (verified by account ID)
- Scan name field contains "scheduled scan"
### Notes:
### Notes
- Test uses environment variables for AWS credentials and role ARN
- Provider cleanup performed before each test to ensure clean state
@@ -137,7 +137,7 @@
- Remove any existing provider with the same Subscription ID before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Subscription ID not to be already registered beforehand.
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -148,14 +148,14 @@
7. Verify redirect to Scans page
8. Verify scheduled scan status in Scans table (provider exists and scan name is "scheduled scan")
### Expected Result:
### Expected Result
- Azure provider successfully added with static credentials
- Initial scan launched successfully
- User redirected to Scans page
- Scheduled scan appears in Scans table with correct provider and scan name
### Key verification points:
### Key verification points
- Provider page loads correctly
- Connect account page displays Azure option
@@ -165,7 +165,7 @@
- Provider exists in Scans table (verified by subscription ID)
- Scan name field contains "scheduled scan"
### Notes:
### Notes
- Test uses environment variables for Azure credentials
- Provider cleanup performed before each test to ensure clean state
@@ -193,7 +193,7 @@
- Remove any existing provider with the same Domain ID before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Domain ID not to be already registered beforehand.
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -205,14 +205,14 @@
8. Verify redirect to Scans page
9. Verify scheduled scan status in Scans table (provider exists and scan name is "scheduled scan")
### Expected Result:
### Expected Result
- M365 provider successfully added with static credentials
- Initial scan launched successfully
- User redirected to Scans page
- Scheduled scan appears in Scans table with correct provider and scan name
### Key verification points:
### Key verification points
- Provider page loads correctly
- Connect account page displays M365 option
@@ -222,7 +222,7 @@
- Provider exists in Scans table (verified by domain ID)
- Scan name field contains "scheduled scan"
### Notes:
### Notes
- Test uses environment variables for M365 credentials
- Provider cleanup performed before each test to ensure clean state
@@ -250,7 +250,7 @@
- Remove any existing provider with the same Domain ID before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Domain ID not to be already registered beforehand.
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -262,14 +262,14 @@
8. Verify redirect to Scans page
9. Verify scheduled scan status in Scans table (provider exists and scan name is "scheduled scan")
### Expected Result:
### Expected Result
- M365 provider successfully added with certificate credentials
- Initial scan launched successfully
- User redirected to Scans page
- Scheduled scan appears in Scans table with correct provider and scan name
### Key verification points:
### Key verification points
- Provider page loads correctly
- Connect account page displays M365 option
@@ -279,7 +279,7 @@
- Provider exists in Scans table (verified by domain ID)
- Scan name field contains "scheduled scan"
### Notes:
### Notes
- Test uses environment variables for M365 certificate credentials
- Provider cleanup performed before each test to ensure clean state
@@ -308,7 +308,7 @@
- Remove any existing provider with the same Context before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Context not to be already registered beforehand.
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -320,14 +320,14 @@
8. Verify redirect to Scans page
9. Verify scheduled scan status in Scans table (provider exists and scan name is "scheduled scan")
### Expected Result:
### Expected Result
- Kubernetes provider successfully added with kubeconfig content
- Initial scan launched successfully
- User redirected to Scans page
- Scheduled scan appears in Scans table with correct provider and scan name
### Key verification points:
### Key verification points
- Provider page loads correctly
- Connect account page displays Kubernetes option
@@ -339,7 +339,7 @@
- Provider exists in Scans table (verified by context)
- Scan name field contains "scheduled scan"
### Notes:
### Notes
- Test uses environment variables for Kubernetes context and kubeconfig file path
- Kubeconfig content is read from file and used for authentication
@@ -369,7 +369,7 @@
- Remove any existing provider with the same Project ID before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Project ID not to be already registered beforehand.
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -381,14 +381,14 @@
8. Verify redirect to Scans page
9. Verify scheduled scan status in Scans table (provider exists and scan name is "scheduled scan")
### Expected Result:
### Expected Result
- GCP provider successfully added with service account key
- Initial scan launched successfully
- User redirected to Scans page
- Scheduled scan appears in Scans table with correct provider and scan name
### Key verification points:
### Key verification points
- Provider page loads correctly
- Connect account page displays GCP option
@@ -400,7 +400,7 @@
- Provider exists in Scans table (verified by project ID)
- Scan name field contains "scheduled scan"
### Notes:
### Notes
- Test uses environment variables for GCP project ID and service account key
- Service account key is provided as base64 encoded JSON content
@@ -431,7 +431,7 @@
- Remove any existing provider with the same Username before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Username not to be already registered beforehand.
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -443,14 +443,14 @@
8. Verify redirect to Scans page
9. Verify scheduled scan status in Scans table (provider exists and scan name is "scheduled scan")
### Expected Result:
### Expected Result
- GitHub provider successfully added with personal access token
- Initial scan launched successfully
- User redirected to Scans page
- Scheduled scan appears in Scans table with correct provider and scan name
### Key verification points:
### Key verification points
- Provider page loads correctly
- Connect account page displays GitHub option
@@ -462,7 +462,7 @@
- Provider exists in Scans table (verified by username)
- Scan name field contains "scheduled scan"
### Notes:
### Notes
- Test uses environment variables for GitHub username and personal access token
- Provider cleanup performed before each test to ensure clean state
@@ -491,7 +491,7 @@
- Remove any existing provider with the same Username before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Username not to be already registered beforehand.
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -503,14 +503,14 @@
8. Verify redirect to Scans page
9. Verify scheduled scan status in Scans table (provider exists and scan name is "scheduled scan")
### Expected Result:
### Expected Result
- GitHub provider successfully added with GitHub App credentials
- Initial scan launched successfully
- User redirected to Scans page
- Scheduled scan appears in Scans table with correct provider and scan name
### Key verification points:
### Key verification points
- Provider page loads correctly
- Connect account page displays GitHub option
@@ -522,7 +522,7 @@
- Provider exists in Scans table (verified by username)
- Scan name field contains "scheduled scan"
### Notes:
### Notes
- Test uses environment variables for GitHub username, App ID, and base64 encoded private key
- Private key is base64 encoded and must be decoded before use
@@ -552,7 +552,7 @@
- Remove any existing provider with the same Organization name before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Organization name not to be already registered beforehand.
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -564,14 +564,14 @@
8. Verify redirect to Scans page
9. Verify scheduled scan status in Scans table (provider exists and scan name is "scheduled scan")
### Expected Result:
### Expected Result
- GitHub provider successfully added with organization personal access token
- Initial scan launched successfully
- User redirected to Scans page
- Scheduled scan appears in Scans table with correct provider and scan name
### Key verification points:
### Key verification points
- Provider page loads correctly
- Connect account page displays GitHub option
@@ -583,7 +583,7 @@
- Provider exists in Scans table (verified by organization name)
- Scan name field contains "scheduled scan"
### Notes:
### Notes
- Test uses environment variables for GitHub organization name and organization access token
- Provider cleanup performed before each test to ensure clean state
@@ -612,7 +612,7 @@
- Remove any existing provider with the same Account ID before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Account ID not to be already registered beforehand
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -625,14 +625,14 @@
9. Verify redirect to Scans page
10. Verify scheduled scan status in Scans table (provider exists and scan name is "scheduled scan")
### Expected Result:
### Expected Result
- AWS provider successfully added using AWS SDK default credentials to assume the role
- Initial scan launched successfully
- User redirected to Scans page
- Scheduled scan appears in Scans table with correct provider and scan name
### Key verification points:
### Key verification points
- Provider page loads correctly
- Connect account page displays AWS option
@@ -643,7 +643,7 @@
- Provider exists in Scans table (verified by account ID)
- Scan name field contains "scheduled scan"
### Notes:
### Notes
- Test leverages AWS SDK default credential chain (environment-configured keys) for Access Key and Secret Key
- Environment variable `E2E_AWS_PROVIDER_ROLE_ARN` must reference a valid assumable role
@@ -671,7 +671,7 @@
- Remove any existing provider with the same Tenancy ID before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Tenancy ID not to be already registered beforehand.
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -683,14 +683,14 @@
8. Verify redirect to Scans page
9. Verify scheduled scan status in Scans table (provider exists and scan name is "scheduled scan")
### Expected Result:
### Expected Result
- OCI provider successfully added with API Key credentials
- Initial scan launched successfully
- User redirected to Scans page
- Scheduled scan appears in Scans table with correct provider and scan name
### Key verification points:
### Key verification points
- Provider page loads correctly
- Connect account page displays OCI option
@@ -702,7 +702,7 @@
- Provider exists in Scans table (verified by tenancy ID)
- Scan name field contains "scheduled scan"
### Notes:
### Notes
- Test uses environment variables for OCI credentials
- Provider cleanup performed before each test to ensure clean state
@@ -730,7 +730,7 @@
- An OCI provider with the specified Tenancy ID must already exist (run PROVIDER-E2E-012 first)
- This test must be run serially and never in parallel with other tests
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Verify OCI provider exists in the table
@@ -742,7 +742,7 @@
8. Click Next to submit
9. Verify successful navigation to test connection page
### Expected Result:
### Expected Result
- Update credentials page loads successfully
- OCI credentials form is displayed with all required fields
@@ -750,7 +750,7 @@
- Credentials can be updated and submitted
- User is redirected to test connection page after successful update
### Key verification points:
### Key verification points
- Provider page loads correctly
- OCI provider row is visible in providers table
@@ -760,7 +760,7 @@
- Form submission succeeds (no silent failures due to missing provider UID)
- Successful redirect to test connection page
### Notes:
### Notes
- Test uses same environment variables as PROVIDER-E2E-012 (add OCI provider)
- Requires PROVIDER-E2E-012 to be run first to create the OCI provider
@@ -788,7 +788,7 @@
- Remove any existing provider with the same Account ID before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Account ID not to be already registered beforehand.
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -802,14 +802,14 @@
10. Verify redirect to Scans page
11. Verify scheduled scan status in Scans table (provider exists and scan name is "scheduled scan")
### Expected Result:
### Expected Result
- AlibabaCloud provider successfully added with static credentials
- Initial scan launched successfully
- User redirected to Scans page
- Scheduled scan appears in Scans table with correct provider and scan name
### Key verification points:
### Key verification points
- Provider page loads correctly
- Connect account page displays AlibabaCloud option
@@ -822,7 +822,7 @@
- Provider exists in Scans table (verified by account ID)
- Scan name field contains "scheduled scan"
### Notes:
### Notes
- Test uses environment variables for AlibabaCloud credentials
- Provider cleanup performed before each test to ensure clean state
@@ -850,7 +850,7 @@
- Remove any existing provider with the same Account ID before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Account ID not to be already registered beforehand.
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -864,14 +864,14 @@
10. Verify redirect to Scans page
11. Verify scheduled scan status in Scans table (provider exists and scan name is "scheduled scan")
### Expected Result:
### Expected Result
- AlibabaCloud provider successfully added with RAM Role credentials
- Initial scan launched successfully
- User redirected to Scans page
- Scheduled scan appears in Scans table with correct provider and scan name
### Key verification points:
### Key verification points
- Provider page loads correctly
- Connect account page displays AlibabaCloud option
@@ -884,7 +884,7 @@
- Provider exists in Scans table (verified by account ID)
- Scan name field contains "scheduled scan"
### Notes:
### Notes
- Test uses environment variables for AlibabaCloud RAM Role credentials
- Provider cleanup performed before each test to ensure clean state
@@ -914,7 +914,7 @@
- StackSet must be deployed in AWS Organizations and expose a valid IAM Role ARN for Prowler
- This test must be run serially and never in parallel with other tests, as it requires the Organization ID not to be already registered beforehand.
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -927,14 +927,14 @@
9. Verify organization launch step, choose single scan schedule, and launch
10. Verify redirect to Scans page
### Expected Result:
### Expected Result
- AWS Organizations flow completes successfully
- Accounts are connected and launch step is displayed
- Scan scheduling selection is applied
- User is redirected to Scans page after launch
### Key verification points:
### Key verification points
- Connect account page displays AWS option
- Organizations method selector is available
@@ -943,7 +943,7 @@
- Accounts connected launch step appears
- Successful redirect to Scans page after launching
### Notes:
### Notes
- Organization ID must follow AWS format (e.g., o-abc123def4)
- Role ARN must belong to the StackSet deployment for Organizations flow
@@ -970,7 +970,7 @@
- Remove any existing provider with the same Customer ID before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Customer ID not to be already registered beforehand.
### Flow Steps:
### Flow Steps
1. Navigate to providers page
2. Click "Add Provider" button
@@ -982,14 +982,14 @@
8. Verify redirect to Scans page
9. Verify scheduled scan status in Scans table (provider exists and scan name is "scheduled scan")
### Expected Result:
### Expected Result
- Google Workspace provider successfully added with Service Account credentials
- Initial scan launched successfully
- User redirected to Scans page
- Scheduled scan appears in Scans table with correct provider and scan name
### Key verification points:
### Key verification points
- Provider page loads correctly
- Connect account page displays Google Workspace option
@@ -1003,7 +1003,7 @@
- Provider exists in Scans table (verified by customer ID)
- Scan name field contains "scheduled scan"
### Notes:
### Notes
- Test uses environment variables for Google Workspace credentials
- Service Account JSON is provided as multi-line JSON string (not base64 encoded)
+4 -4
View File
@@ -23,7 +23,7 @@
- Remove any existing AWS provider with the same Account ID before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Account ID Provider to be already registered.
### Flow Steps:
### Flow Steps
1. Navigate to Scans page
2. Open provider selector and choose the entry whose text contains E2E_AWS_PROVIDER_ACCOUNT_ID
@@ -32,13 +32,13 @@
5. Verify the success toast appears
6. Verify a row in the Scans table contains the provided scan label (or shows the new scan entry)
### Expected Result:
### Expected Result
- Scan is launched successfully
- Success toast is displayed to the user
- Scans table displays the new scan entry (including the alias when provided)
### Key verification points:
### Key verification points
- Scans page loads correctly
- Provider select is available and lists the configured provider UID
@@ -46,7 +46,7 @@
- Success toast message: "The scan was launched successfully."
- Table contains a row with the scan label or new scan state (queued/available/executing)
### Notes:
### Notes
- The table may take a short time to reflect the new scan; assertions look for a row containing the alias.
- Provider cleanup performed before each test to ensure clean state
+36 -36
View File
@@ -20,7 +20,7 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to the Sign in page.
2. Verify page is loaded.
@@ -28,7 +28,7 @@
4. Verify social buttons (Google, GitHub).
5. Verify navigation links.
### Expected Result:
### Expected Result
- All form elements are visible and properly labeled.
@@ -50,14 +50,14 @@
- Application is running.
- Valid test user credentials are configured via `ADMIN_USER` and `ADMIN_PASSWORD` environment variables.
### Flow Steps:
### Flow Steps
1. Navigate to the Sign in page.
2. Enter valid email and password.
3. Click the login button.
4. Verify successful redirect to home page.
### Expected Result:
### Expected Result
- User is authenticated and redirected to the home page.
@@ -78,14 +78,14 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to the Sign in page.
2. Enter invalid email and password.
3. Click the login button.
4. Verify error message is displayed.
### Expected Result:
### Expected Result
- Error message "Invalid email or password" is displayed.
- User remains on the sign-in page.
@@ -107,13 +107,13 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to the Sign in page.
2. Click the login button without filling any fields.
3. Verify validation errors are displayed.
### Expected Result:
### Expected Result
- Form validation errors are shown.
- User remains on the sign-in page.
@@ -135,14 +135,14 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to the Sign in page.
2. Enter an invalid email format.
3. Submit the form.
4. Verify validation error is displayed.
### Expected Result:
### Expected Result
- Email format validation error is shown.
@@ -163,14 +163,14 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to the Sign in page.
2. Fill only the email field.
3. Submit the form.
4. Verify password required error is displayed.
### Expected Result:
### Expected Result
- "Password is required" error is shown.
@@ -191,7 +191,7 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to the Sign in page.
2. Click "Continue with SAML SSO" button.
@@ -199,7 +199,7 @@
4. Click back button.
5. Verify normal mode is restored.
### Expected Result:
### Expected Result
- SAML mode toggles correctly.
- Password field visibility changes accordingly.
@@ -221,14 +221,14 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to the Sign in page.
2. Fill valid credentials.
3. Submit the form.
4. Verify loading state on button.
### Expected Result:
### Expected Result
- Login button shows loading state (disabled with aria-disabled).
@@ -249,14 +249,14 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to the Sign in page.
2. Toggle SAML mode.
3. Enter SAML email.
4. Submit the form.
### Expected Result:
### Expected Result
- SAML flow is initiated (would redirect to IdP in real scenario).
@@ -278,14 +278,14 @@
- Application is running.
- Valid test user credentials.
### Flow Steps:
### Flow Steps
1. Log in with valid credentials.
2. Verify successful login.
3. Refresh the page.
4. Verify user is still logged in.
### Expected Result:
### Expected Result
- Session persists after refresh.
- User remains on the authenticated page.
@@ -308,12 +308,12 @@
- Application is running.
- No active session.
### Flow Steps:
### Flow Steps
1. Navigate directly to a protected route (e.g., /providers).
2. Verify redirect to sign-in page.
### Expected Result:
### Expected Result
- User is redirected to /sign-in.
@@ -335,7 +335,7 @@
- Application is running.
- User is logged in.
### Flow Steps:
### Flow Steps
1. Log in with valid credentials.
2. Click logout/sign out.
@@ -343,7 +343,7 @@
4. Attempt to access protected route.
5. Verify redirect to sign-in.
### Expected Result:
### Expected Result
- User is logged out.
- Session is invalidated.
@@ -366,7 +366,7 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Create authenticated context and log in.
2. Verify session exists.
@@ -374,7 +374,7 @@
4. Verify new context has no session.
5. Verify new context is redirected to sign-in.
### Expected Result:
### Expected Result
- Sessions are isolated between contexts.
- Unauthenticated context cannot access protected routes.
@@ -396,13 +396,13 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to the Sign in page.
2. Click the "Sign up" link.
3. Verify redirect to sign-up page.
### Expected Result:
### Expected Result
- User is navigated to /sign-up.
@@ -423,13 +423,13 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to the Sign up page.
2. Click the login link.
3. Verify redirect to sign-in page.
### Expected Result:
### Expected Result
- User is navigated to /sign-in.
@@ -450,14 +450,14 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to the Sign in page.
2. Navigate to the Sign up page.
3. Click browser back button.
4. Verify return to sign-in page.
### Expected Result:
### Expected Result
- Browser history navigation works correctly.
@@ -478,13 +478,13 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to the Sign in page.
2. Use Tab key to navigate through form elements.
3. Verify focus moves correctly through elements.
### Expected Result:
### Expected Result
- All interactive elements are reachable via keyboard.
- Focus order is logical.
@@ -506,12 +506,12 @@
- Application is running.
### Flow Steps:
### Flow Steps
1. Navigate to the Sign in page.
2. Verify ARIA labels on form elements.
### Expected Result:
### Expected Result
- Email input has proper label.
- Password input has proper label.
+4 -4
View File
@@ -22,7 +22,7 @@
- No existing data in Prowler is required; the test can run on a clean state.
- `E2E_NEW_USER_PASSWORD` environment variable must be set with a valid password for the test.
### Flow Steps:
### Flow Steps
1. Navigate to the Sign up page.
2. Fill the form with valid data (unique email, valid password, terms accepted).
@@ -30,18 +30,18 @@
4. Verify redirect to the Login page.
5. Log in with the newly created credentials.
### Expected Result:
### Expected Result
- Sign-up succeeds and redirects to Login.
- User can log in successfully using the created credentials and reach the home page.
### Key verification points:
### Key verification points
- After submitting sign-up, the URL changes to `/sign-in`.
- The newly created credentials can be used to sign in successfully.
- After login, the user lands on the home (`/`) and main content is visible.
### Notes:
### Notes
- Test data uses a random base36 suffix to avoid collisions with email.
- The test requires the `E2E_NEW_USER_PASSWORD` environment variable to be set before running.
+5 -5
View File
@@ -429,7 +429,7 @@ This is useful for:
### Example Output
```
```text
[1] ✅ Created provider (id=db9a8985-f9ec-4dd8-b5a0-e05ab3880bed)
[1] ✅ Created secret (id=466f76c6-5878-4602-a4bc-13f9522c1fd2)
[1] ✅ Connection test: Connected
@@ -454,25 +454,25 @@ python prowler_bulk_provisioning.py providers.yaml --dry-run
### Common Issues
1. **Invalid API Key**
```
```text
Error: 401 Unauthorized
Solution: Check your PROWLER_API_KEY environment variable or --api-key parameter
```
2. **Network Timeouts**
```
```text
Error: Request timeout
Solution: Increase --timeout value or check network connectivity
```
3. **Invalid Provider Configuration**
```
```text
Error: Each item must include 'provider' and 'uid'
Solution: Verify all required fields are present in your config file
```
4. **File Not Found Errors**
```
```text
Error: No such file or directory
Solution: Check file paths for credentials files (JSON keys, kubeconfig, etc.)
```