7.4 KiB
P7-09 — OAuth callback sender repair
This independently bounded prerequisite protects both existing OAuth-message consumers before Connections presentation. It changes client callback admission only; existing provider credentials, server state exchange, owner checks and routes remain authoritative.
Confirmed contract and finding
EmailProviderConnections handles Gmail/Microsoft in /settings/connected-accounts; Correspondence handles Gmail in Job → Timeline. Both currently accept matching payload discriminators without checking MessageEvent.origin or its source window. A forged success can cause status reads/toasts and, in correspondence, candidate reads. The existing three Connections and six correspondence-import cases do not exercise popup correlation.
The expected callback origin comes from the authenticated connect response's redirect_uri, which the controllers build from App:PublicBaseUrl. It is not necessarily the Axios API origin or the Google/Microsoft authorization host. Documented development uses public/UI localhost:3000 and API localhost:5202; production proxies /api on the public origin. Native UI3300/API5302 with default public origin3000 does not qualify real OAuth.
Bounded repair and evidence requirements
Validate the callback HTTP(S) origin, absence of URL credentials and exact provider callback path. Bind each pending provider flow to the actual returned popup window, origin and provider discriminator. Accept only supported terminal connected / error payloads and a valid optional message; consume once before toast/read effects. Ignore unsolicited/wrong-origin/wrong-window/null-source/malformed/duplicate/disposed callbacks. Keep pending correlation through locale changes, invalidate stale job context and late unmounted connect responses, and prevent overlapping starts against a reused named popup.
The callback posts its message and immediately closes; receiving it must not require popup.closed === false. Preserve existing popup names/features, backend one-use owner-bound state and its 15-minute expiry. No frontend nonce, server protocol change, new route or provider activation belongs here.
Add ordinary rendered-caller REDs before the fix, preserving all nine existing consumer cases. Prove valid Gmail/Microsoft/error paths, strict sender/payload/duplicate rejection, canonical-origin compatibility, blocked popup, disposal/job context and current-language feedback. Real local child-window fixtures can verify browser origin/source behavior, but controlled connect URLs/HTML/messages are client-guard evidence, not a real provider connection. Canonical status must remain server-owned; no grant or connected status is fabricated.
Executed repair history
The fresh entry is frontend 23/3 and unchanged-binary backend 40/40 PASS, as recorded by the checkpoint. The first ordinary caller regression run is 23 passing / 12 failing, followed by 35/3 PASS after the sender repair. No missing helper, compilation failure, skip or expected failure is used as security regression proof. The helper validates the authenticated response's callback URL and both callers bind messages to the pending provider, callback origin and captured popup proxy. Terminal messages consume that pending attempt once; disposal and changed job context invalidate it.
| Attempt | Actual result and disposition |
|---|---|
| First browser TypeScript gate | Three required-window-property cast errors; fixed only the fixture's window type intersection. No build or native execution occurred in that failed batch. Raw capsule .artifacts/phase7/p7-09/oauth-browser-types-failed/results.json |
| First built native attempt | 2 PASS / 1 FAIL: the initial Microsoft failure alert locator also selected Next's empty route announcer. Corrected only the locator; actual HTTP500 and all sender assertions retained. Raw capsule .artifacts/phase7/p7-09/oauth-native-attempt1/results.json |
| Corrected native attempt | 2 PASS / 1 FAIL: held connect GET, actual account-language PUT204 to Bokmål, then blocked popup still produced the starting English fallback. This is a demonstrated product defect. Raw capsule .artifacts/phase7/p7-09/oauth-native-startup-red/results.json |
These native attempts used build 7a02hqPN6YYeJA93z8hZP. Their two passing cases prove actual local child-window origin/proxy isolation and stale-job callback rejection; the third failed before completing its remaining assertions. No three-case acceptance is inferred from those attempts.
Final bounded result
The startup-language reproducer is 35 PASS / 4 FAIL, followed by 39/3 PASS with a current-translation reference used only after delayed startup resolution/rejection. Fresh parent 39/3 PASS, app/browser TypeScript, lint and production build all pass. Final build j_uwah2_BImymFemE3cLg executes sender 3/3, existing Application sections 5/5 and ordinary P2-D01 1/1, with zero skips, expected failures or flaky outcomes. The independent read-only review found no actionable introduced defect. The portable result identifies every raw command, failed attempt and frozen source/runtime capsule.
All 23 finite inputs match between 02:20:39.070048 and 08:24:50.986374 UTC. Final commands executed 02:20–02:23 UTC; the later collection resumed after the conversation interruption and is not a new runtime run. API/test DLL hashes match the existing backend40-case entry; no backend rebuild or test addition is inferred.
Seven of76 retained final PNGs were actually displayed and reviewed, covering Connections and representative EN/NB/light/dark/mobile/768px consumers. The P2-D01 image catches an existing dialog transition; its successful archive/readback test is not a settled visual or PDF fidelity claim. Eight consumer axe scans retain 0 violations / 89 incompletes: eight short badges,15 overlapped form backgrounds,20 partly obscured labels and46 aria-label attributes on roleless spans. Full contexts remain raw; the46 span diagnostics are carried to the responsible P7-11 owners. No new sender axe scan or human/device/zoom acceptance is claimed.
The 16 new ordinary frontend cases / zero suites derive 807/95; three new browser cases derive 326; backend stays 1054. These are inventories, not fresh integrated passes. All57 groups stay56 PARTIAL/C11 DEFERRED and33 routes remain. Final staged hygiene PASS at08:27:17 UTC: secret and all whitespace gates,25 docs/583 links,57 groups/33 routes. Normal commit/publication follows this gate. Bounded repair: CONDITIONAL GO; both P7-09 presentation boundaries remain pending.
Actual OAuth grants, provider interoperability and production qualification remain open. Local callback HTML and connect URLs are explicitly controlled client-guard fixtures, and canonical server status remains disconnected. No mailbox, inference, send or grant is contacted. P5-13/worker/model withholding and production NO-GO remain unchanged.
Normal publication dac29278db3c187349b97771ca2f383c9e6e0962 is directly verified at 2026-10-17T08:27:48.643285 UTC: clean HEAD=origin=live development, local/origin/live main27657f3 unchanged. This observed receipt supersedes the preceding pending-publication observation. Preferences and Connections now proceeds; no production or Phase8 authorization follows.