e2e: the tmux suite never touches the developer's own background timer - #1638
Merged
Merged
Conversation
…duler stand-ins Approving a standing reminder in the real binary writes the timer definition under HOME and then runs `systemctl --user enable --now codeaf-tick.timer`. The tmux suite launched the binary with the developer's HOME and PATH, so the firing subtest replaced the developer's own codeaf-tick unit with one pointing at the test's temporary state root and the checkout's bin/codeaf, and every five-minute pass failed once that checkout was removed (#1631). Every launch in the package now goes through one of two doors: the tmux rig (startWithEnv) or guardedCommand. Both put systemctl, launchctl and crontab stubs first on PATH, which record their argv and exit 0, and point HOME at a throwaway login folder beside the state root unless the scenario named its own. CODEAF_HOME, the provider key the rig hands the child and the engine socket path are unchanged. The firing subtest now asserts the machine's timer files are byte-identical before and after, that the approval asked the stub for `enable --now codeaf-tick.timer`, and that the definition landed in the rig's own login folder naming the rig's CODEAF_HOME. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…host guard An untagged go/parser test reads every source in internal/e2e, tagged or not, and names the file and line of any launch that could start codeaf outside the two guarded doors: a dynamic exec program, a literal codeaf, a tmux respawn or new-window built outside startWithEnv, a raw os.StartProcess or exec.Cmd literal, or an Env/Path reassigned after guardedCommand. It also fails when either door stops calling guardHost. A synthetic source proves each shape is caught. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ground timer Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.
Closes #1631
The tmux suite's firing subtest approves a standing reminder in the real binary. The approval writes the timer definition under HOME and then runs
systemctl --user enable --now codeaf-tick.timer, and the suite launched the binary with the developer's own HOME and PATH. So a run replaced the developer'scodeaf-tickunit with one pointing at the test's temporary state root and the checkout'sbin/codeaf, and every five-minute pass failed once that checkout was gone.Every codeaf process the e2e package starts now goes through one of two doors: the tmux rig (
startWithEnv, and sostartandstartFresh) orguardedCommand(tick,chat --once,engine --stop,do,manual). Both putsystemctl,launchctlandcrontabstubs first on PATH, which record their arguments and exit 0, and point HOME at a throwaway login folder beside the state root, unless the scenario named a HOME of its own. Stubs alone would not be enough: the product writes the unit files itself, in Go, before it calls the scheduler, so HOME has to move too. The state root, the provider key the rig hands the child, and the engine socket path are unchanged. The engine daemon the window spawns inherits the same HOME and PATH.Validation contract
TestEveryLaunchOfCodeafStandsBehindTheHostGuard. It failed on the dev sources before the fix, naming all seven launchers, and it failed again whentickwas temporarily put back to a bareexec.Command.codeaf, a tmux respawn built outside the rig, and anEnvreassigned after the door. Proved byTestTheHostGuardGateCatchesAnUnguardedLauncher, against a synthetic source.systemctl,launchctlandcrontabresolve to the stubs, succeed, and log one line per call. A scenario's own HOME is kept, the developer's HOME is replaced, and a scenario's own PATH gets the stubs prepended. Proved byTestTheHostGuardStandsInForTheMachinesScheduler.standinginstall, run under exactly the environment the doors hand a child, writes its definition into the throwaway login folder and leaves the machine's timer files byte-identical. Proved byTestAnInstallUnderTheGuardNeverReachesTheMachinesTimer, which refuses to call Install until both the stub and the throwaway HOME are confirmed.TestTUIE2E/the_firing_reaches_the_personstill passes. The machine's timer files hash the same before and after, as the subtest asserts itself. The stub log showssystemctl --user enable --now codeaf-tick.timerafter the approval, and the rig's own service definition names the rig'sCODEAF_HOME.How it was verified
systemctl --user daemon-reloadand thensystemctl --user enable --now codeaf-tick.timer. The definition sat under the rig's login folder with the rig'sCODEAF_HOMEand the checkout's binary. The SHA-256 of the developer'scodeaf-tick.serviceandcodeaf-tick.timerwas identical before and after.make pr-ready BASE=origin/devpassed, andgo vetpassed under thee2e,docker_e2eandssh_benchtags.What it deliberately does not do
remotebench_test.go(ssh_bench), which runs the product on another machine over ssh where a local stub cannot reach, orremote_test.go(docker_e2e), whose containers have their own scheduler.🤖 Generated with Claude Code