feat(permissions): pass Claude Code settings keys and Codex CLI [tui] through the permission override - #2720
Merged
dyoshikawa merged 8 commits intoAug 23, 2026
Conversation
… through the permission override The claudecode override block validated any key (looseObject) but the writer only copied permissions and sandbox, so editorMode, emojiCompletionEnabled, workflowSizeGuideline, keybindingFlavor and every future top-level settings key was accepted and then silently dropped. Enumerating them one at a time keeps losing the race, so everything in the block other than permission/permissions/sandbox/hooks/$schema is now deep-merged into the top level of settings.json and lifted back on import. Keys the target file cannot honor are skipped with a warning, derived from the per-key Scope column of the settings reference: User-or-managed keys at project scope, Managed and ~/.claude.json keys in both scopes. For Codex CLI, tui joins the override allowlist so [tui] vim_mode_default and the keymap bindings beside it are authorable.
The claudecode passthrough copied any top-level key into .claude/settings.json. Because .rulesync/permissions.jsonc is fetchable, that let a third-party file author apiKeyHelper, statusLine and friends, whose values Claude Code executes. Refuse those keys in both directions and both scopes, warn on the keys that widen trust (env, enabledPlugins, ...), resolve marketplace aliases before the scope check, and harden the key lookups against prototype-chain hits. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…Claude Code override The first refusal missed fileSuggestion, gcpAuthRefresh, subagentStatusLine and policyHelper, and the sandbox branch never reached the top-level filter at all, so sandbox.ripgrep/bwrapPath/socatPath still named an executable a fetched permissions file could pick. Refuse all of them, warn when the override starts sessions in bypassPermissions, say plainly that env can run code, and share one control-character stripper across doctor, fetch and here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add httpHookAllowedEnvVars, allowedHttpHookUrls, permissions.additionalDirectories and the sandbox network proxy ports to the warn-then-write set. Share one traversal helper between the sandbox path filters, drop command-executing sandbox paths on import too, and remove the dead policyHelper scope entry.
Cover the sandbox paths that let commands out of the sandbox or weaken its isolation, the MCP/agent/output-style keys that redirect what a session trusts, and the acceptEdits and auto permission modes. Warn on the filtered sandbox so a path project scope drops is never reported as written, share one traversal helper across the sandbox filters, and strip the plain LRM/RLM marks from logged names again.
…only widen Claude Code merges a sandbox list across settings scopes rather than replacing it, so filesystem.allowRead, filesystem.allowWrite and network.allowedDomains authored in a project file can only add to the policy. Warn on them, and on disableSkillShellExecution, which re-opens shell execution a user setting closed. Filter prototype keys out of the imported permissions fields too.
…e warn set sandbox.ignoreViolations maps a command substring to the violations to hide, so the boolean predicate never fired. Warn on allowedMcpServers, whose entries merge into an allowlist deployed elsewhere, on network.allowMachLookup, and on autoMode and the two skip-prompt keys in the scope that honors them.
…sens The key restricts at true and re-opens inline shell execution at false, so warning on every value misdirected. Add a small predicate table for keys whose loosening value is the absence of a restriction, restore the alphabetical order of the trust table, and correct why the sandbox deny lists are absent from the warn set.
dyoshikawa
deleted the
resolve-issue-2715-claudecode-settings-passthrough
branch
August 23, 2026 17:08
Owner
Author
|
@dyoshikawa Thank you! |
This was referenced Aug 23, 2026
rudironsoni
pushed a commit
to rudironsoni/rulesync
that referenced
this pull request
Aug 25, 2026
…trust warnings Works through the five follow-ups deferred from dyoshikawa#2720. 1. `sandbox.filesystem.allowManagedReadPathsOnly` and `sandbox.network.allowManagedDomainsOnly` are documented `Managed`, so neither file rulesync writes reads them. They are now dropped in both scopes with a warning, the same treatment the `Managed` top-level keys already get, instead of being committed as a lock that never applies. 2. The per-key trust warnings from the `permissions` fields, the `sandbox` paths and the top-level passthrough are collected and emitted as one summary line per file. The reasons are what differ between them; the "review this as you would a hook" advice only needs saying once. 3. `allowUnsandboxedCommands` and `autoAllowBashIfSandboxed` keep warning on their documented `true` default, now with the reason recorded: a project settings file outranks the user file, so an explicit `true` there re-opens what a user`s `false` closed. 4. Adds the six candidate keys, each checked against the settings reference: `claudeMdExcludes`, `modelOverrides`, `skipWebFetchPreflight`, `remoteControlAtStartup`, `prUrlTemplate` and `companyAnnouncements` are all scoped `Any file`, so all are written and warned about at the value that widens. `remoteControlAtStartup` is the exception: Claude Code honors a `false` from a project file but ignores a `true`, so a `true` is skipped at project scope and emitted only under --global. 5. Guards the `CLAUDECODE_TRUST_KEY_WIDENING_VALUES` lookup with `Object.hasOwn`, so its safety no longer depends on evaluation order.
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
.rulesync/permissions.jsonc'sclaudecodeoverride block validated any key (its schema is alooseObject), butclaudecode-permissions.tsonly ever copiedpermissionsandsandbox. Every other authored key —editorMode, and since thenemojiCompletionEnabled,workflowSizeGuideline,keybindingFlavor,spellcheck,env,model, ... — validated cleanly, produced no warning, and was then dropped. Codex CLI's[tui]table hit the same wall from the other side: it was rejected by theCODEXCLI_OVERRIDE_KEYSallowlist with a warning.Per the maintainer's re-check comment on the issue, the fix is widened from "add
editorModeto the schema" to a general top-level passthrough, because enumerating keys one at a time keeps losing the race (2.1.217 → 2.1.239 alone added five, plus aliases).Claude Code — generic top-level passthrough
claudecodeoverride other thanpermission,permissions,sandbox,hooksand$schemais deep-merged into the top level of.claude/settings.json. Deep-merged for the same reasonsandboxis: setting one key underenvmust not drop the variables beside it. The exclusions keep feature ownership intact —hooksbelongs to the hooks feature,permission/permissions/sandboxhave their own branches, and$schemais an editor pointer rather than a setting.claudecodeoverride, so an importedsettings.jsonsurvives the nextgenerateinstead of being narrowed to the keys this feature happens to model.CLAUDECODE_GLOBAL_ONLY_SANDBOX_PATHSbehavior). The settings reference documents a Scope per key, and rulesync now skips a key the file it is writing cannot honor, warning once per key:User or managed/User, local, or managed(spellcheck,autoMode,vimInsertModeRemaps,pluginConfigs, ...) — skipped at project scope, emitted under--global.Managed(allowManagedHooksOnly,requiredMinimumVersion, ...) andGlobal config(diffTool,autoConnectIde, ...) — skipped in both scopes, since neither.claude/settings.jsonnor~/.claude/settings.jsonis the file that reads them.deepMergeRecords.Codex CLI —
[tui]tuijoinsCODEXCLI_OVERRIDE_KEYS, so it is written verbatim as a top-levelconfig.tomltable (shallow-merged with existing siblings, likeapps) and re-extracted on import.tui: z.optional(z.looseObject({}))is added toCodexcliPermissionsOverrideSchemaso the intent is documented, while staying loose for thetui.keymap.*bindings.CODEXCLI_OVERRIDE_KEYSalso extends the permissions feature'sSHARED_CONFIG_OWNERSHIPdeclaration for.codex/config.toml, which is the single source both the writer and the gateway read.Docs
docs/reference/file-formats.md: the Claude Code override callout gains the passthrough rule, the exclusion list and the scope caveat; the Codex CLI callout liststui.Validation evidence
editorModeand the per-key Scope column: https://code.claude.com/docs/en/settings-reference —editorModeisAny file; the Managed / User-or-managed / Global-config lists in the new constants are taken verbatim from that table.[tui] vim_mode_default: https://developers.openai.com/codex/config-reference and the 0.129.0 modal Vim composer release notes https://github.com/openai/codex/releases/tag/rust-v0.129.0.Test plan
claudecode-permissions.test.ts: unmodeled key passthrough, deep merge preserving siblings, refusal to writehooks/$schema, project-scope drop + warning for a user-scope key,--globalemission of the same key, both-scope drop + warning for managed /~/.claude.jsonkeys, and an import → generate round trip.codexcli-permissions.test.ts:[tui] vim_mode_defaultis written with no "not managed" warning and round-trips on import.pnpm cicheckpasses: 375 test files / 8778 tests, plus fmt / oxlint / typecheck / docs-content / gitignore / supported-tools / cspell / secretlint.Closes #2715