Repository navigation
refactor(exec): share the user-command execution contract - #48
Merged
Merged
Conversation
johnny4young
marked this pull request as ready for review
October 6, 2026 03:50
johnny4young
commented
Oct 6, 2026
johnny4young
left a comment
Owner
Author
There was a problem hiding this comment.
Review: share the user-command execution contract (run / each)
What it does: moves the duplicated unset GOROOT; PATH="<dir>/bin:$PATH" exec "$@" from cmd_run and cmd_each into _gos_exec_version_command (gos.sh ~L2621-2629), documents the contract in docs/ARCHITECTURE.md, and adds regression tests in tests/side-by-side.bash.
Verdict: ready. Nothing blocking or should-fix.
Checked
- Behavior is unchanged. The helper is a plain function, so in
cmd_runtheexecstill replaces the gos process itself after_gos_release_lock. Incmd_eachthe( … ) || rc=$?subshell is still the process boundary, soGOROOT/PATHcannot leak into the next iteration, andset -ecannot abort the loop. Arguments are forwarded as"$@"/"${command[@]}"and never re-split orevaled, so there is no new injection or word-splitting surface.GOTOOLCHAINis left as the caller set it (the probe-onlyGOTOOLCHAIN=localonly appears as command prefixes in the version probes). - Exit status: a failed
exec(command not found) still exits 127 from the non-interactive shell exactly as before. A signal-derived status (143) propagates throughrunand is collected per version byeach. Both are now covered. - The tests are well designed. The PID-capturing launcher proves there is no wrapper process. The child checks the exact argv (
'two words' '' --json '*'), confirmsGOROOTis unset,GOTOOLCHAINis preserved,PATHis prefixed exactly once, and the lock is released.eachcontinuing after failed and signaled children is also asserted. - Local: full
scripts/run-tests.bash --jobs 4passed exceptinstall-transaction.bash, which also fails onmainin this container because it runs as root (environment-only, unrelated).side-by-side.bashpassed. ShellCheck 0.11.0, shfmt 3.13.1 andbash -nwere clean. CI is green on all 11 checks.
Nits (optional)
- 🟡
gos.shhelper comment: the line "Probe-only GOTOOLCHAIN=local must never leak into the user's command" describes an invariant the helper preserves by not touchingGOTOOLCHAIN. Saying that explicitly ("intentionally does not set or unset GOTOOLCHAIN") would stop a future edit from "fixing" it there. - 🟡 Pre-existing, not introduced here:
execskips the EXIT trap, so any temp state registered for cleanup beforecmd_runreaches the helper is never cleaned up. That seems fine today, since the lock is released explicitly, but it is worth keeping in mind as a documented property of the helper.
Generated by Claude Code
This was referenced Oct 6, 2026
…d-execution # Conflicts: # CHANGELOG.md
- drop the helper's named local, which bash exported over a caller variable - assert a caller-exported version_dir reaches the child unchanged - exercise run's install-then-exec path so the lock check is meaningful - document why the helper must stay free of named locals Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ExmnfUngrDYjAheGvYwMnn
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
cmd_runandcmd_eacheach spelled out the same policy for running a user command: unset the inheritedGOROOT, prepend the resolved version'sbintoPATH, keep the caller'sGOTOOLCHAIN, andexecthe original arguments. This PR moves that policy into one normal (non-subshell) function,_gos_exec_version_command, and leaves process ownership visible at the callers.This is a bounded, behavior-preserving refactor. It does not claim the existing CLI is broken or faster.
What changed
gos.sh: new_gos_exec_version_command <version_dir> <command…>, which doesunset GOROOT; PATH="<dir>/bin:$PATH" exec "$@".runcalls it directly after releasing the mutation lock, so the user command replaces gos and supplies the exit status.eachcalls it inside its existing per-version subshell, so the parent keeps the original environment, collects each status, continues, and prints the same aggregate summary.docs/ARCHITECTURE.md: a new "User-command execution" section covering the contract, the ownership of the lock, environment and status, and why the helper must not become a subshell.CHANGELOG.md: an Unreleased entry.tests/side-by-side.bash: new regressions (below).Resolution, installation, locks, child-argument parsing, stdout routing and the Bash 3.2 floor stay at their existing boundaries.
Why
One definition of the execution boundary keeps
runandeachfrom drifting apart, for example one of them starting to leakGOROOTor to overrideGOTOOLCHAIN.How it was tested
tests/side-by-side.bashchecks:gos run→ user command, which detects any extra wrapper process;--jsonand a literal*;GOROOTis removed, an explicitGOTOOLCHAINis preserved,PATHis exactly what is expected, and the lock is released;eachisolatesPATHper version and continues after child status 23;run, and thateachkeeps collecting signaled children.main05d9e25. Two deliberate negative controls failed as intended (turning the helper into a subshell breaks PID identity; forcingGOTOOLCHAIN=localbreaks the caller's policy) and were removed afterwards.scripts/validate-local.bash, with all 31 Linux suites, command-surface sync, workflow YAML/invariants, ShellCheck 0.11.0, shfmt 3.13.1, Zsh syntax, CLI smoke and whitespace checks.bf2c046: fullscripts/run-tests.bash --jobs 4passed. As root, onlyinstall-transaction.bashfailed, and it fails identically onmain(root cause fixed separately in fix(sudo): keep line endings when replaying captured command output #49). ShellCheck 0.11.0, shfmt 3.13.1 andbash -nwere clean.bf2c046in run 37400338952, including native macOS Bash 3.2, Linux Fish and Windows Bash/PowerShell. All 11 commit checks, including GitGuardian, are green.Review follow-ups
GOTOOLCHAINalone;execskips EXIT traps (a pre-existing, documented property).Decisions taken
run's process-replacement semantics.Known limitations & follow-ups
tests/side-by-side.bashkeeps its existing Windows exclusion and symlink capability probe, so these commands are not Windows execution coverage.Merge order
Independent of the other open PRs: it is based on
mainand doesn't touch their files. Merges cleanly with #44, #45, #46, #47 and #49.