feat: default seguro para working_dir en claude-code provider

Cuando WorkingDir esta vacio, se crea un directorio temporal aislado
en lugar de heredar el CWD del launcher (raiz del repo). Esto evita
que el subproceso claude -p tenga acceso de lectura/escritura al
codigo fuente del proyecto.

Si WorkingDir tiene valor, se asegura que el directorio exista
creandolo con MkdirAll. Se loguea WARN cuando se usa el tmpdir
para que el operador lo note y configure explicitamente.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 11:45:42 +00:00
parent e039f6c00c
commit 4f1689c13c
+23 -2
View File
@@ -58,6 +58,26 @@ func NewClaudeCodeComplete(cfg config.ClaudeCodeCfg, log *slog.Logger) coretypes
timeout = defaultClaudeTimeout
}
// Resolve working directory once at init time.
workDir := cfg.WorkingDir
if workDir == "" {
tmp, err := os.MkdirTemp("", "claude-agent-*")
if err != nil {
log.Error("claude-code: failed to create temp working dir", "err", err)
// Fall through — cmd.Dir will remain empty (inherits CWD).
} else {
workDir = tmp
log.Warn("claude-code working_dir is empty, using temporary directory",
"dir", workDir,
)
}
} else {
// Ensure configured directory exists.
if err := os.MkdirAll(workDir, 0o755); err != nil {
log.Error("claude-code: failed to create working dir", "dir", workDir, "err", err)
}
}
return func(ctx context.Context, req coretypes.CompletionRequest) (coretypes.CompletionResponse, error) {
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
@@ -70,11 +90,12 @@ func NewClaudeCodeComplete(cfg config.ClaudeCodeCfg, log *slog.Logger) coretypes
"binary", binary,
"args", strings.Join(args, " "),
"prompt_len", len(prompt),
"working_dir", workDir,
)
cmd := exec.CommandContext(ctx, binary, args...)
if cfg.WorkingDir != "" {
cmd.Dir = cfg.WorkingDir
if workDir != "" {
cmd.Dir = workDir
}
// Build clean env: inherit parent but remove ANTHROPIC_API_KEY
// so claude uses its own OAuth auth instead of a potentially invalid key.