Repository navigation
fix(mitm): serve and trust the active AgentBridge cert in root-CA mode - #16643
Merged
Merged
Conversation
GET /api/tools/agent-bridge/cert/download always streamed the legacy <DATA_DIR>/mitm/server.crt. Under the root-CA model (fresh installs, or MITM_ROOT_CA_ENABLED=true) the MITM server signs per-host leaves with ca.crt, so the file users downloaded (including via the #4546 manual-install guide, which links this endpoint) could never make interception work. The sibling GET/POST/DELETE /api/tools/agent-bridge/cert had the same hard-coded path: status reported no cert, trust returned 404, and untrust silently no-oped while the root CA stayed trusted. Both routes now resolve the file through resolveActiveMitmCert(), a thin wrapper over the existing resolveActiveCertPath() that reads MITM_ROOT_CA_ENABLED the same way manager.ts and the state/diagnose/server routes do. The download filename is mode-specific (omniroute-mitm-ca.crt vs omniroute-mitm.crt), and the not-found message in root-CA mode now says to start the bridge (the only path that mints the CA) instead of pointing at cert/regenerate, which mints a legacy leaf. The integration fixture that wrote a lone server.crt now writes the server.crt + server.key pair, which is what decideCertMigration() treats as a legacy install.
Contributor
CI Coverage Report
Coverage artifact was not available for this run. |
diegosouzapw
added a commit
that referenced
this pull request
Oct 15, 2026
… regenerate mode-aware (#16712) * fix(mitm): use the active cert in settings/mitm and repair; make cert regenerate mode-aware Follow-up to #16643. The remaining consumers still hard-coded the legacy <DATA_DIR>/mitm/server.crt: - /api/settings/mitm: ?download=cert streamed server.crt and the certExists fallback checked it. Both now resolve the active cert through resolveActiveMitmCert() (ca.crt under the root-CA model, server.crt on a legacy-leaf install), with the mode-specific filename and 404 message. - src/mitm/repair.ts: the untrust step only looked at server.crt, so under the root-CA model repair left the CA trusted. The repair plan now carries certPathsToUntrust: the active cert first, plus a leftover legacy leaf. Legacy installs still untrust exactly server.crt. - "Regenerate cert" (POST /api/tools/agent-bridge/cert/regenerate, the dashboard's server action, and POST /api/settings/mitm) always minted a legacy leaf: it never rotated ca.crt and turned a fresh install into a legacy one. The three entry points now share regenerateActiveMitmCert(), which never changes the cert model. Legacy installs get a new leaf as before. Root-CA installs get a rotated CA, refused while the server runs because it loads the CA once at start. A trusted old CA is untrusted first, and the rotation is aborted if that fails. The response says the new CA must be trusted again. rotateMitmCa() writes the new pair through temp files so a failure never leaves the dir without a CA pair. AGENTBRIDGE.md §3.1/§7 now describe the real behavior. * docs(changelog): add fragment for #16712
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
GET /api/tools/agent-bridge/cert/downloadalways streamed<DATA_DIR>/mitm/server.crt. But the cert the MITM server actually uses depends on the cert model (src/mitm/cert/migration.ts::decideCertMigration): under the root-CA model (fresh installs, orMITM_ROOT_CA_ENABLED=true) it signs per-host leaves withca.crt. So in root-CA mode users downloaded the wrong file, and trusting it never made interception work. This also broke the #4546 container/headless fallback, becausebuildCertManualGuide()sends users to this exact endpoint.The sibling
GET/POST/DELETE /api/tools/agent-bridge/certhard-coded the same path:exists:falseon a root-CA install{ok:true, trusted:false}while the root CA stayed trustedThe
state,diagnoseandserver(trust-cert) routes were already moved toresolveActiveCertPath()in #14070. These two routes were missed.Fix
src/mitm/cert/activeCert.ts: addsresolveActiveMitmCert(), a thin wrapper over the existingresolveActiveCertPath()that readsMITM_ROOT_CA_ENABLEDthe same waymanager.tsand the other routes do. No mode logic is duplicated. It also adds two small helpers that pick the filename and the not-found message for each mode.omniroute-mitm-ca.crtfor root-CA,omniroute-mitm.crtfor a legacy leaf. In root-CA mode the 404 message now tells you to start the bridge, which is the only path that mints the CA. It used to point atcert/regenerate, but that mints a legacy leaf and would not fix a root-CA install.installCaCert()in root-CA mode, the same as theserverroute'strust-certaction.createErrorResponse(no rawerr.message).Tests (TDD)
New
tests/unit/agent-bridge-cert-download-active-ca.test.ts(8 cases). Each case uses a temp DATA_DIR with fakeca.crt/ca.key/server.crt/server.keyand setsMITM_ROOT_CA_ENABLEDper case.tests/integration/agent-bridge-cert-flow.test.ts: the fixture wrote a loneserver.crtwith no key.decideCertMigration()does not treat that as a legacy install (it needs theserver.crt+server.keypair), so the fixture now writes the pair. That brings it in line with what the code actually does; no asserts were changed.Related suites (cert routes, trust mismatch #14070, install fallback #4546, sudo gate, removal wiring, regenerate #10467, root-CA persistence #6684, system-trust guard, error sanitization, routeGuard, maintenance API, state payload,
build/mitm-server-bundle-contents): 122/122 pass.Validation
check-complexity-ratchets --base-ref <merge-base>: OK (0 new violations)check:file-size: the only violations are 4 inherited base overages in files this PR doesn't touch (responseSanitizer.ts,open-sse/utils/error.ts, 2 test files)tsc --noEmit -p tsconfig.json: no errors in the touched filesLeft out of scope (same class, follow-ups)
src/app/api/settings/mitm/route.ts: the?download=certandcertExistsfallback still readserver.crt. Itsregenerate-certaction deletesserver.crt/server.keythrough the samegetCertPath(), so this needs its own change.src/mitm/repair.tsstep 2: the repair untrust still gates onserver.crt.POST /api/tools/agent-bridge/cert/regeneratealways mints a legacy leaf. On a fresh install with the flag off, that flips the install to the legacy model. In root-CA mode it doesn't touch the active CA. Rotating the CA is a product decision.docs/frameworks/AGENTBRIDGE.md§3.1: the "Regenerate Cert — Creates a new CA keypair" row is wrong (regenerate mints a legacy leaf). The "Download Cert — Downloadsca.crt" row is now correct for the default root-CA model.