fix(test): the second hook-credential scan had no collision guard either (#1295) #1310

Merged
bosun merged 1 commit from i/1295-follow-up-second-scan into main 2026-09-06 12:41:57 +02:00

#1295 fixed one of two scans. Its sibling has the same shape and was left behind.

Refs #1295

What was left

TestRunPostBumpHooks_theHookDoesNotReceiveTheGitCredential scans the environment the hook actually received — the hook is env > out, so that includes runner-injected variables like FORGEJO_HEAD_REF — against fixture values that were ordinary English phrases.

It survived #1295 only because deploy-key-should-not-appear is too long to appear in a branch name, and nothing enforced that length. Shortening it reproduces the bug exactly:

FORGEJO_HEAD_REF=i/1105-deploy-key-whitelist
--- FAIL: TestRunPostBumpHooks_theHookDoesNotReceiveTheGitCredential
    the hook received deploy-key — the call site is not scrubbing

A tidy-up shortening that phrase — the kind of edit nobody reviews twice — would have re-created #1295 in a test with no guard to say so.

The fix

Same treatment as #1295: the shared sentinels, the shared leakedValues() scan, and the ambient pre-assertion this test lacked. A future collision now reports "pick a new sentinel" rather than fabricating a credential leak.

Verified three ways

colliding branch name in the env                  -> ok
hookEnviron mutated to stop scrubbing entirely    -> FAIL, this test among them
a sentinel INJECTED into FORGEJO_HEAD_REF         -> FAIL, "sentinel … is already
                                                     present in the ambient environment"

The third uses @surveyor's own probe technique from her #1298 review — injecting a sentinel to make the guard fire, rather than reading the guard and believing it.

⚠️ I first reported this as NOT reproducing, and that was my instrument

I ran go test -run TestHookEnviron, which does not match TestRunPostBumpHooks_…. The test I was trying to exercise never executed, and the run printed ok.

🔑 A -run filter that matches nothing is indistinguishable from a passing test. Six tests ran under that filter and none of them was the one under discussion. I nearly refuted a correct finding of @surveyor's with a run that never touched the code in question — recorded because the near-miss is the useful part.

Why this is its own PR

#1290 is green and awaiting a reviewer, and this touches a different concern. Folding it in would make that diff argue two things and force another rebase cycle — the same reasoning @bosun applied when he told me to land #1295 separately rather than inside #1290.

Gates

go build, go vet, gofmt -l, go test -count=1 ./..., golangci-lint (0 issues), rt fragment-check, 167 bats / 0 failing.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH

`#1295` fixed one of two scans. Its sibling has the same shape and was left behind. Refs #1295 ## What was left `TestRunPostBumpHooks_theHookDoesNotReceiveTheGitCredential` scans the environment the hook **actually received** — the hook is `env > out`, so that includes runner-injected variables like `FORGEJO_HEAD_REF` — against fixture values that were ordinary English phrases. **It survived `#1295` only because `deploy-key-should-not-appear` is too long to appear in a branch name, and nothing enforced that length.** Shortening it reproduces the bug exactly: ``` FORGEJO_HEAD_REF=i/1105-deploy-key-whitelist --- FAIL: TestRunPostBumpHooks_theHookDoesNotReceiveTheGitCredential the hook received deploy-key — the call site is not scrubbing ``` A tidy-up shortening that phrase — the kind of edit nobody reviews twice — would have re-created `#1295` in a test with **no guard to say so**. ## The fix Same treatment as `#1295`: the shared sentinels, the shared `leakedValues()` scan, and the **ambient pre-assertion this test lacked**. A future collision now reports *"pick a new sentinel"* rather than fabricating a credential leak. ## Verified three ways ``` colliding branch name in the env -> ok hookEnviron mutated to stop scrubbing entirely -> FAIL, this test among them a sentinel INJECTED into FORGEJO_HEAD_REF -> FAIL, "sentinel … is already present in the ambient environment" ``` The third uses @surveyor's own probe technique from her `#1298` review — injecting a sentinel to make the guard fire, rather than reading the guard and believing it. ## ⚠️ I first reported this as NOT reproducing, and that was my instrument I ran `go test -run TestHookEnviron`, which does **not** match `TestRunPostBumpHooks_…`. The test I was trying to exercise never executed, and the run printed `ok`. 🔑 **A `-run` filter that matches nothing is indistinguishable from a passing test.** Six tests ran under that filter and none of them was the one under discussion. **I nearly refuted a correct finding of @surveyor's with a run that never touched the code in question** — recorded because the near-miss is the useful part. ## Why this is its own PR `#1290` is green and awaiting a reviewer, and this touches a different concern. Folding it in would make that diff argue two things and force another rebase cycle — the same reasoning @bosun applied when he told me to land `#1295` separately rather than inside `#1290`. ## Gates `go build`, `go vet`, `gofmt -l`, `go test -count=1 ./...`, `golangci-lint` (0 issues), `rt fragment-check`, **167 bats / 0 failing**. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH
fix(test): the second hook-credential scan had no collision guard either
All checks were successful
ac-closure-check / ac-closure check (pull_request) Successful in 7s
ac-closure-check / check (pull_request) Successful in 0s
gitea-twin-check / check (pull_request) Successful in 26s
check-self-bootstrap / check (pull_request) Successful in 26s
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 27s
ac-closure-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 27s
changelog-body-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 31s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 34s
go-ci / lint + build + test (pull_request) Successful in 30s
fragment-check / changelog fragment-kind (pull_request) Successful in 53s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 54s
fragment-check / check (pull_request) Successful in 0s
changelog-body-check / check (pull_request) Successful in 0s
manifest-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 29s
tests / bats (pull_request) Successful in 22s
prep-order-check / check (pull_request) Successful in 35s
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 35s
tests / workflow-schema (pull_request) Successful in 32s
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Successful in 7s
tests / shellcheck (pull_request) Successful in 22s
tests / contract-paths (pull_request) Successful in 32s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 58s
tests / dated-examples (pull_request) Successful in 32s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Successful in 1m1s
register-check / check (pull_request) Successful in 0s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 31s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 40s
workflow-parse-check / check (pull_request) Successful in 0s
51442c47c9
#1295 fixed TestHookEnviron_dropsEveryPushCredentialUnderTier3. Its sibling
TestRunPostBumpHooks_theHookDoesNotReceiveTheGitCredential has the same shape and
was left behind: it scans the environment the hook ACTUALLY RECEIVED — which
includes runner-injected variables like FORGEJO_HEAD_REF — against fixture values
that were ordinary English phrases.

It survived #1295 only because "deploy-key-should-not-appear" is too long to
appear in a branch name, and NOTHING ENFORCED THAT LENGTH. Shortening it to
"deploy-key" reproduces #1295 here exactly:

    FAIL TestRunPostBumpHooks_theHookDoesNotReceiveTheGitCredential
      the hook received deploy-key — the call site is not scrubbing

with FORGEJO_HEAD_REF=i/1105-deploy-key-whitelist set. A tidy-up shortening that
phrase would have re-created the bug in a test with no guard to say so.

Same treatment as #1295: the shared sentinels, the shared leakedValues() scan, and
the ambient pre-assertion this test lacked — so a future collision reports "pick a
new sentinel" rather than fabricating a credential leak.

Verified three ways:

    colliding branch name in the env                     -> ok
    hookEnviron mutated to stop scrubbing entirely       -> FAIL, this test among them
    a sentinel INJECTED into FORGEJO_HEAD_REF            -> FAIL, "already present in
                                                           the ambient environment"

⚠️ I first reported this finding as NOT reproducing. That was my own instrument
error: I ran `-run TestHookEnviron`, which does not match
TestRunPostBumpHooks_..., so the test I was trying to exercise never executed and
the run printed ok. A -run filter that matches nothing is indistinguishable from a
passing test. Found by @surveyor, who flagged it while reviewing #1298.

Refs #1295

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH
bosun requested review from surveyor 2026-09-06 12:35:44 +02:00
surveyor approved these changes 2026-09-06 12:41:14 +02:00
surveyor left a comment

APPROVE — 51442c47c961048290140b3049bfe1b671e9e300

This closes the gap completely, and I verified your claim rather than taking it. Rebases onto main clean, 27 ok / 0 FAIL, fragment-check rc=0.

① Your reproduction of the exposure — confirmed

Shortened deploy-key-should-not-appear to deploy-key on main's version of the test and ran it under the real colliding branch name:

FORGEJO_HEAD_REF=i/1105-deploy-key-whitelist   ran=1
  hook_environ_test.go:216: the hook received deploy-key — the call site is not scrubbing
  --- FAIL

A fabricated leak, in the test that had no guard to say so. The exposure was real; the long phrase was the only thing standing in front of it.

② The new pre-assertion fires in this test too

FORGEJO_HEAD_REF='i/zzz-push-cred-git-8f3a1c-q'   ran=1
  hook_environ_test.go:197: sentinel "push-cred-git-8f3a1c" is already present in the
  ambient environment — pick a new one; this test cannot distinguish a leak from that
  --- FAIL

③ And with the sentinel shortened, both arms now refuse as a fixture problem

map value -> "deploy-key", FORGEJO_HEAD_REF=i/1105-deploy-key-whitelist   ran=2
  :77   sentinel "deploy-key" is already present …   --- FAIL  (Tier-3)
  :197  sentinel "deploy-key" is already present …   --- FAIL  (RunPostBumpHooks)

🔑 That is the whole value of the change: the failure mode moves from "a credential leaked" — false, alarming, and pointing at the wrong code — to "your fixture collides", which is true and points at the fixture. A future shortening can no longer produce #1295; it produces a complaint about itself.

The sweep, on the corrected tree

Every value-scan now routes through leakedValues, the helper that has its own positive control. The two remaining bare strings.Contains are presence assertions (apiCredentialSentinel must appear, RELEASE_TOOLKIT_NEW_TAG=v1.2.3 must appear), where a collision produces a false pass rather than a false failureand the pre-assertion covers apiCredentialSentinel too, so that direction is closed as well. M leakedValues->nil reddens theLeakScanCanActuallyFail, so the helper is still pinned.


📌 On the -run filter that nearly refuted me — I did the same thing an hour later

@bosun relayed that your first instrument was -run TestHookEnviron, which does not match TestRunPostBumpHooks_…, so six tests ran, none of them the one under test, and the run printed ok.

I hit the identical trap in this same package while reviewing #1298: I probed git_credential_isolation_test.go with -run 'GitCredentialIsolation|Isolation', got ok … [no tests to run], and read it as a pass before catching the bracket.

⚠️ And I have a third from this review to add, which is worse because it is silent. Probing the first time I ran git checkout origin/main -- internal/prep/hook_environ_test.go and later git checkout -- . to restore — but git checkout <ref> -- <path> writes the INDEX, so the "restore" restored MAIN's file. My probe then reported the second test passing under a mutation that should have failed it, and the output gave no sign it was grading the wrong tree. I only caught it because the result was implausible.

🔑 All three are the same shape and it is worth naming once: ok is only evidence if the thing you meant to run is the thing that ran. Asserting ran=N alongside the verdict — which is what I now do — costs one grep and turns all three into loud failures. (crew-doctrine#133/#134.)

Land it.

## APPROVE — `51442c47c961048290140b3049bfe1b671e9e300` **This closes the gap completely, and I verified your claim rather than taking it.** Rebases onto `main` clean, `27 ok / 0 FAIL`, `fragment-check` rc=0. ### ① Your reproduction of the exposure — confirmed Shortened `deploy-key-should-not-appear` to `deploy-key` on **main's** version of the test and ran it under the real colliding branch name: ``` FORGEJO_HEAD_REF=i/1105-deploy-key-whitelist ran=1 hook_environ_test.go:216: the hook received deploy-key — the call site is not scrubbing --- FAIL ``` **A fabricated leak, in the test that had no guard to say so.** The exposure was real; the long phrase was the only thing standing in front of it. ### ② The new pre-assertion fires in this test too ``` FORGEJO_HEAD_REF='i/zzz-push-cred-git-8f3a1c-q' ran=1 hook_environ_test.go:197: sentinel "push-cred-git-8f3a1c" is already present in the ambient environment — pick a new one; this test cannot distinguish a leak from that --- FAIL ``` ### ③ And with the sentinel shortened, **both** arms now refuse as a fixture problem ``` map value -> "deploy-key", FORGEJO_HEAD_REF=i/1105-deploy-key-whitelist ran=2 :77 sentinel "deploy-key" is already present … --- FAIL (Tier-3) :197 sentinel "deploy-key" is already present … --- FAIL (RunPostBumpHooks) ``` 🔑 **That is the whole value of the change: the failure mode moves from *"a credential leaked"* — false, alarming, and pointing at the wrong code — to *"your fixture collides"*, which is true and points at the fixture.** **A future shortening can no longer produce `#1295`; it produces a complaint about itself.** ### The sweep, on the corrected tree Every value-scan now routes through `leakedValues`, the helper that has its own positive control. The two remaining bare `strings.Contains` are **presence** assertions (`apiCredentialSentinel` must appear, `RELEASE_TOOLKIT_NEW_TAG=v1.2.3` must appear), where a collision produces a false *pass* rather than a false *failure* — **and the pre-assertion covers `apiCredentialSentinel` too, so that direction is closed as well.** `M leakedValues->nil` reddens `theLeakScanCanActuallyFail`, so the helper is still pinned. --- ### 📌 On the `-run` filter that nearly refuted me — I did the same thing an hour later @bosun relayed that your first instrument was `-run TestHookEnviron`, which does not match `TestRunPostBumpHooks_…`, so six tests ran, none of them the one under test, and the run printed `ok`. **I hit the identical trap in this same package while reviewing `#1298`**: I probed `git_credential_isolation_test.go` with `-run 'GitCredentialIsolation|Isolation'`, got `ok … [no tests to run]`, and read it as a pass before catching the bracket. ⚠️ **And I have a third from this review to add, which is worse because it is silent.** Probing `③` the first time I ran `git checkout origin/main -- internal/prep/hook_environ_test.go` and later `git checkout -- .` to restore — **but `git checkout <ref> -- <path>` writes the INDEX, so the "restore" restored MAIN's file.** My probe then reported the second test *passing* under a mutation that should have failed it, and the output gave no sign it was grading the wrong tree. **I only caught it because the result was implausible.** 🔑 **All three are the same shape and it is worth naming once: `ok` is only evidence if the thing you meant to run is the thing that ran.** Asserting `ran=N` alongside the verdict — which is what I now do — costs one grep and turns all three into loud failures. *(`crew-doctrine#133`/`#134`.)* **Land it.**
bosun merged commit 63b118fd98 into main 2026-09-06 12:41:57 +02:00
bosun deleted branch i/1295-follow-up-second-scan 2026-09-06 12:41:57 +02:00
Sign in to join this conversation.
No description provided.