Skip to content

fix: hard guard for settings.json env conflicts#80

Merged
guyskk merged 2 commits into
mainfrom
fix/settings-env-conflict-guard
May 19, 2026
Merged

fix: hard guard for settings.json env conflicts#80
guyskk merged 2 commits into
mainfrom
fix/settings-env-conflict-guard

Conversation

@guyskk

@guyskk guyskk commented May 19, 2026

Copy link
Copy Markdown
Owner

背景

实测验证(claude 2.1.144,隔离环境三组对照实验,详见 `docs/discuss-20260519-env-priority.md`)确认:

Claude Code 中 `~/.claude/settings.json` 的 `env` 字段严格覆盖 claude 进程继承的 OS 环境变量。

ccc 通过 `syscall.Exec` 把 provider env 作为进程环境变量传给 claude(`internal/cli/exec.go`),其优先级低于 settings.json 的 env。因此只要 settings.json 的 `env` 里残留 `ANTHROPIC_`/`CLAUDE_` 或与 provider/base 同名的 key,就会覆盖 ccc 传入的 provider 配置,导致切换 provider 静默失效

当前 main(#76 `FilterUserEnvForSettings`)的做法是静默剥离这些 key 后继续运行——会丢失用户手动配置且无任何提示。

改动

ccc 不再尝试自动剥离/迁移/修改用户 settings.json。检测到冲突就直接报错并中止,无交互、无 y/N,交互与非交互行为一致。`ccc validate` 同样做检测。

冲突判据:

  • key 以 `ANTHROPIC_` 或 `CLAUDE_` 开头,
  • key 与 base / provider env 同名(managed key)。

报错文本只列 key,不列 value(避免 AUTH_TOKEN 打到终端/CI 日志),并打印 settings.json / ccc.json 路径与修复指引。

文件

  • 新增 `internal/config/env_guard.go`:`EnvConflict`、`DetectSettingsEnvConflicts`、`FormatEnvConflictError`
  • 新增 `internal/config/env_guard_test.go`:表驱动检测与脱敏断言测试
  • 新增 `internal/cli/exec_test.go`:runClaude / runValidate 路径集成测试
  • 修改 `internal/cli/exec.go`:`runClaude` 在 `SwitchWithHook` 前插入守卫
  • 修改 `internal/cli/cli.go`:`runValidate` 在 `validate.Run` 前插入守卫,`--all` / 单 provider 范围正确处理
  • 更新 `README.md` / `README-CN.md` / `docs/settings-merge-strategy.md`:从"自动剥离"改为"硬守卫报错"
  • 提交讨论日志 `docs/discuss-20260519-env-priority.md`

破坏性变化

原本"settings.json 有 `ANTHROPIC_*` → 静默剥离后照常启动",现在变为"报错中止,要求用户先清理 settings.json"。

修复方法:从 `/.claude/settings.json` 的 `env` 中删除冲突 key,并把 provider 相关配置改到 `/.claude/ccc.json` 的 `providers..env`。

验证

  • `./check.sh` 全绿(lint + race test + build)
  • 手工冒烟(隔离环境 `CCC_CONFIG_DIR=./tmp/x`,未污染真实配置):
    • `ccc glm` 冲突 → 报错列 key 不列 value、退出码非 0、未启动 claude
    • `ccc validate` / `ccc validate --all` 冲突 → 同样报错中止
    • `ccc glm -p` 非交互场景 → 同样报错退出,无阻塞、无 stdin 读取
    • 移除冲突 key 后回归正常流程
    • `md5sum` 比对:守卫拒绝前后 settings.json 文件内容比特一致(证明 ccc 不修改用户文件)

不在本次范围

  • 不做任何 env 迁移到 ccc.json
  • 不删除 `FilterUserEnvForSettings` / `MergeWithPriority`(守卫命中即中止;未命中时既有逻辑不变,对无冲突输入是恒等行为)

guyskk added 2 commits May 19, 2026 21:32
Detect when settings.json's env field contains keys that would
silently override ccc's provider env (Claude Code's settings.json
env overrides the process env passed via syscall.Exec, empirically
verified). Refuse to launch claude — and refuse to run validate —
when such conflicts are present, instead of silently stripping the
keys.

A key is considered conflicting if it:
- starts with ANTHROPIC_ or CLAUDE_, OR
- collides with any key defined in base/provider env.

The error message lists offending keys (without values, to avoid
leaking secrets) and points the user at the fix: remove from
settings.json's env and move provider configuration to ccc.json.

ccc never modifies the user's settings.json — the user is the only
one who can resolve the conflict.

BREAKING CHANGE: previously, ANTHROPIC_*/CLAUDE_* keys and managed
keys in settings.json env were silently filtered out when writing
the merged settings. Now they cause a hard error and refuse to
start claude until the user removes them.
Replace the previous 'silent strip' description in README/README-CN
and docs/settings-merge-strategy.md with the new hard-guard behavior:
ccc never modifies settings.json's env, and aborts with a clear error
listing offending keys (no values) and the fix path.

Also commit docs/discuss-20260519-env-priority.md — the empirical
investigation log behind the decision (three controlled isolated-env
tests verifying that Claude Code's settings.json env strictly
overrides the process env passed via syscall.Exec).
@guyskk guyskk merged commit 60e671d into main May 19, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant