Skip to content

refactor: delete what buys nothing, and give the trust path one definition - #59

Merged
rldyourmnd merged 2 commits into
mainfrom
feat/no-unenforced-ceremony
Aug 15, 2026
Merged

refactor: delete what buys nothing, and give the trust path one definition#59
rldyourmnd merged 2 commits into
mainfrom
feat/no-unenforced-ceremony

Conversation

@rldyourmnd

Copy link
Copy Markdown
Contributor

Three statements cost maintenance and bought no enforcement.

upstream_go_mod — deleted

Required to be non-empty; read by nothing. Not fetched, not hashed, not parsed, not compared. Either URL could have been replaced with arbitrary text and every check stayed green.

Deleted rather than made executable, because nothing needs the fact it gestured at. That is the criterion: name what gets through if you remove it, or it is ceremony.

The trust path had one fact in two places

git was a constant in signatureverify and a raw literal in provenance, and the isolated git environment was spelled out twice. Which file the name git refers to decides what a signature verdict is worth, so that is the worst possible place for two definitions.

internal/trustedexec is now the single one. It keeps the property that made the hardcoded path defensible — never reads PATH — and adds what the hardcoded path lacked:

  • fixed, ordered search over absolute directories, so a Homebrew macOS host can verify
  • result must be a regular, non-symlink file, not group or world writable
  • children of the trust path get exactly those directories as their PATH, nothing inherited
  • failure names every directory searched instead of surfacing as an obscure exec error

Tested directly rather than assumed: with PATH pointing at a planted git, resolution still returns the fixed location.

The cost is stated, not hidden. Nix and Guix hosts still cannot verify — their tools are outside every absolute directory the resolver will search, and any mechanism covering them (an env override, a PATH search) is an ambient input into the one code path that must not have any. SECURITY.md says so with the reason.

Composing the two environments naively duplicated every git config setting; the shared half now lives in the resolver and the signature verifier adds only what is specific to running git interactively.

The GDS anchor argued against itself

It declared commit-contract / default-branch-commit, justified by a comment saying no semver tag existed. That stopped being true at v0.1.2 — beside publication.github_release: "required" and four live tags.

Now semver / version-tag, matching your answer that the control plane pins by release tag, and stating why those are two axes: what this repository promises a consumer, and how this estate chooses to take it.

Verification

gofmt, go vet, staticcheck v0.7.0, full suite under umask 002, -race, all seven contract checkers. All green.

…ition

Three statements in this repository cost maintenance and bought no enforcement.

upstream_go_mod was required to be non-empty and read by nothing — not fetched,
not hashed, not parsed, not compared. Either URL could have been replaced with
arbitrary text and every check stayed green. It is deleted rather than made
executable, because nothing needs the fact it was gesturing at.

The git executable was a constant in signatureverify and a raw literal in
provenance, and the isolated git environment was spelled out twice. One fact in
two places, in the code path where drift matters most: which file the name git
refers to decides what a signature verdict is worth.

internal/trustedexec is now the single definition. It searches a fixed, ordered
list of absolute directories and never reads PATH, because whoever can set an
environment variable must not be able to choose the program that rules on a
signature. The result must be a regular, non-symlink file that is not group or
world writable. Children of the trust path get exactly those directories as
their PATH and nothing they inherited. A Homebrew macOS host can now verify,
which the single hardcoded path did not allow.

The cost is stated rather than hidden: a host keeping its tools outside those
directories — Nix and Guix in practice — cannot verify at all, because every
mechanism that would cover them is an ambient input into the one code path that
must not have any. Failure names what was searched instead of surfacing as an
obscure exec error.

The GDS anchor said the module carried no semver tag, so the consumer contract
was the pinned commit. That stopped being true at v0.1.2. It now declares semver
and version-tag, and says why those are two axes rather than one: what this
repository promises a consumer, and how this estate chooses to take it.
@rldyourmnd
rldyourmnd enabled auto-merge August 15, 2026 00:13
CI rejected the first attempt on both platforms. The fixture created its file
with WriteFile(0o777), and a creation mode is masked by the process umask: under
the 022 umask CI uses the file landed at 0755, was correctly accepted, and the
case asserted nothing. It only passed locally because the suite had been run
under umask 002, where 0777 becomes 0775 and is group writable.

This repository has paid for that lesson once already, in the release suite, and
the new test reintroduced it. Modes are now set with Chmod, which the umask does
not touch, and asserted before the case runs. Group-writable, world-writable and
both are covered, together with the owner-writable control that must resolve,
and a symlinked tool that a plain Stat would have followed.

The search also no longer reaches through the package-level list, so a test can
exercise the rules without mutating state that parallel tests read.

Verified under umask 022, 002 and 077, and with -race.
@rldyourmnd
rldyourmnd merged commit 9c56c55 into main Aug 15, 2026
4 checks passed
@rldyourmnd
rldyourmnd deleted the feat/no-unenforced-ceremony branch August 15, 2026 00:22
@rldyourmnd rldyourmnd mentioned this pull request Aug 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant