Files
govoplan/docs/SECURITY_AUDIT.md
Albrecht Degering 05ae81d641
Some checks failed
Dependency Audit / dependency-audit (push) Failing after 16s
Security Audit / security-audit (push) Failing after 11s
intermediate commit
2026-07-14 13:32:09 +02:00

165 lines
5.7 KiB
Markdown

# Security Audit Toolchain
GovOPlaN uses a free/open-source-first audit toolchain that can run locally,
inside a container, and in Gitea Actions.
## Tools
- Semgrep: multi-language SAST, with GovOPlaN-specific local rules plus
explicit public registry rulesets in CI/full runs.
- Bandit: Python AST security checks.
- Ruff `S` rules: fast flake8-bandit-compatible Python security linting.
- Gitleaks: committed-secret scanning.
- Trivy: filesystem dependency, secret, and misconfiguration scanning.
- pip-audit and npm audit: package vulnerability scanning from dependency
manifests/locks.
- OSV-Scanner: recursive dependency vulnerability scan in full mode.
- jscpd: duplicated-code reports in full mode.
- Radon/Xenon: Python complexity reports and thresholds in full mode.
## Local Usage
Build and run the toolbox from this repository:
```bash
cd /mnt/DATA/git/govoplan
tools/checks/security-audit/run.sh --mode ci --scope current
```
Scan all sibling GovOPlaN repositories under `/mnt/DATA/git`:
```bash
cd /mnt/DATA/git/govoplan
tools/checks/security-audit/run.sh --mode full --scope govoplan
```
Reports are written to `audit-reports/`, which is intentionally ignored by git.
The wrapper tags the toolbox image by a fingerprint of the Dockerfile and
`requirements-audit.txt`. If those inputs have not changed, subsequent runs reuse
the existing local image instead of reinstalling all tools. The stable alias is
`govoplan/security-audit:local` unless `SECURITY_AUDIT_IMAGE` is set.
Semgrep is installed separately in the toolbox image because current Semgrep
packages pin Click to an affected `8.1.x` line. The image upgrades Click after
Semgrep installation and fails during build if Semgrep no longer starts with the
patched Click version.
Force a cached rebuild:
```bash
tools/checks/security-audit/run.sh --mode ci --scope current --rebuild
```
Refresh from upstream base images and package ranges:
```bash
tools/checks/security-audit/run.sh --mode ci --scope current --update
```
Build or refresh the toolbox without running an audit:
```bash
tools/checks/security-audit/run.sh --mode quick --scope current --build-only
tools/checks/security-audit/run.sh --mode quick --scope current --update --build-only
```
## Modes
- `quick`: local Semgrep rules, Bandit, Ruff security rules, Gitleaks.
- `ci`: quick plus Semgrep public registry rulesets, Trivy, pip-audit, npm audit.
- `full`: ci plus OSV-Scanner, jscpd, Radon, and Xenon.
Bandit and Ruff security reports are split by source kind. Production code under
`src/` is written to `bandit.json` and `ruff-security.json` and controls strict
mode. Test code under `tests/` is still scanned for visibility, but its findings
are written separately to `bandit-tests.json` and `ruff-security-tests.json` so
fixture passwords, assertions, and temporary paths do not hide the production
baseline.
## Gating
The initial Gitea workflow runs in report-only mode:
```bash
SECURITY_AUDIT_FAIL_ON_FINDINGS=0
```
This avoids blocking every push while the first baseline is reviewed. After the
baseline is clean, switch the workflow to:
```bash
SECURITY_AUDIT_FAIL_ON_FINDINGS=1
```
or run locally with:
```bash
tools/checks/security-audit/run.sh --mode ci --scope current --strict
```
## Audit Burndown Workflow
Treat Gitea issues as the active audit state. A full GovOPlaN audit should
produce one tracker issue in `add-ideas/govoplan` and child issues in the
repository that owns each fix.
Use the tracker issue for:
- report path, timestamp, mode, and scope
- scanner counts by category
- clean scanners and resolved findings
- links to child issues
- the next audit run target
Use child issues for concrete code or configuration changes. Apply
`source/security-audit` to every issue created from a report, then add the
most specific audit label:
- `audit/quick-fix`: narrow direct remediation
- `audit/structural`: behavior or architecture needs review
- `audit/complexity`: Radon/Xenon maintainability finding
- `audit/duplication`: jscpd duplication finding
- `audit/false-positive`: reviewed narrow false positive or accepted risk
- `audit/needs-design`: human decision needed before implementation
Keep active implementation status in issues instead of committing generated
audit reports. `audit-reports/` is ignored; quote the report directory and the
important scanner counts in the tracker issue.
The jscpd step is intentionally scoped to application and test source. It
excludes documentation snippets, package manifests, generated translations,
public SVG assets, workflow YAML, and declarative backend schema JSON because
those reports produce metadata or asset repetition rather than actionable source
duplication. Keep exclusions narrow and create child issues for source-code
clusters that cross module ownership or make behavior harder to change safely.
## Image Freshness
The regular `Security Audit` workflow reuses the fingerprinted toolbox image
when the Docker daemon is persistent, which is the normal case for the
self-hosted Gitea runner using the host Docker socket. The separate
`Security Audit Toolbox Update` workflow runs weekly with
`SECURITY_AUDIT_UPDATE=1`; it pulls current base images and re-resolves the
allowed tool version ranges into a refreshed local image.
## Direct Host Usage
The container is the recommended path. For direct host usage, install the Python
tools first:
```bash
cd /mnt/DATA/git/govoplan
python -m venv .venv
./.venv/bin/python -m pip install -r requirements-audit.txt
./.venv/bin/python -m pip install 'semgrep>=1.140,<2'
./.venv/bin/python -m pip install --upgrade --no-deps 'click>=8.3.3'
```
Then install the non-Python tools (`gitleaks`, `trivy`, `osv-scanner`, `jscpd`)
through the host package manager or vendor instructions and run:
```bash
tools/checks/check-security-audit.sh --mode quick --scope current
```