# Priority tiers (lower = runs first, same priority = concurrent): # P0 — fast file fixers # P10 — validators and guards # P20 — auto-formatters # P30 — linters # P40 — security scanners # P50 — dependency validation default_install_hook_types: [pre-commit] # Hooks run on commit only by default; # NOTE: default_stages does NOT override a hook's manifest stages, so fixers shipping pre-push in their # manifest need an explicit stages: ["pre-commit"] below to stay off push. default_stages: [pre-commit] repos: ## GENERAL (prek built-in — no external repo needed) - repo: builtin hooks: - id: check-merge-conflict priority: 10 - id: check-yaml args: ["--allow-multiple-documents"] exclude: (prowler/config/llm_config.yaml|contrib/) priority: 10 - id: check-json priority: 10 - id: end-of-file-fixer stages: ["pre-commit"] priority: 0 - id: trailing-whitespace stages: ["pre-commit"] priority: 0 - id: no-commit-to-branch priority: 10 - id: pretty-format-json args: ["--autofix", --no-sort-keys, --no-ensure-ascii] stages: ["pre-commit"] priority: 10 ## TOML - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks rev: v2.16.0 hooks: - id: pretty-format-toml args: [--autofix] files: pyproject.toml priority: 20 ## GITHUB ACTIONS - repo: https://github.com/zizmorcore/zizmor-pre-commit rev: v1.24.1 hooks: - id: zizmor # zizmor only audits workflows, composite actions and dependabot # config; broader paths trip exit 3 ("no audit was performed"). files: ^\.github/(workflows|actions)/.+\.ya?ml$|^\.github/dependabot\.ya?ml$ priority: 30 ## RENOVATE - repo: https://github.com/renovatebot/pre-commit-hooks rev: 43.150.0 hooks: - id: renovate-config-validator files: ^\.github/renovate\.json$ priority: 10 ## BASH - repo: https://github.com/koalaman/shellcheck-precommit rev: v0.11.0 hooks: - id: shellcheck exclude: contrib priority: 30 ## PYTHON — SDK (prowler/, tests/, dashboard/, util/, scripts/) - repo: https://github.com/myint/autoflake rev: v2.3.3 hooks: - id: autoflake name: "SDK - autoflake" files: { glob: ["{prowler,tests,dashboard,util,scripts}/**/*.py"] } args: ["--in-place", "--remove-all-unused-imports", "--remove-unused-variable"] priority: 20 - repo: https://github.com/pycqa/isort rev: 8.0.1 hooks: - id: isort name: "SDK - isort" files: { glob: ["{prowler,tests,dashboard,util,scripts}/**/*.py"] } args: ["--profile", "black"] stages: ["pre-commit"] priority: 20 - repo: https://github.com/psf/black rev: 26.3.1 hooks: - id: black name: "SDK - black" files: { glob: ["{prowler,tests,dashboard,util,scripts}/**/*.py"] } priority: 20 - repo: https://github.com/pycqa/flake8 rev: 7.3.0 hooks: - id: flake8 name: "SDK - flake8" files: { glob: ["{prowler,tests,dashboard,util,scripts}/**/*.py"] } args: ["--ignore=E266,W503,E203,E501,W605"] priority: 30 ## PYTHON — API + MCP Server (ruff) # Run ruff through `uv run` against each project so prek uses the exact ruff # version pinned in that project's uv.lock — the same version GitHub Actions # runs via `uv run ruff`. This removes the drift between the local hooks and # CI. api/ and mcp_server/ are separate uv projects, so they need separate # hooks (each `uv run --project` resolves its own pinned ruff + config). - repo: local hooks: - id: ruff-check-api name: "API - ruff check" entry: uv run --project ./api ruff check --fix language: system files: { glob: ["api/**/*.py"] } priority: 30 - id: ruff-format-api name: "API - ruff format" entry: uv run --project ./api ruff format language: system files: { glob: ["api/**/*.py"] } priority: 20 - id: ruff-check-mcp name: "MCP - ruff check" entry: uv run --project ./mcp_server ruff check --fix language: system files: { glob: ["mcp_server/**/*.py"] } priority: 30 - id: ruff-format-mcp name: "MCP - ruff format" entry: uv run --project ./mcp_server ruff format language: system files: { glob: ["mcp_server/**/*.py"] } priority: 20 ## PYTHON — uv (API + SDK) - repo: https://github.com/astral-sh/uv-pre-commit rev: 0.11.14 hooks: - id: uv-lock name: API - uv-lock args: ["--check", "--project=./api"] files: { glob: ["api/{pyproject.toml,uv.lock}"] } pass_filenames: false priority: 50 - id: uv-lock name: SDK - uv-lock args: ["--check", "--project=./"] files: { glob: ["{pyproject.toml,uv.lock}"] } 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 hooks: - id: hadolint args: ["--ignore=DL3013"] priority: 30 ## LOCAL HOOKS - repo: local hooks: - id: pylint name: "SDK - pylint" entry: pylint --disable=W,C,R,E -j 0 -rn -sn language: system types: [python] files: { glob: ["{prowler,tests,dashboard,util,scripts}/**/*.py"] } priority: 30 - id: trufflehog name: TruffleHog description: Detect secrets in your data. entry: bash -c 'trufflehog --no-update git file://. --since-commit HEAD --only-verified --fail' # For running trufflehog in docker, use the following entry instead: # entry: bash -c 'docker run -v "$(pwd):/workdir" -i --rm trufflesecurity/trufflehog:latest git file:///workdir --only-verified --fail' language: system pass_filenames: false stages: ["pre-commit", "pre-push"] priority: 40 - id: bandit name: bandit description: "Bandit is a tool for finding common security issues in Python code" entry: bandit -q -lll language: system types: [python] files: '.*\.py' exclude: { glob: ["{contrib,skills}/**", "**/.venv/**", "**/*_test.py"] } priority: 40 - id: vulture name: vulture description: "Vulture finds unused code in Python programs." entry: vulture --min-confidence 100 language: system types: [python] files: '.*\.py' priority: 40