You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@magpie.apache.org by po...@apache.org on 2026/09/21 13:12:19 UTC
(magpie) branch main updated: fix(agent-isolation): disarm the touch overlay when a command never runs (#1316)
This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/magpie.git
The following commit(s) were added to refs/heads/main by this push:
new c36dedf1 fix(agent-isolation): disarm the touch overlay when a command never runs (#1316)
c36dedf1 is described below
commit c36dedf16062c1980262524db7b64fb2e88a46e2
Author: Jarek Potiuk <ja...@potiuk.com>
AuthorDate: Mon Sep 21 15:12:13 2026 +0200
fix(agent-isolation): disarm the touch overlay when a command never runs (#1316)
The documented arm/disarm wiring assumed every armed command
eventually executes. `PreToolUse` fires before the permission prompt,
so a command the operator rejects has already armed a watcher that
`PostToolUse` never tears 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 visible symptom is the one the overlay exists to prevent: a touch
landing while no signature waits fires the key's OTP slot and types
`cccc…` into whatever has focus. Observed three times in one session.
Wires `disarm` onto `PermissionDenied` and `PostToolUseFailure` — the
events that fire when a Bash call does not run — in the setup doc, the
install skill's K.2, the verify skill's check 10a, and the sandbox
spec. `disarm` is already idempotent and exits 0 with nothing armed,
so the extra calls cost nothing and no script change is needed.
Generated-by: Claude Opus 5
---
docs/mode-economics.md | 6 +++---
docs/setup/secure-agent-setup.md | 18 ++++++++++++++++++
.../skills/isolated-setup-install/SKILL.md | 15 ++++++++++-----
.../magpie-setup/skills/isolated-setup-verify/SKILL.md | 10 ++++++++--
tools/spec-loop/specs/agent-isolation-sandbox.md | 6 +++++-
5 files changed, 44 insertions(+), 11 deletions(-)
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-<program>` symlink, `core.sshCommand … wrap ssh`) for
the commits and pushes the operator makes by hand — no git hook type