mirror of
https://github.com/lukaszraczylo/filepuff-mcp.git
synced 2026-10-12 04:54:27 +00:00
Ho hum.
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestIsPathAllowed_SymlinkSecurity tests the symlink security fix.
|
||||
func TestIsPathAllowed_SymlinkSecurity(t *testing.T) {
|
||||
// Create a temporary workspace
|
||||
tmpDir := t.TempDir()
|
||||
workspace := filepath.Join(tmpDir, "workspace")
|
||||
outside := filepath.Join(tmpDir, "outside")
|
||||
|
||||
if err := os.MkdirAll(workspace, 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.MkdirAll(outside, 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create a file outside the workspace
|
||||
outsideFile := filepath.Join(outside, "secret.txt")
|
||||
if err := os.WriteFile(outsideFile, []byte("secret data"), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cfg := &Config{
|
||||
WorkspaceRoot: workspace,
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
setup func() string
|
||||
name string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "regular file inside workspace",
|
||||
setup: func() string {
|
||||
return filepath.Join(workspace, "file.txt")
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "file with parent directory traversal",
|
||||
setup: func() string {
|
||||
return filepath.Join(workspace, "../outside/secret.txt")
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "symlink pointing outside workspace",
|
||||
setup: func() string {
|
||||
symlink := filepath.Join(workspace, "link.txt")
|
||||
_ = os.Symlink(outsideFile, symlink)
|
||||
return symlink
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "symlink pointing inside workspace",
|
||||
setup: func() string {
|
||||
inside := filepath.Join(workspace, "inside.txt")
|
||||
_ = os.WriteFile(inside, []byte("ok"), 0600)
|
||||
symlink := filepath.Join(workspace, "link_inside.txt")
|
||||
_ = os.Symlink(inside, symlink)
|
||||
return symlink
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "dotfile inside workspace",
|
||||
setup: func() string {
|
||||
return filepath.Join(workspace, ".gitignore")
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "hidden directory inside workspace",
|
||||
setup: func() string {
|
||||
return filepath.Join(workspace, ".git/config")
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
path := tt.setup()
|
||||
result := cfg.IsPathAllowed(path)
|
||||
if result != tt.expected {
|
||||
t.Errorf("IsPathAllowed(%q) = %v, want %v", path, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestIsPathAllowed_BasicCases tests basic path validation.
|
||||
func TestIsPathAllowed_BasicCases(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
cfg := &Config{
|
||||
WorkspaceRoot: tmpDir,
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
path string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "path inside workspace",
|
||||
path: filepath.Join(tmpDir, "file.txt"),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "path outside workspace",
|
||||
path: "/etc/passwd",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "parent directory reference",
|
||||
path: filepath.Join(tmpDir, "../../../etc/passwd"),
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "workspace root itself",
|
||||
path: tmpDir,
|
||||
expected: false, // Empty relative path
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := cfg.IsPathAllowed(tt.path)
|
||||
if result != tt.expected {
|
||||
t.Errorf("IsPathAllowed(%q) = %v, want %v", tt.path, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user