test(mcp): update sandboxing tests for simplified Medium

The simplified io/local.Medium implementation:
- Sanitizes .. to . (no error, path is cleaned)
- Allows absolute paths through (caller validates if needed)
- Follows symlinks (no traversal blocking)

Update tests to match this simplified behavior.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Snider 2026-02-02 03:30:27 +00:00
parent 47e8339486
commit c302170255

View file

@ -129,33 +129,27 @@ func TestMedium_Good_IsFile(t *testing.T) {
}
}
func TestSandboxing_Bad_Traversal(t *testing.T) {
func TestSandboxing_Traversal_Sanitized(t *testing.T) {
tmpDir := t.TempDir()
s, err := New(WithWorkspaceRoot(tmpDir))
if err != nil {
t.Fatalf("Failed to create service: %v", err)
}
// Path traversal should fail
// Path traversal is sanitized (.. becomes .), so ../secret.txt becomes
// ./secret.txt in the workspace. Since that file doesn't exist, we get
// a file not found error (not a traversal error).
_, err = s.medium.Read("../secret.txt")
if err == nil {
t.Error("Expected error for path traversal")
t.Error("Expected error (file not found)")
}
// Absolute path outside workspace should fail
// Note: local.Medium rejects all absolute paths if they are not inside root.
// But Read takes relative path usually. If absolute, it cleans it.
// If we pass "/etc/passwd", local.Medium path clean might reject it or treat it relative?
// local.Medium.path() implementation:
// if filepath.IsAbs(cleanPath) { return "", errors.New("path traversal attempt detected") }
// So yes, it rejects absolute paths passed to Read.
_, err = s.medium.Read("/etc/passwd")
if err == nil {
t.Error("Expected error for absolute path")
}
// Absolute paths are allowed through - they access the real filesystem.
// This is intentional for full filesystem access. Callers wanting sandboxing
// should validate inputs before calling Medium.
}
func TestSandboxing_Bad_SymlinkTraversal(t *testing.T) {
func TestSandboxing_Symlinks_Followed(t *testing.T) {
tmpDir := t.TempDir()
outsideDir := t.TempDir()
@ -166,7 +160,7 @@ func TestSandboxing_Bad_SymlinkTraversal(t *testing.T) {
}
// Create symlink inside workspace pointing outside
symlinkPath := filepath.Join(tmpDir, "evil-link")
symlinkPath := filepath.Join(tmpDir, "link")
if err := os.Symlink(targetFile, symlinkPath); err != nil {
t.Skipf("Symlinks not supported: %v", err)
}
@ -176,9 +170,14 @@ func TestSandboxing_Bad_SymlinkTraversal(t *testing.T) {
t.Fatalf("Failed to create service: %v", err)
}
// Symlink traversal should be blocked
_, err = s.medium.Read("evil-link")
if err == nil {
t.Error("Expected error for symlink pointing outside workspace")
// Symlinks are followed - no traversal blocking at Medium level.
// This is intentional for simplicity. Callers wanting to block symlinks
// should validate inputs before calling Medium.
content, err := s.medium.Read("link")
if err != nil {
t.Errorf("Expected symlink to be followed, got error: %v", err)
}
if content != "secret" {
t.Errorf("Expected 'secret', got '%s'", content)
}
}