Fix .gitignore swallowing references/findings-format.md
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.
This commit is contained in:
parent
31c67b9573
commit
249055fe99
10
.gitignore
vendored
10
.gitignore
vendored
@ -10,10 +10,12 @@ __pycache__/
|
|||||||
venv/
|
venv/
|
||||||
env/
|
env/
|
||||||
|
|
||||||
# Generated audit reports (timestamped runs are not source)
|
# Generated audit reports (timestamped runs are not source).
|
||||||
findings-*.md
|
# Scoped to digit-prefixed names so the references/findings-format.md
|
||||||
findings-*.json
|
# doc is NOT swallowed.
|
||||||
findings-*.txt
|
findings-[0-9]*.md
|
||||||
|
findings-[0-9]*.json
|
||||||
|
findings-[0-9]*.txt
|
||||||
|
|
||||||
# Environment / secrets
|
# Environment / secrets
|
||||||
.env
|
.env
|
||||||
|
|||||||
85
repo-hygiene-audit/references/findings-format.md
Normal file
85
repo-hygiene-audit/references/findings-format.md
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
# 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
|
||||||
|
```
|
||||||
Loading…
Reference in New Issue
Block a user