0bef0d432fb6aef09e484583208b66540e89b6d3

Author
Kieran Klukas <kieran@dunkirk.sh>
Committer
GitHub <noreply@github.com>
Date

Message

test: fix Windows assumption in storage confinement test (#924)

Diff

 1diff --git a/pkg/storage/local_test.go b/pkg/storage/local_test.go
 2index aab7b423dbab24ff0a79dd099e766df52414be4d..56532185b1577a5bc6ed29bdcf28e830593a2f2a 100644
 3--- a/pkg/storage/local_test.go
 4+++ b/pkg/storage/local_test.go
 5@@ -18,14 +18,22 @@ func TestLocalStorageConfinesToRoot(t *testing.T) {
 6 		t.Fatal(err)
 7 	}
 8 
 9-	l := NewLocalStorage(root)
10-	for _, name := range []string{
11+	names := []string{
12 		"../secret",
13 		"objects/../../secret",
14 		"../../../../../../../../etc/passwd",
15 		secret,
16-		"/etc/passwd",
17-	} {
18+	}
19+
20+	// A leading slash only means "absolute" where there is no volume name. On
21+	// Windows "/etc/passwd" is a relative path, and Join confines it under the
22+	// root rather than escaping, so there is nothing to reject.
23+	if filepath.IsAbs("/etc/passwd") {
24+		names = append(names, "/etc/passwd")
25+	}
26+
27+	l := NewLocalStorage(root)
28+	for _, name := range names {
29 		t.Run(name, func(t *testing.T) {
30 			if _, err := l.Open(name); !errors.Is(err, ErrPathTraversal) {
31 				t.Errorf("Open: got %v, want ErrPathTraversal", err)
32@@ -59,6 +67,24 @@ func TestLocalStorageConfinesToRoot(t *testing.T) {
33 	}
34 }
35 
36+// Where a leading slash carries no volume name, "/etc/passwd" is a relative
37+// name rather than an absolute one. It must still land under the root, which is
38+// the property that matters on those platforms.
39+func TestLocalStorageConfinesRootedRelativeNames(t *testing.T) {
40+	if filepath.IsAbs("/etc/passwd") {
41+		t.Skip("a leading slash is absolute here, covered by the rejection test")
42+	}
43+
44+	root := t.TempDir()
45+	l := NewLocalStorage(root)
46+	if _, err := l.Put("/etc/passwd", strings.NewReader("x")); err != nil {
47+		t.Fatalf("Put: %v", err)
48+	}
49+	if _, err := os.Stat(filepath.Join(root, "etc", "passwd")); err != nil {
50+		t.Errorf("write should have been confined under root: %v", err)
51+	}
52+}
53+
54 // Ordinary relative names still round-trip through the root. This is the shape
55 // of an LFS upload: stage under "incomplete", then rename into place. Names
56 // crossing the Storage boundary are relative, so callers must not feed back the