Security Review — dependency & static analysis orchestration
Load this skill when you need to run a security review of a codebase:
audit the dependency manifest/lockfile inventory, decide which scanner to run
per ecosystem, interpret scanner exit codes correctly (real findings vs.
infrastructure errors), and normalize reports from different tools into one
unified schema for a final report.
The helper script is offline by design — it inventories, classifies, and
normalizes. Actual scans are executed by the well-known external tools listed
below (install once locally or in CI).
The helper script
scripts/security_review.py — pure Python 3 stdlib (no dependencies).
| Command |
Purpose |
security_review.py inventory --dir . |
List dependency locks with ecosystem + suggested tool |
security_review.py inventory --dir . --json |
Same, machine-readable |
security_review.py classify --tool semgrep --exit-code 1 |
Explain what a tool exit code means |
security_review.py normalize --tool osv-scanner --input out.json |
Flatten a tool JSON report into unified findings |
security_review.py normalize --tool pip-audit --input pip.json --output report.json |
Save unified report |
security_review.py report --root . |
Report skeleton (markdown default, --json for JSON) |
Lockfile inventory (per-ecosystem suggested tool)
| Lockfile / manifest |
Ecosystem |
Suggested tool |
package-lock.json, pnpm-lock.yaml, yarn.lock |
npm / pnpm / yarn |
npm audit / osv-scanner |
requirements*.txt, pyproject.toml, Pipfile.lock, poetry.lock |
pip |
pip-audit |
Cargo.lock |
cargo |
cargo audit |
go.mod, go.sum |
go |
osv-scanner |
Gemfile.lock |
gem |
osv-scanner |
pom.xml, build.gradle(.kts) |
maven / gradle |
osv-scanner / dependency-check |
composer.lock |
composer |
osv-scanner |
package.json alone (no lockfile) is still reported, so gate or scan it with npm audit.
Exit-code semantics (verified August 2026)
Get each tool's meaning on the fly with classify --tool X --exit-code N.
| Tool |
0 |
findings |
error / other |
| semgrep |
clean |
1 (findings) |
2 fatal; 3/4/5/7/8/13/99 specific errors |
| bandit |
clean |
1 (issues) |
2 error |
| gitleaks |
clean |
1 (leaks or error) |
126 unknown flag |
| pip-audit |
clean |
1 (vulns) |
— |
| osv-scanner v2 |
clean |
1 (vulns) |
127 error, 128 no packages, 129 API failed, 130 config |
| npm audit |
clean |
1 (vulns) |
— |
| cargo audit |
clean |
non-zero (vulns / errors) |
— |
| grype |
clean |
2 (vulns ≥ fail-on) |
1 error, 100 DB update |
| truffle |
clean |
183 (findings, only with --fail) |
1 error |
| checkov |
clean |
1 (failed checks) |
2 error |
| trivy |
clean |
1 (vulns, with --exit-code) |
— |
| dependency-check |
clean |
1 (vulns ≥ threshold) |
— |
Rule of thumb: exit 0 == "no findings" only for tools listed as clean=0; other codes are infra errors and must not be treated as "vulnerable".
Workflow
- Inventory —
security_review.py inventory --dir <project> --json → know exactly which lockfiles exist and which tool applies.
- Scan — run the suggested tool per row above with its JSON format (see
references/canonical-patterns.md for exact CLI + JSON shapes; e.g. semgrep JSON with --json, osv-scanner --json, pip-audit --format json, gitleaks --report-format json, bandit -f json).
- Classify exits — in CI, map exit codes via
classify so 1 = findings, 2+ = infra error.
- Normalize —
normalize --tool <t> --input <scanner.json> → unified findings (ruleId/rule/level/message/path/line/col).
- Report — merge all normalized findings into one report (markdown or JSON), present severity rollup.
When NOT to use
- Not a scanner itself — it does not detect vulnerabilities; it orchestrates/normalizes the real scanners. Run the real tools.
- Not a secret detector — use the
secret-scanner skill for credentials/tokens.
- Not a web scanner — OWASP Top-10 dynamic testing is out of scope.
Success criteria
inventory lists every lockfile in the target directory with correct ecosystem + suggested tool.
classify --exit-code matches the verified table above for your installed tools.
normalize produces a valid unified report for the 5 built-in formats (osv-scanner, pip-audit, semgrep, gitleaks, bandit).
- CI gate: exit
1 on real findings, EXIT_NEUTRAL (or 2) on infra errors, clean on 0.
1---2name: security-review3description: Security review orchestrator for dependency lockfiles and source: inventory of lockfiles/manifests (npm, pip, cargo, go, gem, maven, gradle, composer), exit-code classifier for 13 security tools (semgrep, bandit, gitleaks, osv-scanner, pip-audit, trufflehog, checkov, trivy, grype, npm audit, cargo audit), JSON normalizer to a unified finding schema, and human-readable reports. Stdlib-only Python helper + workflow for OWASP-aligned security review.4license: MIT5---67# Security Review — dependency & static analysis orchestration89Load this skill when you need to run a **security review of a codebase**:10audit the dependency manifest/lockfile inventory, decide which scanner to run11per ecosystem, interpret scanner exit codes correctly (real findings vs.12infrastructure errors), and normalize reports from different tools into **one13unified schema** for a final report.1415The helper script is **offline by design** — it inventories, classifies, and16normalizes. Actual scans are executed by the well-known external tools listed17below (install once locally or in CI).1819---2021## The helper script2223`scripts/security_review.py` — pure Python 3 stdlib (no dependencies).2425| Command | Purpose |26|---|---|27| `security_review.py inventory --dir . ` | List dependency locks with ecosystem + suggested tool |28| `security_review.py inventory --dir . --json` | Same, machine-readable |29| `security_review.py classify --tool semgrep --exit-code 1` | Explain what a tool exit code means |30| `security_review.py normalize --tool osv-scanner --input out.json` | Flatten a tool JSON report into unified findings |31| `security_review.py normalize --tool pip-audit --input pip.json --output report.json` | Save unified report |32| `security_review.py report --root .` | Report skeleton (markdown default, `--json` for JSON) |3334### Lockfile inventory (per-ecosystem suggested tool)3536| Lockfile / manifest | Ecosystem | Suggested tool |37|---|---|---|38| `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock` | npm / pnpm / yarn | `npm audit` / `osv-scanner` |39| `requirements*.txt`, `pyproject.toml`, `Pipfile.lock`, `poetry.lock` | pip | `pip-audit` |40| `Cargo.lock` | cargo | `cargo audit` |41| `go.mod`, `go.sum` | go | `osv-scanner` |42| `Gemfile.lock` | gem | `osv-scanner` |43| `pom.xml`, `build.gradle(.kts)` | maven / gradle | `osv-scanner` / `dependency-check` |44| `composer.lock` | composer | `osv-scanner` |4546`package.json` alone (no lockfile) is still reported, so gate or scan it with `npm audit`.4748---4950## Exit-code semantics (verified August 2026)5152Get each tool's meaning on the fly with `classify --tool X --exit-code N`.5354| Tool | `0` | findings | error / other |55|---|---|---|---|56| semgrep | clean | `1` (findings) | `2` fatal; `3/4/5/7/8/13/99` specific errors |57| bandit | clean | `1` (issues) | `2` error |58| gitleaks | clean | `1` (leaks or error) | `126` unknown flag |59| pip-audit | clean | `1` (vulns) | — |60| osv-scanner v2 | clean | `1` (vulns) | `127` error, `128` no packages, `129` API failed, `130` config |61| npm audit | clean | `1` (vulns) | — |62| cargo audit | clean | non-zero (vulns / errors) | — |63| grype | clean | `2` (vulns ≥ fail-on) | `1` error, `100` DB update |64| truffle | clean | `183` (findings, only with `--fail`) | `1` error |65| checkov | clean | `1` (failed checks) | `2` error |66| trivy | clean | `1` (vulns, with `--exit-code`) | — |67| dependency-check | clean | `1` (vulns ≥ threshold) | — |6869**Rule of thumb:** `exit 0` == "no findings" only for tools listed as clean=0; other codes are infra errors and must not be treated as "vulnerable".7071---7273## Workflow74751. **Inventory** — `security_review.py inventory --dir <project> --json` → know exactly which lockfiles exist and which tool applies.762. **Scan** — run the suggested tool per row above with its JSON format (see `references/canonical-patterns.md` for exact CLI + JSON shapes; e.g. semgrep JSON with `--json`, osv-scanner `--json`, pip-audit `--format json`, gitleaks `--report-format json`, bandit `-f json`).773. **Classify exits** — in CI, map exit codes via `classify` so `1 = findings`, `2+ = infra error`.784. **Normalize** — `normalize --tool <t> --input <scanner.json>` → unified findings (ruleId/rule/level/message/path/line/col).795. **Report** — merge all normalized findings into one report (markdown or JSON), present severity rollup.8081## When NOT to use8283- **Not a scanner itself** — it does not detect vulnerabilities; it orchestrates/normalizes the real scanners. Run the real tools.84- **Not a secret detector** — use the `secret-scanner` skill for credentials/tokens.85- **Not a web scanner** — OWASP Top-10 dynamic testing is out of scope.8687## Success criteria8889- `inventory` lists every lockfile in the target directory with correct ecosystem + suggested tool.90- `classify --exit-code` matches the verified table above for your installed tools.91- `normalize` produces a valid unified report for the 5 built-in formats (osv-scanner, pip-audit, semgrep, gitleaks, bandit).92- CI gate: exit `1` on real findings, `EXIT_NEUTRAL` (or `2`) on infra errors, clean on 0.