diff --git a/internal/builder/replay363_test.go b/internal/builder/replay363_test.go new file mode 100644 index 00000000..07271d28 --- /dev/null +++ b/internal/builder/replay363_test.go @@ -0,0 +1,152 @@ +package builder + +import ( + "context" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" +) + +// TestReplay363 is the replay of novox/hq issue 363's built part (ADR 0267 rule 6), written with only what the +// builder had before its fix (mesh-controller #292), so mesh-lab's prover can lay it over the commit before. +// +// A Go module built from its repository's root — the controller, the node-engine — is compiled with the clone's +// `.git` in view, and Go stamped the commit, its time and whether the tree was modified into the binary. On +// 2026-10-13 the node-engine running on the laptop carried `vcs.revision=7a41e120…` in its build info, so a merge +// that changed only its README made a new digest of an unchanged program. Before the fix the two builds below give +// two digests; after it (`-buildvcs=false` in the Go toolchain) they give one. +// +// It runs the builder whole, Build to the published bundle, with a container runtime that runs the toolchain's +// command on this machine: the module's directory mounted where the toolchain would see it, the real git and the +// real Go compiler. Two builds of one module at two commits that differ only in README.md, outside its build source. +func TestReplay363(t *testing.T) { + for _, tool := range []string{"go", "git"} { + if _, err := exec.LookPath(tool); err != nil { + t.Skipf("%s is not on this machine: %v", tool, err) + } + } + root := t.TempDir() + origin := filepath.Join(root, "origin") + files := map[string]string{ + "module.json": `{"module":"ctl","version":"1","build":{"artifacts":[` + + `{"name":"runtime","kind":"bundle","language":"go","system":"arch","from":"cmd/ctl","binary":"ctl"}]},` + + `"resources":[{"id":"runtime","type":"process","name":"ctl","artifact":"runtime","run":["./ctl"]}]}`, + "go.mod": "module example.com/ctl\n\ngo 1.22\n", + "cmd/ctl/main.go": "package main\n\nfunc main() { println(\"ctl\") }\n", + "README.md": "one\n", + } + for name, body := range files { + if err := os.MkdirAll(filepath.Dir(filepath.Join(origin, name)), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(origin, name), []byte(body), 0o644); err != nil { + t.Fatal(err) + } + } + git := func(dir string, args ...string) string { + t.Helper() + cmd := exec.Command("git", append([]string{"-c", "user.name=t", "-c", "user.email=t@example.invalid", + "-c", "commit.gpgsign=false", "-c", "init.defaultBranch=main"}, args...)...) + cmd.Dir = dir + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("git %s: %v\n%s", strings.Join(args, " "), err, out) + } + return strings.TrimSpace(string(out)) + } + git(origin, "init", "-q") + git(origin, "add", ".") + git(origin, "commit", "-q", "-m", "one") + first := git(origin, "rev-parse", "HEAD") + if err := os.WriteFile(filepath.Join(origin, "README.md"), []byte("two\n"), 0o644); err != nil { + t.Fatal(err) + } + git(origin, "commit", "-q", "-am", "only the README") + second := git(origin, "rev-parse", "HEAD") + + held := map[string]string{"mesh-tools-go/build": "registry.invalid/mesh-tools-go/build@sha256:" + strings.Repeat("b", 64)} + build := func(commit, at string) string { + t.Helper() + got, err := Build(context.Background(), replay363Runtime(t), replay363Store{}, origin, "", commit, + filepath.Join(root, at), held, Npmrc{}, GitCredential{}, nil) + if err != nil { + t.Fatalf("the build at %s: %v", commit[:12], err) + } + if len(got.Built) != 1 || got.Built[0].Digest == "" { + t.Fatalf("the build at %s made %+v", commit[:12], got.Built) + } + return got.Built[0].Digest + } + a, b := build(first, "one"), build(second, "elsewhere/two") + if a != b { + t.Fatalf("one build source, two digests: %s at %s, %s at %s — a README-only merge is a new program", + a, first[:12], b, second[:12]) + } +} + +// replay363Store publishes nothing: the digest is the builder's own, over the packed bundle. +type replay363Store struct{} + +func (replay363Store) PublishImage(_ context.Context, local, repository string) (string, error) { + return "registry.invalid/" + repository + "@sha256:" + strings.Repeat("c", 64), nil +} + +func (replay363Store) PublishArchive(_ context.Context, repository string, _ []byte, digest string) (string, error) { + return "artifact-store://" + repository + "@" + digest, nil +} + +// replay363Runtime runs every command on this machine, and a toolchain container's command in the directory +// mounted for it, as the container would see it: nothing above the mounted directory. +func replay363Runtime(t *testing.T) Runner { + t.Helper() + return func(ctx context.Context, dir, name string, args ...string) (string, error) { + if name == "docker" && len(args) > 0 && args[0] == "run" { + mounts := map[string]string{} + workdir := "" + i := 1 + for i < len(args) { + switch args[i] { + case "--rm": + i++ + continue + case "--volume": + host, inside, _ := strings.Cut(args[i+1], ":") + mounts[inside] = host + i += 2 + continue + case "--workdir": + workdir = args[i+1] + i += 2 + continue + case "--network", "--user", "--env", "-e", "--label", "--name": + i += 2 + continue + } + break + } + command := args[i+1:] // the image is args[i] + where := dir + for inside, host := range mounts { + if workdir == inside { + where = host + } else if rest, ok := strings.CutPrefix(workdir, inside+"/"); ok { + where = filepath.Join(host, rest) + } + } + cmd := exec.CommandContext(ctx, command[0], command[1:]...) + cmd.Dir = where + cmd.Env = append(os.Environ(), "GOTOOLCHAIN=local", "GOPROXY=off", "GOWORK=off", "GOFLAGS=") + out, err := cmd.CombinedOutput() + if err != nil { + return string(out), &exec.ExitError{ProcessState: cmd.ProcessState, Stderr: out} + } + return string(out), nil + } + cmd := exec.CommandContext(ctx, name, args...) + cmd.Dir = dir + out, err := cmd.Output() + return string(out), err + } +}