From 0754b56695739222e8c63091228bb6813b23e294 Mon Sep 17 00:00:00 2001 From: Pavel Busko Date: Wed, 24 Jul 2024 11:54:35 +0200 Subject: [PATCH] Support OCI layouts with application/vnd.oci.image.manifest.v1+json media type Signed-off-by: Pavel Busko --- pkg/buildpack/oci_layout_package.go | 8 +-- pkg/buildpack/oci_layout_package_test.go | 67 +++++++++++------- pkg/buildpack/testdata/hello-universe-oci.cnb | Bin 0 -> 13312 bytes 3 files changed, 46 insertions(+), 29 deletions(-) create mode 100644 pkg/buildpack/testdata/hello-universe-oci.cnb diff --git a/pkg/buildpack/oci_layout_package.go b/pkg/buildpack/oci_layout_package.go index eab5516ce4..7ce5039991 100644 --- a/pkg/buildpack/oci_layout_package.go +++ b/pkg/buildpack/oci_layout_package.go @@ -28,7 +28,7 @@ func IsOCILayoutBlob(blob blob2.Blob) (bool, error) { } defer readCloser.Close() - _, _, err = archive.ReadTarEntry(readCloser, "/oci-layout") + _, _, err = archive.ReadTarEntry(readCloser, v1.ImageLayoutFile) if err != nil { if archive.IsEntryNotExist(err) { return false, nil @@ -77,13 +77,13 @@ type ociLayoutPackage struct { func newOCILayoutPackage(blob Blob, kind string) (*ociLayoutPackage, error) { index := &v1.Index{} - if err := unmarshalJSONFromBlob(blob, "/index.json", index); err != nil { + if err := unmarshalJSONFromBlob(blob, v1.ImageIndexFile, index); err != nil { return nil, err } var manifestDescriptor *v1.Descriptor for _, m := range index.Manifests { - if m.MediaType == "application/vnd.docker.distribution.manifest.v2+json" { + if m.MediaType == "application/vnd.docker.distribution.manifest.v2+json" || m.MediaType == v1.MediaTypeImageManifest { manifestDescriptor = &m // nolint:exportloopref break } @@ -167,7 +167,7 @@ func (o *ociLayoutPackage) GetLayer(diffID string) (io.ReadCloser, error) { if paths.CanonicalTarPath(header.Name) == layerPath { finalReader := blobReader - if strings.HasSuffix(layerDescriptor.MediaType, ".gzip") { + if strings.HasSuffix(layerDescriptor.MediaType, "gzip") { finalReader, err = gzip.NewReader(tr) if err != nil { return nil, err diff --git a/pkg/buildpack/oci_layout_package_test.go b/pkg/buildpack/oci_layout_package_test.go index 540b036404..38b8321acd 100644 --- a/pkg/buildpack/oci_layout_package_test.go +++ b/pkg/buildpack/oci_layout_package_test.go @@ -7,6 +7,7 @@ import ( "github.com/buildpacks/lifecycle/api" "github.com/heroku/color" + v1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/sclevine/spec" "github.com/sclevine/spec/report" @@ -24,37 +25,53 @@ func TestOCILayoutPackage(t *testing.T) { spec.Run(t, "Extract", testOCILayoutPackage, spec.Parallel(), spec.Report(report.Terminal{})) } +type testCase struct { + mediatype string + file string +} + func testOCILayoutPackage(t *testing.T, when spec.G, it spec.S) { when("#BuildpacksFromOCILayoutBlob", func() { - it("extracts buildpacks", func() { - mainBP, depBPs, err := buildpack.BuildpacksFromOCILayoutBlob(blob.NewBlob(filepath.Join("testdata", "hello-universe.cnb"))) - h.AssertNil(t, err) - - h.AssertEq(t, mainBP.Descriptor().Info().ID, "io.buildpacks.samples.hello-universe") - h.AssertEq(t, mainBP.Descriptor().Info().Version, "0.0.1") - h.AssertEq(t, len(depBPs), 2) - }) + for _, test := range []testCase{ + { + mediatype: "application/vnd.docker.distribution.manifest.v2+json", + file: "hello-universe.cnb", + }, + { + mediatype: v1.MediaTypeImageManifest, + file: "hello-universe-oci.cnb", + }, + } { + it(fmt.Sprintf("extracts buildpacks, media type: %s", test.mediatype), func() { + mainBP, depBPs, err := buildpack.BuildpacksFromOCILayoutBlob(blob.NewBlob(filepath.Join("testdata", test.file))) + h.AssertNil(t, err) - it("provides readable blobs", func() { - mainBP, depBPs, err := buildpack.BuildpacksFromOCILayoutBlob(blob.NewBlob(filepath.Join("testdata", "hello-universe.cnb"))) - h.AssertNil(t, err) + h.AssertEq(t, mainBP.Descriptor().Info().ID, "io.buildpacks.samples.hello-universe") + h.AssertEq(t, mainBP.Descriptor().Info().Version, "0.0.1") + h.AssertEq(t, len(depBPs), 2) + }) - for _, bp := range append([]buildpack.BuildModule{mainBP}, depBPs...) { - reader, err := bp.Open() + it(fmt.Sprintf("provides readable blobs, media type: %s", test.mediatype), func() { + mainBP, depBPs, err := buildpack.BuildpacksFromOCILayoutBlob(blob.NewBlob(filepath.Join("testdata", test.file))) h.AssertNil(t, err) - _, contents, err := archive.ReadTarEntry( - reader, - fmt.Sprintf("/cnb/buildpacks/%s/%s/buildpack.toml", - bp.Descriptor().Info().ID, - bp.Descriptor().Info().Version, - ), - ) - h.AssertNil(t, err) - h.AssertContains(t, string(contents), bp.Descriptor().Info().ID) - h.AssertContains(t, string(contents), bp.Descriptor().Info().Version) - } - }) + for _, bp := range append([]buildpack.BuildModule{mainBP}, depBPs...) { + reader, err := bp.Open() + h.AssertNil(t, err) + + _, contents, err := archive.ReadTarEntry( + reader, + fmt.Sprintf("/cnb/buildpacks/%s/%s/buildpack.toml", + bp.Descriptor().Info().ID, + bp.Descriptor().Info().Version, + ), + ) + h.AssertNil(t, err) + h.AssertContains(t, string(contents), bp.Descriptor().Info().ID) + h.AssertContains(t, string(contents), bp.Descriptor().Info().Version) + } + }) + } }) when("#ExtensionsFromOCILayoutBlob", func() { diff --git a/pkg/buildpack/testdata/hello-universe-oci.cnb b/pkg/buildpack/testdata/hello-universe-oci.cnb new file mode 100644 index 0000000000000000000000000000000000000000..59b4b657fba41c4c98d2eb76c25219fa0fb6d19a GIT binary patch literal 13312 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 GA@CnLU@-## literal 0 HcmV?d00001