From e023f69989abab0bc618da8a38c617f1162da814 Mon Sep 17 00:00:00 2001 From: mesh-tools Date: Wed, 21 Oct 2026 09:52:22 +0000 Subject: [PATCH] Compare an archive's tar stream with the build agent's always and its digest only under the Go it was captured with (issue 1589) --- .../cmd/mesh-build-go/archive_test.go | 57 ++++++++++++++++--- .../mesh-build-go/testdata/captured/README | 5 ++ 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/archive_test.go b/modules/mesh-build-go/cmd/mesh-build-go/archive_test.go index 90d75fe4..af421032 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/archive_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/archive_test.go @@ -1,12 +1,17 @@ package main import ( + "compress/gzip" "context" + "crypto/sha256" + "encoding/hex" + "io" "net" "net/http" "net/http/httptest" "os" "path/filepath" + "runtime" "strings" "testing" @@ -23,6 +28,44 @@ const ( releaseSHA256 = "2c9e5753c06902072422c4e9424154e8177684cc74af0bcc8dfe2bdf223a7e95" ) +// The sha256 of the same archives once gunzipped: the tar stream the build agent's pack writes. The gzip bytes, and so +// the digest, may belong to the Go that compressed them; the stream does not. The digests above are compared only under +// the Go they were captured with (go1.27.1, testdata/captured/README), the streams always: the first merge check of +// issue 1589 answered other digests than these under another toolchain, and the streams tell whether the cause is the +// compression or the content. +const ( + buildAgentDirectoryStream = "f8af1d94b8753665e34d2f0ac2d576f8488dafd3eaba536ee86831848278d1b6" + buildAgentWithinStream = "294e2bec7548eddc73812dd218fce403cbd460d5d699f497e09f0965e7e607fb" + buildAgentFileStream = "055cffc2e4a8f3af82339dc597328594ff331a48167c6387efebd454f2f3428e" + capturedWithGo = "go1.27.1" +) + +// sameAsBuildAgent says the archive at res.Path holds the tar stream the build agent's pack wrote, and, under the Go the +// digests were captured with, has its digest. +func sameAsBuildAgent(t *testing.T, res BuildResult, stream, digest string) { + t.Helper() + f, err := os.Open(res.Path) + if err != nil { + t.Fatal(err) + } + defer f.Close() + z, err := gzip.NewReader(f) + if err != nil { + t.Fatal(err) + } + raw, err := io.ReadAll(z) + if err != nil { + t.Fatal(err) + } + sum := sha256.Sum256(raw) + if got := hex.EncodeToString(sum[:]); got != stream { + t.Errorf("the tar stream is sha256:%s, the build agent's is sha256:%s", got, stream) + } + if strings.HasPrefix(runtime.Version(), capturedWithGo) && res.Digest != digest { + t.Errorf("digest %s, the build agent's is %s", res.Digest, digest) + } +} + // copyTree copies a directory, keeping modes. func copyTree(t *testing.T, from, to string) { t.Helper() @@ -110,9 +153,7 @@ func TestAnArchiveOfADirectoryHasTheBuildAgentsDigest(t *testing.T) { if st.State != delivery.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } - if res.Digest != buildAgentDirectoryDigest { - t.Errorf("digest %s, the build agent's is %s", res.Digest, buildAgentDirectoryDigest) - } + sameAsBuildAgent(t, res, buildAgentDirectoryStream, buildAgentDirectoryDigest) if res.Artifact != "files" || res.Size == 0 || res.Binary != "" { t.Errorf("result = %+v", res) } @@ -156,17 +197,19 @@ func pinned(url, sha, extra string) string { func TestAPinnedArchiveIsUnpackedWithinAndHasTheBuildAgentsDigest(t *testing.T) { m, states := pinnedModule(t, "/release.tar.gz", releaseSHA256, `,"within":"release/app"`) res, st := runBuild(t, m, states, "files") - if st.State != delivery.StepPassed || res.Digest != buildAgentWithinDigest { - t.Fatalf("%s %q: digest %s, the build agent's is %s", st.State, st.Reason, res.Digest, buildAgentWithinDigest) + if st.State != delivery.StepPassed { + t.Fatalf("%s %q", st.State, st.Reason) } + sameAsBuildAgent(t, res, buildAgentWithinStream, buildAgentWithinDigest) } func TestAPinnedFileKeptWholeHasTheBuildAgentsDigest(t *testing.T) { m, states := pinnedModule(t, "/release.tar.gz", releaseSHA256, `,"file":"tool.bin"`) res, st := runBuild(t, m, states, "files") - if st.State != delivery.StepPassed || res.Digest != buildAgentFileDigest { - t.Fatalf("%s %q: digest %s, the build agent's is %s", st.State, st.Reason, res.Digest, buildAgentFileDigest) + if st.State != delivery.StepPassed { + t.Fatalf("%s %q", st.State, st.Reason) } + sameAsBuildAgent(t, res, buildAgentFileStream, buildAgentFileDigest) } // A file that is not the pin's is refused, naming both digests, and nothing is packed. diff --git a/modules/mesh-build-go/cmd/mesh-build-go/testdata/captured/README b/modules/mesh-build-go/cmd/mesh-build-go/testdata/captured/README index ebedd94a..194bc050 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/testdata/captured/README +++ b/modules/mesh-build-go/cmd/mesh-build-go/testdata/captured/README @@ -19,3 +19,8 @@ release/app/bin/tool (mode 755). Its pinned sha256 is 2c9e5753...7e95 (`sha256su it are what build-agent's `unpackUpstream(file, dir, "release/app")` followed by `pack(dir)` answers (9bacf4aa...790f), and what `pack` answers for a directory holding the file as `tool.bin` (`file: tool.bin`; 0d605adb...716b), captured the same way and the same day. + +The tar streams (the archives gunzipped) of the three archives above, captured the same way (build-agent's `pack`, then +gunzip and sha256) at origin/main 0205b8f7 on 2026-10-21: directory f8af1d94...d1b6, within 294e2bec...07fb, file +055cffc2...428e. The digests above hold the gzip bytes of go1.27.1. The first try of issue 1589 on the merge check's build node answered +other digests; the tests therefore compare the stream always and the digest only under go1.27.1.