diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-03-14 07:24:10 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-03-14 07:24:10 +0000 |
| commit | 02b35218d9aadcaa6a3b52f218b71577ab72c811 (patch) | |
| tree | ffa761a07b940e97bf1e741b0cff8fcd74622a89 /internal/executor/claude.go | |
| parent | e0e81bbdaae37353803d47fa59a36d0472f8146d (diff) | |
fix: trust all directory owners in sandbox git commands
Sandbox setup runs git commands against project_dir which may be owned
by a different OS user, triggering git's 'dubious ownership' error.
Fix by passing -c safe.directory=* on all git commands that touch
project directories. Also add wildcard to global config for immediate
effect on the running server.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/executor/claude.go')
| -rw-r--r-- | internal/executor/claude.go | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/internal/executor/claude.go b/internal/executor/claude.go index a3d304d..626a854 100644 --- a/internal/executor/claude.go +++ b/internal/executor/claude.go @@ -200,12 +200,19 @@ func extractQuestionText(questionJSON string) string { return strings.TrimSpace(q.Text) } +// gitSafe returns git arguments that prepend "-c safe.directory=*" so that +// commands succeed regardless of the repository owner. This is needed when +// claudomator operates on project directories owned by a different OS user. +func gitSafe(args ...string) []string { + return append([]string{"-c", "safe.directory=*"}, args...) +} + // sandboxCloneSource returns the URL to clone the sandbox from. It prefers a // remote named "local" (a local bare repo that accepts pushes cleanly), then // falls back to "origin", then to the working copy path itself. func sandboxCloneSource(projectDir string) string { for _, remote := range []string{"local", "origin"} { - out, err := exec.Command("git", "-C", projectDir, "remote", "get-url", remote).Output() + out, err := exec.Command("git", gitSafe("-C", projectDir, "remote", "get-url", remote)...).Output() if err == nil && len(strings.TrimSpace(string(out))) > 0 { return strings.TrimSpace(string(out)) } @@ -217,14 +224,14 @@ func sandboxCloneSource(projectDir string) string { // If projectDir is not a git repo it is initialised with an initial commit first. func setupSandbox(projectDir string) (string, error) { // Ensure projectDir is a git repo; initialise if not. - if err := exec.Command("git", "-C", projectDir, "rev-parse", "--git-dir").Run(); err != nil { + if err := exec.Command("git", gitSafe("-C", projectDir, "rev-parse", "--git-dir")...).Run(); err != nil { cmds := [][]string{ - {"git", "-C", projectDir, "init"}, - {"git", "-C", projectDir, "add", "-A"}, - {"git", "-C", projectDir, "commit", "--allow-empty", "-m", "chore: initial commit"}, + gitSafe("-C", projectDir, "init"), + gitSafe("-C", projectDir, "add", "-A"), + gitSafe("-C", projectDir, "commit", "--allow-empty", "-m", "chore: initial commit"), } for _, args := range cmds { - if out, err := exec.Command(args[0], args[1:]...).CombinedOutput(); err != nil { //nolint:gosec + if out, err := exec.Command("git", args...).CombinedOutput(); err != nil { //nolint:gosec return "", fmt.Errorf("git init %s: %w\n%s", projectDir, err, out) } } @@ -240,7 +247,7 @@ func setupSandbox(projectDir string) (string, error) { if err := os.Remove(tempDir); err != nil { return "", fmt.Errorf("removing temp dir placeholder: %w", err) } - out, err := exec.Command("git", "clone", "--no-hardlinks", src, tempDir).CombinedOutput() + out, err := exec.Command("git", gitSafe("clone", "--no-hardlinks", src, tempDir)...).CombinedOutput() if err != nil { return "", fmt.Errorf("git clone: %w\n%s", err, out) } |
