diff --git a/plugins/content/local/store.go b/plugins/content/local/store.go index 794c82c25e..1b9abdd3b0 100644 --- a/plugins/content/local/store.go +++ b/plugins/content/local/store.go @@ -18,8 +18,10 @@ package local import ( "context" + "errors" "fmt" "io" + "io/fs" "os" "path/filepath" "strconv" @@ -84,8 +86,18 @@ func NewStore(root string) (content.Store, error) { // require labels and should use `NewStore`. `NewLabeledStore` is primarily // useful for tests or standalone implementations. func NewLabeledStore(root string, ls LabelStore) (content.Store, error) { - supported, _ := fsverity.IsSupported(root) - + if _, err := os.Stat(root); err != nil { + if !errors.Is(err, fs.ErrNotExist) { + return nil, fmt.Errorf("failed to stat %q: %w", root, err) + } + if err := os.MkdirAll(root, 0755); err != nil { + return nil, fmt.Errorf("failed to mkdir %q: %w", root, err) + } + } + supported, err := fsverity.IsSupported(root) + if err != nil { + log.L.WithError(err).WithField("path", root).Warnf("failed check for fsverity support") + } s := &store{ root: root, ls: ls, diff --git a/plugins/content/local/store_test.go b/plugins/content/local/store_test.go index 54b082dcd6..0ce3a9c9c9 100644 --- a/plugins/content/local/store_test.go +++ b/plugins/content/local/store_test.go @@ -25,6 +25,7 @@ import ( "fmt" "io" "os" + "os/exec" "path/filepath" "reflect" "runtime" @@ -94,15 +95,50 @@ func (mls *memoryLabelStore) Update(d digest.Digest, update map[string]string) ( func TestContent(t *testing.T) { testsuite.ContentSuite(t, "fs", func(ctx context.Context, root string) (context.Context, content.Store, func() error, error) { cs, err := NewLabeledStore(root, newMemoryLabelStore()) - if err != nil { - return nil, nil, nil, err - } + assert.NoError(t, err) return ctx, cs, func() error { return nil }, nil }) } +func TestContentRootDir(t *testing.T) { + // test dir exist + dirExist := t.TempDir() + _, err := NewLabeledStore(dirExist, newMemoryLabelStore()) + assert.NoError(t, err) + // test dir doesn't exist + dir := filepath.Join(t.TempDir(), "test_dir001") + _, err = NewLabeledStore(dir, newMemoryLabelStore()) + assert.NoError(t, err) + _, err = os.Stat(dir) + assert.NoError(t, err) +} + +func TestInvalidPermissionRootDir(t *testing.T) { + // test dir permissions are invalid + if os.Getuid() != 0 { + t.Skip("skipping test that requires root") + } + _, err := exec.LookPath("chattr") + if err != nil { + t.Skip("skipping test that requires chattr command") + } + dirBadPermission := t.TempDir() + cmd := exec.Command("chattr", "+i", dirBadPermission) + _, err = cmd.CombinedOutput() + assert.NoError(t, err) + defer func() { + cmd := exec.Command("chattr", "-i", dirBadPermission) + _, err = cmd.CombinedOutput() + assert.NoError(t, err) + }() + _, err = fsverity.IsSupported(dirBadPermission) + if err == nil { + t.Fatal(fmt.Errorf("err can't be nil")) + } +} + func TestContentWriter(t *testing.T) { ctx, tmpdir, cs, cleanup := contentStoreEnv(t) defer cleanup()