diff --git a/build/provenance.go b/build/provenance.go index 4a9b2d188158..44ca10f81dfd 100644 --- a/build/provenance.go +++ b/build/provenance.go @@ -13,6 +13,8 @@ import ( "github.com/containerd/containerd/v2/core/content/proxy" "github.com/docker/buildx/util/confutil" "github.com/docker/buildx/util/progress" + slsa02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" + slsa1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" controlapi "github.com/moby/buildkit/api/services/control" "github.com/moby/buildkit/client" provenancetypes "github.com/moby/buildkit/solver/llbsolver/provenance/types" @@ -22,15 +24,6 @@ import ( "golang.org/x/sync/errgroup" ) -type provenancePredicate struct { - Builder *provenanceBuilder `json:"builder,omitempty"` - provenancetypes.ProvenancePredicateSLSA02 -} - -type provenanceBuilder struct { - ID string `json:"id,omitempty"` -} - func setRecordProvenance(ctx context.Context, c *client.Client, sr *client.SolveResponse, ref string, mode confutil.MetadataProvenanceMode, pw progress.Writer) error { if mode == confutil.MetadataProvenanceModeDisabled { return nil @@ -69,7 +62,7 @@ func fetchProvenance(ctx context.Context, c *client.Client, ref string, mode con continue } if ev.Record.Result != nil { - desc := lookupProvenance(ev.Record.Result) + desc, predicateType := lookupProvenance(ev.Record.Result) if desc == nil { continue } @@ -78,7 +71,7 @@ func fetchProvenance(ctx context.Context, c *client.Client, ref string, mode con if err != nil { return errors.Wrapf(err, "failed to load provenance blob from build record") } - prv, err := encodeProvenance(dt, mode) + prv, err := encodeProvenance(dt, predicateType, mode) if err != nil { return err } @@ -92,7 +85,7 @@ func fetchProvenance(ctx context.Context, c *client.Client, ref string, mode con }) } else if ev.Record.Results != nil { for platform, res := range ev.Record.Results { - desc := lookupProvenance(res) + desc, predicateType := lookupProvenance(res) if desc == nil { continue } @@ -101,7 +94,7 @@ func fetchProvenance(ctx context.Context, c *client.Client, ref string, mode con if err != nil { return errors.Wrapf(err, "failed to load provenance blob from build record") } - prv, err := encodeProvenance(dt, mode) + prv, err := encodeProvenance(dt, predicateType, mode) if err != nil { return err } @@ -119,7 +112,7 @@ func fetchProvenance(ctx context.Context, c *client.Client, ref string, mode con return out, eg.Wait() } -func lookupProvenance(res *controlapi.BuildResultInfo) *ocispecs.Descriptor { +func lookupProvenance(res *controlapi.BuildResultInfo) (*ocispecs.Descriptor, string) { for _, a := range res.Attestations { if a.MediaType == "application/vnd.in-toto+json" && strings.HasPrefix(a.Annotations["in-toto.io/predicate-type"], "https://slsa.dev/provenance/") { return &ocispecs.Descriptor{ @@ -127,27 +120,35 @@ func lookupProvenance(res *controlapi.BuildResultInfo) *ocispecs.Descriptor { Size: a.Size, MediaType: a.MediaType, Annotations: a.Annotations, - } + }, a.Annotations["in-toto.io/predicate-type"] } } - return nil + return nil, "" } -func encodeProvenance(dt []byte, mode confutil.MetadataProvenanceMode) (string, error) { - var prv provenancePredicate - if err := json.Unmarshal(dt, &prv); err != nil { +func encodeProvenance(dt []byte, predicateType string, mode confutil.MetadataProvenanceMode) (string, error) { + var pred *provenancetypes.ProvenancePredicateSLSA1 + if predicateType == slsa02.PredicateSLSAProvenance { + var pred02 *provenancetypes.ProvenancePredicateSLSA02 + if err := json.Unmarshal(dt, &pred02); err != nil { + return "", errors.Wrapf(err, "failed to unmarshal provenance") + } + pred = provenancetypes.ConvertSLSA02ToSLSA1(pred02) + } else if err := json.Unmarshal(dt, &pred); err != nil { return "", errors.Wrapf(err, "failed to unmarshal provenance") } - if prv.Builder != nil && prv.Builder.ID == "" { - // reset builder if id is empty - prv.Builder = nil - } if mode == confutil.MetadataProvenanceModeMin { // reset fields for minimal provenance - prv.BuildConfig = nil - prv.Metadata = nil + pred.BuildDefinition.InternalParameters.BuildConfig = nil + pred.RunDetails.Metadata = nil } - dtprv, err := json.Marshal(prv) + dtprv, err := json.Marshal(struct { + PredicateType string `json:"predicateType"` + provenancetypes.ProvenancePredicateSLSA1 + }{ + PredicateType: slsa1.PredicateSLSAProvenance, + ProvenancePredicateSLSA1: *pred, + }) if err != nil { return "", errors.Wrapf(err, "failed to marshal provenance") } diff --git a/docs/reference/buildx_build.md b/docs/reference/buildx_build.md index dd320cc8f114..63deab94392a 100644 --- a/docs/reference/buildx_build.md +++ b/docs/reference/buildx_build.md @@ -354,13 +354,13 @@ executing the build and evaluating [build checks](https://docs.docker.com/refere For Dockerfiles, the available methods are: -| Command | Description | -| ------------------------------ | ------------------------------------------------------------------------------------------------------------------- | -| `build` (default) | Execute the build and evaluate build checks for the current build target. | -| `check` | Evaluate build checks for the either the entire Dockerfile or the selected target, without executing a build. | -| `outline` | Show the build arguments that you can set for a target, and their default values. | -| `targets` | List all the build targets in the Dockerfile. | -| `subrequests.describe` | List all the frontend methods that the current frontend supports. | +| Command | Description | +|------------------------|---------------------------------------------------------------------------------------------------------------| +| `build` (default) | Execute the build and evaluate build checks for the current build target. | +| `check` | Evaluate build checks for the either the entire Dockerfile or the selected target, without executing a build. | +| `outline` | Show the build arguments that you can set for a target, and their default values. | +| `targets` | List all the build targets in the Dockerfile. | +| `subrequests.describe` | List all the frontend methods that the current frontend supports. | Note that other frontends may implement these or other methods. To see the list of available methods for the frontend you're using, @@ -948,7 +948,7 @@ $ docker buildx build --secret [type=file,]id=[,src=] . ##### `type=file` attributes | Key | Description | Default | -| --------------- | ----------------------------------------------------------------------------------------------------- | -------------------------- | +|-----------------|-------------------------------------------------------------------------------------------------------|----------------------------| | `id` | ID of the secret. | N/A (this key is required) | | `src`, `source` | Filepath of the file containing the secret value (absolute or relative to current working directory). | `id` if unset. | @@ -982,7 +982,7 @@ $ docker buildx build --secret [type=env,]id=[,env=] . ##### `type=env` attributes | Key | Description | Default | -| ---------------------- | ----------------------------------------------- | -------------------------- | +|------------------------|-------------------------------------------------|----------------------------| | `id` | ID of the secret. | N/A (this key is required) | | `env`, `src`, `source` | Environment variable to source the secret from. | `id` if unset. | diff --git a/tests/bake.go b/tests/bake.go index 0ce6d216c8b9..e652de9bdcf3 100644 --- a/tests/bake.go +++ b/tests/bake.go @@ -18,6 +18,7 @@ import ( "github.com/docker/buildx/bake" "github.com/docker/buildx/util/gitutil" "github.com/docker/buildx/util/gitutil/gittestutil" + slsa1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" "github.com/moby/buildkit/client" "github.com/moby/buildkit/frontend/subrequests/lint" "github.com/moby/buildkit/identity" @@ -1396,9 +1397,14 @@ target "default" { dtprv, err := json.Marshal(md.Default.BuildProvenance) require.NoError(t, err) - var prv provenancetypes.ProvenancePredicateSLSA02 + type provenancePredicate struct { + PredicateType string `json:"predicateType"` + provenancetypes.ProvenancePredicateSLSA1 + } + var prv provenancePredicate require.NoError(t, json.Unmarshal(dtprv, &prv)) - require.Equal(t, provenancetypes.BuildKitBuildType, prv.BuildType) + require.Equal(t, slsa1.PredicateSLSAProvenance, prv.PredicateType) + require.Equal(t, "https://github.com/moby/buildkit/blob/master/docs/attestations/slsa-definitions.md", prv.BuildDefinition.BuildType) } func testBakeMetadataWarnings(t *testing.T, sb integration.Sandbox) { diff --git a/tests/build.go b/tests/build.go index e179163cf92a..96152d11fbf6 100644 --- a/tests/build.go +++ b/tests/build.go @@ -20,6 +20,7 @@ import ( "github.com/docker/buildx/util/confutil" "github.com/docker/buildx/util/gitutil" "github.com/docker/buildx/util/gitutil/gittestutil" + slsa1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" "github.com/moby/buildkit/client" "github.com/moby/buildkit/frontend/subrequests/lint" "github.com/moby/buildkit/frontend/subrequests/outline" @@ -833,9 +834,14 @@ func buildMetadataProvenance(t *testing.T, sb integration.Sandbox, metadataMode dtprv, err := json.Marshal(md.BuildProvenance) require.NoError(t, err) - var prv provenancetypes.ProvenancePredicateSLSA02 + type provenancePredicate struct { + PredicateType string `json:"predicateType"` + provenancetypes.ProvenancePredicateSLSA1 + } + var prv provenancePredicate require.NoError(t, json.Unmarshal(dtprv, &prv)) - require.Equal(t, provenancetypes.BuildKitBuildType, prv.BuildType) + require.Equal(t, slsa1.PredicateSLSAProvenance, prv.PredicateType) + require.Equal(t, "https://github.com/moby/buildkit/blob/master/docs/attestations/slsa-definitions.md", prv.BuildDefinition.BuildType) } func testBuildMetadataWarnings(t *testing.T, sb integration.Sandbox) {