package builtin import ( "fmt" "path/filepath" "strings" ) // resolvePath erzwingt die Pfad-Regel aus Abschnitt 5.3: nur unterhalb von // RepoRoot, Symlinks werden aufgelöst und erneut geprüft. func resolvePath(repoRoot, cwd, path string) (string, error) { if !filepath.IsAbs(path) { path = filepath.Join(cwd, path) } clean := filepath.Clean(path) root, err := filepath.EvalSymlinks(repoRoot) if err != nil { return "", fmt.Errorf("repo root nicht auflösbar: %w", err) } // Symlinks im Zielpfad auflösen, soweit er existiert; fehlt er (z.B. bei // write), am nächsten existierenden Vorfahren prüfen. resolved := clean if real, err := filepath.EvalSymlinks(clean); err == nil { resolved = real } else { dir := filepath.Dir(clean) if real, err := filepath.EvalSymlinks(dir); err == nil { resolved = filepath.Join(real, filepath.Base(clean)) } } rel, err := filepath.Rel(root, resolved) if err != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) { return "", fmt.Errorf("path escapes repo root: %s", path) } return clean, nil }