Skip to content

API key 读取容忍首尾引号与空白 - #20

Merged
Lucas1479 merged 2 commits into
Code-Amadeus:mainfrom
Mieluoxxx:fix/api-key-tolerant-parsing
Sep 3, 2026
Merged

API key 读取容忍首尾引号与空白#20
Lucas1479 merged 2 commits into
Code-Amadeus:mainfrom
Mieluoxxx:fix/api-key-tolerant-parsing

Conversation

@Mieluoxxx

Copy link
Copy Markdown
Contributor

问题

.env 中 API key 末尾多一个引号(例如复制粘贴时带上的)会让鉴权串
变成畸形值,表现为 401 Unauthorized,报错完全不会指向引号这个原因,
排查成本很高。

修复

config/settings.py 新增 _secret() 读取器,六个 key
(DEEPSEEK / OPENAI / GEMINI / TTS / MIMO / ASR)统一去除首尾空白与
成对引号后使用。

测试

tests/test_secret_parsing.py:带引号+空白的 key 经 settings 读取后
等于干净值。

说明

该改动原在 #16 中,按评审意见拆出为独立 PR(与依赖分层无共同根因)。

@Lucas1479 Lucas1479 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感谢跟进,并按上次建议把 API-key 容错拆成了独立 PR。复核当前 head 03254d1 后,方向没有问题,但修复边界仍需调整:

  1. 清洗只发生在 settings facade_secret() 仅位于 config/settings.py。Browser Provider 仍通过 EnvironmentReader.string() 直接读取原始环境值,命令式 Provider auth 也没有复用该逻辑。
  2. 同一个 key 在不同消费者中结果不一致:我在当前 head 复现到 config.settings 返回 sk-test,而 Browser 返回 sk-test"。这意味着 Main Chat/TTS 等路径可能恢复,但 Browser 或其他 Provider 仍会携带畸形 key 请求并继续得到 401。
  3. 测试没有覆盖真实故障边界:现有测试只向进程环境注入一个带引号的值,并断言单个 settings 字段;没有使用真实畸形 .env,也没有验证 Browser/Provider auth 与 settings 得到相同结果。

建议在 config.environment 建立明确的 secret/token 读取合同,让 settings、Browser 和 Provider auth 共用,同时保持“进程环境优先于 .env”的现有 authority 顺序。请补充实际 .env 与跨消费者一致性测试;完成后重新请求 review 即可。

Mieluoxxx added a commit to Mieluoxxx/Amadeus that referenced this pull request Sep 1, 2026
1. 拆出 API key 容错改动(revert 60164e1,见 f6d0e06,移交 Code-Amadeus#20)
2. test_profile_contract 读取 pyproject 显式 encoding="utf-8"(CP936 兼容)
3. CI 安装 uv==0.12.8,resolver smoke 不再被静默跳过;补输出目录 mkdir
4. verify_python_environment 提取 PROFILE_TIER_IMPORTS 阶梯映射,
   新增 vad profile(L1+L2+L3);--profile choices 由映射生成防漂移;
   阶梯契约测试冻结严格前缀链
5. asr/manager 新增公开 vad_status()(ready/fallback/degraded 三态),
   runtime_status 投影 snapshot["vad"]/["vad_degraded"],
   readiness 在 vad=="degraded" 时判 False(L2 fallback 保持 ready)

文档同步:README 梯级验证命令、locks README 验证阶梯说明。
Mieluoxxx added a commit to Mieluoxxx/Amadeus that referenced this pull request Sep 1, 2026
1. 拆出 API key 容错改动(revert 60164e1,见 f6d0e06,移交 Code-Amadeus#20)
2. test_profile_contract 读取 pyproject 显式 encoding="utf-8"(CP936 兼容)
3. CI 安装 uv==0.12.8,resolver smoke 不再被静默跳过;补输出目录 mkdir
4. verify_python_environment 提取 PROFILE_TIER_IMPORTS 阶梯映射,
   新增 vad profile(L1+L2+L3);--profile choices 由映射生成防漂移;
   阶梯契约测试冻结严格前缀链
5. asr/manager 新增公开 vad_status()(ready/fallback/degraded 三态),
   runtime_status 投影 snapshot["vad"]/["vad_degraded"],
   readiness 在 vad=="degraded" 时判 False(L2 fallback 保持 ready)

文档同步:README 梯级验证命令、locks README 验证阶梯说明。
Mieluoxxx added a commit to Mieluoxxx/Amadeus that referenced this pull request Sep 2, 2026
1. 拆出 API key 容错改动(revert 60164e1,见 f6d0e06,移交 Code-Amadeus#20)
2. test_profile_contract 读取 pyproject 显式 encoding="utf-8"(CP936 兼容)
3. CI 安装 uv==0.12.8,resolver smoke 不再被静默跳过;补输出目录 mkdir
4. verify_python_environment 提取 PROFILE_TIER_IMPORTS 阶梯映射,
   新增 vad profile(L1+L2+L3);--profile choices 由映射生成防漂移;
   阶梯契约测试冻结严格前缀链
5. asr/manager 新增公开 vad_status()(ready/fallback/degraded 三态),
   runtime_status 投影 snapshot["vad"]/["vad_degraded"],
   readiness 在 vad=="degraded" 时判 False(L2 fallback 保持 ready)

文档同步:README 梯级验证命令、locks README 验证阶梯说明。

@Lucas1479 Lucas1479 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复核当前 head 03254d1。这个分支在上一轮 review 后没有新提交,统一 secret 读取边界仍未闭合。

我再次复现了跨消费者不一致:给 DEEPSEEK_API_KEY 注入带首尾空白/引号的值后,config.settings.DE​​EPSEEK_API_KEY 得到清洗后的 sk-test123,而 server.browser_branch_planner._env("DEEPSEEK_API_KEY") 仍返回原始的带引号值。Codex command auth 的 tools/codex_provider_auth.py::provider_token() 也维护着另一套独立读取/strip 逻辑,没有复用本 PR 的合同。因此 settings 路径可能恢复,但 Browser 或 Provider auth 仍会发送畸形 token 并继续得到 401。

请将 secret/token 解析下沉到 config.environment 的单一读取合同,并让 settings、Browser 与 Provider command auth 共享它,同时保持“进程环境优先于项目 .env”的既有 authority 顺序。测试需要覆盖:

  1. 真实畸形 .env,而不只是向进程环境注入值;
  2. 进程环境覆盖 .env 的优先级;
  3. settings、Browser、Provider auth 对同一个 key 得到完全相同的值;
  4. 明确定义成对引号与孤立引号的处理规则,避免当前连续 strip() 意外改写合法 token。

完成后请 rebase 当前 main、重跑 CI,再请求 review。

.env 中 key 末尾多一个引号会导致 401 鉴权失败且难以定位。
新增 _secret() 读取器:DEEPSEEK/OPENAI/GEMINI/TTS/MIMO/ASR 六个
key 统一去除首尾空白与成对引号。
回应 PR Code-Amadeus#20 两轮评审:清洗此前只存在于 settings._secret() 一个
facade,Browser(browser_branch_planner._env)与 Codex provider auth
(provider_token)各自裸读原始环境值,同一 key 三方结果不一致,
畸形 key 在 Browser/Provider 路径继续 401。

- config.environment 新增 secret_value()(纯函数,单一规范化点)与
  EnvironmentReader.secret()(走既有 _register/_raw 链,继承进程环境
  优先于 .env 的 authority 顺序与 alias 处理)
- 规则:剥首尾空白 → 首尾引号字符各剥一层(成对或孤立,孤立引号是
  常见 .env 手滑)→ 再剥空白;内部引号永不触碰(my"pass"word 原样)。
  与旧 chained strip 的差异:每侧最多一层,保留内层结构。已接受的
  trade-off:真以引号结尾的合法 token 会被改写(真实 key 不以引号
  开头/结尾,而畸形 key 的代价是不透明 401)
- settings._secret 委托 _ENV.secret;browser 新增 _secret 并替换 6 处
  key 读取点(共享同一单例 reader);provider_token 清洗段委托
  secret_value,--env-file 参数化读取链有意保留(Codex bridge 显式
  输入,非项目 .env),空/空白进程值回退 env_file 的边界写入 docstring
- 测试重写:规则 9 例表驱动;真实畸形 .env 三方一致;进程值覆盖三方
  一致;provider_token authority 顺序与空白回退边界
@Mieluoxxx
Mieluoxxx force-pushed the fix/api-key-tolerant-parsing branch from 03254d1 to f23af52 Compare September 2, 2026 09:27
@Mieluoxxx

Copy link
Copy Markdown
Contributor Author

两轮评审的统一读取合同已闭合(commit f23af52,已 rebase 当前 main):

修复config.environment 新增单一 secret 合同——secret_value()(纯函数规范化)+ EnvironmentReader.secret()(走既有 _register/_raw 链,继承"进程环境优先于 .env"的 authority 顺序与 alias 处理)。

  • settings._secret 委托 _ENV.secret
  • browser_branch_planner 新增 _secret(共享同一单例 reader),6 处 API key 读取点换入
  • tools/codex_provider_auth.py::provider_token 清洗段委托 secret_value--env-file 参数化读取链有意保留(它是 Codex bridge 的显式输入,不是项目 .env,项目级单例不适用)——已在 docstring 写明该边界与"空/空白进程值回退 env_file"策略

引号规则(docstring + 测试钉死):剥首尾空白 → 首尾引号字符各剥一层(成对或孤立——孤立引号正是常见 .env 手滑,如评审复现的 sk-test\")→ 再剥空白;内部引号永不触碰(my\"pass\"word 原样)。与旧 chained strip 的差异:每侧最多一层(\"\"sk\"\"\"sk\"),保留内层结构。已接受的 trade-off 在 docstring/commit 说明:真以引号结尾的合法 token 会被改写(真实 key 不含首尾引号,而畸形 key 的代价是不透明 401)。

测试(评审 4 条全覆盖):

  1. 真实畸形 .env(孤立尾引号)→ dotenv 链 → 三方(settings / browser / provider_token)同值
  2. 注入带引号进程值 → 覆盖 .env,三方同值(独立子进程场景)
  3. 即上两条的三方一致性断言;另补"纯空白进程值 → 清洗为空 → provider_token 回退 env_file"边界
  4. 规则 9 例表驱动(成对双/单引号、孤立首/尾引号、内层空白、内部引号合法 token、纯空白、干净值)

本地:secret 相关 4 + codex provider 既有 6 passed,browser 相关 18 passed,ruff 通过。已全局核查无其他 API key 直接读取点。

@Lucas1479 Lucas1479 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感谢跟进修复!已复核 f23af52:secret 读取已统一到 config.environment,原有跨消费者不一致问题已解决;21 项定向测试及 Windows CI 均通过。同意合并。

@Lucas1479
Lucas1479 merged commit 1949a3c into Code-Amadeus:main Sep 3, 2026
2 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.

2 participants