mirror of
https://github.com/docker/compose.git
synced 2026-10-12 02:13:08 +00:00
fix(build): honor provenance/sbom false in per-service bake attest
When a service set `build.provenance: false` (or `sbom: false`), the bake attest entry was silently omitted (the field is `omitempty`), so BuildKit applied its defaults and attached a provenance attestation anyway. The attestation changes the manifest-list digest on every build, which caused containers to be needlessly recreated on `up --build`. Emit `"type=<t>,disabled=true"` instead, which BuildKit's `Attest.UnmarshalText` parses as `Disabled:true` and forwards to BuildKit as an explicit disable signal. Extract `appendAttest` to avoid duplicating the three-branch switch for both provenance and sbom. Fixes #14111 Signed-off-by: Guillaume Lours <[email protected]>
This commit is contained in:
committed by
Nicolas De loof
parent
a472f714d5
commit
03ad3cc1c2
+13
-17
@@ -599,25 +599,21 @@ func toBakeSecrets(project *types.Project, secrets []types.ServiceSecretConfig)
|
||||
|
||||
func toBakeAttest(buildConfig types.BuildConfig) []string {
|
||||
var attests []string
|
||||
attests = appendAttest(attests, "provenance", buildConfig.Provenance)
|
||||
attests = appendAttest(attests, "sbom", buildConfig.SBOM)
|
||||
return attests
|
||||
}
|
||||
|
||||
// Handle per-service provenance configuration (only from build config, not global options)
|
||||
if buildConfig.Provenance != "" {
|
||||
if buildConfig.Provenance == "true" {
|
||||
attests = append(attests, "type=provenance")
|
||||
} else if buildConfig.Provenance != "false" {
|
||||
attests = append(attests, fmt.Sprintf("type=provenance,%s", buildConfig.Provenance))
|
||||
}
|
||||
func appendAttest(attests []string, attestType, value string) []string {
|
||||
switch value {
|
||||
case "":
|
||||
case "true":
|
||||
attests = append(attests, "type="+attestType)
|
||||
case "false":
|
||||
attests = append(attests, "type="+attestType+",disabled=true")
|
||||
default:
|
||||
attests = append(attests, fmt.Sprintf("type=%s,%s", attestType, value))
|
||||
}
|
||||
|
||||
// Handle per-service SBOM configuration (only from build config, not global options)
|
||||
if buildConfig.SBOM != "" {
|
||||
if buildConfig.SBOM == "true" {
|
||||
attests = append(attests, "type=sbom")
|
||||
} else if buildConfig.SBOM != "false" {
|
||||
attests = append(attests, fmt.Sprintf("type=sbom,%s", buildConfig.SBOM))
|
||||
}
|
||||
}
|
||||
|
||||
return attests
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,55 @@ func TestBakeTargetNames(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestToBakeAttest(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config types.BuildConfig
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "empty — no attest entries",
|
||||
config: types.BuildConfig{},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "provenance true",
|
||||
config: types.BuildConfig{Provenance: "true"},
|
||||
expected: []string{"type=provenance"},
|
||||
},
|
||||
{
|
||||
name: "provenance false — must disable, not omit",
|
||||
config: types.BuildConfig{Provenance: "false"},
|
||||
expected: []string{"type=provenance,disabled=true"},
|
||||
},
|
||||
{
|
||||
name: "provenance mode=max",
|
||||
config: types.BuildConfig{Provenance: "mode=max"},
|
||||
expected: []string{"type=provenance,mode=max"},
|
||||
},
|
||||
{
|
||||
name: "sbom true",
|
||||
config: types.BuildConfig{SBOM: "true"},
|
||||
expected: []string{"type=sbom"},
|
||||
},
|
||||
{
|
||||
name: "sbom false — must disable, not omit",
|
||||
config: types.BuildConfig{SBOM: "false"},
|
||||
expected: []string{"type=sbom,disabled=true"},
|
||||
},
|
||||
{
|
||||
name: "provenance false + sbom false",
|
||||
config: types.BuildConfig{Provenance: "false", SBOM: "false"},
|
||||
expected: []string{"type=provenance,disabled=true", "type=sbom,disabled=true"},
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert.DeepEqual(t, toBakeAttest(tc.config), tc.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// makeConsole must hand the genuine *os.File over when the stream wraps one:
|
||||
// on Windows, containerd/console rejects anything but the exact
|
||||
// os.Stdin/Stdout/Stderr values, so a wrapper would disable the TTY progress
|
||||
|
||||
Reference in New Issue
Block a user