diff --git a/internal/pathsafe/ancestor_test.go b/internal/pathsafe/ancestor_test.go index 18b2ab0..1a64328 100644 --- a/internal/pathsafe/ancestor_test.go +++ b/internal/pathsafe/ancestor_test.go @@ -3,6 +3,7 @@ package pathsafe import ( "os" "path/filepath" + "syscall" "testing" ) @@ -13,8 +14,10 @@ func TestAncestorWalk(t *testing.T) { }{ {"walks clean directory tree", testWalksCleanTree}, {"walks single segment parent", testWalksSingleSegment}, - {"rejects symlink component", testWalkRejectsSymlink}, + {"rejects internal symlink component", testWalkRejectsSymlink}, + {"rejects escaping symlink component", testWalkRejectsEscapingSymlink}, {"rejects file component", testWalkRejectsFile}, + {"rejects special component", testWalkRejectsSpecial}, {"rejects missing parent", testWalkRejectsMissing}, {"rejects dot-dot escape", testWalkRejectsDotDot}, } @@ -51,6 +54,17 @@ func testWalkRejectsSymlink(t *testing.T) { } } +func testWalkRejectsEscapingSymlink(t *testing.T) { + root := t.TempDir() + outside := t.TempDir() + if err := os.Symlink(outside, filepath.Join(root, "escape")); err != nil { + t.Skipf("symlink unsupported: %v", err) + } + if err := AncestorWalk(root, "escape/file"); err == nil { + t.Fatal("symlink escaping the root must be rejected") + } +} + func testWalkRejectsFile(t *testing.T) { root := t.TempDir() if err := os.WriteFile(filepath.Join(root, "blocker"), []byte("x"), 0o600); err != nil { @@ -61,6 +75,17 @@ func testWalkRejectsFile(t *testing.T) { } } +func testWalkRejectsSpecial(t *testing.T) { + root := t.TempDir() + path := filepath.Join(root, "pipe") + if err := syscall.Mkfifo(path, 0o600); err != nil { + t.Skipf("FIFO unsupported: %v", err) + } + if err := AncestorWalk(root, "pipe/file"); err == nil { + t.Fatal("special parent component must be rejected") + } +} + func testWalkRejectsMissing(t *testing.T) { root := t.TempDir() if err := AncestorWalk(root, "missing/file"); err == nil { diff --git a/internal/pathsafe/equivalence_test.go b/internal/pathsafe/equivalence_test.go index 99574b4..c9d8369 100644 --- a/internal/pathsafe/equivalence_test.go +++ b/internal/pathsafe/equivalence_test.go @@ -2,7 +2,7 @@ package pathsafe import "testing" -func TestEquivalence(t *testing.T) { +func TestPortableEquivalence(t *testing.T) { scenarios := []struct { name string run func(*testing.T)