From 99dd11945844a0237016e03de80c1a03afba3f2f Mon Sep 17 00:00:00 2001 From: David Trudgian Date: Fri, 27 Sep 2024 14:59:19 +0100 Subject: [PATCH] feat: AppendImage/Index with optional name.Reference Adds `f.AppendImage` and `f.AppendIndex`, which append a `v1.Image` or a `v1.ImageIndex` to the SIF, respectively. The `OptAppendReference` functional option can be used to provide a `name.Reference` that will be stored as an annotation against the new descriptor in the RootIndex, with the key `org.opencontainers.image.ref.name`, as is convention for associating references with items stored in an OCI layout. Fixes #83 Fixes #81 --- .../testdata/TestAppendImage/Default.golden | Bin 0 -> 17780 bytes .../TestAppendImage/WithReference.golden | Bin 0 -> 17845 bytes .../testdata/TestAppendIndex/Default.golden | Bin 0 -> 18017 bytes .../TestAppendIndex/WithReference.golden | Bin 0 -> 18082 bytes pkg/sif/update.go | 68 ++++++++++ pkg/sif/update_test.go | 123 ++++++++++++++++++ 6 files changed, 191 insertions(+) create mode 100644 pkg/sif/testdata/TestAppendImage/Default.golden create mode 100644 pkg/sif/testdata/TestAppendImage/WithReference.golden create mode 100644 pkg/sif/testdata/TestAppendIndex/Default.golden create mode 100644 pkg/sif/testdata/TestAppendIndex/WithReference.golden diff --git a/pkg/sif/testdata/TestAppendImage/Default.golden b/pkg/sif/testdata/TestAppendImage/Default.golden new file mode 100644 index 0000000000000000000000000000000000000000..2d28e076aa3d82ab3db350c2e166d681792b7638 GIT binary patch literal 17780 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 SrXuip{k4jJ)#Xt>x&H%5jkg~F literal 0 HcmV?d00001 diff --git a/pkg/sif/testdata/TestAppendImage/WithReference.golden b/pkg/sif/testdata/TestAppendImage/WithReference.golden new file mode 100644 index 0000000000000000000000000000000000000000..a056e1c03d5694fa3fb8dd6ab344d0efd34251d3 GIT binary patch literal 17845 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 literal 0 HcmV?d00001 diff --git a/pkg/sif/testdata/TestAppendIndex/Default.golden b/pkg/sif/testdata/TestAppendIndex/Default.golden new file mode 100644 index 0000000000000000000000000000000000000000..d1887968fe751660ce87b25745002e106e72356c GIT binary patch literal 18017 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 literal 0 HcmV?d00001 diff --git a/pkg/sif/update.go b/pkg/sif/update.go index 39b0d58..8bd5e0f 100644 --- a/pkg/sif/update.go +++ b/pkg/sif/update.go @@ -11,7 +11,9 @@ import ( "path/filepath" "slices" + "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/types" "github.com/sylabs/sif/v2/pkg/sif" ) @@ -330,3 +332,69 @@ func selectBlobsExcept(keep []v1.Hash) sif.DescriptorSelectorFunc { return false, nil } } + +// appendOpts accumulates append options. +type appendOpts struct { + tempDir string + ref name.Reference +} + +// AppendOpt are used to specify options to apply when appending to a SIF. +type AppendOpt func(*appendOpts) error + +// OptAppendTempDir sets the directory to use for temporary files. If not set, the +// directory returned by os.TempDir is used. +func OptAppendTempDir(d string) AppendOpt { + return func(c *appendOpts) error { + c.tempDir = d + return nil + } +} + +// OptAppendReference sets the reference to be set for the appended item in the +// RootIndex. The reference is added as an `org.opencontainers.image.ref.name` +// in the RootIndex. +func OptAppendReference(r name.Reference) AppendOpt { + return func(c *appendOpts) error { + c.ref = r + return nil + } +} + +// AppendImage appends an image to the SIF f, updating the RootIndex to +// reference it. +func (f *OCIFileImage) AppendImage(img v1.Image, opts ...AppendOpt) error { + return f.append(img, opts...) +} + +// AppendIndex appends an index to the SIF f, updating the RootIndex to +// reference it. +func (f *OCIFileImage) AppendIndex(ii v1.ImageIndex, opts ...AppendOpt) error { + return f.append(ii, opts...) +} + +func (f *OCIFileImage) append(add mutate.Appendable, opts ...AppendOpt) error { + ao := appendOpts{ + tempDir: os.TempDir(), + } + for _, opt := range opts { + if err := opt(&ao); err != nil { + return err + } + } + + ri, err := f.RootIndex() + if err != nil { + return err + } + + ia := mutate.IndexAddendum{Add: add} + if ao.ref != nil { + ia.Annotations = map[string]string{ + "org.opencontainers.image.ref.name": ao.ref.Name(), + } + } + ri = mutate.AppendManifests(ri, ia) + + return f.UpdateRootIndex(ri, OptUpdateTempDir(ao.tempDir)) +} diff --git a/pkg/sif/update_test.go b/pkg/sif/update_test.go index 60426de..5bdee6b 100644 --- a/pkg/sif/update_test.go +++ b/pkg/sif/update_test.go @@ -9,6 +9,7 @@ import ( "os" "testing" + "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/empty" v1mutate "github.com/google/go-containerregistry/pkg/v1/mutate" @@ -152,3 +153,125 @@ func TestUpdate(t *testing.T) { }) } } + +//nolint:dupl +func TestAppendImage(t *testing.T) { + r := rand.NewSource(randomSeed) + newImage, err := random.Image(64, 1, random.WithSource(r)) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + base string + opts []sif.AppendOpt + }{ + { + name: "Default", + base: "hello-world-docker-v2-manifest", + opts: []sif.AppendOpt{}, + }, + { + name: "WithReference", // Replaces many layers with a single layer + base: "hello-world-docker-v2-manifest", + opts: []sif.AppendOpt{ + sif.OptAppendReference(name.MustParseReference("myimage:v1", name.WithDefaultRegistry(""))), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sifPath := corpus.SIF(t, tt.base, sif.OptWriteWithSpareDescriptorCapacity(8)) + fi, err := ssif.LoadContainerFromPath(sifPath) + if err != nil { + t.Fatal(err) + } + + ofi, err := sif.FromFileImage(fi) + if err != nil { + t.Fatal(err) + } + + if err := ofi.AppendImage(newImage, tt.opts...); err != nil { + t.Fatal(err) + } + + if err := fi.UnloadContainer(); err != nil { + t.Fatal(err) + } + + b, err := os.ReadFile(sifPath) + if err != nil { + t.Fatal(err) + } + + g := goldie.New(t, + goldie.WithTestNameForDir(true), + ) + + g.Assert(t, tt.name, b) + }) + } +} + +//nolint:dupl +func TestAppendIndex(t *testing.T) { + r := rand.NewSource(randomSeed) + newIndex, err := random.Index(64, 1, 1, random.WithSource(r)) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + base string + opts []sif.AppendOpt + }{ + { + name: "Default", + base: "hello-world-docker-v2-manifest", + opts: []sif.AppendOpt{}, + }, + { + name: "WithReference", // Replaces many layers with a single layer + base: "hello-world-docker-v2-manifest", + opts: []sif.AppendOpt{ + sif.OptAppendReference(name.MustParseReference("myindex:v1", name.WithDefaultRegistry(""))), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sifPath := corpus.SIF(t, tt.base, sif.OptWriteWithSpareDescriptorCapacity(8)) + fi, err := ssif.LoadContainerFromPath(sifPath) + if err != nil { + t.Fatal(err) + } + + ofi, err := sif.FromFileImage(fi) + if err != nil { + t.Fatal(err) + } + + if err := ofi.AppendIndex(newIndex, tt.opts...); err != nil { + t.Fatal(err) + } + + if err := fi.UnloadContainer(); err != nil { + t.Fatal(err) + } + + b, err := os.ReadFile(sifPath) + if err != nil { + t.Fatal(err) + } + + g := goldie.New(t, + goldie.WithTestNameForDir(true), + ) + + g.Assert(t, tt.name, b) + }) + } +}