Confine chunk plan storage to its cache root
This commit is contained in:
@@ -84,19 +84,118 @@ func TestFilesystemStorePermissions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFilesystemStoreMissingAndOperationalErrors(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
root := filepath.Join(t.TempDir(), "plans")
|
||||
store := newStore(t, root)
|
||||
_, decision, err := store.Load(testSourceDigest)
|
||||
if err != nil || decision.Status != pipeline.ChunkPlanMissing {
|
||||
t.Fatalf("missing decision=%#v error=%v", decision, err)
|
||||
}
|
||||
if _, err := os.Stat(root); !os.IsNotExist(err) {
|
||||
t.Fatalf("Load() created missing root: %v", err)
|
||||
}
|
||||
|
||||
target := filepath.Join(root, strings.TrimPrefix(testSourceDigest, "sha256:"), "plan.json")
|
||||
if err := os.MkdirAll(target, 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, _, err := store.Load(testSourceDigest); err == nil {
|
||||
t.Fatal("Load(plan.json directory) error = nil")
|
||||
_, decision, err = store.Load(testSourceDigest)
|
||||
if err != nil || decision.Status != pipeline.ChunkPlanInvalid {
|
||||
t.Fatalf("Load(plan.json directory) decision=%#v error=%v", decision, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilesystemStoreRejectsSymlinkedEntries(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(t *testing.T, root, outside string)
|
||||
}{
|
||||
{
|
||||
name: "digest directory",
|
||||
setup: func(t *testing.T, root, outside string) {
|
||||
t.Helper()
|
||||
if err := os.MkdirAll(outside, 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
writeFile(t, filepath.Join(outside, "plan.json"), []byte("outside plan"), 0o640)
|
||||
createSymlink(t, outside, filepath.Join(root, strings.TrimPrefix(testSourceDigest, "sha256:")))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "plan file",
|
||||
setup: func(t *testing.T, root, outside string) {
|
||||
t.Helper()
|
||||
digestDir := filepath.Join(root, strings.TrimPrefix(testSourceDigest, "sha256:"))
|
||||
if err := os.MkdirAll(digestDir, 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
writeFile(t, outside, []byte("outside plan"), 0o640)
|
||||
createSymlink(t, outside, filepath.Join(digestDir, "plan.json"))
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
root := filepath.Join(t.TempDir(), "plans")
|
||||
if err := os.MkdirAll(root, 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
outside := filepath.Join(t.TempDir(), "outside")
|
||||
tc.setup(t, root, outside)
|
||||
before := readFile(t, outsidePlanPath(tc.name, outside))
|
||||
beforeMode := fileMode(t, outsidePlanPath(tc.name, outside))
|
||||
|
||||
store := newStore(t, root)
|
||||
_, decision, err := store.Load(testSourceDigest)
|
||||
if err != nil || decision.Status != pipeline.ChunkPlanInvalid {
|
||||
t.Fatalf("Load() decision=%#v error=%v", decision, err)
|
||||
}
|
||||
if err := store.Save(testRecord(t, 1)); err == nil {
|
||||
t.Fatal("Save() error = nil")
|
||||
}
|
||||
outsidePlan := outsidePlanPath(tc.name, outside)
|
||||
if got := readFile(t, outsidePlan); !bytes.Equal(got, before) {
|
||||
t.Fatalf("outside content = %q, want %q", got, before)
|
||||
}
|
||||
if got := fileMode(t, outsidePlan); got != beforeMode {
|
||||
t.Fatalf("outside mode = %04o, want %04o", got, beforeMode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilesystemStoreRejectsUnexpectedEntryTypes(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(t *testing.T, root string)
|
||||
}{
|
||||
{
|
||||
name: "digest file",
|
||||
setup: func(t *testing.T, root string) {
|
||||
writeFile(t, filepath.Join(root, strings.TrimPrefix(testSourceDigest, "sha256:")), []byte("not a directory"), 0o600)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "plan directory",
|
||||
setup: func(t *testing.T, root string) {
|
||||
if err := os.MkdirAll(filepath.Join(root, strings.TrimPrefix(testSourceDigest, "sha256:"), "plan.json"), 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
tc.setup(t, root)
|
||||
store := newStore(t, root)
|
||||
_, decision, err := store.Load(testSourceDigest)
|
||||
if err != nil || decision.Status != pipeline.ChunkPlanInvalid {
|
||||
t.Fatalf("Load() decision=%#v error=%v", decision, err)
|
||||
}
|
||||
if err := store.Save(testRecord(t, 1)); err == nil {
|
||||
t.Fatal("Save() error = nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,7 +394,9 @@ func TestFilesystemStoreInterruptedWritesPreservePreviousRecord(t *testing.T) {
|
||||
{name: "before rename", hooks: atomicWriteHooks{BeforeRename: func() error { return errors.New("interrupted before rename") }}},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
store.write = func(target string, data []byte) error { return writeAtomicWithHooks(target, data, tc.hooks) }
|
||||
store.write = func(root *os.Root, target string, data []byte) error {
|
||||
return writeAtomicWithHooks(root, target, data, tc.hooks)
|
||||
}
|
||||
if err := store.Save(testRecord(t, 2)); err == nil {
|
||||
t.Fatal("Save() error = nil")
|
||||
}
|
||||
@@ -363,3 +464,45 @@ func assertNoTemps(t *testing.T, dir string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createSymlink(t *testing.T, target, link string) {
|
||||
t.Helper()
|
||||
if err := os.Symlink(target, link); err != nil {
|
||||
t.Skipf("create symlink: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeFile(t *testing.T, path string, data []byte, mode os.FileMode) {
|
||||
t.Helper()
|
||||
if err := os.WriteFile(path, data, mode); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Chmod(path, mode); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func readFile(t *testing.T, path string) []byte {
|
||||
t.Helper()
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func fileMode(t *testing.T, path string) os.FileMode {
|
||||
t.Helper()
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return info.Mode().Perm()
|
||||
}
|
||||
|
||||
func outsidePlanPath(name, outside string) string {
|
||||
if name == "digest directory" {
|
||||
return filepath.Join(outside, "plan.json")
|
||||
}
|
||||
return outside
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user