feat: complete v0.3.1 agent workflow
This commit is contained in:
+68
-5
@@ -2,22 +2,85 @@ package tools
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func resolvePath(baseDir, path string) (string, error) {
|
||||
resolved, canonicalBase, err := resolveLexicalPath(baseDir, path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
canonical, err := filepath.EvalSymlinks(resolved)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !isWithinDir(canonical, canonicalBase) {
|
||||
return "", fmt.Errorf("path escapes the project directory through a symbolic link: %s", path)
|
||||
}
|
||||
return canonical, nil
|
||||
}
|
||||
|
||||
// resolvePathForWrite resolves a path that may not exist yet while preventing
|
||||
// existing parent-directory symlinks from escaping the project directory.
|
||||
func resolvePathForWrite(baseDir, path string) (string, error) {
|
||||
resolved, canonicalBase, err := resolveLexicalPath(baseDir, path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
existing := resolved
|
||||
var suffix []string
|
||||
for {
|
||||
_, err := os.Lstat(existing)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if !os.IsNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
parent := filepath.Dir(existing)
|
||||
if parent == existing {
|
||||
return "", err
|
||||
}
|
||||
suffix = append(suffix, filepath.Base(existing))
|
||||
existing = parent
|
||||
}
|
||||
|
||||
canonical, err := filepath.EvalSymlinks(existing)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for i := len(suffix) - 1; i >= 0; i-- {
|
||||
canonical = filepath.Join(canonical, suffix[i])
|
||||
}
|
||||
if !isWithinDir(canonical, canonicalBase) {
|
||||
return "", fmt.Errorf("path escapes the project directory through a symbolic link: %s", path)
|
||||
}
|
||||
return canonical, nil
|
||||
}
|
||||
|
||||
func resolveLexicalPath(baseDir, path string) (string, string, error) {
|
||||
if path == "" {
|
||||
path = "."
|
||||
}
|
||||
if filepath.IsAbs(path) {
|
||||
return "", fmt.Errorf("absolute paths are not allowed; use a path relative to the project directory")
|
||||
return "", "", fmt.Errorf("absolute paths are not allowed; use a path relative to the project directory")
|
||||
}
|
||||
resolved := filepath.Clean(filepath.Join(baseDir, path))
|
||||
if !isWithinDir(resolved, baseDir) {
|
||||
return "", fmt.Errorf("path escapes the project directory: %s", path)
|
||||
absBase, err := filepath.Abs(baseDir)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return resolved, nil
|
||||
canonicalBase, err := filepath.EvalSymlinks(absBase)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
resolved := filepath.Clean(filepath.Join(absBase, path))
|
||||
if !isWithinDir(resolved, absBase) {
|
||||
return "", "", fmt.Errorf("path escapes the project directory: %s", path)
|
||||
}
|
||||
return resolved, canonicalBase, nil
|
||||
}
|
||||
|
||||
func isWithinDir(path, dir string) bool {
|
||||
|
||||
Reference in New Issue
Block a user