diff --git a/.claude/settings.json b/.claude/settings.json index ffa42c0..c8b3df6 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -25,7 +25,19 @@ "Bash(python3 scripts/dc-dc-whole-host-budget.py*)", "Bash(bash tests/*)", "Bash(OPNSENSE_API_HOST=* bash scripts/opnsense-api.sh GET *)", - "Bash(bash scripts/opnsense-plugins.sh list*)" + "Bash(bash scripts/opnsense-plugins.sh list*)", + "Bash(bash scripts/creds-audit.sh *)", + "Bash(bash scripts/dc-dc-ceph-disk-budget.sh *)", + "Bash(bash scripts/site-baseleg.sh check*)", + "Bash(tofu validate*)", + "Bash(tofu -chdir=* validate*)", + "Bash(tofu state list*)", + "Bash(tofu -chdir=* state list*)", + "Bash(tofu state show*)", + "Bash(tofu providers schema*)", + "Bash(tofu version*)", + "Bash(ip route*)", + "Bash(systemctl is-active *)" ], "ask": [ "Bash(juju destroy-model *)", "Bash(juju remove-machine *)", diff --git a/docs/changelog-20260727-creds-consolidation.md b/docs/changelog-20260727-creds-consolidation.md index 1bd188b..fcc6603 100644 --- a/docs/changelog-20260727-creds-consolidation.md +++ b/docs/changelog-20260727-creds-consolidation.md @@ -133,6 +133,52 @@ Revert: `git revert` this commit's changes to `scripts/creds-matrix.py` and `tests/creds-matrix/run-tests.sh`; V2 returns to failing on SEC-006 every run. +## 6. Permission allowlist widened for read-only commands (`.claude/settings.json`) + +Transcript scan of the 44 most-recent session JSONLs across both project dirs, counting Bash +leading command+subcommand pairs (and splitting each candidate into LOCAL vs +nested-inside-`ssh`, since a command that only ever runs inside `ssh host '...'` gains nothing +from its own rule -- the outer `ssh` is what the permission layer matches). + +ADDED to `permissions.allow` only -- 13 entries, 31 -> 44. `ask`, `deny`, `env` and `hooks` +untouched; nothing removed or reordered; JSON re-validated and de-duplicated: + + bash scripts/creds-audit.sh * (33) bash scripts/dc-dc-ceph-disk-budget.sh * (13) + bash scripts/site-baseleg.sh check* (5) tofu validate* + tofu -chdir=* validate* (25) + tofu state list* + -chdir variant (16) tofu state show* (3) + tofu providers schema* (13) tofu version* (11) + ip route* (22) systemctl is-active * (6) + +DELIBERATELY NOT ADDED, and this is the substantive half of the item: + +- **`ssh` (693 calls), `scp` (47), `virsh` (234)** -- the three biggest prompt sources, left + alone. They are this cloud's MUTATION TRANSPORT. CLAUDE.md hard rule 3 makes the `ask` rules + the enforcement mechanism for per-mutation approval and says not to work around them, and + the `Bash(ssh *)` disposition is an OPEN operator item queued at the 2026-07-23 close. + Allowlisting any ssh shape would bypass the gate AND pre-empt an unresolved operator + decision. **This item does NOT discharge that queued prune -- it is still open.** +- **`python3 scripts/creds-matrix.py` (76 local runs -- the largest genuine miss)** -- skipped + because `Bash(*creds-matrix.py *--privileged*)` is an `ask` rule added 2026-07-26 precisely + after the auto-mode classifier incident. Every prefix pattern wide enough to cover the + observed `... 2>&1 | tail` forms would ALSO match `--privileged`, and allow-vs-ask precedence + was not verified this session. Adding a rule that might silently downgrade an + operator-installed gate is exactly the class of change hard rule 3 forbids. Needs the + precedence question answered first, then a narrow set of EXACT forms. +- **`tofu plan` (54)** -- read-only in effect, but CURRENT-STATE section 10 says in terms "Do + NOT re-run `tofu plan` casually against live state". The prompt is deliberate friction. +- `python3 -c`/heredocs (324) and shells: arbitrary code execution. `curl` (114): a mutation + vector via `-X`/`-d`. `tofu fmt` (26): rewrites files. `tofu init` (10): mutates + `.terraform/`. `nft list` (10): normally needs `sudo`, which correctly stays `ask`. + +TWO OBSERVATIONS, no action taken (flagged, not fixed): several existing allow entries are +redundant with Claude Code's built-in auto-allow (`Bash(git status*)`, `Bash(git log*)`, +`Bash(grep *)`, `Bash(ls *)`, `Bash(jq *)`, `Bash(cat scripts/*)`) -- harmless, and removing +entries was out of scope; and `Bash(git pull*)` sits in `allow` although it is a fetch-and-merge +that mutates the working tree. + +Revert: drop the 13 appended lines from `permissions.allow` in `.claude/settings.json`. No +other field was touched, so the revert is a contiguous deletion. + --- ## Findings LOGGED, not actioned (hard rule 1) @@ -180,3 +226,5 @@ S6 conflation x1 (the SEC-020 defect, separate), E4 uncheckable x2 (Stage-5/6 rows). **The register is NOT green and is not expected to be.** - `scripts/repo-lint.sh` + full gauntlet: see the commit message for the recorded results. +- `.claude/settings.json` (item 6): `json.load` parses, 44 allow entries, zero duplicates, + `ask` 52 / `deny` 15 / `env` / `hooks` byte-unchanged.