fix(ai): scope OpenAI Codex credential identity by ChatGPT workspace#6095
Merged
can1357 merged 3 commits intoJul 20, 2026
Merged
Conversation
One ChatGPT email can hold several workspaces (a personal Plus/Pro plan plus Team/Enterprise seats), each with its own workspace-scoped OAuth token and independent limit pools. Codex credentials were deduped by bare email, so logging into the second workspace silently replaced the first, and usage reports from the two pools merged into one row. - capture the workspace (chatgpt_account_id) as orgId at login, with the plan type as its display label; token refreshes never rewrite it - key openai-codex credential identity as email + org via the existing org-scoped machinery; legacy email-keyed rows are claimed in place by the first workspace-scoped login, and workspace-less credentials never clobber workspace-scoped rows - exclude the org-mirroring account base from same-org row claims so two members of one workspace (shared chatgpt_account_id) keep separate rows - partition usage-report dedupe by workspace and require every shared identity dimension to agree when reconciling codex usage blocks Fixes the openai-codex half of can1357#2966 (anthropic half shipped in can1357#5170); also covers the can1357#633 scenario.
Contributor
|
Hi @will-bogusz, thanks for your interest in contributing! This project requires that pull request authors are vouched, and you are not in the list of vouched users. This PR will be closed automatically. See https://github.com/can1357/oh-my-pi/blob/main/CONTRIBUTING.md for more details. |
Drop the codex usage-provider orgId stamp (the provider-neutral report attach path in AuthStorage fetchUsage already stamps metadata.orgId and orgName from an org-carrying credential), drop the test-only fetchImpl seam on refreshOpenAICodexToken plus its dedicated suites in favor of the existing can1357#197/can1357#343/can1357#344 regression pins, and compress commentary to match the surrounding Anthropic patterns.
Restore a curated regression suite for the workspace identity change: same email across workspaces coexists, same-workspace re-login replaces in place, two members of one workspace stay distinct, legacy bare-email rows are claimed by the first workspace-scoped login and never clobbered by workspace-less credentials, and usage reports partition per workspace via the provider-neutral metadata attach path (no codex-specific stamp).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Important
This PR was auto-closed by the vouch bot before the branch advanced, so the diff shown above is frozen at the original commit and is stale. The current, slimmer version lives on the same branch — see the live compare (6 files: ~75-line core diff + a curated regression suite). Vouch request: #6097. The description below matches the current branch.
What
One ChatGPT email can hold several workspaces — a personal Plus/Pro plan plus Team/Enterprise seats, each with its own workspace-scoped OAuth token and independent 5h/weekly limit pools. omp keys
openai-codexcredentials by bare email, so it can only hold one of them at a time. This makes the ChatGPT workspace (chatgpt_account_id) part of the credential identity by routing it through the org-scoped identity machinery that #5170 shipped for Anthropic. It is theopenai-codexhalf of #2966 (the Anthropic half is live and verified there); it also covers the #633 scenario.Why
Logging into the second workspace silently replaces the first — the upsert matches on
email:<same>, so multi-account rotation never sees two accounts and one seat's quota pool is wasted (disabled_cause: "replaced by newer credential").How
oauth/openai-codex.ts: login capturesorgId = chatgpt_account_idandorgName = chatgpt_plan_type(access-token claim,id_tokenfallback) on the returned credentials; refresh deliberately returns no org fields so merge sites preserve the stored value verbatim.auth-storage.ts:openai-codexfolds into the org-composed identity branch (email:<e>|org:<ws>); the codex email short-circuit is removed. Legacy bare-email rows are claimed one-way by the first org-scoped login, mirroring the Anthropic migration. Report-to-credential block reconciliation is tightened so every identity dimension present on both sides must agree — the workspace id is shared by every member, so a single-dimension match can cross-link siblings.accountIdandorgId) carries no per-user identity and is excluded from replacement claims, so one member's login can never re-key another member's same-org row. Provably inert for Anthropic (account UUID ≠ org UUID).AuthStoragealready copiesorgId/orgNamefrom the fetching credential onto the report, and the org-partitioned dedupe branch now covers both providers.Verification
All existing identity/dedupe/usage regression suites green, including every openai-codex collapses distinct emails that share account_id in auth dedupe and /usage #197/fix auth-storage identity regression for Codex and Anthropic OAuth dedupe #343/fix(ai): restore email-first identity matching for Codex and Anthropic #344 pin unchanged (org-less fixtures resolve to byte-identical keys — legacy stores don't re-key until a new login): 152 tests across the 7 ai suites, 36 more across the coding-agent blast radius.
New regression suite (
auth-storage-codex-workspace-identity.test.ts) pins the workspace-identity invariants: same email + different workspace coexists, same-workspace re-login replaces in place, two members of one workspace stay distinct, legacy bare-email rows are claimed by the first workspace-scoped login and never clobbered by workspace-less credentials, and usage reports partition per workspace through the provider-neutral metadata attach path (no codex-specific stamp).bun checkfully clean.Live two-workspace E2E against the real backend (sandboxed agent dir, browser OAuth, one email holding a personal Pro plan and a Team seat): both logins produced coexisting rows keyed
email:<e>|org:<ws>withorgIdbyte-identical to each token'schatgpt_account_idandorgNamefromchatgpt_plan_type("pro"/"team"), andomp usagereports both accounts with independent pools: