From a7b20077f9a6c5f5f23bcd30a481aee8b863fd99 Mon Sep 17 00:00:00 2001 From: Bjorn Neergaard Date: Thu, 17 Jul 2025 16:24:27 -0600 Subject: [PATCH 1/6] exporter/containerimage: remove unused EnableForceCompression This helper has not been used for some time. Signed-off-by: Bjorn Neergaard --- exporter/containerimage/opts.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/exporter/containerimage/opts.go b/exporter/containerimage/opts.go index 1ccadbd946d8..4664b09fb3da 100644 --- a/exporter/containerimage/opts.go +++ b/exporter/containerimage/opts.go @@ -91,18 +91,6 @@ func (c *ImageCommitOpts) EnableOCITypes(ctx context.Context, reason string) { } } -func (c *ImageCommitOpts) EnableForceCompression(ctx context.Context, reason string) { - if !c.RefCfg.Compression.Force { - message := "forcibly turning on force-compression mode" - if reason != "" { - message += " for " + reason - } - bklog.G(ctx).Warn(message) - - c.RefCfg.Compression.Force = true - } -} - func parseBool(dest *bool, key string, value string) error { b, err := strconv.ParseBool(value) if err != nil { From 5ec168d9666bd8ad42f6b2bd9b288b857e33138a Mon Sep 17 00:00:00 2001 From: Bjorn Neergaard Date: Thu, 17 Jul 2025 16:31:05 -0600 Subject: [PATCH 2/6] exporter/containerimage: default to oci-mediatype=true To facilitate this change, we now fail when there is an exporter option conflict instead of implicitly setting oci-mediatypes=true. Signed-off-by: Bjorn Neergaard --- exporter/containerimage/export.go | 1 + exporter/containerimage/opts.go | 19 +++---------------- exporter/containerimage/writer.go | 4 ++-- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/exporter/containerimage/export.go b/exporter/containerimage/export.go index 7055db5ef085..43d7c15a49e8 100644 --- a/exporter/containerimage/export.go +++ b/exporter/containerimage/export.go @@ -77,6 +77,7 @@ func (e *imageExporter) Resolve(ctx context.Context, id int, opt map[string]stri RefCfg: cacheconfig.RefConfig{ Compression: compression.New(compression.Default), }, + OCITypes: true, ForceInlineAttestations: true, }, store: true, diff --git a/exporter/containerimage/opts.go b/exporter/containerimage/opts.go index 4664b09fb3da..d409125feb01 100644 --- a/exporter/containerimage/opts.go +++ b/exporter/containerimage/opts.go @@ -8,7 +8,6 @@ import ( cacheconfig "github.com/moby/buildkit/cache/config" "github.com/moby/buildkit/exporter/containerimage/exptypes" "github.com/moby/buildkit/exporter/util/epoch" - "github.com/moby/buildkit/util/bklog" "github.com/moby/buildkit/util/compression" "github.com/pkg/errors" ) @@ -67,11 +66,11 @@ func (c *ImageCommitOpts) Load(ctx context.Context, opt map[string]string) (map[ } } - if c.RefCfg.Compression.Type.OnlySupportOCITypes() { - c.EnableOCITypes(ctx, c.RefCfg.Compression.Type.String()) + if c.RefCfg.Compression.Type.OnlySupportOCITypes() && !c.OCITypes { + return nil, errors.Errorf("exporter option \"compression=%s\" conflicts with \"oci-mediatypes=false\"", c.RefCfg.Compression.Type) } if c.OCIArtifact && !c.OCITypes { - c.EnableOCITypes(ctx, "oci-artifact") + return nil, errors.New("exporter option \"oci-artifact=true\" conflicts with \"oci-mediatypes=false\"") } c.Annotations = c.Annotations.Merge(as) @@ -79,18 +78,6 @@ func (c *ImageCommitOpts) Load(ctx context.Context, opt map[string]string) (map[ return rest, nil } -func (c *ImageCommitOpts) EnableOCITypes(ctx context.Context, reason string) { - if !c.OCITypes { - message := "forcibly turning on oci-mediatype mode" - if reason != "" { - message += " for " + reason - } - bklog.G(ctx).Warn(message) - - c.OCITypes = true - } -} - func parseBool(dest *bool, key string, value string) error { b, err := strconv.ParseBool(value) if err != nil { diff --git a/exporter/containerimage/writer.go b/exporter/containerimage/writer.go index 63f390a85b49..1c6ac171d971 100644 --- a/exporter/containerimage/writer.go +++ b/exporter/containerimage/writer.go @@ -108,7 +108,7 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, session } } if len(a.Index)+len(a.IndexDescriptor)+len(a.ManifestDescriptor) > 0 { - opts.EnableOCITypes(ctx, "annotations") + return nil, errors.New("cannot export annotations with \"oci-mediatypes=false\"") } } @@ -186,7 +186,7 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, session } if len(inp.Attestations) > 0 { - opts.EnableOCITypes(ctx, "attestations") + return nil, errors.New("cannot export attestations with \"oci-mediatypes=false\"") } refs := make([]cache.ImmutableRef, 0, len(inp.Refs)) From 9e98782f86b40cbe3d1fc3c1fe0e324ad07e699d Mon Sep 17 00:00:00 2001 From: Bjorn Neergaard Date: Thu, 17 Jul 2025 16:32:13 -0600 Subject: [PATCH 3/6] exporter/containerimage: remove unnecessary errors.Errorf Signed-off-by: Bjorn Neergaard --- exporter/containerimage/writer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter/containerimage/writer.go b/exporter/containerimage/writer.go index 1c6ac171d971..e40efad29b16 100644 --- a/exporter/containerimage/writer.go +++ b/exporter/containerimage/writer.go @@ -114,7 +114,7 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, session if !isMap { if len(ps.Platforms) > 1 { - return nil, errors.Errorf("cannot export multiple platforms without multi-platform enabled") + return nil, errors.New("cannot export multiple platforms without multi-platform enabled") } var ref cache.ImmutableRef From eb6d9bf41195ba0253f2d114c2a4fe4b799e797b Mon Sep 17 00:00:00 2001 From: Bjorn Neergaard Date: Thu, 17 Jul 2025 16:40:40 -0600 Subject: [PATCH 4/6] exporter/containerimage: parse oci-mediatypes=bool strictly This matches the documentation, which never specified behavior for empty/unknown (non-boolean) strings. We can also remove the parseBoolWithDefault helper, as this was the last consumer. Signed-off-by: Bjorn Neergaard --- exporter/containerimage/opts.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/exporter/containerimage/opts.go b/exporter/containerimage/opts.go index d409125feb01..bdd8a1da569e 100644 --- a/exporter/containerimage/opts.go +++ b/exporter/containerimage/opts.go @@ -48,7 +48,7 @@ func (c *ImageCommitOpts) Load(ctx context.Context, opt map[string]string) (map[ case exptypes.OptKeyName: c.ImageName = v case exptypes.OptKeyOCITypes: - err = parseBoolWithDefault(&c.OCITypes, k, v, true) + err = parseBool(&c.OCITypes, k, v) case exptypes.OptKeyOCIArtifact: err = parseBool(&c.OCIArtifact, k, v) case exptypes.OptKeyForceInlineAttestations: @@ -87,14 +87,6 @@ func parseBool(dest *bool, key string, value string) error { return nil } -func parseBoolWithDefault(dest *bool, key string, value string, defaultValue bool) error { - if value == "" { - *dest = defaultValue - return nil - } - return parseBool(dest, key, value) -} - func toBytesMap(m map[string]string) map[string][]byte { result := make(map[string][]byte) for k, v := range m { From add1e0e0927c9e1a9c9146cf935f06ca8cb6b17f Mon Sep 17 00:00:00 2001 From: Bjorn Neergaard Date: Thu, 17 Jul 2025 16:41:25 -0600 Subject: [PATCH 5/6] exporter/containerimage: document "oci-artifact=" values Signed-off-by: Bjorn Neergaard --- exporter/containerimage/exptypes/keys.go | 1 + 1 file changed, 1 insertion(+) diff --git a/exporter/containerimage/exptypes/keys.go b/exporter/containerimage/exptypes/keys.go index 7cfa8dc024d9..1f34132dca76 100644 --- a/exporter/containerimage/exptypes/keys.go +++ b/exporter/containerimage/exptypes/keys.go @@ -51,6 +51,7 @@ var ( OptKeyOCITypes ImageExporterOptKey = "oci-mediatypes" // Use OCI artifact format for the attestation manifest. + // Value: bool OptKeyOCIArtifact ImageExporterOptKey = "oci-artifact" // Force attestation to be attached. From 76a3271a4dab966bf90356e9ee9ae300eb0e0308 Mon Sep 17 00:00:00 2001 From: Bjorn Neergaard Date: Fri, 18 Jul 2025 12:49:56 -0600 Subject: [PATCH 6/6] all: use well-known zstd mediaType constants When support for zstd was introduced, these mediaTypes were not yet available in released versions of their respective Go packages. That is no longer the case. Signed-off-by: Bjorn Neergaard --- cache/manager_test.go | 2 +- client/client_nydus_test.go | 2 +- client/client_test.go | 14 +++++++------- util/compression/compression.go | 10 +++------- util/winlayers/applier.go | 2 +- 5 files changed, 13 insertions(+), 17 deletions(-) diff --git a/cache/manager_test.go b/cache/manager_test.go index 7d86fff73962..20042d4f6c81 100644 --- a/cache/manager_test.go +++ b/cache/manager_test.go @@ -1747,7 +1747,7 @@ func TestGetRemotes(t *testing.T) { case compression.EStargz: require.Equal(t, ocispecs.MediaTypeImageLayerGzip, desc.MediaType) case compression.Zstd: - require.Equal(t, ocispecs.MediaTypeImageLayer+"+zstd", desc.MediaType) + require.Equal(t, ocispecs.MediaTypeImageLayerZstd, desc.MediaType) default: require.Fail(t, "unhandled media type", compressionType) } diff --git a/client/client_nydus_test.go b/client/client_nydus_test.go index 299cfc0d03be..7721f182c406 100644 --- a/client/client_nydus_test.go +++ b/client/client_nydus_test.go @@ -97,7 +97,7 @@ func testBuildExportNydusWithHybrid(t *testing.T, sb integration.Sandbox) { mediaTypes := map[compression.Type]string{ compression.Gzip: ocispecs.MediaTypeImageLayerGzip, - compression.Zstd: ocispecs.MediaTypeImageLayer + "+zstd", + compression.Zstd: ocispecs.MediaTypeImageLayerZstd, } target := fmt.Sprintf("%s/%s/alpine:%s", registry, compType, identity.NewID()) _, err = c.Solve(sb.Context(), def, SolveOpt{ diff --git a/client/client_test.go b/client/client_test.go index 46b8632649a3..73ed8d117d6b 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -2464,7 +2464,7 @@ func testSessionExporter(t *testing.T, sb integration.Sandbox) { require.Equal(t, 2, len(mfst.Layers)) for _, layer := range mfst.Layers { - require.Contains(t, layer.MediaType, "application/vnd.oci.image.layer.v1.tar+zstd") + require.Contains(t, layer.MediaType, ocispecs.MediaTypeImageLayerZstd) } } @@ -3485,7 +3485,7 @@ func testMultipleExporters(t *testing.T, sb integration.Sandbox) { Type: ExporterImage, Attrs: map[string]string{ "name": target2, - "oci-mediatypes": "true", + "oci-mediatypes": "false", }, }, }...) @@ -4866,7 +4866,7 @@ func testBuildExportZstd(t *testing.T, sb integration.Sandbox) { require.NoError(t, err) lastLayer := mfst.Layers[len(mfst.Layers)-1] - require.Equal(t, ocispecs.MediaTypeImageLayer+"+zstd", lastLayer.MediaType) + require.Equal(t, ocispecs.MediaTypeImageLayerZstd, lastLayer.MediaType) zstdLayerDigest := lastLayer.Digest.Hex() require.Equal(t, []byte{0x28, 0xb5, 0x2f, 0xfd}, m[ocispecs.ImageBlobsDir+"/sha256/"+zstdLayerDigest].Data[:4]) @@ -4902,7 +4902,7 @@ func testBuildExportZstd(t *testing.T, sb integration.Sandbox) { require.NoError(t, err) lastLayer = mfst.Layers[len(mfst.Layers)-1] - require.Equal(t, images.MediaTypeDockerSchema2Layer+".zstd", lastLayer.MediaType) + require.Equal(t, images.MediaTypeDockerSchema2LayerZstd, lastLayer.MediaType) require.Equal(t, lastLayer.Digest.Hex(), zstdLayerDigest) } @@ -4989,9 +4989,9 @@ func testPullZstdImage(t *testing.T, sb integration.Sandbox) { firstLayer := mfst.Layers[0] if ociMediaTypes { - require.Equal(t, ocispecs.MediaTypeImageLayer+"+zstd", firstLayer.MediaType) + require.Equal(t, ocispecs.MediaTypeImageLayerZstd, firstLayer.MediaType) } else { - require.Equal(t, images.MediaTypeDockerSchema2Layer+".zstd", firstLayer.MediaType) + require.Equal(t, images.MediaTypeDockerSchema2LayerZstd, firstLayer.MediaType) } zstdLayerDigest := firstLayer.Digest.Hex() @@ -5906,7 +5906,7 @@ func testZstdLocalCacheExport(t *testing.T, sb integration.Sandbox) { require.NoError(t, err) lastLayer := layerIndex.Manifests[len(layerIndex.Manifests)-2] - require.Equal(t, ocispecs.MediaTypeImageLayer+"+zstd", lastLayer.MediaType) + require.Equal(t, ocispecs.MediaTypeImageLayerZstd, lastLayer.MediaType) zstdLayerDigest := lastLayer.Digest.Hex() dt, err = os.ReadFile(filepath.Join(destDir, ocispecs.ImageBlobsDir+"/sha256/"+zstdLayerDigest)) diff --git a/util/compression/compression.go b/util/compression/compression.go index e60ea1503a4d..a25bf1d39a98 100644 --- a/util/compression/compression.go +++ b/util/compression/compression.go @@ -75,10 +75,6 @@ func (c Config) SetLevel(l int) Config { return c } -const ( - mediaTypeDockerSchema2LayerZstd = images.MediaTypeDockerSchema2Layer + ".zstd" -) - var Default = Gzip func parse(t string) (Type, error) { @@ -191,8 +187,8 @@ var toDockerLayerType = map[string]string{ images.MediaTypeDockerSchema2LayerForeignGzip: images.MediaTypeDockerSchema2LayerForeignGzip, ocispecs.MediaTypeImageLayerNonDistributable: images.MediaTypeDockerSchema2LayerForeign, //nolint:staticcheck // ignore SA1019: Non-distributable layers are deprecated, and not recommended for future use. ocispecs.MediaTypeImageLayerNonDistributableGzip: images.MediaTypeDockerSchema2LayerForeignGzip, //nolint:staticcheck // ignore SA1019: Non-distributable layers are deprecated, and not recommended for future use. - ocispecs.MediaTypeImageLayerZstd: mediaTypeDockerSchema2LayerZstd, - mediaTypeDockerSchema2LayerZstd: mediaTypeDockerSchema2LayerZstd, + ocispecs.MediaTypeImageLayerZstd: images.MediaTypeDockerSchema2LayerZstd:, + images.MediaTypeDockerSchema2LayerZstd: images.MediaTypeDockerSchema2LayerZstd:, } var toOCILayerType = map[string]string{ @@ -206,7 +202,7 @@ var toOCILayerType = map[string]string{ images.MediaTypeDockerSchema2LayerForeign: ocispecs.MediaTypeImageLayerNonDistributable, //nolint:staticcheck // ignore SA1019: Non-distributable layers are deprecated, and not recommended for future use. images.MediaTypeDockerSchema2LayerForeignGzip: ocispecs.MediaTypeImageLayerNonDistributableGzip, //nolint:staticcheck // ignore SA1019: Non-distributable layers are deprecated, and not recommended for future use. ocispecs.MediaTypeImageLayerZstd: ocispecs.MediaTypeImageLayerZstd, - mediaTypeDockerSchema2LayerZstd: ocispecs.MediaTypeImageLayerZstd, + images.MediaTypeDockerSchema2LayerZstd: ocispecs.MediaTypeImageLayerZstd, } func convertLayerMediaType(ctx context.Context, mediaType string, oci bool) string { diff --git a/util/winlayers/applier.go b/util/winlayers/applier.go index 7bfc3ca7fa2d..8e6451bee30b 100644 --- a/util/winlayers/applier.go +++ b/util/winlayers/applier.go @@ -39,7 +39,7 @@ type winApplier struct { func (s *winApplier) Apply(ctx context.Context, desc ocispecs.Descriptor, mounts []mount.Mount, opts ...diff.ApplyOpt) (d ocispecs.Descriptor, err error) { // HACK:, containerd doesn't know about vnd.docker.image.rootfs.diff.tar.zstd, but that // media type is compatible w/ the oci type, so just lie and say it's the oci type - if desc.MediaType == images.MediaTypeDockerSchema2Layer+".zstd" { + if desc.MediaType == images.MediaTypeDockerSchema2LayerZstd { desc.MediaType = ocispecs.MediaTypeImageLayerZstd }