Prove a done build's artifacts resolve in a real artifact store, in both build modules (issue 1587, S9 S10, ADR 0498's check)

The integration tests start the distribution registry (the store's own program) in the
test with its in-memory storage and the real PushBlob: the built bundle and archive each
answer a reference ending in its digest, the key the builder would write is valid and
deliverable, and the store serves bytes of that digest at the reference. The registry is
imported by these tests alone (go list -deps of the programs does not name it).
This commit is contained in:
2026-10-22 18:28:52 +02:00
parent 3a25b6e1f8
commit 889fa09ea4
7 changed files with 612 additions and 1 deletions
@@ -0,0 +1,77 @@
//go:build integration
package main
import (
"context"
"crypto/sha256"
"encoding/hex"
"io"
"net/http"
"net/http/httptest"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"github.com/distribution/distribution/v3/configuration"
"github.com/distribution/distribution/v3/registry/handlers"
_ "github.com/distribution/distribution/v3/registry/storage/driver/inmemory"
"git.novox.be/novox/mesh-sdk/go/delivery"
)
// realStore starts the artifact store's own program (the distribution registry, modules/distribution) inside this
// test, with its in-memory storage, on a loopback port, and points m at it with the real push client. It is imported
// by this integration test alone: the module's program does not carry it.
func realStore(t *testing.T, m *Module) string {
t.Helper()
config := &configuration.Configuration{Storage: configuration.Storage{"inmemory": configuration.Parameters{}}}
config.HTTP.Secret = "a throwaway store"
config.Log.Level = "error"
config.Log.AccessLog.Disabled = true
srv := httptest.NewServer(handlers.NewApp(context.Background(), config))
t.Cleanup(srv.Close)
addr := strings.TrimPrefix(srv.URL, "http://")
m.RegistryFile = filepath.Join(t.TempDir(), "registry")
if err := os.WriteFile(m.RegistryFile, []byte(addr+"\n"), 0o644); err != nil {
t.Fatal(err)
}
m.Push = nil
return addr
}
// 1587-S10 (ADR 0498's check): a done bundle names a reference whose tail is its digest, and that reference resolves in
// a real artifact store to bytes of that digest. The build is the real tsc's and esbuild's, shut off.
func TestADoneBundleResolvesInARealArtifactStore(t *testing.T) {
if _, err := exec.LookPath("bwrap"); err != nil {
t.Skip("NOT RUN: no bubblewrap installed where this check runs; every build node has it (the module declares it)")
}
m, _ := realMachine(t)
addr := realStore(t, m)
out, err := m.build(context.Background(), map[string]any{"workspace": "w1", "module": "modules/m", "artifact": "tools"})
if err != nil {
t.Fatal(err)
}
r := out.(BuildResult)
done := delivery.BuilderBuild{V: 1, State: delivery.BuildDone, Manifest: strings.Repeat("0", 64),
Artifacts: []delivery.BuiltArtifact{{Name: "tools", Kind: "bundle", Digest: r.Digest, Reference: r.Reference}}}
if _, err := delivery.EncodeBuilderBuild(done); err != nil {
t.Errorf("the done key the builder would write is refused: %v", err)
}
path, ok := strings.CutPrefix(r.Reference, "artifact-store://")
if !ok || !strings.HasSuffix(r.Reference, "/blobs/"+r.Digest) {
t.Fatalf("the reference %q", r.Reference)
}
resp, err := http.Get("http://" + addr + "/v2/" + path)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
sum := sha256.Sum256(body)
if resp.StatusCode != http.StatusOK || "sha256:"+hex.EncodeToString(sum[:]) != r.Digest {
t.Errorf("the store answered %s with bytes of sha256:%x for %s", resp.Status, sum, r.Reference)
}
}