oficina / meet Public

feat/home-consumer: connect 01166fc, sign-out chain, All apps open

On branch feat/home-consumer

Preparation for switching Calls to Oficina sign-in (Paul, 2026-09-30: "Definitely switch to Oficina sign-in"). Plan: oficina/polish-audit/SSO-SWITCH.md.

Why: Calls pins amadan.net/oficina/home/connect at 5b8d841 (2026-09-10). That is before 01166fc, which added the sign-out chain to id.*, the signed-in /signin shortcut and Credentials.Directory.

What changed:

  • connect is bumped to 01166fc. The bump is additive.
  • Viewer.Directory is set only in Home mode. The layout's account corner shows "All apps", linking to {directory}/. The room's own menu (room.html) is unchanged.
  • callscore.SignOut now accepts 307 as well as 303. It is the native apps' best-effort sign-out, and it never follows redirects. In Home mode the server ends the session and then 307s to the issuer, so the old check would have reported "Calls did not confirm the sign-out". The Mac and iPhone apps pick this up only when they are next rebuilt. Until then the error is best-effort only, because the session row is already gone.

Tests: these failed first and pass now:

  • TestHomeSignoutChainsToIssuer (was 303 to /signed-out)
  • TestHomeSigninWhenSignedInReturnsToPage (was /auth/start?...)
  • TestAllAppsLinksToDirectory (no link)
  • TestSignOutAcceptsTheHomeChain ("did not confirm")

home_consumer_test.go configures Home from the environment through connect.CredentialsFromEnv("CALLS"), as cmd/calls does. The existing Home router, release and native tests now expect the chain. GOTOOLCHAIN=go1.26.5 make ci exits 0, and credits were regenerated with no change.

Known, not fixed here:

  • "Connect Home account" appears only on the meetings index page, not in the account menu.
  • /help/open-source, the share page and the native pages send Referrer-Policy: no-referrer. A browser sign-out from them lands on id.*'s "Finish signing out" page, which is recoverable.

Not deployed and not merged. A whole-branch review is needed first.

Added commit: in Home mode, a signed-out page request now carries return_to (homeReturnTo in front of requireParticipant). The local plugin's RequireSession redirected to a bare /signin, so after Home sign-in you landed on the root. TestHomeSigninReturnsToTheExactPage failed first (/settings went to /signin) and passes now. Guests hold a session, so they are unaffected. GOTOOLCHAIN=go1.26.5 make ci exits 0.

Reviewer: Astra (GPT-6-Astra via Codex), whole-branch review requested by Paul, 2026-10-01.

VERDICT: APPROVE-WITH-NITS — feat/home-consumer at 83a18aa4d30240000d9104452025b2616af75ea9, one merge-base diff against fetched main 84ed5dc. No blocking findings.

  1. P3 / non-blocking — internal/calls/home.go:114–119 (activated by the connect bump at go.mod:7): a revoked Home session still takes the signed-in shortcut. After the fixture links a local member to Home, signs in and removes admission, /signin redirects to /, which terminates at 404. /settings also refuses; there is no automatic redirect loop or access bypass. The ordinary Sign in URL nevertheless does not start recovery while that session exists; /signin/local remains reachable. Fix: use current resolved/admitted identity for the shortcut, handle storage failures distinctly, and render a terminating recovery/refusal outcome. Add a real-router regression for a live session whose local admission was revoked; preserve the guest/pending-invitation behavior.
  2. P3 / known, non-blocking — internal/calls/credits.go:31, internal/calls/handlers_meetings.go:177, internal/calls/native_auth.go:96: no-referrer pages cannot complete the issuer logout in one hop. When they expose Sign out, the originating page strips the Referer evidence that Home needs after the cross-origin 307. Home safely shows “Finish signing out,” requiring another click. Fix: retain no-referrer on sensitive/outbound links but provide an origin-referrer-safe sign-out surface, or use strict-origin on pages where that reveals no sensitive path. This extra click is explicitly accepted by SSO-SWITCH.md and does not block this branch.

Native 307 safety — callscore/session.go:152–181, callscore/transport.go:71–85: no unexpected redirect navigation. SignOut validates the configured origin, builds only its /signout, posts an empty form body with that Origin, and uses safeClient. safeClient clones the provided client and overrides CheckRedirect with http.ErrUseLastResponse, even if the supplied client normally follows redirects. Therefore an arbitrary Location in the 307 is not fetched and no held credential is forwarded to it. The new two-server test independently asserts that the purported issuer was never contacted. Accepting 307 confirms the app's sign-out response only; it does not claim to revoke the browser's separate id.* session. Native callers already treat sign-out as best effort.

Consumer security: audited connect 5b8d841 → 01166fc and Home main 7a0f19c (signout.go, exchange.go; connect source is identical at those latter two revisions). The first sign-out POST keeps CSRF, the ordinary button has no named payload, and the app clears its local session/handoff cookies before a fixed 307 to the validated issuer. The response has no-store and the required policy; CSP allows the issuer. Home admits registered consumer-origin evidence, checks Fetch Metadata, and chooses only the matching registration's /signed-out, never a supplied destination. It handles missing referrer and cross-site Lax cookies through confirmation. Assertions remain consumer-audience/nonce bound. Opaque Home subjects resolve explicit local-person links with current membership checks, not email matching or auto-creation.

return_to: homeReturnTo wraps the existing participant/session/person guards, changes only signed-out GET/HEAD navigation in Home mode, and encodes RequestURI into the local sign-in query. connect applies handoff.SafePath before use and authenticated storage; no open redirect. Guest sessions retain their existing participant restrictions and are not treated as full sign-ins by connect.

Verification: GOTOOLCHAIN=go1.26.5 CGO_ENABLED=0 TMPDIR=/tmp make ci passed, including credits and migration checks. Hub CI PASS at 83a18aa, CLI exit 0. GOTOOLCHAIN=go1.26.5 CGO_ENABLED=0 TMPDIR=/tmp make browser ran to completion: all JavaScript suites passed and 41/42 Chromium scenarios passed. The speaker scenario failed its saved tile-order check at test/browser/call.mjs:4751 after reload (full run 1095.42s). A focused, uncached repeat through a temporary make target passed on the reviewed branch (42.44s) and separately on detached main 84ed5dc (43.02s). The scenario, room JS and layout assets are unchanged by this branch, and the browser fixture runs standalone. This is a non-reproducing timing-sensitive browser failure, not evidence of a sign-in regression; the full browser command was not green and is not reported as green.

All Calls checks ran through make with the pinned toolchain. Extra scratch router probes passed for hostile/missing-origin and same-site first-hop CSRF rejection without session revocation, unsafe absolute/scheme-relative/encoded-slash/backslash/auth/dot/control return paths, deep-path query preservation, and revoked-user root/signin/deep navigation terminating at 404 with local recovery reachable. Existing unknown-subject/no-auto-create, invited-guest and native router tests ran in the gate. Focused Home sign-out/assertion tests and connect/linkstore tests passed. I did not run the optional real-Home browser SSO stack or change production configuration.

Mutation proof: removed 307 from callscore.SignOut's accepted statuses in scratch. New TestSignOutAcceptsTheHomeChain failed with “Calls did not confirm the sign-out.” Restored source; the same uncached test passed, including its assertion that no redirect target was contacted.

Chrome overlap: fetched feat/r2-shared-chrome is 6d30ba6, explicitly “WIP…untested,” with no branch discussion returned by amadan. It is a sibling of #22, not its descendant. Both touch go.mod/go.sum, render.go and Home/native router tests; read-only merge-tree flags dependency and render.go conflicts. Its newer 7a0f19c connect pseudo-version has identical connect source to 01166fc: keep the newer pin rather than downgrading when reconciling. Land #22 first, then carry its native SignOut change and regression coverage forward. Reconcile its homeReturnTo wrapper with the chrome branch's return flow so there is one active path, and move the directory link into the final chrome without duplication. That unfinished branch needs completion, gates, a discussion and its own whole-branch review.

Order: Docs #73; Calendar #17 → rebased #23; Memoria #20 → #21; Calls #22 before its unfinished chrome branch. The three app sequences are otherwise independent; Paul applies Home registration and app config after code deployment as the switch plan directs.

Review only in detached /tmp worktrees. Mutations restored; no existing checkout moved and no commits, pushes, merges, deployments or config/secret writes. Posted as the agent account under the repository's amadan skill, never -as-human.