package builder import ( "bytes" "crypto/sha256" "encoding/hex" "os" "os/exec" "path/filepath" "strings" "testing" ) // **A Go bundle does not vary with the commit it was built at** (novox/hq ADR 0267 rule 6, issue 363). A // module built from its repository's root — the controller — is compiled with the clone's `.git` in what // the toolchain sees, and Go stamps the commit, its time and whether the tree was modified into every // binary built there unless told not to. Two builds of one program at commits that differ only in a // README then made two binaries, so an unchanged build source was a new digest. // // The toolchain's own compile line is run here, as the build seat runs it inside the toolchain image: in // two clones at two paths, of two commits that differ outside the program. One digest is wanted. func TestAGoBundleBuiltTwiceFromOneBuildSourceIsOneDigest(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) } } chain, err := ToolchainFor("go") if err != nil { t.Fatal(err) } root := t.TempDir() repo := filepath.Join(root, "origin") files := map[string]string{ "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(repo, name)), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(repo, 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(repo, "init", "-q") git(repo, "add", ".") git(repo, "commit", "-q", "-m", "one") first := git(repo, "rev-parse", "HEAD") if err := os.WriteFile(filepath.Join(repo, "README.md"), []byte("two\n"), 0o644); err != nil { t.Fatal(err) } git(repo, "commit", "-q", "-am", "only the README") second := git(repo, "rev-parse", "HEAD") build := func(commit, at string) string { t.Helper() clone := filepath.Join(root, at) git(root, "clone", "-q", repo, clone) git(clone, "checkout", "-q", commit) out := filepath.Join(clone, Out("server"), "ctl") line := append([]string(nil), chain.Compile...) line = append(line, "-ldflags", strings.Join(chain.LinkerFlags, " "), chain.OutputFlag, out, "./cmd/ctl") cmd := exec.Command(line[0], line[1:]...) cmd.Dir = clone cmd.Env = append(os.Environ(), "GOTOOLCHAIN=local", "GOPROXY=off", "GOWORK=off") if b, err := cmd.CombinedOutput(); err != nil { t.Fatalf("%s: %v\n%s", strings.Join(line, " "), err, b) } body, err := os.ReadFile(out) if err != nil { t.Fatal(err) } if bytes.Contains(body, []byte(commit)) { t.Errorf("the binary built at %s carries the commit it was built at", commit[:12]) } sum := sha256.Sum256(body) return hex.EncodeToString(sum[:]) } a, b := build(first, "a"), build(second, "elsewhere/b") if a != b { t.Fatalf("one build source, two digests: %s at %s, %s at %s (compiled with %q)", a[:12], first[:12], b[:12], second[:12], strings.Join(chain.Compile, " ")) } } // The toolchain says so itself, so a reader of the compile line sees it without running a build. func TestTheGoToolchainStampsNoVersionControl(t *testing.T) { chain, err := ToolchainFor("go") if err != nil { t.Fatal(err) } if joined := strings.Join(chain.Compile, " "); !strings.Contains(joined, "-buildvcs=false") { t.Fatalf("the go toolchain stamps the commit into what it compiles: %q", joined) } } // **And so does every recipe in this repository that compiles Go** (review of issue 363's fix): the // controller's genesis image copies the whole clone, `.git` with it, and the reference images beside it // are built the same way by the Makefile. func TestEveryGoRecipeInThisRepositoryStampsNoVersionControl(t *testing.T) { root := filepath.Join("..", "..") var recipes []string err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error { if err != nil { return err } if d.IsDir() && (d.Name() == "vendor" || d.Name() == "testdata" || d.Name() == ".git") { return filepath.SkipDir } if !d.IsDir() && d.Name() == "Dockerfile" { recipes = append(recipes, path) } return nil }) if err != nil { t.Fatal(err) } if len(recipes) == 0 { t.Fatal("no recipe found in this repository") } for _, path := range recipes { body, err := os.ReadFile(path) if err != nil { t.Fatal(err) } for _, line := range strings.Split(string(body), "\n") { if strings.Contains(line, "go build") && !strings.Contains(line, "-buildvcs=false") { t.Errorf("%s compiles Go and stamps the commit into it: %s", path, strings.TrimSpace(line)) } } } }