Three stub-kit dispatch tests used ['ufw', ...] as an arbitrary example
argv and one popen-guard test expected the real Popen to fail on it. Both
assumed ufw is absent on the running machine — true on every dev box, false
on CI's runners, where ufw exists sbin-only: the sbin guard fired inside
the stub path (SbinPathError instead of the scripted result) and the real
exec succeeded instead of raising FileNotFoundError. Red on every CI run
since the stub kit landed; invisible in local runs.
The dispatch tests now pin the guard's view of ufw to 'absent' (they test
dispatch mechanics, not the guard), and the guard test execs a name that
exists on no machine.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Plan 75 §G7. The suite's hand-rolled stubs were entrenching the very
duplication the plan removes: _FakeProc pasted byte-identical in four
modules, ~25 fake_run closures re-implementing argv dispatch, and zero
tests patching the wrappers — every stub targeted raw subprocess inside
one service module, so each new service test recreated the raw seam.
tests/subprocess_stub.py is that seam. Tests script argv → result; when
G1 moves services onto run_checked() the retarget happens here once
instead of in twelve files.
Two properties are deliberate:
- An unscripted command raises instead of inventing returncode=0. It is a
BaseException for the same reason SbinPathError is — services wrap
subprocess in `except Exception`, so an AssertionError would be eaten
by exactly the handlers the kit exists to test.
- Stubbed execs are still sbin-guarded. Patching subprocess removes the
§B2 runtime guard, so the kit re-applies it; popen_guard grows a public
guard_argv() as the one door for that check.
Matching normalises away a sudo prefix and argv[0] absolutisation, so one
scripted rule matches on a root box, a sudo box and a dev box alike.
Mutation-checked: removing the guard call fails the guard test.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>