Isolate synthetic module downloads in workflow tests

This commit is contained in:
2026-10-08 14:30:08 +00:00
parent ae0e4a0263
commit f2124b3b7b
2 changed files with 49 additions and 19 deletions

View File

@@ -150,6 +150,19 @@ func TestWoodpeckerTagDeliveryTemplate(t *testing.T) {
}
func TestWoodpeckerTagDeliveryUsesTaggedModuleVersion(t *testing.T) {
// Synthetic downloads must leave the caller's module cache untouched.
callerCache := t.TempDir()
t.Setenv("GOMODCACHE", callerCache)
t.Cleanup(func() {
entries, err := os.ReadDir(callerCache)
if err != nil {
t.Fatal(err)
}
if len(entries) != 0 {
t.Errorf("synthetic module downloads modified the caller's cache: %v", entries)
}
})
root := cliRepositoryRoot(t)
contents, err := os.ReadFile(filepath.Join(root, "examples", "woodpecker", "tag-delivery.yml"))
if err != nil {
@@ -185,7 +198,7 @@ func TestWoodpeckerTagDeliveryUsesTaggedModuleVersion(t *testing.T) {
moduleBefore := readWoodpeckerFixtureFile(t, filepath.Join(repository, "go.mod"))
commit := oldCommit
env := templateEnvironment(repository, commit, goDir, goLog)
env["GOPROXY"] = "file://" + filepath.ToSlash(proxy)
useSyntheticModuleProxy(t, env, "file://"+filepath.ToSlash(proxy))
sumLog := filepath.Join(t.TempDir(), "tool-only-sums")
env["RELEASEKIT_SUM_LOG"] = sumLog
output := runWoodpeckerBlock(t, command, repository, env)
@@ -207,7 +220,7 @@ func TestWoodpeckerTagDeliveryUsesTaggedModuleVersion(t *testing.T) {
commit := pushTaggedCLIRepository(t, repository)
moduleBefore := readWoodpeckerFixtureFile(t, filepath.Join(repository, "go.mod"))
env := templateEnvironment(repository, commit, goDir, goLog)
env["GOPROXY"] = "file://" + filepath.ToSlash(proxy)
useSyntheticModuleProxy(t, env, "file://"+filepath.ToSlash(proxy))
sumLog := filepath.Join(t.TempDir(), "tool-only-sums")
env["RELEASEKIT_SUM_LOG"] = sumLog
output := runWoodpeckerBlock(t, command, repository, env)
@@ -245,21 +258,15 @@ func TestWoodpeckerSourceDeliveryTemplateSelfBootstraps(t *testing.T) {
defer proxy.Close()
writeRepositoryFile(t, repository, "go.mod", "module example.com/cli-candidate\n\ngo 1.25.0\n\nrequire "+dependency+" v1.0.0\n")
writeRepositoryFile(t, repository, "cmd/releasekit/main.go", "package main\n\nimport (\"fmt\"; \"os\"; helper \""+dependency+"\")\n\nfunc main() {\n\tfmt.Println(\"self-bootstrap \" + helper.Message)\n\tfmt.Printf(\"tool-args=%q\\n\", os.Args[1:])\n}\n")
preparationEnv := map[string]string{
"GOPROXY": proxy.URL, "GOSUMDB": "off", "GONOPROXY": "none", "GOPRIVATE": "",
"GOWORK": "off", "GOTOOLCHAIN": "local", "GOENV": "off", "GOFLAGS": "-modcacherw",
"GOMODCACHE": t.TempDir(),
}
preparationEnv := map[string]string{}
useSyntheticModuleProxy(t, preparationEnv, proxy.URL)
runWoodpeckerBlock(t, "go mod download "+dependency, repository, preparationEnv)
cliGitRun(t, repository, "add", "cmd/releasekit/main.go", "go.mod", "go.sum")
cliGitRun(t, repository, "commit", "-m", "add the self-bootstrapped command")
commit := pushTaggedCLIRepository(t, repository)
goDir, goLog := installGoBootstrapShim(t)
env := templateEnvironment(repository, commit, goDir, goLog)
for key, value := range preparationEnv {
env[key] = value
}
env["GOMODCACHE"] = t.TempDir()
useSyntheticModuleProxy(t, env, proxy.URL)
proxyRequests.Store(0)
env["CI_COMMIT_SHA"] = strings.Repeat("0", len(commit))
if output, err := executeWoodpeckerBlock(command, repository, env); err == nil {
@@ -426,6 +433,19 @@ esac
return shimDir, goLog
}
func useSyntheticModuleProxy(t *testing.T, environment map[string]string, proxyURL string) {
t.Helper()
environment["GOMODCACHE"] = t.TempDir()
environment["GOPROXY"] = proxyURL
environment["GOSUMDB"] = "off"
environment["GONOPROXY"] = "none"
environment["GOPRIVATE"] = ""
environment["GOWORK"] = "off"
environment["GOTOOLCHAIN"] = "local"
environment["GOENV"] = "off"
environment["GOFLAGS"] = "-modcacherw"
}
func templateEnvironment(repository, commit, shimDir, goLog string) map[string]string {
realGo, _ := exec.LookPath("go")
return map[string]string{

View File

@@ -1,7 +1,7 @@
# PromptKit Bug Report: v0.2.0 Module Checksum Mismatch
**Status:** Stale local module metadata confirmed; cache recovery and test
isolation follow-up remain pending.
**Status:** Stale local module metadata confirmed; test isolation fixed.
Shared-cache recovery and PromptKit's adoption retry remain pending.
## Summary
@@ -95,22 +95,32 @@ Recovery was verified in a copied cache; PromptKit's adoption retry remains pend
### Related Test-Isolation Defect
The workflow tests' [environment helper](../../cmd/releasekit/woodpecker_test.go)
disables checksum verification for synthetic fixtures and inherits the caller's
disabled checksum verification for synthetic fixtures and inherited the caller's
module cache. The version-selection test serves synthetic ReleaseKit versions
from a local module proxy.
Running `TestWoodpeckerTagDeliveryUsesTaggedModuleVersion` with a disposable
inherited `GOMODCACHE` passed and left synthetic `v0.2.197` and `v0.2.198`
metadata in that cache. This confirms that the tests can contaminate a
developer's module cache. It establishes a related defect; attribution of the
metadata in that cache. This confirmed that the tests could contaminate a
developer's module cache. It established a related defect; attribution of the
stale `v0.2.0` entry to a particular test or command remains unconfirmed.
### Test-Isolation Resolution
Both synthetic-proxy test families now use a shared environment helper that
assigns a fresh test-owned `GOMODCACHE` and scopes proxy/checksum settings to
their Go subprocesses. Source-bootstrap preparation and execution retain
separate caches. Tests that build real ReleaseKit source continue to use their
prepared dependencies.
The existing tagged-version test now supplies a disposable caller cache and
asserts that it remains empty after fixture execution. This regression failed
before the fix and passed afterward. All Woodpecker workflow tests passed.
## Recommended Follow-Up
1. Quarantine the affected local `v0.2.0.mod` entry and retry PromptKit's adoption
with normal checksum verification. Retain the quarantined bytes as evidence.
2. Give synthetic module-proxy tests a temporary `GOMODCACHE` owned by the test
fixture, with focused regression coverage for cache isolation.
3. Record the actual cache recovery and consumer retry outcomes here. Preserve
2. Record the actual cache recovery and consumer retry outcomes here. Preserve
the published v0.2.0 tag and checksums; this incident requires no replacement
release.