fix(ahoy): an explicit ABCD_BIN_TARGET is a sandbox, not a hint - #520
Merged
Conversation
effectiveBinTarget answers which PATH entry a verb acts on, and it answered by preferring any owned entry it could find, falling back to binTarget() only when there was none. In production that is right: ABCD_BIN_TARGET is unset, and an install that finds an abcd it already owns should update that one rather than leave a second copy elsewhere. Under test it escapes the sandbox. hermeticRepo's own docstring says it "redirects HOME, the plugin root and the PATH symlink target to temp locations", so sandboxing the install target is its stated contract; the preference silently overrode it, and an `ahoy install` reached from such a test adopted a real PATH entry and rewrote it to point inside a tempdir the test then deleted. The machines that dogfood the installer are exactly the machines with an owned entry to find. So an explicitly set ABCD_BIN_TARGET now wins. Adoption is untouched when it is unset, which is every production path. The precondition is narrower than the naive statement of the bug, and the record says so rather than overclaiming: classifyBinTarget calls an entry owned only for a symlink into the plugin root, a dev shim, or a regular file whose provenance is recorded at ~/.abcd/path-entry and whose bytes still hash to the recorded sha. A plain release binary with no provenance record classifies foreign and was never adopted, which is why a release-only install on this machine survived two full suite runs untouched while a dev-shim install on the same machine sits in the at-risk population. Two tests, both halves. The suppression case was watched failing against the old adoption order; the unset case guards the production behaviour the fix must not change. Resolves: iss-2608261447262355 Assisted-by: Claude:claude-opus-5
REPPL
enabled auto-merge
August 26, 2026 15:02
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 the sandbox escape #515 deliberately left open, and the one it labelled a design decision rather than a bug fix.
The defect
effectiveBinTargetanswers which PATH entry a verb acts on. It preferred any owned entry it could find, falling back tobinTarget()only when there was none.In production that is correct:
ABCD_BIN_TARGETis unset, and an install that finds anabcdit already owns should update that one rather than leave a second copy elsewhere. Adoption is howahoy installstays idempotent.Under test it escapes the sandbox.
hermeticRepo's own docstring says it "redirects HOME, the plugin root and the PATH symlink target to temp locations" — sandboxing the install target is its stated contract. The preference silently overrode it, so anahoy installreached from such a test adopted a real PATH entry and rewrote it to point inside a tempdir the test then deleted. The machines that dogfood the installer are exactly the machines with an owned entry to find.The fix
An explicitly set
ABCD_BIN_TARGETwins. A caller that names a target has asked for a specific file, and the only callers that name one are tests asking for a sandbox. Adoption is untouched when the variable is unset, which is every production path.The precondition, measured
The naive statement of this bug overclaims, and the record says so rather than repeating it.
classifyBinTargetcalls an entry owned only for a symlink into the plugin root, a dev shim, or a regular file whose provenance is recorded at~/.abcd/path-entryand whose bytes still hash to the recorded sha. A plain release binary with no provenance record classifiesbinTargetForeignand was never adopted.That is why a release-only install on this machine survived two full
go test ./...runs today byte-identical, while a dev-shim install on the same machine sits squarely in the at-risk population. A peer session supplied the survival datum, which is what prompted measuring the precondition instead of asserting it — a test pinning the wrong precondition would have gone green while guarding nothing.Tests
Two, both halves:
TestExplicitBinTargetSuppressesAdoption— watched failing against the old adoption order, which returned the owned entry instead of the named sandbox.TestAdoptionStillWinsWhenBinTargetIsUnset— guards the production behaviour the fix must not change.Checks
make preflightexit 0,gofmt -l .clean. Branched from currentorigin/main. Resolvesiss-2608261447262355, whose record movesopen/→resolved/in this diff, so RS001 is satisfied.Assisted-by: Claude:claude-opus-5