Repository navigation
Description
Summary
On macOS, bili codex cannot make any HTTPS request. Codex refuses to load the SSL_CERT_FILE bundle bili writes (~/.local/share/billion-context/ca/combined-ca.pem):
Failed to build HTTP client while using CA bundle from SSL_CERT_FILE (~/.local/share/billion-context/ca/combined-ca.pem): builder error
This breaks both the model transport (Reconnecting... 5/5, workspace routing discovery failed) and every MCP client (rmcp::transport::worker: worker quit with fatal), so the bili tools never appear either.
The culprit is a single certificate that bili copies from the System keychain: CN=com.apple.kerberos.kdc, O=System Identity. It is a leaf identity cert (no basicConstraints), not a trust anchor, and it carries two Extended Key Usage extensions (TLS Web Server Authentication and Signing KDC Response). RFC 5280 §4.2 forbids repeating an extension. OpenSSL accepts the cert, but Codex's Rust HTTP client fails to build with it in the bundle. The duplicate EKU is the most likely reason; I have not traced the exact rejection inside Codex.
bili claude is unaffected (base-URL rewrite, no CA).
Environment
- billion-context 0.1.212 (daa082e), installed with
npm install -g --prefix ~/.local - codex-cli 0.162.1
- macOS 15.6 (24G84), x86_64
- Node v22.17.0
Reproduce
bili codex -- exec --skip-git-repo-check "hi"You can reproduce it without bili running. Point Codex at the bundle and send traffic to a dead port; the builder error appears before any connection:
SSL_CERT_FILE=~/.local/share/billion-context/ca/combined-ca.pem \
HTTPS_PROXY=http://127.0.0.1:9 \
codex exec --skip-git-repo-check "hi"Bisect results
The generated bundle had 190 certs. I tested subsets, each with bili's root CA appended, using the same SSL_CERT_FILE check:
| Bundle | Codex builder error |
|---|---|
bili's combined-ca.pem as written (190) |
yes |
root-ca.pem only |
no |
| combined, CRLF stripped | yes (CRLF in root-ca.pem is not the cause) |
| combined minus the two negative-serial certs | yes (not the cause) |
com.apple.kerberos.kdc + root only |
yes |
combined minus com.apple.kerberos.kdc (189) |
no: Codex connects and routes through bili |
Of the 190 certs, 9 came from the keychains (2 from System, 7 from login). Only 3 of those 9 are CAs. The rest are leaf certs: Apple system identities, application content-signing certs, and personal email/S-MIME certs. None of them belong in a trust bundle.
Cause in code
On darwin, collectOsStorePems() exports every certificate in both keychains:
execFileSync("/usr/bin/security", ["find-certificate", "-a", "-p", k2], …)
// k2 ∈ ["/Library/Keychains/System.keychain", "~/Library/Keychains/login.keychain-db"]writeCombinedBundle() then merges these unfiltered into combined-ca.pem. find-certificate -a returns identities and leaf certs as well as trust anchors.
Suggested fix
Keep only CA certificates from the OS-store export. Node's built-in X509Certificate is enough:
import { X509Certificate } from "node:crypto";
const caOnly = pems.filter((pem) => {
try { return new X509Certificate(pem).ca; } catch { return false; }
});I tested this against the same 190-cert bundle. It drops exactly the 6 non-CA keychain certs, including com.apple.kerberos.kdc, and keeps the 184 CAs, including user-installed CAs from the login keychain. Codex then builds its HTTP client with no error.
Optionally, apply the same filter to the whole merged bundle, so a malformed non-CA entry from any source cannot break replacement-semantics clients again.
Workaround
Remove the com.apple.kerberos.kdc cert from combined-ca.pem, then make the file read-only (chmod 444). writeCombinedBundle() hits EACCES on its 24 h rebuild, logs [ca] cannot rebuild … continuing with the EXISTING bundle, and keeps the filtered file. The downside is that keychain CAs added later are not picked up.
Activity
ranxianglei commentedon Nov 6, 2026
(ai: vllm-qwen/qwen3.8-27b)
查重: 不重复。 combined-ca.pem 家族里已有条目都是不同机制:#5725/#5736 是 zcode GUI 把 CA 路径指错了文件(root-ca.pem vs combined-ca.pem),#2439 是 Windows 重建时闪 PowerShell 黑窗,#1807/#1808 是引入 OS 信任存储合并的功能本身(即本缺陷的源头)。没有针对「keychain 导出混入非 CA 叶证书」的既有 issue/PR。
标签: bug · codex · scope/wiring · p1(macOS 上
bili codex完全不可用——Codex 拒绝整个信任包,模型流量与 MCP 全断)。审核结论(动手前已核实三步):
src/ca.ts逐字节一致——问题真实存在,不是版本滞后。darwin 分支确实用security find-certificate -a -p全量导出 System + login 两个 keychain(身份证书、应用签名、S-MIME 都在内),writeCombinedBundle()零过滤直接并入;你的 bisect(去掉 kdc 一张证书即恢复)与代码路径完全吻合。X509Certificate.ca过滤)打到了核心,我在此基础上略扩两处:① 过滤放在最终合并落盘前的单一收口处,覆盖所有来源(keychain、文件系统 bundle、Mozilla 快照、用户 SSL_CERT_FILE),不只 darwin 导出;② CA 判定除 basicConstraints CA:TRUE 外兼容 keyUsage 含 Certificate Sign 的老式锚点,避免误伤少数不带 basicConstraints 的用户自装 CA。另加一个收敛标记行:升级后首次启动强制重建一次 bundle——否则你机器上现有的坏包要等 24h 才过期重建,修复体感上像没生效。开始实现,PR 稍后贴这里。
ranxianglei commentedon Nov 6, 2026
(ai: vllm-qwen/qwen3.8-27b)
修复完成 → PR #5809: #5809 (
Closes #5802,分支2026-11-06_ca-bundle-ca-only-filter)并行 PR 核对:镜像 open [PR] 行里没有指向本线程的既有修复 PR(5810 行的
#5805是 GitHub 侧另一个存储性能帖,与本主题无关),本 PR 是唯一在途修复。结构化八问:
bili codex完全发不出 HTTPS 请求——Codex 拒绝加载 bili 生成的combined-ca.pem(Failed to build HTTP client ... builder error),模型连接(Reconnecting... 5/5)和全部 MCP client 一起死掉,bili 工具永远不出现。security find-certificate -a -p把 System + login 两个钥匙串的全部条目(含叶子身份证书、S-MIME、应用签名证书)无过滤合并进 bundle。其中com.apple.kerberos.kdc是叶子证书(无 basicConstraints)且带两个 EKU 扩展(违反 RFC 5280 §4.2)。Codex 的 rustls 栈对SSL_CERT_FILE是替换语义、逐条解析全部条目,任何一条解析失败就拒绝构建客户端——一张坏证书废掉整份 bundle。OpenSSL 系客户端(Node/curl)容忍这种证书,所以只有 codex 被废。bili claude与 NODE_EXTRA_CA_CERTS 车道不受影响。writeCombinedBundle()加一道 CA 判定门——只保留可解析为 X509 且 basicConstraints CA:TRUE 或 keyUsage 含 keyCertSign 位(覆盖 BC 引入前的遗留锚点)的条目,对所有来源统一生效(system bundle、OS store、Mozilla roots、MITM root)。配套两件事:① bundle 头部加一行 marker 注释,升级后遇到没有 marker 的新鲜文件(= 旧版坏 bundle)立即重建一次,不用等满 24h 新鲜期,否则修复看起来像没生效;② 兜底:若过滤把一切都丢了(解析能力异常),回退未过滤 bundle + error 日志,绝不发布空信任库(MITM 根恒过判定,实际不可达)。keyUsage 判定走原始 DER 扫描 OID 2.5.29.15,因为 Node v22 的X509Certificate.keyUsagegetter 对所有证书都返回 undefined,node-forge 又解析不了 ECDSA 证书(用它会静默丢掉 EC 根)。tests/ca-combined.test.ts19/19(含 4 个新回归钉)、其余引用 src/ca.ts 的三个套件 32/32、typecheck 干净;全量回归以 CI 为准。行为变更披露(旧→新):
SSL_CERT_FILE覆盖源同样生效),不可解析条目丢弃。原因:严格替换语义客户端逐条解析,一张 RFC 违规叶子证书废整份文件。本 PR 触碰 CA/信任面,属 §7.4 人工评审类,请评审后自行合并:#5809
fix(ca): let hasKeyCertSign see critical-marked keyUsage (#5802)
merge origin/master: resolve #5809 docs-move conflicts
Merge pull request #5809 from ranxianglei/2026-11-06_ca-bundle-ca-onl…
fix: keep only CA certificates in combined-ca.pem (ranxianglei#5802)