From a883ddf3af0da1fc48f55c06f5aff3e3d5d9bfd9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 03:04:00 +0000 Subject: [PATCH] layer: add filesystem MediaType To enable mounting of node filesystems, a new MediaType, 'application/x-filesystem' is introduced. As the fileystem does not provide a ReaderAt, the Reader function has been updated with a check to return an error if the layer does not have a ReaderAt. Signed-off-by: Matthias Meidinger Signed-off-by: Piotr Rygielski --- layer.go | 10 +++++++++ layer_test.go | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/layer.go b/layer.go index e2a7a1f03..0bed79048 100644 --- a/layer.go +++ b/layer.go @@ -112,6 +112,13 @@ func (l *Layer) Init(ctx context.Context, desc *LayerDescription, r io.ReaderAt) return fmt.Errorf("claircore: layer %v: unable to create fs.FS: %w", desc.Digest, err) } l.sys = sys + case `application/vnd.claircore.filesystem`: + if desc.URI == "" { + return fmt.Errorf("claircore: layer %v: unable to create fs.FS: no URI provided", desc.Digest) + } + sys := os.DirFS(desc.URI) + l.sys = sys + l.rd = nil // The reader cannot be used for a filesystem default: return fmt.Errorf("claircore: layer %v: unknown MediaType %q", desc.Digest, desc.MediaType) } @@ -196,6 +203,9 @@ func (l *Layer) Reader() (ReadAtCloser, error) { if !l.init { return nil, errors.New("claircore: unable to return Reader: uninitialized Layer") } + if l.rd == nil { + return nil, errors.New("claircore: unable to return Reader: ReaderAt is nil") + } // Some hacks for making the returned ReadAtCloser implements as many // interfaces as possible. switch rd := l.rd.(type) { diff --git a/layer_test.go b/layer_test.go index c03b2202b..c35e1b684 100644 --- a/layer_test.go +++ b/layer_test.go @@ -48,6 +48,21 @@ func TestLayer(t *testing.T) { return &l } + goodFilesystem := func(t *testing.T) *claircore.Layer { + t.Helper() + var l claircore.Layer + desc := claircore.LayerDescription{ + Digest: "sha256:" + strings.Repeat("00c0ffee", 8), + MediaType: `application/vnd.claircore.filesystem`, + URI: t.TempDir(), + } + + if err := l.Init(ctx, &desc, nil); err != nil { + t.Fatalf("unexpected error: %v", err) + } + return &l + } + t.Run("Init", func(t *testing.T) { t.Run("Checksum", func(t *testing.T) { var l claircore.Layer @@ -94,6 +109,25 @@ func TestLayer(t *testing.T) { t.Error("unexpected success") } }) + t.Run("Filesystem", func(t *testing.T) { + l := goodFilesystem(t) + if err := l.Close(); err != nil { + t.Errorf("close error: %v", err) + } + }) + t.Run("FilesystemNoURI", func(t *testing.T) { + var l claircore.Layer + desc := claircore.LayerDescription{ + Digest: "sha256:" + strings.Repeat("00c0ffee", 8), + MediaType: `application/vnd.claircore.filesystem`, + URI: "", + } + + if err := l.Init(ctx, &desc, nil); err == nil { + t.Error("unexpected success") + } + }) + }) t.Run("Close", func(t *testing.T) { t.Run("Success", func(t *testing.T) { @@ -177,6 +211,19 @@ func TestLayer(t *testing.T) { t.Error("unexpected error") } }) + t.Run("FilesystemSuccess", func(t *testing.T) { + l := goodFilesystem(t) + t.Cleanup(func() { + if err := l.Close(); err != nil { + t.Errorf("close error: %v", err) + } + }) + _, err := l.FS() + t.Logf("error: %v", err) + if err != nil { + t.Error("unexpected error") + } + }) }) t.Run("Reader", func(t *testing.T) { t.Run("Fail", func(t *testing.T) { @@ -208,5 +255,17 @@ func TestLayer(t *testing.T) { t.Errorf("unexpected error: read %d bytes, got error: %v", n, err) } }) + t.Run("Filesystem", func(t *testing.T) { + l := goodFilesystem(t) + t.Cleanup(func() { + if err := l.Close(); err != nil { + t.Errorf("close error: %v", err) + } + }) + _, err := l.Reader() + if err == nil { + t.Error("unexpected success") + } + }) }) }