fix(installer): retry backend install with --native-tls on TLS trust failure#1694
Conversation
…failure A corporate MITM proxy presents PyPI with a certificate signed by a custom root CA that uv's bundled webpki roots don't include, so the install fails with "invalid peer certificate: UnknownIssuer". It surfaces wrapped in "Failed to fetch", so the existing transient-network retry burned all three attempts against the same bundled roots. Detect the cert error first and retry once with --native-tls, which makes uv trust the OS certificate store where IT installs the corporate CA. Closes #1693
SummaryClean, well-scoped fix for issue #1693. It correctly identifies that uv's bundled webpki roots can't validate a corporate MITM proxy's CA, that the resulting Issues Found🟢 The TLS branch sets In practice a TLS-intercepting proxy fails deterministically from attempt 1, so this is unlikely to ever fire — hence minor, not blocking. If you want to close it cleanly, gate the loop bound so a not-yet-tried (with a 🟢 Consider noting the redundant native-TLS retries via the transient path ( Once Strengths
VerdictApprove. No blocking issues. The two minor notes are optional polish; the change is correct, well-tested, and safe to merge for the scenario it targets. Worth honoring the PR's own call-out for one manual validation on a real (or simulated) TLS-intercepting proxy before relying on it in the field. |
|
🟡 If the TLS error only surfaces on the last attempt (e.g. attempts 1–2 failed with transient errors and used up Fix: gate the user-facing message on whether native-TLS was actually executed: } else if (isTlsCertError(output)) {
suggestion = useNativeTls
? "PyPI's certificate isn't trusted on this network — usually a corporate proxy. " +
"GAIA retried with the OS certificate store and it still failed. " +
"Ask IT to install the proxy's root CA in your system's trusted certificate store, then relaunch GAIA. " +
"See https://amd-gaia.ai/quickstart#cli-install"
: "PyPI's certificate isn't trusted on this network — usually a corporate proxy. " +
"Try rerunning; if that also fails, ask IT to install the proxy's root CA. " +
"See https://amd-gaia.ai/quickstart#cli-install";
}The happy path (TLS error on attempt 1, native-tls succeeds or gives a clear second failure) is unaffected. |
Addresses review feedback on the issue #1693 TLS fix. The TLS branch flips useNativeTls and continues, consuming a loop iteration; if the UnknownIssuer signature only surfaced on the final attempt (e.g. after two transient failures), the loop exited without ever running the --native-tls retry — and the failure message still claimed GAIA had retried against the OS trust store. Extend the loop bound by one when a not-yet-run --native-tls is pending, and gate that message on whether the retry actually executed.
|
Addressed the review feedback in d1c39f5 — the ordering gap where The TLS branch flips
Traced the edge case (transient×2 → TLS on attempt 3 now runs a real |
The Electron framework test suite is silently broken on `main`: any PR
touching a `webui/` path fails CI with
`expect(msgCss).toContain('border-left: 2px solid var(--amd-red)')`,
even when unrelated to the UI (e.g. #1694, an installer fix). This
unblocks those PRs.
Root cause: the Agent Hub redesign (#1564) renamed the error message's
left-border token from `--amd-red` to `--danger` in `MessageBubble.css`
but didn't update the CSS-assertion test that pins the old token.
`main`'s own Electron CI is path-filtered and hadn't re-run since the
rename landed, so it stayed latent until a webui-touching PR triggered
it. Same class of issue as #1701.
## Test plan
- [ ] `cd tests/electron && npm test` — all suites pass (was 1 failed)
- [ ] `npx jest test_electron_chat_app.js` — the previously-failing
assertion passes
The Agent Hub redesign renamed the error message's left-border token from --amd-red to --danger in MessageBubble.css; this webui-touching PR trips the stale CSS assertion in the Electron suite. Same fix as #1704 — included here so this PR's CI is green independently.
# Conflicts: # src/gaia/apps/webui/services/backend-installer.cjs
The Agent UI Vitest suite was silently broken on `main`: any PR touching a `webui/` path (e.g. amd#1694, an installer fix) fails CI with `TypeError: Cannot read properties of undefined (reading 'then')` in `ChatView.test.tsx`, even when the PR has nothing to do with the UI. This unblocks those PRs. Root cause: amd#1656 added an `api.getActiveRuns().then(...)` call to `ChatView`'s mount effect but never stubbed `getActiveRuns` in the test's auto-mocked api module, so it returned `undefined`. `main`'s own Vitest is path-filtered and hadn't re-run since the regression landed, so it stayed latent until a webui-touching PR triggered it. ## Test plan - [ ] `cd src/gaia/apps/webui && npx vitest run` — all 62 tests pass - [ ] `npx vitest run src/components/__tests__/ChatView.test.tsx` — the previously-failing test passes
Before: on a corporate network that inspects TLS (a MITM proxy with its own root CA), the GAIA backend installer failed every update with
error: Failed to fetch: https://pypi.org/simple/amd-gaia/ … invalid peer certificate: UnknownIssuer. uv ships its own bundled webpki root certificates and doesn't trust the proxy's CA, so the install could never complete — and because the error wraps in "Failed to fetch", the installer's transient-network retry burned all three attempts against the same bundled roots. After: the installer detects a TLS trust failure and retries once with--native-tls, which makes uv use the OS certificate store where IT departments install the corporate root CA, so the install succeeds on these networks. If it still fails, the error message now names the cause (untrusted proxy certificate) and the fix (install the CA in the system store) instead of the generic manual-install hint.Closes #1693
Test plan
npx jest tests/electron/backend-installer-lock.test.cjspasses (covers the newisTlsCertErrordetector against the exact issue [Bug]: GAIA install fails on update #1693 signature)python -m pytest tests/unit/ -xpassespython util/lint.py --allpasses