You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
All git subprocess calls go through the _run_git chokepoint in verify.py (timeouts, LC_ALL=C) — no bare subprocess git.
Nothing enforces it.tests/test_portability_guard.py is the only AST scan over src/bmad_loop, and it collects six finding kinds — ["tmux", …] argv, hardcoded POSIX paths, SIGKILL, os.kill, start_new_session=True, shell=True. There is no git detector and no subprocess.run detector at all. AGENTS.md is asymmetric about this too: the tmux quarantine
line explicitly names its enforcer, the git line names none.
That is how #389's bypass survived as long as it did — it was found by reading, not by CI.
What exists to build on
The ["tmux", …] detector is structurally the same shape: an ast.List whose first element is
the string constant. A git-flavoured copy would fire on ["git", "-C", str(repo), *args]
(still an ast.List with "git" first). verify.py is the allowlisted owner.
tui/app.py:_commit_subject — the one worth fixing first. text=True with no LC_ALL=C, guarded by except (OSError, subprocess.SubprocessError). UnicodeDecodeError
is a ValueError and is in neither arm, so a commit subject carrying bytes invalid in the
run's codec crashes the TUI render. This is exactly the hole _run_git's decode fault escapes the GitError taxonomy on -z output #377 closed at the chokepoint,
still open here. It also carries its own 5s timeout, ignoring limits.git_timeout_s, and has
no comment explaining the exemption.
install._warn_if_policy_tracked — git ls-files --error-unmatch with cwd= and a 10s
timeout. Benign (best-effort, rc-only), but undocumented as an exemption.
Scope
Add the git-argv detector to tests/test_portability_guard.py, allowlisting verify.py.
Ablate it: reintroduce a bare git spawn elsewhere and confirm the guard FAILS.
AGENTS.md states the invariant:
Nothing enforces it.
tests/test_portability_guard.pyis the only AST scan oversrc/bmad_loop, and it collects six finding kinds —["tmux", …]argv, hardcoded POSIX paths,SIGKILL,os.kill,start_new_session=True,shell=True. There is no git detector and nosubprocess.rundetector at all. AGENTS.md is asymmetric about this too: the tmux quarantineline explicitly names its enforcer, the git line names none.
That is how #389's bypass survived as long as it did — it was found by reading, not by CI.
What exists to build on
The
["tmux", …]detector is structurally the same shape: anast.Listwhose first element isthe string constant. A git-flavoured copy would fire on
["git", "-C", str(repo), *args](still an
ast.Listwith"git"first).verify.pyis the allowlisted owner.Two live bypasses remain after #389
tui/app.py:_commit_subject— the one worth fixing first.text=Truewith noLC_ALL=C, guarded byexcept (OSError, subprocess.SubprocessError).UnicodeDecodeErroris a
ValueErrorand is in neither arm, so a commit subject carrying bytes invalid in therun's codec crashes the TUI render. This is exactly the hole _run_git's decode fault escapes the GitError taxonomy on -z output #377 closed at the chokepoint,
still open here. It also carries its own 5s timeout, ignoring
limits.git_timeout_s, and hasno comment explaining the exemption.
install._warn_if_policy_tracked—git ls-files --error-unmatchwithcwd=and a 10stimeout. Benign (best-effort, rc-only), but undocumented as an exemption.
Scope
tests/test_portability_guard.py, allowlistingverify.py.Ablate it: reintroduce a bare git spawn elsewhere and confirm the guard FAILS.
git_bytesfor_commit_subject, since theTUI must not raise on a subject it cannot decode), re-deriving their guards the way Route install._shield_git through verify.git_bytes now that #377 has landed #389
did — a timeout is
GitError, a spawn faultGitSpawnError.so the invariant and the code stop disagreeing.
Follow-up to #389 / #385.