chore(memory): BDR-112 + LRN-194..196 + journal — feat manual-push-guard run B
This commit is contained in:
@@ -1371,3 +1371,10 @@ Branch feature/user-writing-web-rules, UNMERGED (human gate).
|
||||
- **Alternatives rejected**: new `gitflow.mode auto|manual` (duplicates autopush); tty-only lock on `finish` (user wants local merges); `-D` after ancestor gate (statically denied form, reviewers' red flag); fail-closed in lib only (hooks would still push → inconsistent).
|
||||
- **Gates**: 3 lenses CONCERNS(1/2/2) + confirmation FATAL(4) → r2 fixes (T22j containing base, `-u` fixture, T18n before T18l); feater ×2; GATE 0 7/8 (AC6 = env red); verifier ECARTS(1) = AC6 only; security PASS ×2 (1 MEDIUM fail-open → run B).
|
||||
- **Refs**: contract `.claude/tasks/contracts/2026-10-06-manual-push-mode-1632.md`, plan `.claude/tasks/plans/2026-10-06-manual-push-mode-1632.md`, commit 2fc8830 (feature/manual-push-mode, UNMERGED). Extends [[BDR-095]] (c); [[LRN-161]], [[LRN-191]], [[LRN-192]], [[LRN-193]], [[BLK-022]].
|
||||
|
||||
## BDR-112 — push-guard: text-only PreToolUse deny of Claude's `git push` in manual-push mode, fail closed [accepted] (2026-10-07)
|
||||
- **Decision**: run B of [[BDR-111]]. `hooks/push-guard.sh` (own PreToolUse group `Bash|Monitor`, timeout 10) reads `tool_input.command` + `cwd`; folds `\`-newline in bash (BSD sed unsafe, [[LRN-195]]); three ERE matches on `/usr/bin/grep`: STRICT (git + `-opt [arg]`* + push|send-pack, boundaries `[^[:alnum:]_.-]` / `[^[:alnum:]_-]`), LOOSE on quote-stripped text (any later ` push` word in the same simple command), ALIAS (`alias.x=…push`). Candidate dirs = cwd + literal `-C`/`cd`/`pushd` tokens (quotes stripped, never eval/expand), dedup `sort -u`, >20 distinct → deny before any fork. Mode per dir via `git config --bool gitflow.autopush` rc: 0 → value, 1 → auto, else → deny; NO work-tree gate (global key = work-machine deployment). Deny = JSON `permissionDecision=deny` exit 0, reason carries `! <cmd>`; EXIT trap emits static deny + `exit 0` once a push is detected and nothing decided; jq missing → stderr + allow (sibling policy). User gated: fail-closed cases (cap, unenterable dir, git failure) fire in auto mode too. settings.json: 18 deny entries on WRITE forms of `gitflow.*` (any `git … config` spelling, remove/rename-section, `-c`, config env overrides, Edit/Write of git config files); soft_deny "pushing in manual-push mode, any form, no per-turn clearance"; routing-around hard_deny names hook refusals; banner `🔒 push : manual (autopush=false) — ! git push` (`%-46s`, bytes).
|
||||
- **Why**: `ask` inert under auto ([[LRN-155]]); `hooks/guard-bash.sh` withheld ([[BLK-022]]) → one narrow rule instead. Trailing ` *` glob matches end-of-string ([[LRN-194]]) → no infix rule spares the bare read → Claude loses `git config … gitflow.autopush`; hooks/lib keep it; run C gets `gitflow.sh push-mode`. Text-only guard cannot see scripts/aliases → soft_deny is the declared backstop.
|
||||
- **Alternatives rejected**: no-jq fallback (greps whole payload, denies in auto, untestable without shim; jq hard dep); `-C` dir unresolvable → allow (fail-open; now skipped, cwd still checked); `rev-parse` work-tree gate (drops the global key); `--default true` read (hides git failure); narrowing deny to spare the read (impossible with end-matching globs).
|
||||
- **Gates**: 3 lenses CONCERNS(2)/CONCERNS(5)/FATAL(7) + confirmation FATAL(8) → r2 (BSD sed, oracle naming denied tokens, read loss); feater ×3 (58 → 61 → 71 checks); GATE 0 MET ×3; verifier CONFORME, then ECARTS(1) on hardening closed by gated clarification; security PASS ×2 (3 MEDIUM closed: 20k-token flood denied in 0.15 s, git absent → deny, `bash -c 'cd … && git push'` extracted; residuals → run D).
|
||||
- **Refs**: contract `.claude/tasks/contracts/2026-10-07-manual-push-guard-1003.md`, plan `.claude/tasks/plans/2026-10-07-manual-push-guard-1003.md`, commits a2ac018 + 6468eda (feature/manual-push-mode, UNMERGED). Links [[BDR-095]], [[BDR-100]], [[LRN-069]], [[LRN-196]]. Open: user probe `! git push --dry-run` under autopush=false (bang commands assumed hook-free).
|
||||
|
||||
Reference in New Issue
Block a user