The findings-*.md rule (for generated timestamped reports) also matched the findings-format.md reference doc, so it was never tracked. Scope the rule to digit-prefixed names (findings-[0-9]*) and add the missing reference.
86 lines
3.1 KiB
Markdown
86 lines
3.1 KiB
Markdown
# Findings output format
|
|
|
|
Three renderers, one finding model. Pick the format for the consumer:
|
|
|
|
- `text` — terminal triage. Summary line, full `INVENTORY` (every repo, clean
|
|
ones included), then findings grouped by category.
|
|
- `md` — phase-mapped markdown. Each finding is a `- [ ]` checkbox under the
|
|
remediation-plan phase heading it belongs to, so a run pastes straight into
|
|
the project plan as actionable items.
|
|
- `json` — machine-readable for week-over-week diffing and automation.
|
|
|
|
## Finding model
|
|
|
|
Every finding is one record:
|
|
|
|
| Field | Meaning |
|
|
|-------|---------|
|
|
| `domain` | `homelab` / `pbs` / `docker` (the Obsidian vault is out of scope by default — see check-catalog.md) |
|
|
| `repo` | Directory name within the domain |
|
|
| `path` | Absolute path |
|
|
| `category` | `SECURITY` / `AUDITABILITY` / `CLEANUP` / `GIT_STATE` / `DOCS` |
|
|
| `severity` | `high` / `medium` / `low` / `info` |
|
|
| `check` | Stable check id (e.g. `no-git`, `env-world-readable:.env`) |
|
|
| `detail` | Human-readable description of what was found |
|
|
| `hint` | Suggested remediation (informational — the skill does not apply it) |
|
|
| `key` | `domain/repo:check` — stable identifier for dedup/diffing (JSON only) |
|
|
|
|
The `key` is deliberately stable across runs: a finding that persists keeps the
|
|
same key, so diffing two JSON runs cleanly separates *new drift* (keys that
|
|
appeared) from *remediated items* (keys that disappeared).
|
|
|
|
## Category → phase mapping
|
|
|
|
This is how findings line up with the repo-hygiene-remediation plan, so the
|
|
recurring review feeds the same backlog structure the original audit used:
|
|
|
|
| Category | Plan phase |
|
|
|----------|-----------|
|
|
| `SECURITY` | Phase 2 — Security remediation |
|
|
| `AUDITABILITY` | Phase 3 — Unblock un-auditable repos |
|
|
| `CLEANUP` | Phase 4 — Cross-repo cleanups |
|
|
| `GIT_STATE` | Git state (review before commit/merge) |
|
|
| `DOCS` | Docs (audit follow-up) |
|
|
|
|
## JSON shape
|
|
|
|
```json
|
|
{
|
|
"generated": "2026-05-22T23:05:00",
|
|
"host": "herbys-dev",
|
|
"repos_scanned": 39,
|
|
"summary": {
|
|
"by_severity": {"high": 11, "medium": 19, "low": 23, "info": 9},
|
|
"by_category": {"SECURITY": 5, "AUDITABILITY": 9, "CLEANUP": 8,
|
|
"GIT_STATE": 27, "DOCS": 13}
|
|
},
|
|
"inventory": [
|
|
{"domain": "docker", "repo": "authelia", "path": "...",
|
|
"is_git": false, "owner": "root", "git_owner": "", "group": "root",
|
|
"branch": "", "finding_count": 2}
|
|
],
|
|
"findings": [
|
|
{"domain": "docker", "repo": "authelia", "path": "...",
|
|
"category": "AUDITABILITY", "severity": "high", "check": "no-git",
|
|
"detail": "directory holds real content but has no .git",
|
|
"hint": "git init + initial commit ...", "key": "docker/authelia:no-git"}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Diffing two runs
|
|
|
|
```bash
|
|
python scripts/audit.py --format json -o this-week.json
|
|
# ... a week later ...
|
|
python scripts/audit.py --format json -o next-week.json
|
|
|
|
python3 - <<'PY'
|
|
import json
|
|
a = {f["key"] for f in json.load(open("this-week.json"))["findings"]}
|
|
b = {f["key"] for f in json.load(open("next-week.json"))["findings"]}
|
|
print("NEW drift :", sorted(b - a))
|
|
print("REMEDIATED :", sorted(a - b))
|
|
PY
|
|
```
|