From 09823c48535c8e6d4d0c23e825f5526051460c7d Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 11 Jul 2025 17:23:38 +0100 Subject: [PATCH 01/15] fix: failing Rdev: unix.Mkdev(0, 0) --- snapshot/diffapply_unix.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snapshot/diffapply_unix.go b/snapshot/diffapply_unix.go index 11f29640f..bb45e5198 100644 --- a/snapshot/diffapply_unix.go +++ b/snapshot/diffapply_unix.go @@ -297,7 +297,7 @@ func (a *applier) applyDelete(ctx context.Context, ca *changeApply) (bool, error if ca.srcStat == nil { ca.srcStat = &syscall.Stat_t{ Mode: syscall.S_IFCHR, - Rdev: uint32(unix.Mkdev(0, 0)), + Rdev: unix.Mkdev(0, 0), } ca.srcPath = "" } From 902e309959a852d92480b32e8b02820e4e753d91 Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 11 Jul 2025 18:19:35 +0100 Subject: [PATCH 02/15] chore: remove bake output --- .github/workflows/.test.yml | 2 - .../dockerfile/dockerfile_provenance_test.go | 2540 ++++++++--------- 2 files changed, 1270 insertions(+), 1272 deletions(-) diff --git a/.github/workflows/.test.yml b/.github/workflows/.test.yml index 43c3d3546..6ff445e87 100644 --- a/.github/workflows/.test.yml +++ b/.github/workflows/.test.yml @@ -105,7 +105,6 @@ jobs: TESTFLAGS: "-v --parallel=6 --timeout=30m" GOTESTSUM_FORMAT: "standard-verbose" TEST_IMAGE_BUILD: "0" - TEST_IMAGE_ID: "buildkit-tests" strategy: fail-fast: false matrix: @@ -151,7 +150,6 @@ jobs: targets: integration-tests set: | *.cache-from=type=gha,scope=${{ inputs.cache_scope }} - *.output=type=docker,name=${{ env.TEST_IMAGE_ID }} env: BUILDKITD_TAGS: ${{ matrix.tags }} - diff --git a/frontend/dockerfile/dockerfile_provenance_test.go b/frontend/dockerfile/dockerfile_provenance_test.go index 9885b85df..e66fff771 100644 --- a/frontend/dockerfile/dockerfile_provenance_test.go +++ b/frontend/dockerfile/dockerfile_provenance_test.go @@ -1,1270 +1,1270 @@ -// package dockerfile - -// import ( -// "context" -// "encoding/json" -// "fmt" -// "io" -// "net/http" -// "net/http/httptest" -// "net/url" -// "os" -// "os/exec" -// "path/filepath" -// "strings" -// "testing" -// "time" - -// "github.com/containerd/containerd/content" -// "github.com/containerd/containerd/content/local" -// "github.com/containerd/containerd/content/proxy" -// "github.com/containerd/containerd/platforms" -// "github.com/containerd/continuity/fs/fstest" -// intoto "github.com/in-toto/in-toto-golang/in_toto" -// provenanceCommon "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" -// controlapi "github.com/moby/buildkit/api/services/control" -// "github.com/moby/buildkit/client" -// "github.com/moby/buildkit/client/llb" -// "github.com/moby/buildkit/exporter/containerimage/exptypes" -// "github.com/moby/buildkit/frontend/dockerui" -// gateway "github.com/moby/buildkit/frontend/gateway/client" -// "github.com/moby/buildkit/identity" -// "github.com/moby/buildkit/solver/llbsolver/provenance" -// "github.com/moby/buildkit/solver/pb" -// "github.com/moby/buildkit/util/contentutil" -// "github.com/moby/buildkit/util/testutil" -// "github.com/moby/buildkit/util/testutil/integration" -// "github.com/moby/buildkit/util/testutil/workers" -// ocispecs "github.com/opencontainers/image-spec/specs-go/v1" -// "github.com/pkg/errors" -// "github.com/stretchr/testify/require" -// ) - -// func testProvenanceAttestation(t *testing.T, sb integration.Sandbox) { -// workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush, workers.FeatureProvenance) -// ctx := sb.Context() - -// c, err := client.New(ctx, sb.Address()) -// require.NoError(t, err) -// defer c.Close() - -// registry, err := sb.NewRegistry() -// if errors.Is(err, integration.ErrRequirements) { -// t.Skip(err.Error()) -// } -// require.NoError(t, err) - -// f := getFrontend(t, sb) - -// dockerfile := []byte(` -// FROM busybox:latest -// RUN echo "ok" > /foo -// `) -// dir := integration.Tmpdir( -// t, -// fstest.CreateFile("Dockerfile", dockerfile, 0600), -// ) - -// for _, mode := range []string{"", "min", "max"} { -// t.Run(mode, func(t *testing.T) { -// var target string -// if target == "" { -// target = registry + "/buildkit/testwithprovenance:none" -// } else { -// target = registry + "/buildkit/testwithprovenance:" + mode -// } - -// provReq := "" -// if mode != "" { -// provReq = "mode=" + mode -// } -// _, err = f.Solve(sb.Context(), c, client.SolveOpt{ -// LocalDirs: map[string]string{ -// dockerui.DefaultLocalNameDockerfile: dir, -// dockerui.DefaultLocalNameContext: dir, -// }, -// FrontendAttrs: map[string]string{ -// "attest:provenance": provReq, -// "build-arg:FOO": "bar", -// "label:lbl": "abc", -// "vcs:source": "https://user:pass@example.invalid/repo.git", -// "vcs:revision": "123456", -// "filename": "Dockerfile", -// dockerui.DefaultLocalNameContext + ":foo": "https://foo:bar@example.invalid/foo.html", -// }, -// Exports: []client.ExportEntry{ -// { -// Type: client.ExporterImage, -// Attrs: map[string]string{ -// "name": target, -// "push": "true", -// }, -// }, -// }, -// }, nil) -// require.NoError(t, err) - -// desc, provider, err := contentutil.ProviderFromRef(target) -// require.NoError(t, err) -// imgs, err := testutil.ReadImages(sb.Context(), provider, desc) -// require.NoError(t, err) -// require.Equal(t, 2, len(imgs.Images)) - -// img := imgs.Find(platforms.Format(platforms.Normalize(platforms.DefaultSpec()))) -// require.NotNil(t, img) -// require.Equal(t, []byte("ok\n"), img.Layers[1]["foo"].Data) - -// att := imgs.Find("unknown/unknown") -// require.NotNil(t, att) -// require.Equal(t, att.Desc.Annotations["vnd.docker.reference.digest"], string(img.Desc.Digest)) -// require.Equal(t, att.Desc.Annotations["vnd.docker.reference.type"], "attestation-manifest") -// var attest intoto.Statement -// require.NoError(t, json.Unmarshal(att.LayersRaw[0], &attest)) -// require.Equal(t, "https://in-toto.io/Statement/v0.1", attest.Type) -// require.Equal(t, "https://slsa.dev/provenance/v0.2", attest.PredicateType) // intentionally not const - -// type stmtT struct { -// Predicate provenance.ProvenancePredicate `json:"predicate"` -// } -// var stmt stmtT -// require.NoError(t, json.Unmarshal(att.LayersRaw[0], &stmt)) -// pred := stmt.Predicate - -// require.Equal(t, "https://mobyproject.org/buildkit@v1", pred.BuildType) -// require.Equal(t, "", pred.Builder.ID) - -// require.Equal(t, "", pred.Invocation.ConfigSource.URI) - -// _, isClient := f.(*clientFrontend) -// _, isGateway := f.(*gatewayFrontend) - -// args := pred.Invocation.Parameters.Args -// if isClient { -// require.Equal(t, "", pred.Invocation.Parameters.Frontend) -// require.Equal(t, 0, len(args), "%v", args) -// require.False(t, pred.Metadata.Completeness.Parameters) -// require.Equal(t, "", pred.Invocation.ConfigSource.EntryPoint) -// } else if isGateway { -// require.Equal(t, "gateway.v0", pred.Invocation.Parameters.Frontend) - -// if mode == "max" || mode == "" { -// require.Equal(t, 4, len(args), "%v", args) -// require.True(t, pred.Metadata.Completeness.Parameters) - -// require.Equal(t, "bar", args["build-arg:FOO"]) -// require.Equal(t, "abc", args["label:lbl"]) -// require.Contains(t, args["source"], "buildkit_test/") -// } else { -// require.False(t, pred.Metadata.Completeness.Parameters) -// require.Equal(t, 2, len(args), "%v", args) -// require.Contains(t, args["source"], "buildkit_test/") -// } -// require.Equal(t, "https://xxxxx:xxxxx@example.invalid/foo.html", args["context:foo"]) -// } else { -// require.Equal(t, "dockerfile.v0", pred.Invocation.Parameters.Frontend) - -// if mode == "max" || mode == "" { -// require.Equal(t, 3, len(args)) -// require.True(t, pred.Metadata.Completeness.Parameters) - -// require.Equal(t, "bar", args["build-arg:FOO"]) -// require.Equal(t, "abc", args["label:lbl"]) -// } else { -// require.False(t, pred.Metadata.Completeness.Parameters) -// require.Equal(t, 1, len(args), "%v", args) -// } -// require.Equal(t, "https://xxxxx:xxxxx@example.invalid/foo.html", args["context:foo"]) -// } - -// expectedBase := "pkg:docker/busybox@latest?platform=" + url.PathEscape(platforms.Format(platforms.Normalize(platforms.DefaultSpec()))) -// if isGateway { -// require.Equal(t, 2, len(pred.Materials), "%+v", pred.Materials) -// require.Contains(t, pred.Materials[0].URI, "docker/buildkit_test") -// require.Equal(t, expectedBase, pred.Materials[1].URI) -// require.NotEmpty(t, pred.Materials[1].Digest["sha256"]) -// } else { -// require.Equal(t, 1, len(pred.Materials), "%+v", pred.Materials) -// require.Equal(t, expectedBase, pred.Materials[0].URI) -// require.NotEmpty(t, pred.Materials[0].Digest["sha256"]) -// } - -// if !isClient { -// require.Equal(t, "Dockerfile", pred.Invocation.ConfigSource.EntryPoint) -// require.Equal(t, "https://xxxxx:xxxxx@example.invalid/repo.git", pred.Metadata.BuildKitMetadata.VCS["source"]) -// require.Equal(t, "123456", pred.Metadata.BuildKitMetadata.VCS["revision"]) -// } - -// require.NotEmpty(t, pred.Metadata.BuildInvocationID) - -// require.Equal(t, 2, len(pred.Invocation.Parameters.Locals), "%+v", pred.Invocation.Parameters.Locals) -// require.Equal(t, "context", pred.Invocation.Parameters.Locals[0].Name) -// require.Equal(t, "dockerfile", pred.Invocation.Parameters.Locals[1].Name) - -// require.NotNil(t, pred.Metadata.BuildFinishedOn) -// require.True(t, time.Since(*pred.Metadata.BuildFinishedOn) < 5*time.Minute) -// require.NotNil(t, pred.Metadata.BuildStartedOn) -// require.True(t, time.Since(*pred.Metadata.BuildStartedOn) < 5*time.Minute) -// require.True(t, pred.Metadata.BuildStartedOn.Before(*pred.Metadata.BuildFinishedOn)) - -// require.True(t, pred.Metadata.Completeness.Environment) -// require.Equal(t, platforms.Format(platforms.Normalize(platforms.DefaultSpec())), pred.Invocation.Environment.Platform) - -// require.False(t, pred.Metadata.Completeness.Materials) -// require.False(t, pred.Metadata.Reproducible) -// require.False(t, pred.Metadata.Hermetic) - -// if mode == "max" || mode == "" { -// require.Equal(t, 2, len(pred.Metadata.BuildKitMetadata.Layers)) -// require.NotNil(t, pred.Metadata.BuildKitMetadata.Source) -// require.Equal(t, "Dockerfile", pred.Metadata.BuildKitMetadata.Source.Infos[0].Filename) -// require.Equal(t, dockerfile, pred.Metadata.BuildKitMetadata.Source.Infos[0].Data) -// require.NotNil(t, pred.BuildConfig) - -// require.Equal(t, 3, len(pred.BuildConfig.Definition)) -// } else { -// require.Equal(t, 0, len(pred.Metadata.BuildKitMetadata.Layers)) -// require.Nil(t, pred.Metadata.BuildKitMetadata.Source) -// require.Nil(t, pred.BuildConfig) -// } -// }) -// } -// } - -// func testGitProvenanceAttestation(t *testing.T, sb integration.Sandbox) { -// workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush, workers.FeatureProvenance) -// ctx := sb.Context() - -// c, err := client.New(ctx, sb.Address()) -// require.NoError(t, err) -// defer c.Close() - -// registry, err := sb.NewRegistry() -// if errors.Is(err, integration.ErrRequirements) { -// t.Skip(err.Error()) -// } -// require.NoError(t, err) - -// f := getFrontend(t, sb) - -// dockerfile := []byte(` -// FROM busybox:latest -// RUN --network=none echo "git" > /foo -// COPY myapp.Dockerfile / -// `) -// dir := integration.Tmpdir( -// t, -// fstest.CreateFile("myapp.Dockerfile", dockerfile, 0600), -// ) - -// err = runShell(dir, -// "git init", -// "git config --local user.email test", -// "git config --local user.name test", -// "git add myapp.Dockerfile", -// "git commit -m initial", -// "git branch v1", -// "git update-server-info", -// ) -// require.NoError(t, err) - -// cmd := exec.Command("git", "rev-parse", "v1") -// cmd.Dir = dir -// expectedGitSHA, err := cmd.Output() -// require.NoError(t, err) - -// server := httptest.NewServer(http.FileServer(http.Dir(filepath.Join(dir)))) -// defer server.Close() - -// target := registry + "/buildkit/testwithprovenance:git" - -// // inject dummy credentials to test that they are masked -// expectedURL := strings.Replace(server.URL, "http://", "http://xxxxx:xxxxx@", 1) -// require.NotEqual(t, expectedURL, server.URL) -// server.URL = strings.Replace(server.URL, "http://", "http://user:pass@", 1) - -// _, err = f.Solve(sb.Context(), c, client.SolveOpt{ -// FrontendAttrs: map[string]string{ -// "context": server.URL + "/.git#v1", -// "attest:provenance": "", -// "filename": "myapp.Dockerfile", -// }, -// Exports: []client.ExportEntry{ -// { -// Type: client.ExporterImage, -// Attrs: map[string]string{ -// "name": target, -// "push": "true", -// }, -// }, -// }, -// }, nil) -// require.NoError(t, err) - -// desc, provider, err := contentutil.ProviderFromRef(target) -// require.NoError(t, err) -// imgs, err := testutil.ReadImages(sb.Context(), provider, desc) -// require.NoError(t, err) -// require.Equal(t, 2, len(imgs.Images)) - -// img := imgs.Find(platforms.Format(platforms.Normalize(platforms.DefaultSpec()))) -// require.NotNil(t, img) -// require.Equal(t, []byte("git\n"), img.Layers[1]["foo"].Data) - -// att := imgs.Find("unknown/unknown") -// require.NotNil(t, att) -// require.Equal(t, att.Desc.Annotations["vnd.docker.reference.digest"], string(img.Desc.Digest)) -// require.Equal(t, att.Desc.Annotations["vnd.docker.reference.type"], "attestation-manifest") -// var attest intoto.Statement -// require.NoError(t, json.Unmarshal(att.LayersRaw[0], &attest)) -// require.Equal(t, "https://in-toto.io/Statement/v0.1", attest.Type) -// require.Equal(t, "https://slsa.dev/provenance/v0.2", attest.PredicateType) // intentionally not const - -// type stmtT struct { -// Predicate provenance.ProvenancePredicate `json:"predicate"` -// } -// var stmt stmtT -// require.NoError(t, json.Unmarshal(att.LayersRaw[0], &stmt)) -// pred := stmt.Predicate - -// _, isClient := f.(*clientFrontend) -// _, isGateway := f.(*gatewayFrontend) - -// if isClient { -// require.Empty(t, pred.Invocation.Parameters.Frontend) -// require.Equal(t, "", pred.Invocation.ConfigSource.URI) -// require.Equal(t, "", pred.Invocation.ConfigSource.EntryPoint) -// } else { -// require.NotEmpty(t, pred.Invocation.Parameters.Frontend) -// require.Equal(t, expectedURL+"/.git#v1", pred.Invocation.ConfigSource.URI) -// require.Equal(t, "myapp.Dockerfile", pred.Invocation.ConfigSource.EntryPoint) -// } - -// expBase := "pkg:docker/busybox@latest?platform=" + url.PathEscape(platforms.Format(platforms.Normalize(platforms.DefaultSpec()))) -// if isGateway { -// require.Equal(t, 3, len(pred.Materials), "%+v", pred.Materials) - -// require.Contains(t, pred.Materials[0].URI, "pkg:docker/buildkit_test/") -// require.NotEmpty(t, pred.Materials[0].Digest) - -// require.Equal(t, expBase, pred.Materials[1].URI) -// require.NotEmpty(t, pred.Materials[1].Digest["sha256"]) - -// require.Equal(t, expectedURL+"/.git#v1", pred.Materials[2].URI) -// require.Equal(t, strings.TrimSpace(string(expectedGitSHA)), pred.Materials[2].Digest["sha1"]) -// } else { -// require.Equal(t, 2, len(pred.Materials), "%+v", pred.Materials) - -// require.Equal(t, expBase, pred.Materials[0].URI) -// require.NotEmpty(t, pred.Materials[0].Digest["sha256"]) - -// require.Equal(t, expectedURL+"/.git#v1", pred.Materials[1].URI) -// require.Equal(t, strings.TrimSpace(string(expectedGitSHA)), pred.Materials[1].Digest["sha1"]) -// } - -// require.Equal(t, 0, len(pred.Invocation.Parameters.Locals)) - -// require.True(t, pred.Metadata.Completeness.Materials) -// require.True(t, pred.Metadata.Completeness.Environment) -// require.True(t, pred.Metadata.Hermetic) - -// if isClient { -// require.False(t, pred.Metadata.Completeness.Parameters) -// } else { -// require.True(t, pred.Metadata.Completeness.Parameters) -// } -// require.False(t, pred.Metadata.Reproducible) - -// require.Equal(t, 0, len(pred.Metadata.BuildKitMetadata.VCS), "%+v", pred.Metadata.BuildKitMetadata.VCS) -// } - -// func testMultiPlatformProvenance(t *testing.T, sb integration.Sandbox) { -// workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush, workers.FeatureMultiPlatform, workers.FeatureProvenance) -// ctx := sb.Context() - -// c, err := client.New(ctx, sb.Address()) -// require.NoError(t, err) -// defer c.Close() - -// registry, err := sb.NewRegistry() -// if errors.Is(err, integration.ErrRequirements) { -// t.Skip(err.Error()) -// } -// require.NoError(t, err) - -// f := getFrontend(t, sb) - -// dockerfile := []byte(` -// FROM busybox:latest -// ARG TARGETARCH -// RUN echo "ok-$TARGETARCH" > /foo -// `) -// dir := integration.Tmpdir( -// t, -// fstest.CreateFile("Dockerfile", dockerfile, 0600), -// ) - -// target := registry + "/buildkit/testmultiprovenance:latest" - -// _, err = f.Solve(sb.Context(), c, client.SolveOpt{ -// LocalDirs: map[string]string{ -// dockerui.DefaultLocalNameDockerfile: dir, -// dockerui.DefaultLocalNameContext: dir, -// }, -// FrontendAttrs: map[string]string{ -// "attest:provenance": "mode=max", -// "build-arg:FOO": "bar", -// "label:lbl": "abc", -// "platform": "linux/amd64,linux/arm64", -// }, -// Exports: []client.ExportEntry{ -// { -// Type: client.ExporterImage, -// Attrs: map[string]string{ -// "name": target, -// "push": "true", -// }, -// }, -// }, -// }, nil) -// require.NoError(t, err) - -// desc, provider, err := contentutil.ProviderFromRef(target) -// require.NoError(t, err) -// imgs, err := testutil.ReadImages(sb.Context(), provider, desc) -// require.NoError(t, err) -// require.Equal(t, 4, len(imgs.Images)) - -// _, isClient := f.(*clientFrontend) -// _, isGateway := f.(*gatewayFrontend) - -// for _, p := range []string{"linux/amd64", "linux/arm64"} { -// img := imgs.Find(p) -// require.NotNil(t, img) -// if p == "linux/amd64" { -// require.Equal(t, []byte("ok-amd64\n"), img.Layers[1]["foo"].Data) -// } else { -// require.Equal(t, []byte("ok-arm64\n"), img.Layers[1]["foo"].Data) -// } - -// att := imgs.FindAttestation(p) -// require.NotNil(t, att) -// require.Equal(t, att.Desc.Annotations["vnd.docker.reference.type"], "attestation-manifest") -// var attest intoto.Statement -// require.NoError(t, json.Unmarshal(att.LayersRaw[0], &attest)) -// require.Equal(t, "https://in-toto.io/Statement/v0.1", attest.Type) -// require.Equal(t, "https://slsa.dev/provenance/v0.2", attest.PredicateType) // intentionally not const - -// type stmtT struct { -// Predicate provenance.ProvenancePredicate `json:"predicate"` -// } -// var stmt stmtT -// require.NoError(t, json.Unmarshal(att.LayersRaw[0], &stmt)) -// pred := stmt.Predicate - -// require.Equal(t, "https://mobyproject.org/buildkit@v1", pred.BuildType) -// require.Equal(t, "", pred.Builder.ID) -// require.Equal(t, "", pred.Invocation.ConfigSource.URI) - -// if isGateway { -// require.Equal(t, 2, len(pred.Materials), "%+v", pred.Materials) -// require.Contains(t, pred.Materials[0].URI, "buildkit_test") -// require.Contains(t, pred.Materials[1].URI, "pkg:docker/busybox@latest") -// require.Contains(t, pred.Materials[1].URI, url.PathEscape(p)) -// } else { -// require.Equal(t, 1, len(pred.Materials), "%+v", pred.Materials) -// require.Contains(t, pred.Materials[0].URI, "pkg:docker/busybox@latest") -// require.Contains(t, pred.Materials[0].URI, url.PathEscape(p)) -// } - -// args := pred.Invocation.Parameters.Args -// if isClient { -// require.Equal(t, 0, len(args), "%+v", args) -// } else if isGateway { -// require.Equal(t, 3, len(args), "%+v", args) -// require.Equal(t, "bar", args["build-arg:FOO"]) -// require.Equal(t, "abc", args["label:lbl"]) -// require.Contains(t, args["source"], "buildkit_test/") -// } else { -// require.Equal(t, 2, len(args), "%+v", args) -// require.Equal(t, "bar", args["build-arg:FOO"]) -// require.Equal(t, "abc", args["label:lbl"]) -// } -// } -// } - -// func testClientFrontendProvenance(t *testing.T, sb integration.Sandbox) { -// workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush, workers.FeatureProvenance) -// // Building with client frontend does not capture frontend provenance -// // because frontend runs in client, not in BuildKit. -// // This test builds Dockerfile inside a client frontend ensuring that -// // in that case frontend provenance is captured. -// ctx := sb.Context() - -// c, err := client.New(ctx, sb.Address()) -// require.NoError(t, err) -// defer c.Close() - -// registry, err := sb.NewRegistry() -// if errors.Is(err, integration.ErrRequirements) { -// t.Skip(err.Error()) -// } -// require.NoError(t, err) - -// target := registry + "/buildkit/clientprovenance:latest" - -// f := getFrontend(t, sb) - -// _, isClient := f.(*clientFrontend) -// if !isClient { -// t.Skip("not a client frontend") -// } - -// dockerfile := []byte(` -// FROM alpine as x86target -// RUN echo "alpine" > /foo - -// FROM busybox:latest AS armtarget -// RUN --network=none echo "bbox" > /foo -// `) -// dir := integration.Tmpdir( -// t, -// fstest.CreateFile("Dockerfile", dockerfile, 0600), -// ) - -// frontend := func(ctx context.Context, c gateway.Client) (*gateway.Result, error) { -// st := llb.HTTP("https://raw.githubusercontent.com/moby/moby/v20.10.21/README.md") -// def, err := st.Marshal(ctx) -// if err != nil { -// return nil, err -// } -// // This does not show up in provenance -// res0, err := c.Solve(ctx, gateway.SolveRequest{ -// Definition: def.ToPB(), -// }) -// if err != nil { -// return nil, err -// } -// dt, err := res0.Ref.ReadFile(ctx, gateway.ReadRequest{ -// Filename: "README.md", -// }) -// if err != nil { -// return nil, err -// } - -// res1, err := c.Solve(ctx, gateway.SolveRequest{ -// Frontend: "dockerfile.v0", -// FrontendOpt: map[string]string{ -// "build-arg:FOO": string(dt[:3]), -// "target": "armtarget", -// }, -// }) -// if err != nil { -// return nil, err -// } - -// res2, err := c.Solve(ctx, gateway.SolveRequest{ -// Frontend: "dockerfile.v0", -// FrontendOpt: map[string]string{ -// "build-arg:FOO": string(dt[4:8]), -// "target": "x86target", -// }, -// }) -// if err != nil { -// return nil, err -// } - -// res := gateway.NewResult() -// res.AddRef("linux/arm64", res1.Ref) -// res.AddRef("linux/amd64", res2.Ref) - -// pl, err := json.Marshal(exptypes.Platforms{ -// Platforms: []exptypes.Platform{ -// { -// ID: "linux/arm64", -// Platform: ocispecs.Platform{OS: "linux", Architecture: "arm64"}, -// }, -// { -// ID: "linux/amd64", -// Platform: ocispecs.Platform{OS: "linux", Architecture: "amd64"}, -// }, -// }, -// }) -// if err != nil { -// return nil, err -// } -// res.AddMeta(exptypes.ExporterPlatformsKey, pl) - -// return res, nil -// } - -// _, err = c.Build(sb.Context(), client.SolveOpt{ -// FrontendAttrs: map[string]string{ -// "attest:provenance": "mode=full", -// }, -// Exports: []client.ExportEntry{ -// { -// Type: client.ExporterImage, -// Attrs: map[string]string{ -// "name": target, -// "push": "true", -// }, -// }, -// }, -// LocalDirs: map[string]string{ -// dockerui.DefaultLocalNameDockerfile: dir, -// dockerui.DefaultLocalNameContext: dir, -// }, -// }, "", frontend, nil) -// require.NoError(t, err) - -// desc, provider, err := contentutil.ProviderFromRef(target) -// require.NoError(t, err) -// imgs, err := testutil.ReadImages(sb.Context(), provider, desc) -// require.NoError(t, err) -// require.Equal(t, 4, len(imgs.Images)) - -// img := imgs.Find("linux/arm64") -// require.NotNil(t, img) -// require.Equal(t, []byte("bbox\n"), img.Layers[1]["foo"].Data) - -// att := imgs.FindAttestation("linux/arm64") -// require.NotNil(t, att) -// require.Equal(t, att.Desc.Annotations["vnd.docker.reference.type"], "attestation-manifest") -// var attest intoto.Statement -// require.NoError(t, json.Unmarshal(att.LayersRaw[0], &attest)) -// require.Equal(t, "https://in-toto.io/Statement/v0.1", attest.Type) -// require.Equal(t, "https://slsa.dev/provenance/v0.2", attest.PredicateType) // intentionally not const - -// type stmtT struct { -// Predicate provenance.ProvenancePredicate `json:"predicate"` -// } -// var stmt stmtT -// require.NoError(t, json.Unmarshal(att.LayersRaw[0], &stmt)) -// pred := stmt.Predicate - -// require.Equal(t, "https://mobyproject.org/buildkit@v1", pred.BuildType) -// require.Equal(t, "", pred.Builder.ID) -// require.Equal(t, "", pred.Invocation.ConfigSource.URI) - -// args := pred.Invocation.Parameters.Args -// require.Equal(t, 2, len(args), "%+v", args) -// require.Equal(t, "The", args["build-arg:FOO"]) -// require.Equal(t, "armtarget", args["target"]) - -// require.Equal(t, 2, len(pred.Invocation.Parameters.Locals)) -// require.Equal(t, 1, len(pred.Materials)) -// require.Contains(t, pred.Materials[0].URI, "docker/busybox") - -// // amd64 -// img = imgs.Find("linux/amd64") -// require.NotNil(t, img) -// require.Equal(t, []byte("alpine\n"), img.Layers[1]["foo"].Data) - -// att = imgs.FindAttestation("linux/amd64") -// require.NotNil(t, att) -// require.Equal(t, att.Desc.Annotations["vnd.docker.reference.type"], "attestation-manifest") -// attest = intoto.Statement{} -// require.NoError(t, json.Unmarshal(att.LayersRaw[0], &attest)) -// require.Equal(t, "https://in-toto.io/Statement/v0.1", attest.Type) -// require.Equal(t, "https://slsa.dev/provenance/v0.2", attest.PredicateType) // intentionally not const - -// stmt = stmtT{} -// require.NoError(t, json.Unmarshal(att.LayersRaw[0], &stmt)) -// pred = stmt.Predicate - -// require.Equal(t, "https://mobyproject.org/buildkit@v1", pred.BuildType) -// require.Equal(t, "", pred.Builder.ID) -// require.Equal(t, "", pred.Invocation.ConfigSource.URI) - -// args = pred.Invocation.Parameters.Args -// require.Equal(t, 2, len(args), "%+v", args) -// require.Equal(t, "Moby", args["build-arg:FOO"]) -// require.Equal(t, "x86target", args["target"]) - -// require.Equal(t, 2, len(pred.Invocation.Parameters.Locals)) -// require.Equal(t, 1, len(pred.Materials)) -// require.Contains(t, pred.Materials[0].URI, "docker/alpine") -// } - -// func testClientLLBProvenance(t *testing.T, sb integration.Sandbox) { -// workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush, workers.FeatureProvenance) -// ctx := sb.Context() - -// c, err := client.New(ctx, sb.Address()) -// require.NoError(t, err) -// defer c.Close() - -// registry, err := sb.NewRegistry() -// if errors.Is(err, integration.ErrRequirements) { -// t.Skip(err.Error()) -// } -// require.NoError(t, err) - -// target := registry + "/buildkit/clientprovenance:llb" - -// f := getFrontend(t, sb) - -// _, isClient := f.(*clientFrontend) -// if !isClient { -// t.Skip("not a client frontend") -// } - -// frontend := func(ctx context.Context, c gateway.Client) (*gateway.Result, error) { -// st := llb.HTTP("https://raw.githubusercontent.com/moby/moby/v20.10.21/README.md") -// def, err := st.Marshal(ctx) -// if err != nil { -// return nil, err -// } -// // this also shows up in the provenance -// res0, err := c.Solve(ctx, gateway.SolveRequest{ -// Definition: def.ToPB(), -// }) -// if err != nil { -// return nil, err -// } -// dt, err := res0.Ref.ReadFile(ctx, gateway.ReadRequest{ -// Filename: "README.md", -// }) -// if err != nil { -// return nil, err -// } - -// st = llb.Image("alpine").File(llb.Mkfile("/foo", 0600, dt)) -// def, err = st.Marshal(ctx) -// if err != nil { -// return nil, err -// } -// res1, err := c.Solve(ctx, gateway.SolveRequest{ -// Definition: def.ToPB(), -// }) -// if err != nil { -// return nil, err -// } -// return res1, nil -// } - -// _, err = c.Build(sb.Context(), client.SolveOpt{ -// FrontendAttrs: map[string]string{ -// "attest:provenance": "mode=full", -// }, -// Exports: []client.ExportEntry{ -// { -// Type: client.ExporterImage, -// Attrs: map[string]string{ -// "name": target, -// "push": "true", -// }, -// }, -// }, -// LocalDirs: map[string]string{}, -// }, "", frontend, nil) -// require.NoError(t, err) - -// desc, provider, err := contentutil.ProviderFromRef(target) -// require.NoError(t, err) -// imgs, err := testutil.ReadImages(sb.Context(), provider, desc) -// require.NoError(t, err) -// require.Equal(t, 2, len(imgs.Images)) - -// nativePlatform := platforms.Format(platforms.Normalize(platforms.DefaultSpec())) - -// img := imgs.Find(nativePlatform) -// require.NotNil(t, img) -// require.Contains(t, string(img.Layers[1]["foo"].Data), "The Moby Project") - -// att := imgs.FindAttestation(nativePlatform) -// require.NotNil(t, att) -// require.Equal(t, att.Desc.Annotations["vnd.docker.reference.type"], "attestation-manifest") -// var attest intoto.Statement -// require.NoError(t, json.Unmarshal(att.LayersRaw[0], &attest)) -// require.Equal(t, "https://in-toto.io/Statement/v0.1", attest.Type) -// require.Equal(t, "https://slsa.dev/provenance/v0.2", attest.PredicateType) // intentionally not const - -// type stmtT struct { -// Predicate provenance.ProvenancePredicate `json:"predicate"` -// } -// var stmt stmtT -// require.NoError(t, json.Unmarshal(att.LayersRaw[0], &stmt)) -// pred := stmt.Predicate - -// require.Equal(t, "https://mobyproject.org/buildkit@v1", pred.BuildType) -// require.Equal(t, "", pred.Builder.ID) -// require.Equal(t, "", pred.Invocation.ConfigSource.URI) - -// args := pred.Invocation.Parameters.Args -// require.Equal(t, 0, len(args), "%+v", args) -// require.Equal(t, 0, len(pred.Invocation.Parameters.Locals)) - -// require.Equal(t, 2, len(pred.Materials), "%+v", pred.Materials) -// require.Contains(t, pred.Materials[0].URI, "docker/alpine") -// require.Contains(t, pred.Materials[1].URI, "README.md") -// } - -// func testSecretSSHProvenance(t *testing.T, sb integration.Sandbox) { -// workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush, workers.FeatureProvenance) -// ctx := sb.Context() - -// c, err := client.New(ctx, sb.Address()) -// require.NoError(t, err) -// defer c.Close() - -// registry, err := sb.NewRegistry() -// if errors.Is(err, integration.ErrRequirements) { -// t.Skip(err.Error()) -// } -// require.NoError(t, err) - -// f := getFrontend(t, sb) - -// dockerfile := []byte(` -// FROM busybox:latest -// RUN --mount=type=secret,id=mysecret --mount=type=secret,id=othersecret --mount=type=ssh echo "ok" > /foo -// `) -// dir := integration.Tmpdir( -// t, -// fstest.CreateFile("Dockerfile", dockerfile, 0600), -// ) - -// target := registry + "/buildkit/testsecretprovenance:latest" -// _, err = f.Solve(sb.Context(), c, client.SolveOpt{ -// LocalDirs: map[string]string{ -// dockerui.DefaultLocalNameDockerfile: dir, -// dockerui.DefaultLocalNameContext: dir, -// }, -// FrontendAttrs: map[string]string{ -// "attest:provenance": "mode=max", -// }, -// Exports: []client.ExportEntry{ -// { -// Type: client.ExporterImage, -// Attrs: map[string]string{ -// "name": target, -// "push": "true", -// }, -// }, -// }, -// }, nil) -// require.NoError(t, err) - -// desc, provider, err := contentutil.ProviderFromRef(target) -// require.NoError(t, err) -// imgs, err := testutil.ReadImages(sb.Context(), provider, desc) -// require.NoError(t, err) -// require.Equal(t, 2, len(imgs.Images)) - -// expPlatform := platforms.Format(platforms.Normalize(platforms.DefaultSpec())) - -// img := imgs.Find(expPlatform) -// require.NotNil(t, img) -// require.Equal(t, []byte("ok\n"), img.Layers[1]["foo"].Data) - -// att := imgs.FindAttestation(expPlatform) -// type stmtT struct { -// Predicate provenance.ProvenancePredicate `json:"predicate"` -// } -// var stmt stmtT -// require.NoError(t, json.Unmarshal(att.LayersRaw[0], &stmt)) -// pred := stmt.Predicate - -// require.Equal(t, 2, len(pred.Invocation.Parameters.Secrets), "%+v", pred.Invocation.Parameters.Secrets) -// require.Equal(t, "mysecret", pred.Invocation.Parameters.Secrets[0].ID) -// require.True(t, pred.Invocation.Parameters.Secrets[0].Optional) -// require.Equal(t, "othersecret", pred.Invocation.Parameters.Secrets[1].ID) -// require.True(t, pred.Invocation.Parameters.Secrets[1].Optional) - -// require.Equal(t, 1, len(pred.Invocation.Parameters.SSH), "%+v", pred.Invocation.Parameters.SSH) -// require.Equal(t, "default", pred.Invocation.Parameters.SSH[0].ID) -// require.True(t, pred.Invocation.Parameters.SSH[0].Optional) -// } - -// func testOCILayoutProvenance(t *testing.T, sb integration.Sandbox) { -// workers.CheckFeatureCompat(t, sb, workers.FeatureProvenance) -// ctx := sb.Context() - -// c, err := client.New(ctx, sb.Address()) -// require.NoError(t, err) -// defer c.Close() - -// registry, err := sb.NewRegistry() -// if errors.Is(err, integration.ErrRequirements) { -// t.Skip(err.Error()) -// } -// require.NoError(t, err) -// target := registry + "/buildkit/clientprovenance:ocilayout" - -// f := getFrontend(t, sb) -// _, isGateway := f.(*gatewayFrontend) - -// ocidir := t.TempDir() -// ociDockerfile := []byte(` -// FROM scratch -// COPY < /foo +`) + dir := integration.Tmpdir( + t, + fstest.CreateFile("Dockerfile", dockerfile, 0600), + ) + + for _, mode := range []string{"", "min", "max"} { + t.Run(mode, func(t *testing.T) { + var target string + if target == "" { + target = registry + "/buildkit/testwithprovenance:none" + } else { + target = registry + "/buildkit/testwithprovenance:" + mode + } + + provReq := "" + if mode != "" { + provReq = "mode=" + mode + } + _, err = f.Solve(sb.Context(), c, client.SolveOpt{ + LocalDirs: map[string]string{ + dockerui.DefaultLocalNameDockerfile: dir, + dockerui.DefaultLocalNameContext: dir, + }, + FrontendAttrs: map[string]string{ + "attest:provenance": provReq, + "build-arg:FOO": "bar", + "label:lbl": "abc", + "vcs:source": "https://user:pass@example.invalid/repo.git", + "vcs:revision": "123456", + "filename": "Dockerfile", + dockerui.DefaultLocalNameContext + ":foo": "https://foo:bar@example.invalid/foo.html", + }, + Exports: []client.ExportEntry{ + { + Type: client.ExporterImage, + Attrs: map[string]string{ + "name": target, + "push": "true", + }, + }, + }, + }, nil) + require.NoError(t, err) + + desc, provider, err := contentutil.ProviderFromRef(target) + require.NoError(t, err) + imgs, err := testutil.ReadImages(sb.Context(), provider, desc) + require.NoError(t, err) + require.Equal(t, 2, len(imgs.Images)) + + img := imgs.Find(platforms.Format(platforms.Normalize(platforms.DefaultSpec()))) + require.NotNil(t, img) + require.Equal(t, []byte("ok\n"), img.Layers[1]["foo"].Data) + + att := imgs.Find("unknown/unknown") + require.NotNil(t, att) + require.Equal(t, att.Desc.Annotations["vnd.docker.reference.digest"], string(img.Desc.Digest)) + require.Equal(t, att.Desc.Annotations["vnd.docker.reference.type"], "attestation-manifest") + var attest intoto.Statement + require.NoError(t, json.Unmarshal(att.LayersRaw[0], &attest)) + require.Equal(t, "https://in-toto.io/Statement/v0.1", attest.Type) + require.Equal(t, "https://slsa.dev/provenance/v0.2", attest.PredicateType) // intentionally not const + + type stmtT struct { + Predicate provenance.ProvenancePredicate `json:"predicate"` + } + var stmt stmtT + require.NoError(t, json.Unmarshal(att.LayersRaw[0], &stmt)) + pred := stmt.Predicate + + require.Equal(t, "https://mobyproject.org/buildkit@v1", pred.BuildType) + require.Equal(t, "", pred.Builder.ID) + + require.Equal(t, "", pred.Invocation.ConfigSource.URI) + + _, isClient := f.(*clientFrontend) + _, isGateway := f.(*gatewayFrontend) + + args := pred.Invocation.Parameters.Args + if isClient { + require.Equal(t, "", pred.Invocation.Parameters.Frontend) + require.Equal(t, 0, len(args), "%v", args) + require.False(t, pred.Metadata.Completeness.Parameters) + require.Equal(t, "", pred.Invocation.ConfigSource.EntryPoint) + } else if isGateway { + require.Equal(t, "gateway.v0", pred.Invocation.Parameters.Frontend) + + if mode == "max" || mode == "" { + require.Equal(t, 4, len(args), "%v", args) + require.True(t, pred.Metadata.Completeness.Parameters) + + require.Equal(t, "bar", args["build-arg:FOO"]) + require.Equal(t, "abc", args["label:lbl"]) + require.Contains(t, args["source"], "buildkit_test/") + } else { + require.False(t, pred.Metadata.Completeness.Parameters) + require.Equal(t, 2, len(args), "%v", args) + require.Contains(t, args["source"], "buildkit_test/") + } + require.Equal(t, "https://xxxxx:xxxxx@example.invalid/foo.html", args["context:foo"]) + } else { + require.Equal(t, "dockerfile.v0", pred.Invocation.Parameters.Frontend) + + if mode == "max" || mode == "" { + require.Equal(t, 3, len(args)) + require.True(t, pred.Metadata.Completeness.Parameters) + + require.Equal(t, "bar", args["build-arg:FOO"]) + require.Equal(t, "abc", args["label:lbl"]) + } else { + require.False(t, pred.Metadata.Completeness.Parameters) + require.Equal(t, 1, len(args), "%v", args) + } + require.Equal(t, "https://xxxxx:xxxxx@example.invalid/foo.html", args["context:foo"]) + } + + expectedBase := "pkg:docker/busybox@latest?platform=" + url.PathEscape(platforms.Format(platforms.Normalize(platforms.DefaultSpec()))) + if isGateway { + require.Equal(t, 2, len(pred.Materials), "%+v", pred.Materials) + require.Contains(t, pred.Materials[0].URI, "docker/buildkit_test") + require.Equal(t, expectedBase, pred.Materials[1].URI) + require.NotEmpty(t, pred.Materials[1].Digest["sha256"]) + } else { + require.Equal(t, 1, len(pred.Materials), "%+v", pred.Materials) + require.Equal(t, expectedBase, pred.Materials[0].URI) + require.NotEmpty(t, pred.Materials[0].Digest["sha256"]) + } + + if !isClient { + require.Equal(t, "Dockerfile", pred.Invocation.ConfigSource.EntryPoint) + require.Equal(t, "https://xxxxx:xxxxx@example.invalid/repo.git", pred.Metadata.BuildKitMetadata.VCS["source"]) + require.Equal(t, "123456", pred.Metadata.BuildKitMetadata.VCS["revision"]) + } + + require.NotEmpty(t, pred.Metadata.BuildInvocationID) + + require.Equal(t, 2, len(pred.Invocation.Parameters.Locals), "%+v", pred.Invocation.Parameters.Locals) + require.Equal(t, "context", pred.Invocation.Parameters.Locals[0].Name) + require.Equal(t, "dockerfile", pred.Invocation.Parameters.Locals[1].Name) + + require.NotNil(t, pred.Metadata.BuildFinishedOn) + require.True(t, time.Since(*pred.Metadata.BuildFinishedOn) < 5*time.Minute) + require.NotNil(t, pred.Metadata.BuildStartedOn) + require.True(t, time.Since(*pred.Metadata.BuildStartedOn) < 5*time.Minute) + require.True(t, pred.Metadata.BuildStartedOn.Before(*pred.Metadata.BuildFinishedOn)) + + require.True(t, pred.Metadata.Completeness.Environment) + require.Equal(t, platforms.Format(platforms.Normalize(platforms.DefaultSpec())), pred.Invocation.Environment.Platform) + + require.False(t, pred.Metadata.Completeness.Materials) + require.False(t, pred.Metadata.Reproducible) + require.False(t, pred.Metadata.Hermetic) + + if mode == "max" || mode == "" { + require.Equal(t, 2, len(pred.Metadata.BuildKitMetadata.Layers)) + require.NotNil(t, pred.Metadata.BuildKitMetadata.Source) + require.Equal(t, "Dockerfile", pred.Metadata.BuildKitMetadata.Source.Infos[0].Filename) + require.Equal(t, dockerfile, pred.Metadata.BuildKitMetadata.Source.Infos[0].Data) + require.NotNil(t, pred.BuildConfig) + + require.Equal(t, 3, len(pred.BuildConfig.Definition)) + } else { + require.Equal(t, 0, len(pred.Metadata.BuildKitMetadata.Layers)) + require.Nil(t, pred.Metadata.BuildKitMetadata.Source) + require.Nil(t, pred.BuildConfig) + } + }) + } +} + +func testGitProvenanceAttestation(t *testing.T, sb integration.Sandbox) { + workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush, workers.FeatureProvenance) + ctx := sb.Context() + + c, err := client.New(ctx, sb.Address()) + require.NoError(t, err) + defer c.Close() + + registry, err := sb.NewRegistry() + if errors.Is(err, integration.ErrRequirements) { + t.Skip(err.Error()) + } + require.NoError(t, err) + + f := getFrontend(t, sb) + + dockerfile := []byte(` +FROM busybox:latest +RUN --network=none echo "git" > /foo +COPY myapp.Dockerfile / +`) + dir := integration.Tmpdir( + t, + fstest.CreateFile("myapp.Dockerfile", dockerfile, 0600), + ) + + err = runShell(dir, + "git init", + "git config --local user.email test", + "git config --local user.name test", + "git add myapp.Dockerfile", + "git commit -m initial", + "git branch v1", + "git update-server-info", + ) + require.NoError(t, err) + + cmd := exec.Command("git", "rev-parse", "v1") + cmd.Dir = dir + expectedGitSHA, err := cmd.Output() + require.NoError(t, err) + + server := httptest.NewServer(http.FileServer(http.Dir(filepath.Join(dir)))) + defer server.Close() + + target := registry + "/buildkit/testwithprovenance:git" + + // inject dummy credentials to test that they are masked + expectedURL := strings.Replace(server.URL, "http://", "http://xxxxx:xxxxx@", 1) + require.NotEqual(t, expectedURL, server.URL) + server.URL = strings.Replace(server.URL, "http://", "http://user:pass@", 1) + + _, err = f.Solve(sb.Context(), c, client.SolveOpt{ + FrontendAttrs: map[string]string{ + "context": server.URL + "/.git#v1", + "attest:provenance": "", + "filename": "myapp.Dockerfile", + }, + Exports: []client.ExportEntry{ + { + Type: client.ExporterImage, + Attrs: map[string]string{ + "name": target, + "push": "true", + }, + }, + }, + }, nil) + require.NoError(t, err) + + desc, provider, err := contentutil.ProviderFromRef(target) + require.NoError(t, err) + imgs, err := testutil.ReadImages(sb.Context(), provider, desc) + require.NoError(t, err) + require.Equal(t, 2, len(imgs.Images)) + + img := imgs.Find(platforms.Format(platforms.Normalize(platforms.DefaultSpec()))) + require.NotNil(t, img) + require.Equal(t, []byte("git\n"), img.Layers[1]["foo"].Data) + + att := imgs.Find("unknown/unknown") + require.NotNil(t, att) + require.Equal(t, att.Desc.Annotations["vnd.docker.reference.digest"], string(img.Desc.Digest)) + require.Equal(t, att.Desc.Annotations["vnd.docker.reference.type"], "attestation-manifest") + var attest intoto.Statement + require.NoError(t, json.Unmarshal(att.LayersRaw[0], &attest)) + require.Equal(t, "https://in-toto.io/Statement/v0.1", attest.Type) + require.Equal(t, "https://slsa.dev/provenance/v0.2", attest.PredicateType) // intentionally not const + + type stmtT struct { + Predicate provenance.ProvenancePredicate `json:"predicate"` + } + var stmt stmtT + require.NoError(t, json.Unmarshal(att.LayersRaw[0], &stmt)) + pred := stmt.Predicate + + _, isClient := f.(*clientFrontend) + _, isGateway := f.(*gatewayFrontend) + + if isClient { + require.Empty(t, pred.Invocation.Parameters.Frontend) + require.Equal(t, "", pred.Invocation.ConfigSource.URI) + require.Equal(t, "", pred.Invocation.ConfigSource.EntryPoint) + } else { + require.NotEmpty(t, pred.Invocation.Parameters.Frontend) + require.Equal(t, expectedURL+"/.git#v1", pred.Invocation.ConfigSource.URI) + require.Equal(t, "myapp.Dockerfile", pred.Invocation.ConfigSource.EntryPoint) + } + + expBase := "pkg:docker/busybox@latest?platform=" + url.PathEscape(platforms.Format(platforms.Normalize(platforms.DefaultSpec()))) + if isGateway { + require.Equal(t, 3, len(pred.Materials), "%+v", pred.Materials) + + require.Contains(t, pred.Materials[0].URI, "pkg:docker/buildkit_test/") + require.NotEmpty(t, pred.Materials[0].Digest) + + require.Equal(t, expBase, pred.Materials[1].URI) + require.NotEmpty(t, pred.Materials[1].Digest["sha256"]) + + require.Equal(t, expectedURL+"/.git#v1", pred.Materials[2].URI) + require.Equal(t, strings.TrimSpace(string(expectedGitSHA)), pred.Materials[2].Digest["sha1"]) + } else { + require.Equal(t, 2, len(pred.Materials), "%+v", pred.Materials) + + require.Equal(t, expBase, pred.Materials[0].URI) + require.NotEmpty(t, pred.Materials[0].Digest["sha256"]) + + require.Equal(t, expectedURL+"/.git#v1", pred.Materials[1].URI) + require.Equal(t, strings.TrimSpace(string(expectedGitSHA)), pred.Materials[1].Digest["sha1"]) + } + + require.Equal(t, 0, len(pred.Invocation.Parameters.Locals)) + + require.True(t, pred.Metadata.Completeness.Materials) + require.True(t, pred.Metadata.Completeness.Environment) + require.True(t, pred.Metadata.Hermetic) + + if isClient { + require.False(t, pred.Metadata.Completeness.Parameters) + } else { + require.True(t, pred.Metadata.Completeness.Parameters) + } + require.False(t, pred.Metadata.Reproducible) + + require.Equal(t, 0, len(pred.Metadata.BuildKitMetadata.VCS), "%+v", pred.Metadata.BuildKitMetadata.VCS) +} + +func testMultiPlatformProvenance(t *testing.T, sb integration.Sandbox) { + workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush, workers.FeatureMultiPlatform, workers.FeatureProvenance) + ctx := sb.Context() + + c, err := client.New(ctx, sb.Address()) + require.NoError(t, err) + defer c.Close() + + registry, err := sb.NewRegistry() + if errors.Is(err, integration.ErrRequirements) { + t.Skip(err.Error()) + } + require.NoError(t, err) + + f := getFrontend(t, sb) + + dockerfile := []byte(` +FROM busybox:latest +ARG TARGETARCH +RUN echo "ok-$TARGETARCH" > /foo +`) + dir := integration.Tmpdir( + t, + fstest.CreateFile("Dockerfile", dockerfile, 0600), + ) + + target := registry + "/buildkit/testmultiprovenance:latest" + + _, err = f.Solve(sb.Context(), c, client.SolveOpt{ + LocalDirs: map[string]string{ + dockerui.DefaultLocalNameDockerfile: dir, + dockerui.DefaultLocalNameContext: dir, + }, + FrontendAttrs: map[string]string{ + "attest:provenance": "mode=max", + "build-arg:FOO": "bar", + "label:lbl": "abc", + "platform": "linux/amd64,linux/arm64", + }, + Exports: []client.ExportEntry{ + { + Type: client.ExporterImage, + Attrs: map[string]string{ + "name": target, + "push": "true", + }, + }, + }, + }, nil) + require.NoError(t, err) + + desc, provider, err := contentutil.ProviderFromRef(target) + require.NoError(t, err) + imgs, err := testutil.ReadImages(sb.Context(), provider, desc) + require.NoError(t, err) + require.Equal(t, 4, len(imgs.Images)) + + _, isClient := f.(*clientFrontend) + _, isGateway := f.(*gatewayFrontend) + + for _, p := range []string{"linux/amd64", "linux/arm64"} { + img := imgs.Find(p) + require.NotNil(t, img) + if p == "linux/amd64" { + require.Equal(t, []byte("ok-amd64\n"), img.Layers[1]["foo"].Data) + } else { + require.Equal(t, []byte("ok-arm64\n"), img.Layers[1]["foo"].Data) + } + + att := imgs.FindAttestation(p) + require.NotNil(t, att) + require.Equal(t, att.Desc.Annotations["vnd.docker.reference.type"], "attestation-manifest") + var attest intoto.Statement + require.NoError(t, json.Unmarshal(att.LayersRaw[0], &attest)) + require.Equal(t, "https://in-toto.io/Statement/v0.1", attest.Type) + require.Equal(t, "https://slsa.dev/provenance/v0.2", attest.PredicateType) // intentionally not const + + type stmtT struct { + Predicate provenance.ProvenancePredicate `json:"predicate"` + } + var stmt stmtT + require.NoError(t, json.Unmarshal(att.LayersRaw[0], &stmt)) + pred := stmt.Predicate + + require.Equal(t, "https://mobyproject.org/buildkit@v1", pred.BuildType) + require.Equal(t, "", pred.Builder.ID) + require.Equal(t, "", pred.Invocation.ConfigSource.URI) + + if isGateway { + require.Equal(t, 2, len(pred.Materials), "%+v", pred.Materials) + require.Contains(t, pred.Materials[0].URI, "buildkit_test") + require.Contains(t, pred.Materials[1].URI, "pkg:docker/busybox@latest") + require.Contains(t, pred.Materials[1].URI, url.PathEscape(p)) + } else { + require.Equal(t, 1, len(pred.Materials), "%+v", pred.Materials) + require.Contains(t, pred.Materials[0].URI, "pkg:docker/busybox@latest") + require.Contains(t, pred.Materials[0].URI, url.PathEscape(p)) + } + + args := pred.Invocation.Parameters.Args + if isClient { + require.Equal(t, 0, len(args), "%+v", args) + } else if isGateway { + require.Equal(t, 3, len(args), "%+v", args) + require.Equal(t, "bar", args["build-arg:FOO"]) + require.Equal(t, "abc", args["label:lbl"]) + require.Contains(t, args["source"], "buildkit_test/") + } else { + require.Equal(t, 2, len(args), "%+v", args) + require.Equal(t, "bar", args["build-arg:FOO"]) + require.Equal(t, "abc", args["label:lbl"]) + } + } +} + +func testClientFrontendProvenance(t *testing.T, sb integration.Sandbox) { + workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush, workers.FeatureProvenance) + // Building with client frontend does not capture frontend provenance + // because frontend runs in client, not in BuildKit. + // This test builds Dockerfile inside a client frontend ensuring that + // in that case frontend provenance is captured. + ctx := sb.Context() + + c, err := client.New(ctx, sb.Address()) + require.NoError(t, err) + defer c.Close() + + registry, err := sb.NewRegistry() + if errors.Is(err, integration.ErrRequirements) { + t.Skip(err.Error()) + } + require.NoError(t, err) + + target := registry + "/buildkit/clientprovenance:latest" + + f := getFrontend(t, sb) + + _, isClient := f.(*clientFrontend) + if !isClient { + t.Skip("not a client frontend") + } + + dockerfile := []byte(` + FROM alpine as x86target + RUN echo "alpine" > /foo + + FROM busybox:latest AS armtarget + RUN --network=none echo "bbox" > /foo + `) + dir := integration.Tmpdir( + t, + fstest.CreateFile("Dockerfile", dockerfile, 0600), + ) + + frontend := func(ctx context.Context, c gateway.Client) (*gateway.Result, error) { + st := llb.HTTP("https://raw.githubusercontent.com/moby/moby/v20.10.21/README.md") + def, err := st.Marshal(ctx) + if err != nil { + return nil, err + } + // This does not show up in provenance + res0, err := c.Solve(ctx, gateway.SolveRequest{ + Definition: def.ToPB(), + }) + if err != nil { + return nil, err + } + dt, err := res0.Ref.ReadFile(ctx, gateway.ReadRequest{ + Filename: "README.md", + }) + if err != nil { + return nil, err + } + + res1, err := c.Solve(ctx, gateway.SolveRequest{ + Frontend: "dockerfile.v0", + FrontendOpt: map[string]string{ + "build-arg:FOO": string(dt[:3]), + "target": "armtarget", + }, + }) + if err != nil { + return nil, err + } + + res2, err := c.Solve(ctx, gateway.SolveRequest{ + Frontend: "dockerfile.v0", + FrontendOpt: map[string]string{ + "build-arg:FOO": string(dt[4:8]), + "target": "x86target", + }, + }) + if err != nil { + return nil, err + } + + res := gateway.NewResult() + res.AddRef("linux/arm64", res1.Ref) + res.AddRef("linux/amd64", res2.Ref) + + pl, err := json.Marshal(exptypes.Platforms{ + Platforms: []exptypes.Platform{ + { + ID: "linux/arm64", + Platform: ocispecs.Platform{OS: "linux", Architecture: "arm64"}, + }, + { + ID: "linux/amd64", + Platform: ocispecs.Platform{OS: "linux", Architecture: "amd64"}, + }, + }, + }) + if err != nil { + return nil, err + } + res.AddMeta(exptypes.ExporterPlatformsKey, pl) + + return res, nil + } + + _, err = c.Build(sb.Context(), client.SolveOpt{ + FrontendAttrs: map[string]string{ + "attest:provenance": "mode=full", + }, + Exports: []client.ExportEntry{ + { + Type: client.ExporterImage, + Attrs: map[string]string{ + "name": target, + "push": "true", + }, + }, + }, + LocalDirs: map[string]string{ + dockerui.DefaultLocalNameDockerfile: dir, + dockerui.DefaultLocalNameContext: dir, + }, + }, "", frontend, nil) + require.NoError(t, err) + + desc, provider, err := contentutil.ProviderFromRef(target) + require.NoError(t, err) + imgs, err := testutil.ReadImages(sb.Context(), provider, desc) + require.NoError(t, err) + require.Equal(t, 4, len(imgs.Images)) + + img := imgs.Find("linux/arm64") + require.NotNil(t, img) + require.Equal(t, []byte("bbox\n"), img.Layers[1]["foo"].Data) + + att := imgs.FindAttestation("linux/arm64") + require.NotNil(t, att) + require.Equal(t, att.Desc.Annotations["vnd.docker.reference.type"], "attestation-manifest") + var attest intoto.Statement + require.NoError(t, json.Unmarshal(att.LayersRaw[0], &attest)) + require.Equal(t, "https://in-toto.io/Statement/v0.1", attest.Type) + require.Equal(t, "https://slsa.dev/provenance/v0.2", attest.PredicateType) // intentionally not const + + type stmtT struct { + Predicate provenance.ProvenancePredicate `json:"predicate"` + } + var stmt stmtT + require.NoError(t, json.Unmarshal(att.LayersRaw[0], &stmt)) + pred := stmt.Predicate + + require.Equal(t, "https://mobyproject.org/buildkit@v1", pred.BuildType) + require.Equal(t, "", pred.Builder.ID) + require.Equal(t, "", pred.Invocation.ConfigSource.URI) + + args := pred.Invocation.Parameters.Args + require.Equal(t, 2, len(args), "%+v", args) + require.Equal(t, "The", args["build-arg:FOO"]) + require.Equal(t, "armtarget", args["target"]) + + require.Equal(t, 2, len(pred.Invocation.Parameters.Locals)) + require.Equal(t, 1, len(pred.Materials)) + require.Contains(t, pred.Materials[0].URI, "docker/busybox") + + // amd64 + img = imgs.Find("linux/amd64") + require.NotNil(t, img) + require.Equal(t, []byte("alpine\n"), img.Layers[1]["foo"].Data) + + att = imgs.FindAttestation("linux/amd64") + require.NotNil(t, att) + require.Equal(t, att.Desc.Annotations["vnd.docker.reference.type"], "attestation-manifest") + attest = intoto.Statement{} + require.NoError(t, json.Unmarshal(att.LayersRaw[0], &attest)) + require.Equal(t, "https://in-toto.io/Statement/v0.1", attest.Type) + require.Equal(t, "https://slsa.dev/provenance/v0.2", attest.PredicateType) // intentionally not const + + stmt = stmtT{} + require.NoError(t, json.Unmarshal(att.LayersRaw[0], &stmt)) + pred = stmt.Predicate + + require.Equal(t, "https://mobyproject.org/buildkit@v1", pred.BuildType) + require.Equal(t, "", pred.Builder.ID) + require.Equal(t, "", pred.Invocation.ConfigSource.URI) + + args = pred.Invocation.Parameters.Args + require.Equal(t, 2, len(args), "%+v", args) + require.Equal(t, "Moby", args["build-arg:FOO"]) + require.Equal(t, "x86target", args["target"]) + + require.Equal(t, 2, len(pred.Invocation.Parameters.Locals)) + require.Equal(t, 1, len(pred.Materials)) + require.Contains(t, pred.Materials[0].URI, "docker/alpine") +} + +func testClientLLBProvenance(t *testing.T, sb integration.Sandbox) { + workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush, workers.FeatureProvenance) + ctx := sb.Context() + + c, err := client.New(ctx, sb.Address()) + require.NoError(t, err) + defer c.Close() + + registry, err := sb.NewRegistry() + if errors.Is(err, integration.ErrRequirements) { + t.Skip(err.Error()) + } + require.NoError(t, err) + + target := registry + "/buildkit/clientprovenance:llb" + + f := getFrontend(t, sb) + + _, isClient := f.(*clientFrontend) + if !isClient { + t.Skip("not a client frontend") + } + + frontend := func(ctx context.Context, c gateway.Client) (*gateway.Result, error) { + st := llb.HTTP("https://raw.githubusercontent.com/moby/moby/v20.10.21/README.md") + def, err := st.Marshal(ctx) + if err != nil { + return nil, err + } + // this also shows up in the provenance + res0, err := c.Solve(ctx, gateway.SolveRequest{ + Definition: def.ToPB(), + }) + if err != nil { + return nil, err + } + dt, err := res0.Ref.ReadFile(ctx, gateway.ReadRequest{ + Filename: "README.md", + }) + if err != nil { + return nil, err + } + + st = llb.Image("alpine").File(llb.Mkfile("/foo", 0600, dt)) + def, err = st.Marshal(ctx) + if err != nil { + return nil, err + } + res1, err := c.Solve(ctx, gateway.SolveRequest{ + Definition: def.ToPB(), + }) + if err != nil { + return nil, err + } + return res1, nil + } + + _, err = c.Build(sb.Context(), client.SolveOpt{ + FrontendAttrs: map[string]string{ + "attest:provenance": "mode=full", + }, + Exports: []client.ExportEntry{ + { + Type: client.ExporterImage, + Attrs: map[string]string{ + "name": target, + "push": "true", + }, + }, + }, + LocalDirs: map[string]string{}, + }, "", frontend, nil) + require.NoError(t, err) + + desc, provider, err := contentutil.ProviderFromRef(target) + require.NoError(t, err) + imgs, err := testutil.ReadImages(sb.Context(), provider, desc) + require.NoError(t, err) + require.Equal(t, 2, len(imgs.Images)) + + nativePlatform := platforms.Format(platforms.Normalize(platforms.DefaultSpec())) + + img := imgs.Find(nativePlatform) + require.NotNil(t, img) + require.Contains(t, string(img.Layers[1]["foo"].Data), "The Moby Project") + + att := imgs.FindAttestation(nativePlatform) + require.NotNil(t, att) + require.Equal(t, att.Desc.Annotations["vnd.docker.reference.type"], "attestation-manifest") + var attest intoto.Statement + require.NoError(t, json.Unmarshal(att.LayersRaw[0], &attest)) + require.Equal(t, "https://in-toto.io/Statement/v0.1", attest.Type) + require.Equal(t, "https://slsa.dev/provenance/v0.2", attest.PredicateType) // intentionally not const + + type stmtT struct { + Predicate provenance.ProvenancePredicate `json:"predicate"` + } + var stmt stmtT + require.NoError(t, json.Unmarshal(att.LayersRaw[0], &stmt)) + pred := stmt.Predicate + + require.Equal(t, "https://mobyproject.org/buildkit@v1", pred.BuildType) + require.Equal(t, "", pred.Builder.ID) + require.Equal(t, "", pred.Invocation.ConfigSource.URI) + + args := pred.Invocation.Parameters.Args + require.Equal(t, 0, len(args), "%+v", args) + require.Equal(t, 0, len(pred.Invocation.Parameters.Locals)) + + require.Equal(t, 2, len(pred.Materials), "%+v", pred.Materials) + require.Contains(t, pred.Materials[0].URI, "docker/alpine") + require.Contains(t, pred.Materials[1].URI, "README.md") +} + +func testSecretSSHProvenance(t *testing.T, sb integration.Sandbox) { + workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush, workers.FeatureProvenance) + ctx := sb.Context() + + c, err := client.New(ctx, sb.Address()) + require.NoError(t, err) + defer c.Close() + + registry, err := sb.NewRegistry() + if errors.Is(err, integration.ErrRequirements) { + t.Skip(err.Error()) + } + require.NoError(t, err) + + f := getFrontend(t, sb) + + dockerfile := []byte(` +FROM busybox:latest +RUN --mount=type=secret,id=mysecret --mount=type=secret,id=othersecret --mount=type=ssh echo "ok" > /foo +`) + dir := integration.Tmpdir( + t, + fstest.CreateFile("Dockerfile", dockerfile, 0600), + ) + + target := registry + "/buildkit/testsecretprovenance:latest" + _, err = f.Solve(sb.Context(), c, client.SolveOpt{ + LocalDirs: map[string]string{ + dockerui.DefaultLocalNameDockerfile: dir, + dockerui.DefaultLocalNameContext: dir, + }, + FrontendAttrs: map[string]string{ + "attest:provenance": "mode=max", + }, + Exports: []client.ExportEntry{ + { + Type: client.ExporterImage, + Attrs: map[string]string{ + "name": target, + "push": "true", + }, + }, + }, + }, nil) + require.NoError(t, err) + + desc, provider, err := contentutil.ProviderFromRef(target) + require.NoError(t, err) + imgs, err := testutil.ReadImages(sb.Context(), provider, desc) + require.NoError(t, err) + require.Equal(t, 2, len(imgs.Images)) + + expPlatform := platforms.Format(platforms.Normalize(platforms.DefaultSpec())) + + img := imgs.Find(expPlatform) + require.NotNil(t, img) + require.Equal(t, []byte("ok\n"), img.Layers[1]["foo"].Data) + + att := imgs.FindAttestation(expPlatform) + type stmtT struct { + Predicate provenance.ProvenancePredicate `json:"predicate"` + } + var stmt stmtT + require.NoError(t, json.Unmarshal(att.LayersRaw[0], &stmt)) + pred := stmt.Predicate + + require.Equal(t, 2, len(pred.Invocation.Parameters.Secrets), "%+v", pred.Invocation.Parameters.Secrets) + require.Equal(t, "mysecret", pred.Invocation.Parameters.Secrets[0].ID) + require.True(t, pred.Invocation.Parameters.Secrets[0].Optional) + require.Equal(t, "othersecret", pred.Invocation.Parameters.Secrets[1].ID) + require.True(t, pred.Invocation.Parameters.Secrets[1].Optional) + + require.Equal(t, 1, len(pred.Invocation.Parameters.SSH), "%+v", pred.Invocation.Parameters.SSH) + require.Equal(t, "default", pred.Invocation.Parameters.SSH[0].ID) + require.True(t, pred.Invocation.Parameters.SSH[0].Optional) +} + +func testOCILayoutProvenance(t *testing.T, sb integration.Sandbox) { + workers.CheckFeatureCompat(t, sb, workers.FeatureProvenance) + ctx := sb.Context() + + c, err := client.New(ctx, sb.Address()) + require.NoError(t, err) + defer c.Close() + + registry, err := sb.NewRegistry() + if errors.Is(err, integration.ErrRequirements) { + t.Skip(err.Error()) + } + require.NoError(t, err) + target := registry + "/buildkit/clientprovenance:ocilayout" + + f := getFrontend(t, sb) + _, isGateway := f.(*gatewayFrontend) + + ocidir := t.TempDir() + ociDockerfile := []byte(` +FROM scratch +COPY < Date: Fri, 11 Jul 2025 19:02:30 +0100 Subject: [PATCH 03/15] chore: tidy --- .github/workflows/.test.yml | 58 ++++++++++++++----------------------- 1 file changed, 21 insertions(+), 37 deletions(-) diff --git a/.github/workflows/.test.yml b/.github/workflows/.test.yml index 6ff445e87..282cab1f7 100644 --- a/.github/workflows/.test.yml +++ b/.github/workflows/.test.yml @@ -28,7 +28,7 @@ on: env: GO_VERSION: "1.21" - SETUP_BUILDX_VERSION: "latest" + SETUP_BUILDX_VERSION: "0.12.1" SETUP_BUILDKIT_IMAGE: "moby/buildkit:latest" jobs: @@ -40,28 +40,22 @@ jobs: tags: ${{ steps.set.outputs.tags }} includes: ${{ steps.set.outputs.includes }} steps: - - - name: Checkout + - name: Checkout uses: actions/checkout@v4 - - - name: Expose GitHub Runtime + - name: Expose GitHub Runtime uses: crazy-max/ghaction-github-runtime@v3 - - - name: Set up QEMU + - name: Set up QEMU uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: version: ${{ env.SETUP_BUILDX_VERSION }} driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }} buildkitd-flags: --debug - - - name: Deps + - name: Deps run: | npm install js-yaml - - - name: Set outputs + - name: Set outputs id: set uses: actions/github-script@v6 with: @@ -87,8 +81,7 @@ jobs: core.info(JSON.stringify(includes, null, 2)); core.setOutput('includes', JSON.stringify(includes ?? [])); }); - - - name: Build + - name: Build uses: docker/bake-action@v4 with: targets: integration-tests-base @@ -105,6 +98,7 @@ jobs: TESTFLAGS: "-v --parallel=6 --timeout=30m" GOTESTSUM_FORMAT: "standard-verbose" TEST_IMAGE_BUILD: "0" + TEST_IMAGE_ID: "buildkit-tests" strategy: fail-fast: false matrix: @@ -121,39 +115,33 @@ jobs: tags: ${{ fromJson(needs.prepare.outputs.tags) }} include: ${{ fromJson(needs.prepare.outputs.includes) }} steps: - - - name: Environment variables + - name: Environment variables run: | for l in "${{ inputs.env }}"; do echo "${l?}" >> $GITHUB_ENV done - - - name: Checkout + - name: Checkout uses: actions/checkout@v4 - - - name: Expose GitHub Runtime + - name: Expose GitHub Runtime uses: crazy-max/ghaction-github-runtime@v3 - - - name: Set up QEMU + - name: Set up QEMU uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: version: ${{ env.SETUP_BUILDX_VERSION }} driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }} buildkitd-flags: --debug - - - name: Build test image + - name: Build test image uses: docker/bake-action@v4 with: targets: integration-tests set: | *.cache-from=type=gha,scope=${{ inputs.cache_scope }} + *.output=type=docker,name=${{ env.TEST_IMAGE_ID }} env: BUILDKITD_TAGS: ${{ matrix.tags }} - - - name: Test + - name: Test continue-on-error: ${{ matrix.tags == 'nydus' }} run: | export TEST_REPORT_SUFFIX=-${{ github.job }}-$(echo "${{ matrix.pkg }}-${{ matrix.skip-integration-tests }}-${{ matrix.kind }}-${{ matrix.worker }}-${{ matrix.tags }}" | tr -dc '[:alnum:]-\n\r' | tr '[:upper:]' '[:lower:]') @@ -170,27 +158,23 @@ jobs: TESTPKGS: ${{ matrix.pkg }} SKIP_INTEGRATION_TESTS: 1 CACHE_FROM: type=gha,scope=${{ inputs.cache_scope }} - - - name: Send to Codecov + - name: Send to Codecov if: always() uses: codecov/codecov-action@v3 with: directory: ./bin/testreports flags: ${{ matrix.codecov_flags }} - - - name: Generate annotations + - name: Generate annotations if: always() uses: crazy-max/.github/.github/actions/gotest-annotations@5af0882e0496d2f7e98a53ae4048e3d86682496f with: directory: ./bin/testreports - - - name: Upload test reports + - name: Upload test reports if: always() uses: actions/upload-artifact@v4 with: name: test-reports path: ./bin/testreports - - - name: Dump context + - name: Dump context if: failure() uses: crazy-max/ghaction-dump-context@v2 From 18467e6ef4894cb0d42b6be399d11764f4bf267e Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 11 Jul 2025 19:03:53 +0100 Subject: [PATCH 04/15] chore: tidy --- .github/workflows/.test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/.test.yml b/.github/workflows/.test.yml index 282cab1f7..099c2c716 100644 --- a/.github/workflows/.test.yml +++ b/.github/workflows/.test.yml @@ -28,7 +28,7 @@ on: env: GO_VERSION: "1.21" - SETUP_BUILDX_VERSION: "0.12.1" + SETUP_BUILDX_VERSION: "v0.12.1" SETUP_BUILDKIT_IMAGE: "moby/buildkit:latest" jobs: From 6842e53b1bf940d5ba4c131afdcd47f2f9cc5ace Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 11 Jul 2025 19:25:23 +0100 Subject: [PATCH 05/15] chore: tidy --- .github/workflows/.test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/.test.yml b/.github/workflows/.test.yml index 099c2c716..88db50f4a 100644 --- a/.github/workflows/.test.yml +++ b/.github/workflows/.test.yml @@ -28,7 +28,7 @@ on: env: GO_VERSION: "1.21" - SETUP_BUILDX_VERSION: "v0.12.1" + SETUP_BUILDX_VERSION: "v0.13.0" SETUP_BUILDKIT_IMAGE: "moby/buildkit:latest" jobs: From a7d4c821605966f86219609eabb206f8f9565b4b Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 11 Jul 2025 19:39:55 +0100 Subject: [PATCH 06/15] chore: undo locking buildx version --- .github/workflows/.test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/.test.yml b/.github/workflows/.test.yml index 88db50f4a..2f23223c8 100644 --- a/.github/workflows/.test.yml +++ b/.github/workflows/.test.yml @@ -28,7 +28,7 @@ on: env: GO_VERSION: "1.21" - SETUP_BUILDX_VERSION: "v0.13.0" + SETUP_BUILDX_VERSION: "latest" SETUP_BUILDKIT_IMAGE: "moby/buildkit:latest" jobs: From 18a0330a7efd701e5033ab2ee666098a8e10be6c Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 11 Jul 2025 20:45:17 +0100 Subject: [PATCH 07/15] chore: tidy --- docker-bake.hcl | 9 --------- 1 file changed, 9 deletions(-) diff --git a/docker-bake.hcl b/docker-bake.hcl index ef46ea2b7..178c636e5 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -42,11 +42,6 @@ variable "CGO_ENABLED" { variable "DESTDIR" { default = "" } - -variable "TEST_IMAGE_NAME" { - default = "buildkit-tests" -} - function "bindir" { params = [defaultdir] result = DESTDIR != "" ? DESTDIR : "./bin/${defaultdir}" @@ -110,10 +105,6 @@ target "integration-tests-base" { target "integration-tests" { inherits = ["integration-tests-base"] target = "integration-tests" - attest = [] - output = [ - "type=docker,name=${TEST_IMAGE_NAME}", - ] } group "validate" { From b96a1ddf96420cb1e8df1fdc1f9f18c588b7c5ae Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 11 Jul 2025 21:26:05 +0100 Subject: [PATCH 08/15] chore: test with buildx 0.8.2 --- .github/workflows/.test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/.test.yml b/.github/workflows/.test.yml index 2f23223c8..c8ee72ba3 100644 --- a/.github/workflows/.test.yml +++ b/.github/workflows/.test.yml @@ -28,7 +28,7 @@ on: env: GO_VERSION: "1.21" - SETUP_BUILDX_VERSION: "latest" + SETUP_BUILDX_VERSION: "v0.8.2" SETUP_BUILDKIT_IMAGE: "moby/buildkit:latest" jobs: From 52325b5bef1fb3938179dbb3c072a0612b26fccd Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 11 Jul 2025 21:28:30 +0100 Subject: [PATCH 09/15] chore: test with buildx v0.11.1 --- .github/workflows/.test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/.test.yml b/.github/workflows/.test.yml index c8ee72ba3..6f6960e97 100644 --- a/.github/workflows/.test.yml +++ b/.github/workflows/.test.yml @@ -28,7 +28,7 @@ on: env: GO_VERSION: "1.21" - SETUP_BUILDX_VERSION: "v0.8.2" + SETUP_BUILDX_VERSION: "v0.11.1" SETUP_BUILDKIT_IMAGE: "moby/buildkit:latest" jobs: From 417e95e76b0074120cf6254b01c5f62ba9573545 Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 11 Jul 2025 21:41:49 +0100 Subject: [PATCH 10/15] chore: test falsy proverance --- .github/workflows/.test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/.test.yml b/.github/workflows/.test.yml index 6f6960e97..2701d86f2 100644 --- a/.github/workflows/.test.yml +++ b/.github/workflows/.test.yml @@ -28,7 +28,7 @@ on: env: GO_VERSION: "1.21" - SETUP_BUILDX_VERSION: "v0.11.1" + SETUP_BUILDX_VERSION: "latest" SETUP_BUILDKIT_IMAGE: "moby/buildkit:latest" jobs: @@ -84,6 +84,7 @@ jobs: - name: Build uses: docker/bake-action@v4 with: + provenance: false targets: integration-tests-base set: | *.cache-from=type=gha,scope=${{ inputs.cache_scope }} From 9196d62a160ee78eafae22df7ac067989e51c70c Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 11 Jul 2025 21:52:45 +0100 Subject: [PATCH 11/15] chore: test falsy proverance --- .github/workflows/.test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/.test.yml b/.github/workflows/.test.yml index 2701d86f2..547dab5fd 100644 --- a/.github/workflows/.test.yml +++ b/.github/workflows/.test.yml @@ -136,6 +136,7 @@ jobs: - name: Build test image uses: docker/bake-action@v4 with: + provenance: false targets: integration-tests set: | *.cache-from=type=gha,scope=${{ inputs.cache_scope }} From fdd50eeab3a7c22b7ccb387d695a67a3dd091a98 Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Sat, 12 Jul 2025 14:00:18 +0100 Subject: [PATCH 12/15] style: unformat .test.yml --- .github/workflows/.test.yml | 56 ++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/.github/workflows/.test.yml b/.github/workflows/.test.yml index 547dab5fd..43c3d3546 100644 --- a/.github/workflows/.test.yml +++ b/.github/workflows/.test.yml @@ -40,22 +40,28 @@ jobs: tags: ${{ steps.set.outputs.tags }} includes: ${{ steps.set.outputs.includes }} steps: - - name: Checkout + - + name: Checkout uses: actions/checkout@v4 - - name: Expose GitHub Runtime + - + name: Expose GitHub Runtime uses: crazy-max/ghaction-github-runtime@v3 - - name: Set up QEMU + - + name: Set up QEMU uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx + - + name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: version: ${{ env.SETUP_BUILDX_VERSION }} driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }} buildkitd-flags: --debug - - name: Deps + - + name: Deps run: | npm install js-yaml - - name: Set outputs + - + name: Set outputs id: set uses: actions/github-script@v6 with: @@ -81,10 +87,10 @@ jobs: core.info(JSON.stringify(includes, null, 2)); core.setOutput('includes', JSON.stringify(includes ?? [])); }); - - name: Build + - + name: Build uses: docker/bake-action@v4 with: - provenance: false targets: integration-tests-base set: | *.cache-from=type=gha,scope=${{ inputs.cache_scope }} @@ -116,34 +122,40 @@ jobs: tags: ${{ fromJson(needs.prepare.outputs.tags) }} include: ${{ fromJson(needs.prepare.outputs.includes) }} steps: - - name: Environment variables + - + name: Environment variables run: | for l in "${{ inputs.env }}"; do echo "${l?}" >> $GITHUB_ENV done - - name: Checkout + - + name: Checkout uses: actions/checkout@v4 - - name: Expose GitHub Runtime + - + name: Expose GitHub Runtime uses: crazy-max/ghaction-github-runtime@v3 - - name: Set up QEMU + - + name: Set up QEMU uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx + - + name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: version: ${{ env.SETUP_BUILDX_VERSION }} driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }} buildkitd-flags: --debug - - name: Build test image + - + name: Build test image uses: docker/bake-action@v4 with: - provenance: false targets: integration-tests set: | *.cache-from=type=gha,scope=${{ inputs.cache_scope }} *.output=type=docker,name=${{ env.TEST_IMAGE_ID }} env: BUILDKITD_TAGS: ${{ matrix.tags }} - - name: Test + - + name: Test continue-on-error: ${{ matrix.tags == 'nydus' }} run: | export TEST_REPORT_SUFFIX=-${{ github.job }}-$(echo "${{ matrix.pkg }}-${{ matrix.skip-integration-tests }}-${{ matrix.kind }}-${{ matrix.worker }}-${{ matrix.tags }}" | tr -dc '[:alnum:]-\n\r' | tr '[:upper:]' '[:lower:]') @@ -160,23 +172,27 @@ jobs: TESTPKGS: ${{ matrix.pkg }} SKIP_INTEGRATION_TESTS: 1 CACHE_FROM: type=gha,scope=${{ inputs.cache_scope }} - - name: Send to Codecov + - + name: Send to Codecov if: always() uses: codecov/codecov-action@v3 with: directory: ./bin/testreports flags: ${{ matrix.codecov_flags }} - - name: Generate annotations + - + name: Generate annotations if: always() uses: crazy-max/.github/.github/actions/gotest-annotations@5af0882e0496d2f7e98a53ae4048e3d86682496f with: directory: ./bin/testreports - - name: Upload test reports + - + name: Upload test reports if: always() uses: actions/upload-artifact@v4 with: name: test-reports path: ./bin/testreports - - name: Dump context + - + name: Dump context if: failure() uses: crazy-max/ghaction-dump-context@v2 From 12f03ac2b910fad490e1591e423bc4b9d5cc5a37 Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Mon, 14 Jul 2025 10:06:45 +0100 Subject: [PATCH 13/15] style: unformat .test.yml --- .github/workflows/.test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/.test.yml b/.github/workflows/.test.yml index 43c3d3546..45919f25b 100644 --- a/.github/workflows/.test.yml +++ b/.github/workflows/.test.yml @@ -91,6 +91,7 @@ jobs: name: Build uses: docker/bake-action@v4 with: + provenance: false targets: integration-tests-base set: | *.cache-from=type=gha,scope=${{ inputs.cache_scope }} @@ -148,6 +149,7 @@ jobs: name: Build test image uses: docker/bake-action@v4 with: + provenance: false targets: integration-tests set: | *.cache-from=type=gha,scope=${{ inputs.cache_scope }} From 904b33d5567cae0eeece6b86b92d8618da26e35d Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Mon, 14 Jul 2025 14:53:31 +0100 Subject: [PATCH 14/15] chore: allow to overwrite test reports --- .github/workflows/.test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/.test.yml b/.github/workflows/.test.yml index 45919f25b..66a08ca45 100644 --- a/.github/workflows/.test.yml +++ b/.github/workflows/.test.yml @@ -194,6 +194,7 @@ jobs: with: name: test-reports path: ./bin/testreports + overwrite: true - name: Dump context if: failure() From 58e660d5ed52578ee3f2e424f2629495fb2bbaca Mon Sep 17 00:00:00 2001 From: Squirrel Date: Wed, 16 Jul 2025 21:25:35 +0100 Subject: [PATCH 15/15] Update snapshot/diffapply_unix.go Good call Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- snapshot/diffapply_unix.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snapshot/diffapply_unix.go b/snapshot/diffapply_unix.go index bb45e5198..2cd9e9b34 100644 --- a/snapshot/diffapply_unix.go +++ b/snapshot/diffapply_unix.go @@ -297,7 +297,7 @@ func (a *applier) applyDelete(ctx context.Context, ca *changeApply) (bool, error if ca.srcStat == nil { ca.srcStat = &syscall.Stat_t{ Mode: syscall.S_IFCHR, - Rdev: unix.Mkdev(0, 0), + Rdev: 0, } ca.srcPath = "" }