Skip to content

fix(atlas): signing out actually disconnects — clear synced credentials, env, and queued usage#81

Merged
Aayam Bansal (aayambansal) merged 1 commit into
mainfrom
fix/logout-credential-cleanup
Jul 5, 2026
Merged

fix(atlas): signing out actually disconnects — clear synced credentials, env, and queued usage#81
Aayam Bansal (aayambansal) merged 1 commit into
mainfrom
fix/logout-credential-cleanup

Conversation

@aayambansal

Copy link
Copy Markdown
Member

Fixes #56

Problem

clearSession() only unlinked the session file. Everything else the sync path created stayed live after sign-out:

  • synced-env.json kept replaying the still-valid thk_ key into process.env on every boot (preload-env.ts), so the billing gate kept classifying calls as managed and routing them through the Atlas proxy — the signed-out account's wallet kept getting debited.
  • openscience-synced.json (model lockdown config) stayed in place.
  • The api_key seeded into the bundled atlas-cli's default profile stayed authenticated.
  • Env vars already injected into the running process (syncedSecretValues) were never unset — and the map only ever grew, so a provider disconnected or a key rotated on the dashboard stayed live in the CLI indefinitely and was re-persisted on every sync.
  • Queued usage rows (usage-queue.jsonl) survived logout; flushPendingUsage would bill them to whichever account logged in next.

Fix

clearSession() (covers explicit logout and the 401-triggered clear; all steps best-effort, never throw):

  • deletes synced-env.json and openscience-synced.json
  • unsets every synced env var — union of the in-process map and the on-disk snapshot (a fresh connect logout process only has the latter, replayed by preload) — but only when the live value still matches what sync injected, so an explicit shell export survives
  • clears the map
  • removes the seeded api_key from the atlas-cli default profile (ATLAS_CLI_CONFIG_PATH respected); only when it matches the session key, or with no readable session, when the profile points at our backend — a hand-configured profile is left alone
  • drops the pending usage queue with a log line, so stale rows can never bill a different account

syncServices() now rebuilds the synced snapshot from the current response only: previously-synced vars absent from the new response are unset (same live-value-match rule), mirroring the ownedKeys cleanup in server/routes/settings/credentials.ts, and synced-env.json is written from the fresh set instead of the accumulated map.

Server-side revocation on logout: both the /account/logout route and openscience connect logout now best-effort revoke this device's key before clearing. Note: the session stores only the raw api_key, never its key_id, so there is no direct way to name the current device's key. The device is identified by a unique key_prefix match against listDevices() (prefix longer than thk_, exactly one match required); when zero or several devices match, revocation is skipped rather than guessed, and the CLI prints a pointer to the dashboard Devices tab. Local cleanup runs regardless.

Tests

New test/openscience-logout.test.ts (isolated XDG dirs via the test preload, real files, no mocks):

  • after clearSession(): session file, synced-env.json, openscience-synced.json, and the usage queue are gone; a previously-injected env var is out of process.env; a shell export with a different value survives; the seeded atlas profile loses its api_key while other profiles/fields are untouched
  • with no session, the seeded profile is still cleared by backend base_url match
  • a hand-configured atlas profile (different key + backend) is left alone

cd backend/cli && bun test — 833 pass. bun run typecheck clean (all workspaces, via pre-push hook).

…ls, env, and queued usage

clearSession() only unlinked the session file, so signing out left every
managed credential live: synced-env.json kept replaying thk_ keys into
process.env on every boot, the seeded atlas-cli profile stayed
authenticated, injected env vars survived in the running process, and
queued usage rows could be flushed against whichever account logged in
next.

- clearSession now removes synced-env.json, openscience-synced.json,
  every env var the sync path injected (only when the live value still
  matches, so shell exports survive), the api_key it seeded into the
  atlas-cli default profile, and the pending usage queue. Applies to
  explicit logout and the 401-triggered clear alike; all best-effort.
- syncServices rebuilds the synced env from the current response only,
  unsetting previously-synced vars absent from it (provider disconnected
  or key rotated on the dashboard), mirroring the ownedKeys cleanup in
  settings/credentials.ts. The persisted snapshot is written from the
  fresh set instead of the ever-growing accumulated map.
- Both logout paths (server route and `connect logout`) best-effort
  revoke this device's key server-side before clearing, identified by a
  unique key_prefix match against the devices list.
- Queued usage is dropped on sign-out with a log line so it can never
  bill a different account.

Fixes #56
@vercel

vercel Bot commented Jul 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
openscience Ready Ready Preview, Comment Jul 5, 2026 11:41am

Request Review

@aayambansal Aayam Bansal (aayambansal) merged commit 1e0e245 into main Jul 5, 2026
11 checks passed
@aayambansal Aayam Bansal (aayambansal) deleted the fix/logout-credential-cleanup branch July 5, 2026 11:44
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.

Logout leaves synced credentials active: signed-out wallets keep getting billed and queued usage can bill the wrong account

1 participant