github / github/copilot-cli

macOS: explicit `tls.getCACertificates("system")` call adds 5+ seconds to every CLI invocation

Đang mở
#3,330 1 bình luận 0 reaction 0 người được giao Xem trên GitHub
area:networking
Ngôn ngữ chính
Shell
Star
11.2k
Fork
1.9k
Merge trung bình
14 giờ 16 phút
Pull request đã merge (30 ngày)
6

Mô tả

### Describe the bug

GitHub Copilot CLI's CA loader calls `tls.getCACertificates("system")` on every invocation in addition to `"bundled"` and `"extra"`. On macOS, that call iterates every keychain cert and invokes `SecTrustEvaluateWithError` synchronously via XPC to `trustd` — which (because of a Node bug, see References) uses a revocation-enabled trust policy and triggers OCSP/CRL fetches per cert. On machines with any network-flow filter (corporate NetworkExtension, ZeroTier, etc.), each fetch pays a per-flow cost and totals **5-10 seconds of latency on every CLI invocation** — even sub-commands like `--version` that don't make HTTPS requests inherit the cost because the call happens during SEA startup.

The `"system"` arg is also functionally redundant with `"bundled"` for `*.github.com` / `*.githubcopilot.com` endpoints. See related #869 (which reports a separate failure caused by the duplicate-certs concatenation from this same code).

### Affected version

GitHub Copilot CLI 1.0.48 (also reproduced on 1.0.39). macOS 26.4.1, Apple Silicon. Node 24.15.0 inside the SEA.

### Steps to reproduce the behavior

```bash
$ time copilot --allow-all-tools -p "reply with exactly: ack"
ack

real 0m12.43s
user 0m1.98s
sys 0m0.17s
```

Wall-clock vs user CPU mismatch confirms it's I/O wait, not CPU work. `sample(1)` on the grandchild SEA process during the wait:

```
node::crypto::GetSystemCACertificates
node::crypto::ReadMacOSKeychainCertificates
node::crypto::IsCertificateTrustedForPolicy
node::crypto::IsCertificateTrustValid
SecTrustEvaluateWithError
SecTrustEvaluateIfNecessary
securityd_send_sync_and_do ← synchronous XPC to trustd
xpc_connection_send_message_with_reply_sync
mach_msg2_trap
```

Isolated reproduction with standalone Node 24 on the same machine:

```bash
$ node -e 'const t0=process.hrtime.bigint();
require("tls").getCACertificates("system");
console.log(`${(Number(process.hrtime.bigint()-t0)/1e6).toFixed(0)}ms`)'
5287ms
$ node -e 'const t0=process.hrtime.bigint();
require("tls").getCACertificates("bundled");
console.log(`${(Number(process.hrtime.bigint()-t0)/1e6).toFixed(0)}ms`)'
0.1ms
```

HTTPS request to `api.github.com`:
- default (bundled): **53ms**
- `node --use-bundled-ca …`: **103ms**
- `node --use-system-ca …`: **5093ms** — 96× slower

### Expected behavior

CLI startup should not pay multi-second latency for a CA loader that produces certs equivalent to the bundled Mozilla store.

### Root cause in copilot-cli source

Decoded from `app.js` (npm-loader fallback; the SEA's bundled JS contains the same logic):

```js
function buildCAList() {
const envCerts = ["NODE_EXTRA_CA_CERTS","SSL_CERT_FILE","CURL_CA_BUNDLE"].flatMap(readEnvCAFile);
return typeof tls.getCACertificates === "function"
? [...envCerts,
...tls.getCACertificates(), // default (bundled in Node 24+)
...tls.getCACertificates("system"), // ← THIS LINE
...tls.getCACertificates("bundled"), // bundled (already implied above)
...tls.getCACertificates("extra")]
: [...envCerts, ...tls.rootCertificates];
}
```

### Proposed fix

Remove the `tls.getCACertificates("system")` line. One-line patch. If retaining the option for users with private CAs is desired, gate it behind a `COPILOT_USE_SYSTEM_CA=1` env var defaulting OFF. The current always-on cost is borne by every macOS user even when they don't need it. This also resolves the duplicate-certs issue tracked at #869.

### Why this user sees the upper end

My login keychain had 1589 certs (mostly auto-imported S/MIME contact certs from Mail.app over 20 years). After pruning 1478 long-expired certs, the call dropped from ~10s to ~5s — the floor on this machine, set by ~270 still-valid certs each costing ~20 ms in `SecTrustEvaluateWithError`. ZeroTier's `feth1960` virtual interface and `zerotier-one` daemon further amplify per-flow cost for the trustd OCSP traffic.

Users without a flow filter and a smaller keychain see a smaller version of this same tax (1-2s baseline, per anthropics/claude-code#53660's measurements).

### Related

- **anthropics/claude-code#53660** — same Node-side root cause analyzed in detail (revocation-enabled trust policy in `SecTrustEvaluateWithError`). Their workaround was to ship a `CLAUDE_CODE_CERT_STORE=bundled` env var users can set.
- **#1250** — Windows variant of the same call: throws "X509 to PEM conversion" instead of slow execution. Different symptom, same offending line.
- **#869** — duplicate certs from this same `bundled + system` concatenation cause `Failed to list available models` for some users.
- **nodejs/node#58990** — Node tracking issue for custom CA support; needs a sub-issue for the revocation-policy perf bug specifically, which I'm filing separately.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Hướng nghiên cứu

Bắt đầu trong hàm buildCAList của app.js đã được giải mã và kiểm tra các lệnh gọi tls.getCACertificates, đặc biệt là lệnh gọi đến kho hệ thống. Xóa tra cứu hệ thống luôn bật, sau đó xác minh rằng việc khởi động CLI không còn gây ra độ trễ vài giây trên macOS và rằng hành vi CA được đóng gói vẫn khả dụng.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
macos, node.js
Lĩnh vực
cli, operating-systems, performance
Loại issue
Lỗi
Độ khó
1/5
Thời gian dự kiến
Dưới một giờ
Mức độ hoạt động
Ít trao đổi
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
55/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.