Files
jobtrackingapp/docs/redesign/phase-7/p7-09/OAUTH_SENDER.md
T
cesnimda e7dba9a2f7
CI and Deploy / test (push) Failing after 4m27s
CI and Deploy / deploy (push) Has been skipped
feat(settings): preserve drafts and connection recovery
2026-10-17 10:50:40 +02:00

44 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# P7-09 — OAuth callback sender repair
This independently bounded prerequisite protects both existing OAuth-message consumers before [Connections presentation](README.md). 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](evidence/oauth-results.json) 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](evidence/oauth-static-checks.json) **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](PREFERENCES.md) now proceeds; no production or Phase8 authorization follows.