fix(agent-isolation): raise the touch overlay for key users other than git - #1314
Merged
Merged
Conversation
…n git The hook armed only on `git <subcommand>`, so anything reaching the security key without git in front of it — `ssh`, `scp`, `sftp`, `rsync -e ssh`, `svn+ssh`, a direct `gpg --detach-sign` — blocked for its touch with nothing on screen. Add those under the same whole-command shape rule. Arming stays deliberately broad: the watcher shows no window until something has actually blocked on the key for longer than the grace, so a false positive costs one short-lived background process and nothing visible. `wrap` reaches the same commands through an optional shim directory on PATH. Git can be told which program to call; a bare `ssh` cannot, so only PATH can put the wrapper in front of it. The script now dispatches on its own basename for a key command's name, not only for `gpg-touch-wrap-<program>`. That surfaced a latent bug in the lookup for the real program. `command -v -a` is not valid bash — `-a` belongs to `type` — so the loop never saw a candidate and every call fell through to exec'ing the bare name, relying on PATH to resolve it. Harmless while the script was never on PATH; with a shim it re-execs itself indefinitely, leaving a hung terminal, no window, and a load average that climbs until someone goes looking. Use `type -aP`, and exit 127 rather than falling back to the name. That same self-skip is what keeps a wrapped git from chaining into a shim, so one connection still gets one wrapper and one window. Generated-by: Claude Opus 5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
git <subcommand>. Anything that reaches the security key without git in front of it —ssh,scp,sftp,rsync -e ssh,svn+ssh, a directgpg --detach-sign,ssh-keygen -Y sign— blocked for its touch with nothing on screen. A newKEY_COMMANDSmatcher covers them under the same whole-command shape rule as the git list.wrappast git. Git can be told which program to call (gpg.ssh.program,core.sshCommand); a baresshyou type cannot, so onlyPATHcan put the wrapper in front of it. The script now dispatches on its own basename for a key command's name, not only forgpg-touch-wrap-<program>. Opt-in, and thePATHline is printed for the operator rather than written into their rc.command -v -ais not valid bash (-abelongs totype), sowrap's "find the real program behind me" loop never saw a candidate and every call fell through to exec'ing the bare name. Harmless while the script was never onPATH; with a shim it re-execs itself indefinitely — hung terminal, no window, climbing load average. Nowtype -aP, and exit 127 instead of falling back to the name.Arming stays deliberately over-broad: the watcher shows no window until something has actually blocked on the key for longer than
SHOW_DELAY, so a false-positive arm costs one short-lived background process and nothing visible. That is also why no "is a YubiKey configured?" probe was added — a machine with no touch-required key never reaches the window, and a probe would add a dependency, per-call latency and a cache that goes stale on replug, in exchange for a false-negative risk (a silent block with no window), which is the expensive direction.No double overlay. The self-skip in the program lookup is load-bearing twice: a wrapped git does not chain into a shim (one connection, one wrapper), and the lookup must fail rather than fall back to the bare name. The pre-existing guarantees still hold and are still tested —
CLAUDECODE=1makes the wrapper stand aside inside an agent session, and across contexts the window is leased by atomic directory create with reclaim from a dead holder.Type of change
isolated-setup-install/-verify/-update(no eval-fixture change needed; see Test plan)tools/<system>/*.md)tools/*/withpyproject.toml) —tools/agent-isolationtestsdocs/,README.md,CONTRIBUTING.md)projects/_template/)prek, workflows, validators)Test plan
prek run --all-filespasses (32 hooks, exit 0)uv run pytest tools/agent-isolation/tests/— 233 passed, 7 skippedcat ~/.ssh/config,ls -la ~/.ssh,sshuttle …andssh-agent -smust not arm.timeout=30, so a regression shows up as a failure rather than a hung suite — this bug originally presented as two pytest runs stuck for 3.5 hours.isolated-setup-*skills: not re-run. The--cliharness cannot authenticate a nestedclaude -pfrom inside the sandbox. The verify change is a sub-check (10e) under existing check 10, so the graded schema (n: 1-10) is unchanged; the install and update edits are additive prose. Happy to run them outside the sandbox if you want them before merge.RFC-AI-0004 compliance
PATHline is printed for the operator; the install skill still never edits a shell rc.gpg-touch-overlay.sh, already covered by the K.4allowReadentry, and the sandbox checks the resolved path.Linked issues
None.
Notes for reviewers (optional)
Two things worth a second opinion:
KEY_COMMANDS. It matches a bare word in command position or after any whitespace, following the existing git matcher's shape rule, soman ssharms too. That is consistent with the file's stated bias ("a false positive costs one short-lived watcher, a false negative costs a silent block with no window"), but it is a judgement call — tightening to command position only would dropsudo ssh,env … sshandtime ssh.tools/skill-evals/evals/setup-isolated-setup-verify/step-1-classify/fixtures/output-spec.mdstill saysn=1 through n=10 at most, but the skill has had a check 11 since feat(agent-isolation): hint when gh ran inside the sandbox and catalogue the TLS -26276 shape #1289. Out of scope here; flagging it rather than folding an unrelated fix in.🤖 Generated with Claude Code