harden storage paths and trash handling

This commit is contained in:
OpenClaw Agent
2026-09-21 17:15:27 +08:00
parent 0f071f396b
commit 09b808042d
2 changed files with 211 additions and 5 deletions
+78
View File
@@ -0,0 +1,78 @@
package storage
import (
"os"
"path/filepath"
"testing"
"time"
)
func TestLocalRejectsSymlinkEscapeAndAllowsNestedCreate(t *testing.T) {
root := t.TempDir()
outside := t.TempDir()
if err := os.WriteFile(filepath.Join(outside, "secret.txt"), []byte("secret"), 0o644); err != nil {
t.Fatal(err)
}
if err := os.Symlink(outside, filepath.Join(root, "escape")); err != nil {
t.Fatal(err)
}
s := Local{Root: root}
if _, err := s.Open("escape/secret.txt"); err == nil {
t.Fatal("expected symlink escape to be rejected")
}
f, err := s.Create("a/b/c.txt")
if err != nil {
t.Fatalf("nested create failed: %v", err)
}
_ = f.Close()
}
func TestMoveToTrashPreservesRelativePathAndCleansOldEntries(t *testing.T) {
root := t.TempDir()
trash := t.TempDir()
s := Local{Root: root}
if err := os.MkdirAll(filepath.Join(root, "one", "two"), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(root, "one", "two", "same.txt"), []byte("x"), 0o644); err != nil {
t.Fatal(err)
}
if err := os.MkdirAll(filepath.Join(trash, "old"), 0o755); err != nil {
t.Fatal(err)
}
old := filepath.Join(trash, "old", "stale.txt")
if err := os.WriteFile(old, []byte("old"), 0o644); err != nil {
t.Fatal(err)
}
oldTime := time.Now().Add(-31 * 24 * time.Hour)
if err := os.Chtimes(old, oldTime, oldTime); err != nil {
t.Fatal(err)
}
if err := s.MoveToTrash("one/two/same.txt", trash); err != nil {
t.Fatal(err)
}
if _, err := os.Stat(filepath.Join(trash, "one", "two", "same.txt")); err != nil {
t.Fatalf("trash path not preserved: %v", err)
}
if _, err := os.Stat(old); !os.IsNotExist(err) {
t.Fatalf("stale trash entry was not cleaned: %v", err)
}
}
func TestCopyPathPreservesSymlink(t *testing.T) {
src := filepath.Join(t.TempDir(), "link")
dst := filepath.Join(t.TempDir(), "link")
if err := os.Symlink("target", src); err != nil {
t.Fatal(err)
}
if err := copyPath(src, dst); err != nil {
t.Fatal(err)
}
got, err := os.Readlink(dst)
if err != nil {
t.Fatal(err)
}
if got != "target" {
t.Fatalf("got symlink target %q", got)
}
}