Skip to content

Select a live GitHub session cookie across multiple browser stores#18

Merged
drogers0 merged 2 commits into
mainfrom
fix/15-stale-session-cookie-selection
Jun 3, 2026
Merged

Select a live GitHub session cookie across multiple browser stores#18
drogers0 merged 2 commits into
mainfrom
fix/15-stale-session-cookie-selection

Conversation

@drogers0

@drogers0 drogers0 commented Jun 3, 2026

Copy link
Copy Markdown
Owner

Problem

cookies.GetGitHubSession read every user_session cookie across all browsers/profiles via kooky (filtered only by expiry) and returned cookies[0] — the first in kooky's nondeterministic store-discovery order. When more than one cookie store holds an unexpired user_session (multiple profiles in any browser, multiple browsers installed, or Firefox containers — not Firefox-specific), a stale/logged-out cookie can win. It passes expiry checks but fails on use: the repo page returns no uploadToken; check-token returns 302.

Closes #15.

Change

Selection now:

  1. Gathers all user_session candidates with per-store identity (FilePath() + Container), scoped to host-only github.com.
  2. Prefers candidates whose same store has logged_in=yes (GitHub sets it on login, removes it on logout) — a free, local, browser-agnostic signal that alone fixes the reported scenario.
  3. Validates only to disambiguate: with a single candidate it's used as-is (if dead, the upload fails the same as before — a request buys nothing); with 2+ logged-in candidates it validates against GitHub and takes the first live one. This closes the server-side-revocation gap that logged_in=yes can't catch.

It's a picker, not a gate: if validation is inconclusive (all fail, or offline), it returns the first candidate (by store key) and lets the caller surface the authoritative error. check-token remains the explicit validity gate.

Validation is injected (validate func(*http.Cookie) error) because internal/session imports internal/cookies, so cookies can't import session. extract-token passes nil to stay offline.

Notes

  • --token / GH_SESSION_TOKEN bypass GetGitHubSession entirely and are unaffected.
  • Selection deliberately ignores cookie recency: kooky derives Creation from the SQLite rowid on the Chromium family (a real cookie's creation reads back as the year 2185), so it's a false signal. Candidates are ordered by store key alone — deterministic across kooky's nondeterministic discovery order — and validation, not recency, chooses among multiple live candidates.
  • Out of scope (noted on the issue): a --browser/--profile flag, a multi-account warning, and a clearer logged-out error message.

Tests

Adds internal/cookies/cookies_test.go (the package's first cookie tests) over a pure, kooky-free core — real structs + a stub validator func, no kooky/HTTP mocks. Covers the #15 regression, cross-store correlation guard, subdomain exclusion, logged_in value handling, and the full selectSession decision matrix (single-skips-validation, short-circuit, fall-through, all-dead fallback, determinism). go build/vet, go test -race -cover ./... all pass.

Verified end-to-end against real browser cookies: logged_in is read from a live Chrome store, the per-store correlation works, and check-token resolves + validates the session.

drogers0 added 2 commits June 3, 2026 17:22
GetGitHubSession previously returned kooky's cookies[0] filtered only by
expiry, so with multiple cookie stores (multiple profiles in any browser,
multiple browsers, or Firefox containers) a stale/logged-out user_session
could win — passing expiry checks but failing on use.

Selection now: gather user_session candidates with per-store identity
(FilePath+Container, host-only github.com); prefer stores whose same store
has logged_in=yes; and when more than one logged-in candidate remains,
validate against GitHub and take the first live one (a lone candidate is
used as-is — no point spending a request). It is a picker, not a gate:
if validation is inconclusive it returns the most-recent candidate and lets
the caller surface the authoritative error.

Validation is injected (cookies cannot import session) so extract-token
stays offline by passing nil. Adds the package's first cookie tests over a
pure, kooky-free core.
kooky derives Creation from the SQLite rowid on the Chromium family (a real
cookie's creation reads back as the year 2185), so recency was a false signal
dressed up as meaningful. Selection now orders candidates by store key alone —
deterministic across kooky's nondeterministic discovery order — and relies on
validation, not recency, to choose among multiple live candidates. The actual
#15 fix (the logged_in filter) is unaffected.
@drogers0 drogers0 marked this pull request as ready for review June 3, 2026 23:43
@drogers0 drogers0 merged commit 3ae33a4 into main Jun 3, 2026
1 check passed
@drogers0 drogers0 deleted the fix/15-stale-session-cookie-selection branch June 3, 2026 23:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stale/logged-out session cookie can be selected when multiple cookie stores exist

1 participant