oficina / home Public

Keymail sign-in continuation CSP fix open

On branch fix-keymail-oauth-continuation

Confirmed on main6bf0944: detected Keymail sign-in returned external303 after POST, while form-action permits only registered origins. Reuse Home chooser200 continuation with auto meta refresh and fallback link, shared App renderer, no CSP change. Preserve pending cookie and callback/second-factor/freshness flow. Baseline regression fails original303; focused tests pass. Eight synthetic browser cases Chromium/WebKit JS on/off auto/fallback pass, no referrer and pending cookie preserved. Full gate running; review packet pending Fable availability. No live email/OAuth, merge or deploy.

Final9a4dcd71ea852a0cc0843d260f22eb3a0d43f1b4 updates one pre-existing assertion freshness test to expect200 OAuth continuation instead of303; same ordinary/tampered/duplicate/expired intent scenarios retained. Original gate failure saved. All Home package tests pass; full finalgate in race phase (Home/operator race already pass), exact finalCI running. Eight local browser cases remain valid as production code unchanged since fixture. Immutable finalsource/review packet saved /home/paulca/.cache/oficina-home-keymail-continuation. Fable not invoked under current quota instruction; no merge/deploy.

Final9a4dcd71ea852a0cc0843d260f22eb3a0d43f1b4 full make test PASS exit0, including all required race packages; exact finalCI success. Eight local Chromium/WebKit automatic/fallback JS on/off OAuth continuation cases pass with unchanged CSP/no-referrer/pending-cookie preservation. Worktree clean. Immutable source-final.tar, changes-final.diff, review-final-prompt.txt and candidate.json saved /home/paulca/.cache/oficina-home-keymail-continuation. Fable NOT invoked per quota instruction; branch remains unreviewed/unmerged/undeployed. Task48 bounded implementation/validation complete only.

APPROVE — fix-keymail-oauth-continuation, exact SHA 9a4dcd71ea852a0cc0843d260f22eb3a0d43f1b4 (base 6bf094416deebb3f29cbe21f820e2eae10091ab3). Reviewer model: claude-fable-5-1. Read-only; nothing written, run, merged or deployed.

Verified in source-final (matches changes-final.diff line for line)

  • internal/home/signin.go:213 replaces the external 303 with a.renderContinuation(w, next.Redirect, "Continue to Keymail"). Pending cookie is still set first via unchanged setPending. Classifier, callback, takePending, completeSignIn, passkey Gate and session minting are untouched.
  • internal/home/continuation.go sets Cache-Control: no-store and Referrer-Policy: no-referrer then renders the existing docs_continue.html with status 200 through the buffered renderer. docs_chooser.go:155 delegates to it with the fixed "Continue to Docs" label, so chooser destination and copy are unchanged.
  • Template change is title/heading/anchor text only; meta refresh and referrerpolicy="no-referrer" anchor unchanged. SecurityPolicy() untouched; no provider origin added.
  • next.Redirect is signin.Keymail.AuthorizeURL: fixed https:// + DNS-delegated host + /oauth/authorize? + url.Values.Encode(). Same trust boundary the old Location header had; the library README already calls it attacker-influencable and CSRF-gated, and app.go:183 keeps csrf.Protect on POST /signin.
  • No address or destination is logged or persisted by this delta.

Evidence

| Artifact | Result | |---|---| | baseline.log | new test fails on base with 303 (correct control) | | focused.log, home-test-final.log | internal/home ok | | gate-final.log | vet/build/test/race all ok, but carries no SHA marker | | ci-final.json | sha exact match, state: success, all 5 steps (vet, fmt, build, go-test, race) success | | results.json | 8/8 Chromium+WebKit, JS on/off, auto/fallback: arrived, no referer, no CSP errors, pending cookie present | | continuation.json | byte-identical to what renderContinuation + setPending + SecurityPolicy() emit; synthetic provider URL |

Findings (none blocking)

  • Low: docs_continue.html now requires .Title; a future direct render without it fails at execution (500), not at boot. Both callers go through App.renderContinuation, and docs_continue_test.go:92 covers the struct shape.
  • Info: The meta content attribute is HTML-attribute-escaped only, while the anchor gets URL-context escaping. Scheme is fixed and %22%3C survives escaped with no ZgotmplZ (tested), so no new injection surface versus the 303.
  • Info: Back from the provider returns to a page that immediately refreshes forward again. Same usability limit the Docs chooser design records; the browser fixture did not exercise Back for this path.
  • Info: The "CSP broadened" assertion in keymail_continue_test.go:23 compares a deterministic function before and after; the strings.Contains(policy, stub.host) half is the meaningful check.

Scope limits

  • source-final has no .git, so tree-to-SHA binding rests solely on ci-final.json and the frozen tar name. gate-final.log alone does not prove the SHA.
  • Browser evidence is a fixture at the response boundary with synthetic keymail.example.test; no live OAuth, mail, DNS, or real provider tested.
  • I could not write the requested plan file: no Write or ExitPlanMode tool is available in this session, and the deliverable is this verdict.

Preview deployment verified: immutable Home eabd7e1d234ed458b8b68f22ad895adffb5d5292 live on BOTH overnight-home-id.bds.oncarlos.com and overnight-home.bds.oncarlos.com, /api/version response body and X-Carlos-Version exactly match. OAuth9a review approved then mergedd4b; required ARM64 cast/build-gate followup20a Fableapproved/fullgate/exactCI passed, mergedeabd. Reviewed20a and mergedeabd share exact tree8a1c8bd271bdae405d372bc48a2f23b2442e4ac9. Correct cmd/home ARM64 versionstamped binary built from frozenarchive excludeschecker533. Named bds canary/overnight-home deployment only; host+environment scoped restarts after initial watcher timedout old asleep build, then realpageGET woke previews and final versions matched. Unsigned signin/Docs entry verified; no human mail/OAuth and no config/roster/operator activation. Evidence /home/paulca/.cache/oficina-home-keymail-deploy/deployment.json. What to see: detectedKeymail continuation auto-navigation/fallback link under unchanged CSP.