From 21b3318ebea2185d6a6abbfa9c9631860daef3f2 Mon Sep 17 00:00:00 2001 From: Tianon Gravi Date: Wed, 7 Sep 2022 17:22:08 -0700 Subject: [PATCH] Fix several conversions of "ocispec.Image" to "ocispec.Platform" Several bits of code unmarshal image config JSON into an `ocispec.Image`, and then immediately create an `ocispec.Platform` out of it, but then discard the original image *and* miss several potential platform fields (most notably, `variant`). Because `ocispec.Platform` is a strict subset of `ocispec.Image`, most of these can be updated to simply unmarshal the image config directly to `ocispec.Platform` instead, which allows these additional fields to be picked up appropriately. We can use `tianon/raspbian` as a concrete reproducer to demonstrate. Before: ```console $ ctr content fetch docker.io/tianon/raspbian:bullseye-slim ... $ ctr image ls REF TYPE DIGEST SIZE PLATFORMS LABELS docker.io/tianon/raspbian:bullseye-slim application/vnd.docker.distribution.manifest.v2+json sha256:66e96f8af40691b335acc54e5f69711584ef7f926597b339e7d12ab90cc394ce 28.6 MiB linux/arm/v7 - ``` (Note that the `PLATFORMS` column lists `linux/arm/v7` -- the image itself is actually `linux/arm/v6`, but one of these bits of code leads to only `linux/arm` being extracted from the image config, which `platforms.Normalize` then updates to an explicit `v7`.) After: ```console $ ctr image ls REF TYPE DIGEST SIZE PLATFORMS LABELS docker.io/tianon/raspbian:bullseye-slim application/vnd.docker.distribution.manifest.v2+json sha256:66e96f8af40691b335acc54e5f69711584ef7f926597b339e7d12ab90cc394ce 28.6 MiB linux/arm/v6 - ``` Signed-off-by: Tianon Gravi Co-authored-by: Sebastiaan van Stijn --- image.go | 8 +++++--- images/image.go | 17 ++++++++++------- pkg/unpack/unpacker.go | 2 +- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/image.go b/image.go index 6d0a67617..d3cfdba6f 100644 --- a/image.go +++ b/image.go @@ -472,11 +472,13 @@ func (i *image) getManifestPlatform(ctx context.Context, manifest ocispec.Manife return ocispec.Platform{}, err } - var image ocispec.Image - if err := json.Unmarshal(p, &image); err != nil { + // Technically, this should be ocispec.Image, but we only need the + // ocispec.Platform that is embedded in the image struct. + var imagePlatform ocispec.Platform + if err := json.Unmarshal(p, &imagePlatform); err != nil { return ocispec.Platform{}, err } - return platforms.Normalize(ocispec.Platform{OS: image.OS, Architecture: image.Architecture}), nil + return platforms.Normalize(imagePlatform), nil } func (i *image) checkSnapshotterSupport(ctx context.Context, snapshotterName string, manifest ocispec.Manifest) error { diff --git a/images/image.go b/images/image.go index 2d2e36a9a..f3c8d4de3 100644 --- a/images/image.go +++ b/images/image.go @@ -174,12 +174,14 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc return nil, err } - var image ocispec.Image - if err := json.Unmarshal(p, &image); err != nil { + // Technically, this should be ocispec.Image, but we only need the + // ocispec.Platform that is embedded in the image struct. + var imagePlatform ocispec.Platform + if err := json.Unmarshal(p, &imagePlatform); err != nil { return nil, err } - if !platform.Match(platforms.Normalize(ocispec.Platform{OS: image.OS, Architecture: image.Architecture})) { + if !platform.Match(platforms.Normalize(imagePlatform)) { return nil, nil } @@ -279,13 +281,14 @@ func Platforms(ctx context.Context, provider content.Provider, image ocispec.Des return nil, err } - var image ocispec.Image - if err := json.Unmarshal(p, &image); err != nil { + // Technically, this should be ocispec.Image, but we only need the + // ocispec.Platform that is embedded in the image struct. + var imagePlatform ocispec.Platform + if err := json.Unmarshal(p, &imagePlatform); err != nil { return nil, err } - platformSpecs = append(platformSpecs, - platforms.Normalize(ocispec.Platform{OS: image.OS, Architecture: image.Architecture})) + platformSpecs = append(platformSpecs, platforms.Normalize(imagePlatform)) } return nil, nil }), ChildrenHandler(provider)), image) diff --git a/pkg/unpack/unpacker.go b/pkg/unpack/unpacker.go index b160da652..43c963f90 100644 --- a/pkg/unpack/unpacker.go +++ b/pkg/unpack/unpacker.go @@ -253,7 +253,7 @@ func (u *Unpacker) unpack( // TODO: Support multiple unpacks rather than just first match var unpack *Platform - imgPlatform := platforms.Normalize(ocispec.Platform{OS: i.OS, Architecture: i.Architecture}) + imgPlatform := platforms.Normalize(i.Platform) for _, up := range u.platforms { if up.Platform.Match(imgPlatform) { unpack = up