Remove browser-cookie authentication from the CLI

Merged
RO
2d ago
+793-270

Summary

Remove browser-cookie authentication from the CLI. Normal browser OAuth, stored bearer tokens, and HEY_TOKEN remain supported. Cookie-only sign-ins now explain that the person must sign in again, instead of appearing authenticated until a write fails.

Basecamp card

  • Remove --cookie from both login commands, cookie headers, cookie-as-token fallback, and obsolete WebSocket recovery advice.
  • Preserve OAuth refresh/retry/reconnect and token migration. Legacy cookie fields remain inert for useful migration guidance and cleanup; cookie-only legacy config is scrubbed without creating a usable credential. Existing stored records can be replaced by login or removed by logout.
  • Move smoke-test CLI login onto actual browser OAuth/PKCE. Browser checks retain their own browser session; no cookie is passed to the CLI. Consent uses form submission rather than a layout-sensitive coordinate click, and codes/tokens/progress are not printed.
  • Make auth token --stored actually ignore HEY_TOKEN.
  • Update help, docs and the acknowledged breaking command surface. No SDK or server change; the malformed-403 fix from hey-sdk#240 is already in pinned SDK v0.35.0.
  • Update Go to 1.27.4 to fix GO-2026-6859. Development, smoke and Nix compiler pins agree; Nix uses the verified official source while its locked nixpkgs still supplies 1.27.3. No module dependencies or security gates change.

Verification

  • Go 1.27.4: make check and go test -race ./internal/auth ./internal/cable ./internal/cmd pass. govulncheck ./... passes with zero affected vulnerabilities; its existing report of an uncalled module vulnerability is not suppressed.
  • Actual Nix package build with Go 1.27.4: pass, including its tests. The resulting binary reports Go 1.27.4, and evaluation confirms the development shell shares that compiler. Independent review found no actionable findings across the five-file compiler-update delta.
  • New SDK wire tests: 7/7 scenarios; legacy migration: 6/6 scenarios; refresh-only recovery: both token getters, CLI status and actual SDK requests. A 429 hold cannot authenticate an empty access token. Cookie-only authentication counts zero network requests.
  • Actual local Haystack: browser OAuth, status, token output, refresh, logout and re-login pass over HTTP and HTTPS. Final helper passes 20 consecutive HTTPS logout/re-login checks.
  • Opt-in verification smoke tests: a real HTTPS cookie-only write is refused with 403, while CLI OAuth approves/denies/approves the same disposable clearance; browser reads independently reflect each decision. Real hey watch reaches its ready subscription. This is not an end-to-end mail-change/TUI-rendering claim.
  • Isolated combination with Jeremy's open #640 at 8875d21: 38 local-command tests pass (including stored and legacy cookie-only fixtures), plus the local socket-client suite. No CLI sign-in or direct server request is needed. Not tested against the real desktop app; its local door is not available here.
  • Mutation checks: restoring cookie-header authentication fails the wire regression test; breaking refresh-only recovery fails both getter tests; reverting refresh-only status or the 429 hold guard fails the corresponding regression. All four mutations were confined to the separate integration checkout and restored.
  • Independent local review: two initial findings corrected, followed by review of all 29 changed files with no actionable findings. The PR-feedback delta was independently reviewed too; a refresh-only/429 interaction was corrected and re-reviewed with no remaining findings. Two PR review rounds are complete on b53910e: Copilot and Greptile approved; Codex reported no findings; cubic's final-head check reports zero issues in the 8-file delta. All 5 review threads are resolved.

Follow-up live verification / resolved security gate

Full strict live smoke re-run with this head's Go 1.27.4 build: 147/147 top-level tests pass, zero skips (403.9 seconds), including browser OAuth and SMTP capture/read-back. The earlier five baseline failures are resolved by running the required Elasticsearch 8, configured image-processing cell and disposable local-mail fixtures. No assertions are skipped or weakened. Temporary development OAuth registration and its sessions were removed afterward.

The run uses go test -v -count=1 -timeout 10m ./... with strict mode and all SMTP prerequisites. The complete suite exceeds the old five-minute overall deadline; main test-reliability PR #642 corrects that budget and documents the setup (its full strict run also passes 147/147). Haystack bootstrap PR #9325 starts the configured ES8 service, waits for health and stops hiding index-reload errors. Neither follow-up is folded into this auth-only PR.

The earlier Go 1.27.3 Security failure was reproduced on unchanged main. This PR now includes the authorized Go 1.27.4 fix in 6183f56; both local vulnerability scanning and the CI Security check pass without any waiver or gate change. Final-head CI is green: 31 checks pass, 5 are skipped, none fail or remain pending, including Security, race detection, Nix builds and native self-update tests on Linux/macOS/Windows. In the third and final review round, Copilot approved, Codex reported no findings, and cubic reports zero issues across the five-file compiler-update delta. No review threads remain open.

CI race detection initially reported a time.Local race in the unchanged timezone test fixture (original job). One bounded, same-head rerun passed, with no suppression or source change; dependency jobs reran as part of that attempt and reproduced the security failure. Local baseline command tests also passed two race runs. Both CI results remain recorded; this PR does not claim to fix that intermittent fixture race. Its permanent fix is independently reviewed in #642, where all packages pass three shuffled race repetitions and CI race detection passes.

No production mutations, merge, deployment, or release performed. This PR intentionally breaks scripts using --cookie; existing cookie users must sign in again.