diff --git a/sdk/buildstep/ask.go b/sdk/buildstep/ask.go index a739fe8a..55a63241 100644 --- a/sdk/buildstep/ask.go +++ b/sdk/buildstep/ask.go @@ -242,6 +242,18 @@ type Fetch struct { // member ({repository, commit, ref}). Package *FetchPackage `json:"package,omitempty"` Beside []FetchBeside `json:"beside,omitempty"` + // Builds name a group run's package members by their builds' digests (design 47 G §465): a package named here is named in + // neither Packages nor Package. + Builds []FetchBuild `json:"builds,omitempty"` +} + +// FetchBuild is one package member of a group run by its build: the package's name in its ecosystem (the Go module path, the +// npm name), the member's module and artifact, and its build's `sha256:` digest (design 47 G §465). +type FetchBuild struct { + Package string `json:"package"` + Module string `json:"module"` + Artifact string `json:"artifact"` + Digest string `json:"digest"` } // FetchPackage is the group package a TypeScript fetch takes (ADR 0607 §3, ADR 0500 §5): either the group's tagged version @@ -265,6 +277,9 @@ type ToolchainUsed struct { Language string `json:"language"` Recipe string `json:"recipe"` Version string `json:"version"` + // Digest is the building node's digest of its toolchain program, the entry of kind 3 (design 47 G §466, §472), never the + // build module's own program. + Digest string `json:"digest,omitempty"` } // AskArtifact is one artifact of a build ask: built from the fetched tree, or copied from an upstream pin (From). @@ -620,6 +635,16 @@ type AskBuilt struct { Artifact string `json:"artifact"` Digest string `json:"digest"` Reference string `json:"reference,omitempty"` + // Resolved are the mesh packages the build resolved, one each, with the digest of the package's bytes as the build fetched + // them (design 47 G §466). + Resolved []AskResolved `json:"resolved,omitempty"` +} + +// AskResolved is one mesh package a build resolved: its name, its version and the `sha256:` digest of its bytes. +type AskResolved struct { + Package string `json:"package"` + Version string `json:"version"` + Digest string `json:"digest"` } // CheckAnswer is what a check ask's step answers. diff --git a/sdk/buildstep/ask_test.go b/sdk/buildstep/ask_test.go index 41a83ca7..b394f66f 100644 --- a/sdk/buildstep/ask_test.go +++ b/sdk/buildstep/ask_test.go @@ -566,3 +566,31 @@ func TestTheThreeSeatsFixturesFitTheNeutralForms(t *testing.T) { t.Errorf("only %d fixtures read", seen) } } + +// 1966 (G §465, §466): a build ask's fetch names each package member's build, a built artifact the packages it resolved, +// and the toolchain the building node's digest, each read whole by the neutral forms. +func TestFetchBuildsResolvedAndToolchainDigestAreRead(t *testing.T) { + strict := func(raw string, into any) { + t.Helper() + dec := json.NewDecoder(strings.NewReader(raw)) + dec.DisallowUnknownFields() + if err := dec.Decode(into); err != nil { + t.Error(err) + } + } + var job BuildJob + strict(`{"module":"m","fetch":{"repository":"r","commit":"c","builds":[{"package":"example.org/m/go","module":"m","artifact":"go-m","digest":"sha256:aa"}]},"artifacts":[]}`, &job) + if job.Fetch == nil || len(job.Fetch.Builds) != 1 || job.Fetch.Builds[0] != (FetchBuild{Package: "example.org/m/go", Module: "m", Artifact: "go-m", Digest: "sha256:aa"}) { + t.Errorf("fetch builds: %+v", job.Fetch) + } + var built AskBuilt + strict(`{"artifact":"go-m","digest":"sha256:bb","resolved":[{"package":"example.org/s/go","version":"0.1.4","digest":"sha256:cc"}]}`, &built) + if len(built.Resolved) != 1 || built.Resolved[0] != (AskResolved{Package: "example.org/s/go", Version: "0.1.4", Digest: "sha256:cc"}) { + t.Errorf("resolved: %+v", built) + } + var tc ToolchainUsed + strict(`{"language":"go","recipe":"r","version":"1.26.0","digest":"sha256:dd"}`, &tc) + if tc.Digest != "sha256:dd" { + t.Errorf("toolchain digest: %+v", tc) + } +}