Skip to content

Commit 8f91793

Browse files
ndeloofglours
authored andcommitted
introduce build.provenance and sbom support
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
1 parent 1d2223f commit 8f91793

File tree

7 files changed

+63
-9
lines changed

7 files changed

+63
-9
lines changed

cmd/compose/build.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ type buildOptions struct {
4545
deps bool
4646
print bool
4747
check bool
48-
provenance bool
48+
sbom string
49+
provenance string
4950
}
5051

5152
func (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions, error) {
@@ -84,6 +85,7 @@ func (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions,
8485
Check: opts.check,
8586
SSHs: SSHKeys,
8687
Builder: builderName,
88+
SBOM: opts.sbom,
8789
Provenance: opts.provenance,
8890
}, nil
8991
}
@@ -125,6 +127,8 @@ func buildCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
125127
flags.StringVar(&opts.ssh, "ssh", "", "Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent)")
126128
flags.StringVar(&opts.builder, "builder", "", "Set builder to use")
127129
flags.BoolVar(&opts.deps, "with-dependencies", false, "Also build dependencies (transitively)")
130+
flags.StringVar(&opts.provenance, "provenance", "", `Add a provenance attestation`)
131+
flags.StringVar(&opts.sbom, "sbom", "", `Add a SBOM attestation`)
128132

129133
flags.Bool("parallel", true, "Build images in parallel. DEPRECATED")
130134
flags.MarkHidden("parallel") //nolint:errcheck
@@ -156,7 +160,7 @@ func runBuild(ctx context.Context, dockerCli command.Cli, backend api.Service, o
156160
}
157161

158162
apiBuildOptions, err := opts.toAPIBuildOptions(services)
159-
apiBuildOptions.Provenance = true
163+
apiBuildOptions.Attestations = true
160164
if err != nil {
161165
return err
162166
}

docs/reference/compose_build.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ run `docker compose build` to rebuild it.
2222
| `-m`, `--memory` | `bytes` | `0` | Set memory limit for the build container. Not supported by BuildKit. |
2323
| `--no-cache` | `bool` | | Do not use cache when building the image |
2424
| `--print` | `bool` | | Print equivalent bake file |
25+
| `--provenance` | `string` | | Add a provenance attestation |
2526
| `--pull` | `bool` | | Always attempt to pull a newer version of the image |
2627
| `--push` | `bool` | | Push service images |
2728
| `-q`, `--quiet` | `bool` | | Don't print anything to STDOUT |
29+
| `--sbom` | `string` | | Add a SBOM attestation |
2830
| `--ssh` | `string` | | Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent) |
2931
| `--with-dependencies` | `bool` | | Also build dependencies (transitively) |
3032

docs/reference/docker_compose_build.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,15 @@ options:
125125
experimentalcli: false
126126
kubernetes: false
127127
swarm: false
128+
- option: provenance
129+
value_type: string
130+
description: Add a provenance attestation
131+
deprecated: false
132+
hidden: false
133+
experimental: false
134+
experimentalcli: false
135+
kubernetes: false
136+
swarm: false
128137
- option: pull
129138
value_type: bool
130139
default_value: "false"
@@ -156,6 +165,15 @@ options:
156165
experimentalcli: false
157166
kubernetes: false
158167
swarm: false
168+
- option: sbom
169+
value_type: string
170+
description: Add a SBOM attestation
171+
deprecated: false
172+
hidden: false
173+
experimental: false
174+
experimentalcli: false
175+
kubernetes: false
176+
swarm: false
159177
- option: ssh
160178
value_type: string
161179
description: |

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require (
88
github.com/Microsoft/go-winio v0.6.2
99
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
1010
github.com/buger/goterm v1.0.4
11-
github.com/compose-spec/compose-go/v2 v2.7.1
11+
github.com/compose-spec/compose-go/v2 v2.7.2-0.20250721082312-a42e7579d813
1212
github.com/containerd/containerd/v2 v2.1.3
1313
github.com/containerd/errdefs v1.0.0
1414
github.com/containerd/platforms v1.0.0-rc.1
@@ -181,6 +181,7 @@ require (
181181
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
182182
go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
183183
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
184+
go.yaml.in/yaml/v3 v3.0.4 // indirect
184185
golang.org/x/crypto v0.37.0 // indirect
185186
golang.org/x/net v0.39.0 // indirect
186187
golang.org/x/oauth2 v0.29.0 // indirect

go.sum

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e
8080
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
8181
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
8282
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
83-
github.com/compose-spec/compose-go/v2 v2.7.1 h1:EUIbuaD0R/J1KA+FbJMNbcS9+jt/CVudbp5iHqUllSs=
84-
github.com/compose-spec/compose-go/v2 v2.7.1/go.mod h1:TmjkIB9W73fwVxkYY+u2uhMbMUakjiif79DlYgXsyvU=
83+
github.com/compose-spec/compose-go/v2 v2.7.2-0.20250721082312-a42e7579d813 h1:Lmtch++VWP8Oqzff+FJflVW3g6/JFtDc3wq+tvRsagE=
84+
github.com/compose-spec/compose-go/v2 v2.7.2-0.20250721082312-a42e7579d813/go.mod h1:veko/VB7URrg/tKz3vmIAQDaz+CGiXH8vZsW79NmAww=
8585
github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJHo6Bzo=
8686
github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
8787
github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/qqsc=
@@ -539,6 +539,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
539539
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
540540
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
541541
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
542+
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
543+
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
542544
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
543545
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
544546
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=

pkg/api/api.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,12 @@ type BuildOptions struct {
170170
Print bool
171171
// Check let builder validate build configuration
172172
Check bool
173-
// Provenance
174-
Provenance bool
173+
// Attestations allows to enable attestations generation
174+
Attestations bool
175+
// Provenance generate a provenance attestation
176+
Provenance string
177+
// SBOM generate a SBOM attestation
178+
SBOM string
175179
}
176180

177181
// Apply mutates project according to build options

pkg/compose/build.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"errors"
2222
"fmt"
2323
"os"
24+
"strconv"
2425
"strings"
2526
"time"
2627

@@ -397,6 +398,7 @@ func resolveAndMergeBuildArgs(dockerCli command.Cli, project *types.Project, ser
397398
return result
398399
}
399400

401+
//nolint:gocyclo
400402
func (s *composeService) toBuildOptions(project *types.Project, service types.ServiceConfig, options api.BuildOptions) (build.Options, error) {
401403
plats, err := parsePlatforms(service)
402404
if err != nil {
@@ -471,8 +473,19 @@ func (s *composeService) toBuildOptions(project *types.Project, service types.Se
471473
}
472474

473475
attests := map[string]*string{}
474-
if !options.Provenance {
475-
attests["provenance"] = nil
476+
if options.Attestations {
477+
if service.Build.Provenance != "" {
478+
attests["provenance"] = attestation(service.Build.Provenance, "provenance")
479+
}
480+
if service.Build.SBOM != "" {
481+
attests["sbom"] = attestation(service.Build.SBOM, "sbom")
482+
}
483+
}
484+
if options.Provenance != "" {
485+
attests["provenance"] = attestation(options.Provenance, "provenance")
486+
}
487+
if options.SBOM != "" {
488+
attests["sbom"] = attestation(options.SBOM, "sbom")
476489
}
477490

478491
return build.Options{
@@ -502,6 +515,16 @@ func (s *composeService) toBuildOptions(project *types.Project, service types.Se
502515
}, nil
503516
}
504517

518+
func attestation(attest string, val string) *string {
519+
if b, err := strconv.ParseBool(val); err == nil {
520+
s := fmt.Sprintf("type=%s,disabled=%t", attest, b)
521+
return &s
522+
} else {
523+
s := fmt.Sprintf("type=%s,%s", attest, val)
524+
return &s
525+
}
526+
}
527+
505528
func toUlimitOpt(ulimits map[string]*types.UlimitsConfig) *cliopts.UlimitOpt {
506529
ref := map[string]*container.Ulimit{}
507530
for _, limit := range toUlimits(ulimits) {

0 commit comments

Comments
 (0)