Redirect direct backend git global config to an isolated per-task file#77
Conversation
9045d9d to
2fc5a48
Compare
The direct backend runs the oz CLI directly on the host, so git config --global writes from the agent (notably the url.<host>.insteadOf rewrites set up by the warp driver) persisted into the real ~/.gitconfig. Set GIT_CONFIG_GLOBAL to a per-task .gitconfig (inside the per-task workspace, or a temp dir in shared --target-dir mode) for the agent invocation and the setup/teardown commands, so those global writes stay isolated and are removed with the task. HOME is left unchanged, so the plaintext credential files the driver writes (~/.git-credentials, ~/.config/gh/hosts.yml) are intentionally untouched. Docker and Kubernetes backends are unaffected. Add a regression test that runs git config --global insteadOf and asserts it lands in the per-task config rather than the real ~/.gitconfig. Co-Authored-By: Oz <oz-agent@warp.dev>
ea226ea to
ac86713
Compare
The direct backend joins the server-provided task ID with the workspace root and uses it as a temp-dir name component. A task ID that is absolute or contains ".." could escape the intended directory (CodeQL go/path-injection). Reject non-local task IDs via filepath.IsLocal before any path is constructed, and add a regression test. Co-Authored-By: Oz <oz-agent@warp.dev>
ac86713 to
12c79c2
Compare
Co-Authored-By: Oz <oz-agent@warp.dev>
harryalbert
left a comment
There was a problem hiding this comment.
nice! Just had one question about gating
| // global config keeps writes like `git config --global url.<x>.insteadOf` out of | ||
| // the developer's real ~/.gitconfig (and $XDG_CONFIG_HOME/git/config) without | ||
| // repointing HOME for every tool the agent runs. | ||
| func prepareTaskGitConfig(workspaceDir string, usingTargetDir bool) (string, func(), error) { |
There was a problem hiding this comment.
it seems like we're not gating this on the oz-local script — OOC is there a reason to do this across the board instead of limiting to only when debugging (maybe self hosted)?
There was a problem hiding this comment.
We should definitely use a per-task config file for any run with the direct backend. There may be multiple concurrent runs on the same host, and while we can't fully isolate them, we should do so as much as possible.
There was a problem hiding this comment.
I also dont think its as straight forward to differentiate between selfhosted workers (used by real clients) and local, and ideally our oz-local is as similar to real production behavior as possible too
| // global config keeps writes like `git config --global url.<x>.insteadOf` out of | ||
| // the developer's real ~/.gitconfig (and $XDG_CONFIG_HOME/git/config) without | ||
| // repointing HOME for every tool the agent runs. | ||
| func prepareTaskGitConfig(workspaceDir string, usingTargetDir bool) (string, func(), error) { |
There was a problem hiding this comment.
We should definitely use a per-task config file for any run with the direct backend. There may be multiple concurrent runs on the same host, and while we can't fully isolate them, we should do so as much as possible.
| return err | ||
| } | ||
| defer cleanupGitConfig() | ||
| gitConfigEnv := []string{fmt.Sprintf("GIT_CONFIG_GLOBAL=%s", gitConfigPath)} |
There was a problem hiding this comment.
We may need to escape the path, in case the workspace dir is set to something with spaces
There was a problem hiding this comment.
added testing for a workspace path with spaces. Since we are using exec.Cmd.Env, it shouldnt need escaping
Problem
When oz-local is run locally by developers, an
insteadOfentry gets written to the user's gitconfig, redirecting ssh urls to https. This is not desirable for developers because we generally prefer ssh auth and we get errors when trying to push to git.Description
The direct backend runs the oz CLI directly on the host, so
git config --globalwrites from the agent (notably theurl.<host>.insteadOfrewrites configured by the warp driver) persisted into the real~/.gitconfigwhen running locally (oz-local). Docker and Kubernetes backends are unaffected because their home is ephemeral.This sets
GIT_CONFIG_GLOBALto a per-task.gitconfigfor the direct backend (inside the per-task workspace, or a temporary directory in shared--target-dirmode), applied to the agent invocation and the setup/teardown commands. Those global writes now stay isolated and are cleaned up with the task. The agent git operations during the run still work because they inheritGIT_CONFIG_GLOBAL.Intentionally out of scope
HOMEis left unchanged, so the plaintext credential files the driver writes (~/.git-credentials,~/.config/gh/hosts.yml) still go to the real home. That is deliberate for this change. Source-side hardening is tracked in warpdotdev/warp#11886.Testing
go vet ./internal/workergo test ./...includes a new regression test that runsgit config --global insteadOfand asserts it lands in the per-task config, not the real~/.gitconfig.Related
This is the direct-backend piece of the broader Oz git-auth cleanup; the writes themselves originate in the warp driver (
app/src/ai/agent_sdk/driver/git_credentials.rs,setup_git_config).entrypoint.sh, consolidating to the driver. Complementary, container-only; does not run on the direct/local path, so it does not address this bug.taskGitCredentialsquery and clean up; orthogonal to where git config is written, so they do not fix the home pollution.--globalwrites and plaintext credential files across all backends.Oz
Conversation: https://staging.warp.dev/conversation/370f424c-2dc3-4fe1-b4a6-c3c39dcc70fe
Co-Authored-By: Oz oz-agent@warp.dev