feat(desktop): add per-provider TLS verification bypass#355
Conversation
Adds an opt-in tlsRejectUnauthorized boolean to ProviderEntry plus a ref-counted withTlsBypass(enabled, fn) helper that swaps the global undici dispatcher for one with rejectUnauthorized:false around outbound HTTPS calls. Built-in providers (anthropic, openai, openrouter, ollama) force-ignore the flag so a tampered config cannot weaken trusted endpoints. The toggle surfaces only on non-built-in providers in AddCustomProviderModal, gated behind a confirm prompt on first enable, and rendered as a yellow "TLS verify off" badge on the provider row. Threading covers all outbound paths: connection-test (test-active / test-provider / config:v1:test-endpoint), models discovery (models:v1:list-for-provider), and generation (codesign:v1:generate + codesign:v1:generate-title via pi-ai). The known concurrency window — parallel requests during the bypass interval inherit the loose dispatcher — is documented in tls-override.ts and the design spec. Unblocks users on corporate networks whose internal OpenAI-compatible gateways serve self-signed or private-CA certificates that Node 22's built-in fetch (undici) cannot otherwise accept, since NODE_TLS_REJECT_UNAUTHORIZED is intentionally ignored by undici. Closes #229.
There was a problem hiding this comment.
Review mode: initial
Findings
-
[Major] Missing
codesign:apply-commentIPC bypass — the PR explicitly acknowledges this as out-of-scope (apps/desktop/src/main/ipc/generate.tslines not shown in patch but referenced in PR body). However, sinceapply-commentalso callsrunGenerateagainst the active provider, users connecting via a self-signed gateway will get SSL errors on inline-edit operations immediately after they enable the bypass. This is a user-visible regression for the very use case the PR enables. The fix is small (~3 lines around theapply-commenthandler ingenerate.ts) and closing #229 without it leaves a broken path.
Suggested fix: wrap theapply-commentIPC handler withwithTlsBypass(tlsBypass, () => ...)following the same pattern as the other generate paths. -
[Major] Linked issue #229 claims closure but
apply-commentpath is unwired — the PR'sCloses #229implies full resolution of the issue. The issue's scope (connecting to internal gateways with self-signed certs) is incomplete if inline-comment edits fail. Change the issue link toRefs #229or implement the bypass in theapply-commenthandler before marking it closed. -
[Minor] Hardcoded UI tokens in
primitives.tsxbadge — the TLS badge usesclassName="inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full border border-[var(--color-warning)] text-[var(--color-warning)] bg-[color-mix(in_oklab,var(--color-warning)_12%,transparent)] text-[var(--font-size-badge)] font-medium leading-none". While--color-warningand--font-size-badgeare tokens, the spacing/padding values (px-1.5,py-0.5,gap-1) are raw Tailwind utilities that duplicatepackages/uisemantic token values (e.g.,--spacing-1,--spacing-1_5). For a new UI element, prefer token-based spacing to maintain consistency.
Suggested fix: useclassName="rounded-full border border-[var(--color-warning)] text-[var(--color-warning)] bg-[color-mix(in_oklab,var(--color-warning)_12%,transparent)] text-[var(--font-size-badge)] font-medium leading-none"and apply padding viastyle={{ padding: 'var(--spacing-1_5) var(--spacing-1)' }}or define a component-level token. However, this is a minor style consistency issue and does not block merge. -
[Nit]
undicipromoted to direct dependency — this is justified (previously transitive, now explicitly declared), but the lockfile diff shows[email protected]was already present as a transitive dep viapi-ai. No new install weight. Acceptable. -
[Nit]
window.confirmfor security warning — the PR useswindow.confirm()which matches existing patterns (perClaude.md: no AlertDialog primitive). Fine, but the confirm text contains locale keys resolved viat()— ensure the translation files have matching keys (they do in all 4 locales). No action needed.
Questions
- None.
Summary
- Well-structured PR with thorough testing (new
tls-override.test.ts, extendedconnection-ipc.test.ts, extendedconfig.test.ts). The core mechanism (withTlsBypass) is cleanly designed with ref counting and exception safety. The concurrency window is documented and accepted. All hard constraints are satisfied: no bundled runtimes, BYOK preserved, local-first, permissive deps (undici is MIT), no bloat (minimal ~90 lines). The missingapply-commentpath is the only material gap; fixing it is straightforward. Once addressed, this is ready to merge.
Testing
- New tests: 6 unit tests for
tls-override.ts, 7 integration tests forconnection-ipc.ts, 3 schema tests forconfig.ts. All pass. Missing test for theapply-commentpath (since it's not wired).
Open-CoDesign Bot
The apply-comment IPC handler also calls runGenerate against the active provider; left unwrapped in the original change it would surface SSL errors on inline-edit operations for users who enabled the bypass on a self-signed gateway. Wrap runGenerate the same way the codesign:v1:generate and codesign:v1:generate-title handlers do, deriving tlsBypass from the same resolveTlsBypassFor helper. Addresses codex bot review #1 on PR #355.
|
Thanks for the review. ✅ Major #1 — fixed in aca58c9
✅ Major #2 — auto-resolved by #1With apply-comment wired, the 🟢 Minor #3 — declined, with rationaleThe bot suggested replacing More importantly, the new TLS badge is immediately adjacent to an existing Happy to revisit if a Test plan
|
There was a problem hiding this comment.
Review mode: follow-up after new commits
Findings
- [Resolved] Missing
codesign:apply-commentIPC bypass — the previous review flagged that theapply-commenthandler ingenerate.tswas not wrapped withwithTlsBypass. The latest commits now addconst tlsBypass = resolveTlsBypassFor(cfg, active.model.provider);and wrap therunGeneratecall in that handler withwithTlsBypass(tlsBypass, () => runGenerate(...)). This closes the gap. Seeapps/desktop/src/main/ipc/generate.tslines ~1332 and ~1380-1416 in the compare diff. - [Resolved] Linked issue #229 closure now complete — the
apply-commentbypass is wired, so the issue's acceptance criteria (all outbound HTTPS paths through custom providers respect the toggle) are fully satisfied. TheCloses #229claim is now accurate. - [Minor] No test for
apply-commentTLS bypass routing — the new path is functionally identical to the other generate paths (sameresolveTlsBypassFor+withTlsBypasspattern) and shares the already-testedwithTlsBypassmock, but there is no dedicated test asserting thatapply-commentcallswithTlsBypasswith the correctenabledflag. Adding one inconnection-ipc.test.tsor a newgenerate.test.tswould prevent regression. This is non-blocking because the existing routing tests cover the same logic.
Summary
Both material issues from the previous review have been addressed. The apply-comment handler is now wrapped with the TLS bypass, making the PR complete for all generation paths. The architecture remains clean (withTlsBypass + ref-counted dispatcher swap), tests pass, all hard constraints are satisfied, and the linked issue #229 is now fully closed. This is ready to merge after considering the minor test-coverage gap above.
Open-CoDesign Bot
Summary
tlsRejectUnauthorizedboolean onProviderEntryso users can connect to internal LLM gateways whose self-signed / private-CA certificates Node 22's built-in fetch (undici) rejects —NODE_TLS_REJECT_UNAUTHORIZEDis intentionally ignored by undici, so a runtime dispatcher swap is the only working bypass.withTlsBypass(enabled, fn)helper inapps/desktop/src/main/tls-override.tsthat swaps the global undici dispatcher for one withrejectUnauthorized: falsearound the wrapped call, and restores the original infinally.test-active/test-provider/config:v1:test-endpoint), models discovery (models:v1:list-for-provider), and generation (codesign:v1:generate+codesign:v1:generate-title).AddCustomProviderModalfor non-built-in providers only, gated behind a confirm prompt on first enable, and renders a yellow "TLS verify off" badge on the affected provider row in Settings.Closes #229.
Hard-constraints check (PRINCIPLES §5b)
undiciwas already a transitive dep via pi-ai; now promoted to a direct dep so resolution is explicit. Helper is ~90 lines; UI delta is a single checkbox + badgetry/finally, ref-count handles nested / concurrent acquiresDesign notes
Full design spec lives at
docs/superpowers/specs/2026-05-23-tls-bypass-design.md(gitignored per project convention, local-only). The known concurrency window (parallel non-bypass requests during a bypass interval inherit the loose dispatcher) is documented intls-override.tsand accepted as a trade-off — eliminating it would require monkey-patchingglobalThis.fetch, which touches every outbound call in the main process and was deemed disproportionate. See spec §9 for rationale.Test plan
pnpm typecheck— clean across all 10 workspacespnpm test— 1354/1354 desktop, 228/228 shared, 208/208 providers, etc.pnpm lint— only existing-on-main biome version-mismatch info; no errorsapps/desktop/src/main/tls-override.test.ts— 6 tests covering: enabled=false noop, single acquire/release, nested acquire (ref-count), throw-in-fn release, log emission, parallel acquireapps/desktop/src/main/connection-ipc.test.ts— 7 new TLS bypass routing tests (built-in force-disable, non-built-in enable, undefined/false → disable, payload flag enable, non-boolean reject)packages/shared/src/config.test.ts— schema accepts/rejects/round-trips the new fieldKnown out-of-scope items
codesign:apply-commentIPC also callsrunGenerateagainst the active provider; left unwrapped to stay in scope per spec. Recommend a tiny follow-up to apply the same wrapper there for inline-comment edits against bypass-enabled providers.