Pin every agent run to its own CLI settings - #2068
Merged
Merged
Conversation
A target repository is untrusted input, yet every Claude run without a projected skill or acceptance oracle loaded its .claude/settings.json and settings.local.json. Against the pinned 2.1.263 CLI, a planted env.ANTHROPIC_BASE_URL took the model call off the run's broker to the repository's endpoint, carrying the repository's token and its apiKeyHelper's key; every planted hook ran; and a project .mcp.json server was spawned whenever no declaration of ours made the MCP config strict. Every Claude run now gets --setting-sources user. That source also gates project memory, so the workspace is added back with --add-dir and CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1, the one loader route that reads CLAUDE.md, .claude/CLAUDE.md and .claude/rules without project settings. A multi-repo run's cwd is the workspace root, which holds no CLAUDE.md, so the executor now stamps every repository directory onto the task and each one inside the workspace is added too; unpinned, such a run loaded a repository's memory only once it read a file there. Project commands, agents, skills and nested subdirectory CLAUDE.md files have no such route and no longer load. Codex 0.142.2 had the same shape. With no trust entry for its workspace it spawned a repository's [mcp_servers] on every run and ran its .codex/hooks.json on every acceptance-bearing run, where --dangerously-bypass-hook-trust waives review for every hook. Each run now marks its workspace untrusted with one -c override, keyed by the path it was given and by the physical path Codex resolves as its cwd. Keyed only as given, a workspace under macOS's /var symlink, where every local workspace lives, matched nothing and the repository's config loaded as before. AGENTS.md and skills still load, and Codex already ignored a project model_provider. RepositoryConfigE2ETests plants hostile config for both real CLIs at the unresolved temp path production uses, in a single-repo and a multi-repo workspace, and in the shipped Standard posture as uid 1654 in the non-root lane. The root lane now requires 90 cases and the non-root lane 11.
7 of 8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
--setting-sources user, so a target repository's.claude/settings.json,.claude/settings.local.jsonand.mcp.jsonnever apply. Unpinned, Claude 2.1.263 sent its model call to a plantedenv.ANTHROPIC_BASE_URLwith the repository's token andapiKeyHelperkey, ran every planted hook, and spawned the project MCP server. The workspace is added back with--add-dirplusCLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1, soCLAUDE.md,.claude/CLAUDE.mdand.claude/rulesstill load. Every repository directory inside the workspace is added as well, so each repository in a multi-repo workspace keeps its memory. The workspace root holds noCLAUDE.md, and per-repository--add-dirloads every repository's memory with none of its settings.AgentRunExecutor.InWorkspacesets the newAgentTask.WorkspaceRepositoryDirectoriesfrom the materialised workspace. A sibling repository outside a primary-repo cwd is not added.-c projects={...}override, so a repository's.codex/config.toml[mcp_servers]and its.codex/hooks.jsonnever load. Before this, the hooks ran unreviewed on acceptance-bearing runs under--dangerously-bypass-hook-trust. Codex looks trust up by the physical cwd, so the table holds both the given path and its fully resolved path (CodexHarness.PhysicalDirectory). Keyed only by the given path, a workspace under macOS's/varsymlink matched nothing.CLAUDE.md. 2.1.263 has no route that loads them without project settings.Test plan
--setting-sources useron every run shape;--add-dirfor single-repo, multi-repo root, primary-repo cwd and producer-named workspaces; Codex trust keys for a symlinked parent, a chained link, a path with no link and a missing path, checked against the shell'spwd -P(full unit suite green)AgentRunExecutorhands the real Claude adapter the workspace root and every repository directoryRepositoryConfigE2ETests), real Claude 2.1.263 and Codex 0.142.2 against a stub model at the unresolved temp path: single-repo Claude, multi-repo Claude and Codex arms green on macOS; each goes red when its fix is reverted