diff --git a/docs/mode-economics.md b/docs/mode-economics.md index 0c2f982c..6b6e2df3 100644 --- a/docs/mode-economics.md +++ b/docs/mode-economics.md @@ -92,7 +92,7 @@ special-token spellings counted as ordinary text. Coverage: **75 of 75 local `skills/*/SKILL.md` files**. External `source.md` redirects and harness symlinks are excluded. -Measurement manifest SHA-256: `026fe6f701d8b3c1050c01f3a7bc192b8996ae0f5f7702290cab4c5c052806d8`. +Measurement manifest SHA-256: `4556129999018ce339eb0f7c8292e18a424d57716fadd8407f29d9c4a9decec3`. | Skill file | Measured tokens | Source SHA-256 (first 16 characters) | |---|---:|---| @@ -160,9 +160,9 @@ Measurement manifest SHA-256: `026fe6f701d8b3c1050c01f3a7bc192b8996ae0f5f7702290 | [security-tracker-stats-dashboard](../skills/security-tracker-stats-dashboard/SKILL.md) | 4,897 | `b52154deb8557ba4` | | [setup](../skills/setup/SKILL.md) | 8,724 | `82788542bb240309` | | [setup-isolated-setup-doctor](../skills/setup-isolated-setup-doctor/SKILL.md) | 7,950 | `3fa5d728fa080ed0` | -| [setup-isolated-setup-install](../skills/setup-isolated-setup-install/SKILL.md) | 11,197 | `c046c45d2e176827` | +| [setup-isolated-setup-install](../skills/setup-isolated-setup-install/SKILL.md) | 11,278 | `418ea9794077c6e9` | | [setup-isolated-setup-update](../skills/setup-isolated-setup-update/SKILL.md) | 5,069 | `dd56cf376cd14f55` | -| [setup-isolated-setup-verify](../skills/setup-isolated-setup-verify/SKILL.md) | 8,409 | `3ba7f351ebfa32bd` | +| [setup-isolated-setup-verify](../skills/setup-isolated-setup-verify/SKILL.md) | 8,502 | `6f0a2594801bdf27` | | [setup-override-upstream](../skills/setup-override-upstream/SKILL.md) | 4,012 | `fb583feb56b7f77c` | | [setup-privacy-llm](../skills/setup-privacy-llm/SKILL.md) | 2,145 | `0e27b542a1656846` | | [setup-shared-config-sync](../skills/setup-shared-config-sync/SKILL.md) | 4,357 | `d1dfcd7cdeb5f5a6` | diff --git a/docs/setup/secure-agent-setup.md b/docs/setup/secure-agent-setup.md index f696a664..b47eb49d 100644 --- a/docs/setup/secure-agent-setup.md +++ b/docs/setup/secure-agent-setup.md @@ -2182,11 +2182,29 @@ in the `Bash` matcher groups you already have: "hooks": [ { "type": "command", "command": "~/.claude/scripts/gpg-touch-overlay.sh disarm" } ] } + ], + "PermissionDenied": [ + { "matcher": "Bash", + "hooks": [ + { "type": "command", "command": "~/.claude/scripts/gpg-touch-overlay.sh disarm" } + ] } + ], + "PostToolUseFailure": [ + { "matcher": "Bash", + "hooks": [ + { "type": "command", "command": "~/.claude/scripts/gpg-touch-overlay.sh disarm" } + ] } ] } } ``` +**Disarm is wired to three events, not one.** +`PreToolUse` fires *before* the permission prompt, so a command the operator rejects has already armed a watcher that `PostToolUse` will never tear down. +It then lives until `MAX_WAIT` — ten minutes — and because `signing_in_flight` is a machine-wide `pgrep` for `gpg` / `ssh-keygen` rather than something scoped to the armed context, any unrelated signature inside that window raises the window with nothing of the operator's pending. +The touch that follows lands while no signature waits, which fires the key's OTP slot and types `cccc…` into whatever has focus. +`PermissionDenied` and `PostToolUseFailure` are the events that fire when a Bash call does not run; `disarm` is idempotent and exits 0 with nothing armed, so the extra calls cost nothing. + On Linux this needs `python3` with PyGObject for the dimmed overlay; where that is missing it falls back to a `zenity` dialog. On macOS it needs a `python3` with Tk 8.6 or newer — a uv-managed python or diff --git a/plugins/magpie-setup/skills/isolated-setup-install/SKILL.md b/plugins/magpie-setup/skills/isolated-setup-install/SKILL.md index f28e4725..8d98a614 100644 --- a/plugins/magpie-setup/skills/isolated-setup-install/SKILL.md +++ b/plugins/magpie-setup/skills/isolated-setup-install/SKILL.md @@ -654,11 +654,16 @@ key. Leave the attestation slot alone. A slot already at `On` or `tools/agent-isolation/gpg-touch-overlay.sh`, `gpg-touch-overlay-window.py` and `gpg-touch-overlay-window-macos.py` into `~/.claude/scripts/`, `chmod +x` them, and wire a `PreToolUse` -`Bash` hook running `gpg-touch-overlay.sh arm` and a `PostToolUse` -`Bash` hook running `gpg-touch-overlay.sh disarm` into -`~/.claude/settings.json` — merging into existing arrays with a diff -the operator approves, exactly as for the bypass-warn hook. Install -detail: +`Bash` hook running `gpg-touch-overlay.sh arm` and a +`gpg-touch-overlay.sh disarm` hook on **three** events — +`PostToolUse`, `PermissionDenied` and `PostToolUseFailure`, each on +the `Bash` matcher — into `~/.claude/settings.json`, merging into +existing arrays with a diff the operator approves, exactly as for the +bypass-warn hook. The last two matter because `PreToolUse` fires +before the permission prompt: a command the operator rejects has +already armed a watcher that `PostToolUse` never tears down, and it +lives until `MAX_WAIT` raising the window for somebody else's +signature. Install detail: [docs/setup/secure-agent-setup.md → Hardware-key touch overlay](../../../../docs/setup/secure-agent-setup.md#hardware-key-touch-overlay). **K.3 — Git from the operator's own terminal.** The hook covers only diff --git a/plugins/magpie-setup/skills/isolated-setup-verify/SKILL.md b/plugins/magpie-setup/skills/isolated-setup-verify/SKILL.md index 8aacdef8..15b084f8 100644 --- a/plugins/magpie-setup/skills/isolated-setup-verify/SKILL.md +++ b/plugins/magpie-setup/skills/isolated-setup-verify/SKILL.md @@ -348,8 +348,14 @@ Walk each in order: **10a — wiring and scripts.** User-scope `~/.claude/settings.json` has a `PreToolUse` `Bash` hook running - `gpg-touch-overlay.sh arm` and a `PostToolUse` `Bash` hook running - `gpg-touch-overlay.sh disarm`, and the scripts are present and + `gpg-touch-overlay.sh arm` and a `gpg-touch-overlay.sh disarm` + `Bash` hook on each of `PostToolUse`, `PermissionDenied` and + `PostToolUseFailure`. A missing `PostToolUse` disarm is ✗; a + missing `PermissionDenied` or `PostToolUseFailure` disarm is ⚠ + with the reason — the overlay still works, but a rejected or + failed command leaves its watcher armed until `MAX_WAIT`, and any + unrelated signature in that window raises the window with nothing + pending. The scripts must also be present and executable: `~/.claude/scripts/gpg-touch-overlay.sh`, plus `gpg-touch-overlay-window.py` (Linux) or `gpg-touch-overlay-window-macos.py` (macOS) beside it. Compare diff --git a/tools/spec-loop/specs/agent-isolation-sandbox.md b/tools/spec-loop/specs/agent-isolation-sandbox.md index 7aeb7831..8c5835f8 100644 --- a/tools/spec-loop/specs/agent-isolation-sandbox.md +++ b/tools/spec-loop/specs/agent-isolation-sandbox.md @@ -47,7 +47,11 @@ existing sandbox grants can widen the baseline. See `docs/adapters/gemini.md`. signing key or ssh authentication key with a touch policy blocks waiting for a touch. Two entry points: `arm` / `disarm` as a `PreToolUse` / `PostToolUse` `Bash` hook around the - agent's git commands, and `wrap` as git's own signing program and ssh + agent's git commands — with `disarm` also on `PermissionDenied` and + `PostToolUseFailure`, because `PreToolUse` fires before the + permission prompt and a command that never runs would otherwise + leave its watcher armed until `MAX_WAIT`, raising the window for an + unrelated signature — and `wrap` as git's own signing program and ssh command (`gpg.ssh.program` / `gpg.program` through an argument-free `gpg-touch-wrap-` symlink, `core.sshCommand … wrap ssh`) for the commits and pushes the operator makes by hand — no git hook type