Skip to content

Commit

Permalink
[goreleaser] test: add MacOS path validation tests and fix path norma…
Browse files Browse the repository at this point in the history
…lization

Co-Authored-By: [email protected] <[email protected]>
  • Loading branch information
devin-ai-integration[bot] and trajan0x committed Dec 14, 2024
1 parent 90d49a3 commit a5e78f6
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 9 deletions.
38 changes: 29 additions & 9 deletions contrib/golang-ci-lint/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,41 +109,61 @@ func validatePath(path string, allowedDirs ...string) error {
return fmt.Errorf("failed to resolve absolute path: %w", err)
}

resolvedPath, err := filepath.EvalSymlinks(absPath)
// Get the real path, following all symlinks
realPath, err := filepath.EvalSymlinks(absPath)
if err != nil {
// If the file doesn't exist yet, use the absolute path
if !os.IsNotExist(err) {
return fmt.Errorf("failed to resolve symlinks: %w", err)
}
resolvedPath = absPath
realPath = absPath
}

if strings.Contains(resolvedPath, "..") {
return fmt.Errorf("path contains directory traversal: %s", resolvedPath)
// Normalize paths for MacOS by removing /private prefix from /var paths
if runtime.GOOS == "darwin" {
if strings.HasPrefix(realPath, "/private/var") {
realPath = strings.Replace(realPath, "/private/var", "/var", 1)
}
if strings.HasPrefix(absPath, "/private/var") {
absPath = strings.Replace(absPath, "/private/var", "/var", 1)
}
}

if strings.Contains(realPath, "..") {
return fmt.Errorf("path contains directory traversal: %s", realPath)
}

// Always allow temp dir and cache dir
tmpDir := filepath.Clean(os.TempDir())
if runtime.GOOS == "darwin" && strings.HasPrefix(tmpDir, "/private/var") {
tmpDir = strings.Replace(tmpDir, "/private/var", "/var", 1)
}

defaultDirs := []string{
filepath.Clean(os.TempDir()),
tmpDir,
filepath.Clean(cacheDir),
}

// Combine default and additional allowed directories
allowedDirs = append(defaultDirs, allowedDirs...)

// Resolve and clean all allowed directories
// Check against allowed directories
for _, dir := range allowedDirs {
absDir, err := filepath.Abs(dir)
if err != nil {
continue // Skip invalid directories
continue
}
cleanDir := filepath.Clean(absDir)
if strings.HasPrefix(resolvedPath, cleanDir) {
if runtime.GOOS == "darwin" && strings.HasPrefix(cleanDir, "/private/var") {
cleanDir = strings.Replace(cleanDir, "/private/var", "/var", 1)
}
// Check both realPath and absPath for compatibility
if strings.HasPrefix(realPath, cleanDir) || strings.HasPrefix(absPath, cleanDir) {
return nil
}
}

return fmt.Errorf("path outside allowed directories: %s", resolvedPath)
return fmt.Errorf("path outside allowed directories: %s", realPath)
}

// safeJoin safely joins paths, preventing directory traversal.
Expand Down
81 changes: 81 additions & 0 deletions contrib/golang-ci-lint/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package main

import (
"os"
"path/filepath"
"runtime"
"testing"
)

func TestValidatePath(t *testing.T) {
// Create a temporary directory for testing
tmpDir := os.TempDir()
cacheDir := filepath.Join(tmpDir, "cache")

tests := []struct {
name string
path string
allowedDir []string
wantErr bool
onlyDarwin bool // Skip test on non-Darwin systems
}{
{
name: "Valid temp path on MacOS",
path: "/private/var/folders/test",
allowedDir: []string{"/var/folders"},
wantErr: false,
onlyDarwin: true,
},
{
name: "Valid cache path on MacOS",
path: "/private/var/cache/golangci-lint",
allowedDir: []string{"/var/cache"},
wantErr: false,
onlyDarwin: true,
},
{
name: "Invalid path with directory traversal",
path: filepath.Join(tmpDir, "../outside"),
allowedDir: nil,
wantErr: true,
},
{
name: "Valid path in temp directory",
path: filepath.Join(tmpDir, "test"),
allowedDir: nil,
wantErr: false,
},
{
name: "Valid path in cache directory",
path: filepath.Join(cacheDir, "test"),
allowedDir: nil,
wantErr: false,
},
{
name: "Path outside allowed directories",
path: "/usr/local/bin",
allowedDir: nil,
wantErr: true,
},
{
name: "MacOS specific temp folder path",
path: "/private/var/folders/12/8xtw48x951g0vv4z_ctcr2hr0000gn/T/golangci-lint-3961080532.tar.gz",
allowedDir: nil,
wantErr: false,
onlyDarwin: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.onlyDarwin && runtime.GOOS != "darwin" {
t.Skip("Skipping MacOS-specific test on non-Darwin system")
}

err := validatePath(tt.path, tt.allowedDir...)
if (err != nil) != tt.wantErr {
t.Errorf("validatePath() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

0 comments on commit a5e78f6

Please sign in to comment.