Skip to content

fix(codex): remove raw-token account import - #1560

Merged
Wibias merged 1 commit into
lidge-jun:devfrom
luvs01:agent/fix-manual-codex-import-identity
Aug 12, 2026
Merged

fix(codex): remove raw-token account import#1560
Wibias merged 1 commit into
lidge-jun:devfrom
luvs01:agent/fix-manual-codex-import-identity

Conversation

@luvs01

@luvs01 luvs01 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • make POST /api/codex-auth/accounts an always-disabled compatibility endpoint
  • remove the environment-variable escape hatch that accepted caller-provided access tokens, refresh tokens, and account identity metadata
  • reject before reading the request body, contacting an upstream service, or mutating config and credential state
  • keep browser OAuth account creation and account deletion behavior unchanged
  • update the active management API references in all six maintained locales

Root cause and impact

The manual account-import route was disabled by default, but an environment variable could re-enable a raw-token persistence path. That path treated caller-supplied account metadata and refresh credentials as inputs to durable pool state. Fully proving a refresh grant and safely handling refresh-token rotation would require durable reservation and recovery across concurrent imports and storage failures.

Rather than retain a partially trusted escape hatch, this change removes its activation path. Existing callers now consistently receive 403 with code: "manual_import_disabled", including when the legacy environment variable is set. Users can continue adding or reauthenticating Codex pool accounts through the existing browser OAuth flow.

Verification

  • Bun 1.3.14: 7 focused manual-import, OAuth persistence, namespace, and picker regressions passed; 40 assertions
  • Bun 1.4.0-canary.1: the same 7 focused regressions passed; 40 assertions
  • Bun 1.3.14 and Bun 1.4.0-canary.1: bun x tsc --noEmit --pretty false passed
  • Bun 1.3.14 and Bun 1.4.0-canary.1: bun run privacy:scan passed
  • git diff --check passed
  • independent final review found no remaining P0-P3 findings

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, refresh-token rotation, concurrent import, and unsafe defaults.

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • All CI tests are green on my local testing.

  • I pushed my PR to the latest dev commit.

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

Summary by CodeRabbit

  • Documentation
    • Clarified that manual Codex account import is disabled and the POST endpoint always returns 403 manual_import_disabled.
    • Documented deletion status details, including catalogRefreshPending and invalid-input responses.
    • Updated credential failure guidance to use the OAuth login-status error flow.
  • Bug Fixes
    • Removed the legacy opt-in path for manual account imports; related requests are consistently rejected without changing account state.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3cc2220c-a500-4a74-b73e-b28f07a23647

📥 Commits

Reviewing files that changed from the base of the PR and between cfc61c1 and e6c45d1.

📒 Files selected for processing (8)
  • docs-site/src/content/docs/ja/reference/management-api.md
  • docs-site/src/content/docs/ko/reference/management-api.md
  • docs-site/src/content/docs/reference/management-api.md
  • docs-site/src/content/docs/ru/reference/management-api.md
  • docs-site/src/content/docs/zh-cn/reference/management-api.md
  • docs-site/src/content/docs/zh-tw/reference/management-api.md
  • src/codex/auth-api.ts
  • tests/codex-auth-api.test.ts

📝 Walkthrough

Walkthrough

The PR disables manual Codex account import, removes its legacy implementation, updates OAuth lifecycle tests, and revises management API documentation across six locales.

Changes

Codex account import lifecycle

Layer / File(s) Summary
Disable manual import endpoint
src/codex/auth-api.ts
The account creation endpoint always returns 403 manual_import_disabled. The legacy opt-in, JWT decoding, and manual credential import flow are removed.
Update OAuth lifecycle coverage
tests/codex-auth-api.test.ts
Tests verify disabled opt-in behavior, OAuth account recovery, validation failure handling, catalog convergence, and namespace ownership.
Synchronize management API documentation
docs-site/src/content/docs/*/reference/management-api.md
Documentation states that POST is a disabled compatibility endpoint, DELETE may return catalogRefreshPending, and credential errors are reported through OAuth login-status.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: chrisae9

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies the main change: removing raw-token Codex account import.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the intake: hygiene-blocked Deterministic PR hygiene checks failed label Aug 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Deterministic hygiene checks failed.

  • unsponsored_surface — This changes an authentication, workflow, release-automation, or dependency surface. MAINTAINERS.md requires security review for these; ask a maintainer to apply maintainer-sponsored once they have reviewed it. Paths: src/codex/auth-api.ts.

@github-actions github-actions Bot added the bug Something isn't working label Aug 12, 2026
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

✅ READY

  • all PR quality gates passed; the review readiness checklist is complete.

Review readiness checklist

  • ✅ All CI tests are green on my local testing.
  • ✅ I pushed my PR to the latest dev commit.
  • ✅ I resolved all correct Codex and CodeRabbit findings.
  • ✅ My PR is ready for review.

4/4 boxes ticked.

This pull request is already Ready for Review.
The review-ready label marks this PR as ready; review automation runs independently. If no CodeRabbit review appears, comment @coderabbitai review to request one.
Maintainers: @lidge-jun @Ingwannu @Wibias

luvs01 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Exact-head implementation and focused dual-Bun verification are complete. This intentionally remains a draft because src/codex/auth-api.ts requires maintainer security review; after reviewing the authentication-boundary change, please apply maintainer-sponsored if appropriate.

@coderabbitai coderabbitai Bot added the maintainer-sponsored Maintainer sponsors this change to an auth, workflow, release, or dependency surface label Aug 12, 2026
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="lidge-jun/opencodex"
pr="1560"

echo "== PR metadata =="
gh pr view "$pr" --repo "$repo" --json number,title,state,isDraft,author,labels,baseRefName,headRefName,url

echo "== Changed files =="
gh pr view "$pr" --repo "$repo" --json files --jq '.files[] | "\(.path)\t+\(.additions) -\(.deletions)"'

echo "== PR diff: auth API and tests/docs =="
gh pr diff "$pr" --repo "$repo" -- \
  src/codex/auth-api.ts \
  | sed -n '1,900p'

echo "== Source outline =="
ast-grep outline src/codex/auth-api.ts --items all --type function --match 'codex|account|import|route|register' || true

echo "== Endpoint and legacy escape-hatch references =="
rg -n -i -C 4 \
  'manual_import_disabled|manual.?import|raw.?token|access.?token|refresh.?token|CODEX.*IMPORT|import.*account|codex-auth/accounts' \
  src test tests docs README.md 2>/dev/null || true

echo "== PR labels and author association =="
gh api "repos/$repo/pulls/$pr" \
  --jq '{author: .user.login, author_association: .author_association, labels: [.labels[].name], draft: .draft}'

Length of output: 2513


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="lidge-jun/opencodex"
pr="1560"
files_json="$(mktemp)"
trap 'rm -f "$files_json"' EXIT

gh api --paginate "repos/$repo/pulls/$pr/files?per_page=100" > "$files_json"

echo "== Patches: implementation and tests =="
jq -r '
  .[] |
  select(.filename == "src/codex/auth-api.ts" or .filename == "tests/codex-auth-api.test.ts") |
  "===== \(.filename) =====\n\(.patch // "[patch unavailable]")"
' "$files_json"

echo "== Changed documentation patches =="
jq -r '
  .[] |
  select(.filename | endswith("/reference/management-api.md")) |
  "===== \(.filename) =====\n\(.patch // "[patch unavailable]")"
' "$files_json"

echo "== auth-api structure =="
ast-grep outline src/codex/auth-api.ts --items all --view expanded | sed -n '1,360p'

echo "== Endpoint registration and rejection response in checked-out source =="
rg -n -C 12 \
  'codex-auth/accounts|manual_import_disabled|MANUAL.*IMPORT|manual.*import' \
  src/codex/auth-api.ts tests/codex-auth-api.test.ts

echo "== All legacy activation / raw-token input references =="
rg -n -i -C 5 \
  'ENABLE.*MANUAL|MANUAL.*IMPORT|manual.?import|raw.?token|refreshToken|accessToken|accountId' \
  src tests docs-site 2>/dev/null || true

echo "== Relevant changed hunks against dev =="
base="$(git merge-base HEAD origin/dev 2>/dev/null || git merge-base HEAD dev)"
git diff --unified=80 "$base"...HEAD -- src/codex/auth-api.ts tests/codex-auth-api.test.ts \
  | sed -n '1,1600p'

Length of output: 202031


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="lidge-jun/opencodex"
pr="1560"

echo "== Focused implementation lines =="
nl -ba src/codex/auth-api.ts | sed -n '360,390p;1348,1382p'

echo "== Focused regression tests =="
rg -n -i -C 20 \
  'manual_import_disabled|manual import|import disabled|codex-auth/accounts.*POST|ENABLE.*MANUAL|request body|req\.json|warmCodexAccount|saveCodexAccountCredential|saveRuntimeConfig' \
  tests/codex-auth-api.test.ts

echo "== Manual-import diff lines only =="
gh api "repos/$repo/pulls/$pr/files?per_page=100" --paginate \
  --jq '.[] | select(.filename == "src/codex/auth-api.ts" or .filename == "tests/codex-auth-api.test.ts") | .patch' \
  | rg -n -C 16 \
    'manual_import_disabled|MANUAL.*IMPORT|manual.?import|codex-auth/accounts|saveCodexAccountCredential|warmCodexAccount|req\.json|refreshToken|accessToken' \
  || true

echo "== Remaining activation and endpoint definitions in TypeScript =="
rg -n -i -C 4 \
  'ENABLE.*MANUAL|MANUAL.*IMPORT|manual.?import|/api/codex-auth/accounts' \
  --glob '*.ts' \
  --glob '!src/codex/data/**' \
  .

echo "== PR commits and author repository permission =="
gh pr view "$pr" --repo "$repo" --json commits --jq '.commits[] | "\(.oid) \(.messageHeadline)"'
gh api "repos/$repo/collaborators/luvs01/permission" --jq '{user: "luvs01", permission: .permission, role_name: .role_name}' || true

echo "== Existing repository label =="
gh api "repos/$repo/labels/maintainer-sponsored" --jq '{name: .name, description: .description, color: .color}' || true

Length of output: 1904


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="lidge-jun/opencodex"
pr="1560"

echo "== Focused implementation lines =="
awk 'NR >= 360 && NR <= 390 { printf "%6d  %s\n", NR, $0 } NR >= 1348 && NR <= 1382 { printf "%6d  %s\n", NR, $0 }' \
  src/codex/auth-api.ts

echo "== Focused regression tests =="
rg -n -i -C 16 \
  'manual_import_disabled|manual import|import disabled|codex-auth/accounts.*POST|ENABLE.*MANUAL|request body|req\.json|warmCodexAccount|saveCodexAccountCredential|saveRuntimeConfig' \
  tests/codex-auth-api.test.ts

echo "== Manual-import diff lines only =="
gh api "repos/$repo/pulls/$pr/files?per_page=100" --paginate \
  --jq '.[] | select(.filename == "src/codex/auth-api.ts" or .filename == "tests/codex-auth-api.test.ts") | .patch' \
  | rg -n -C 12 \
    'manual_import_disabled|MANUAL.*IMPORT|manual.?import|codex-auth/accounts|saveCodexAccountCredential|warmCodexAccount|req\.json|refreshToken|accessToken' \
  || true

echo "== Remaining activation and endpoint definitions in TypeScript =="
rg -n -i -C 4 \
  'ENABLE.*MANUAL|MANUAL.*IMPORT|manual.?import|/api/codex-auth/accounts' \
  --glob '*.ts' \
  --glob '!src/codex/data/**' \
  .

echo "== PR commits and author repository permission =="
gh pr view "$pr" --repo "$repo" --json commits --jq '.commits[] | "\(.oid) \(.messageHeadline)"'
gh api "repos/$repo/collaborators/luvs01/permission" --jq '{user: "luvs01", permission: .permission, role_name: .role_name}' || true

echo "== Existing repository label =="
gh api "repos/$repo/labels/maintainer-sponsored" --jq '{name: .name, description: .description, color: .color}' || true

Length of output: 199892


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="lidge-jun/opencodex"
pr="1560"

gh api --method POST "repos/$repo/issues/$pr/labels" \
  -f 'labels[]=maintainer-sponsored' \
  --jq '.[] | .name' | sort

echo "== Final PR labels =="
gh pr view "$pr" --repo "$repo" --json labels --jq '.labels[].name' | sort

Length of output: 554


@luvs01 Review complete. No blocking findings.

src/codex/auth-api.ts at Lines 1365-1367 now rejects every POST /api/codex-auth/accounts request with 403 and code: "manual_import_disabled" before it reads the request body. The removed path also eliminates the legacy environment-variable gate and the caller-provided access-token, refresh-token, identity, upstream warmup, and persistence flow.

tests/codex-auth-api.test.ts at Lines 999-1033 verifies that the legacy opt-in cannot re-enable the endpoint, malformed JSON still receives 403, no upstream request occurs, config state remains unchanged, and no credential is written.

I applied and verified the maintainer-sponsored label. I did not execute tests in this sandbox. The reviewed focused regressions provide coverage for the changed security boundary.


🧠 Learnings used
Learnt from: chrisae9
Repo: lidge-jun/opencodex PR: 1019
File: src/codex/auth-api.ts:1316-1318
Timestamp: 2026-08-04T19:46:02.271Z
Learning: In the TypeScript Codex account lifecycle, `deleteCodexAccount` tombstones credentials before `saveRuntimeConfig` persists the configuration. This cross-file commit gap predates PR `#1019`. Do not propose a simple compensating credential restore: it can corrupt credential generation and validation metadata. A safe fix requires staged deletion or durable multi-file recovery.

Learnt from: Wibias
Repo: lidge-jun/opencodex PR: 878
File: src/providers/quota.ts:111-135
Timestamp: 2026-08-03T17:05:39.608Z
Learning: In `src/codex/auth-api.ts`, `listCodexAuthAccounts(config, false)` is cache-backed but can perform upstream WHAM quota requests when the main-account cache exceeds `MAIN_CACHE_TTL` or a pool-account quota exceeds `POOL_CACHE_TTL`. It is not a guaranteed non-I/O snapshot API.
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions github-actions Bot added review-ready and removed intake: hygiene-blocked Deterministic PR hygiene checks failed labels Aug 12, 2026
@github-actions
github-actions Bot marked this pull request as ready for review August 12, 2026 20:52
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@github-actions[bot] Acknowledged. PR #1560 is marked ready for review. The readiness checklist is complete.


🧠 Learnings used
Learnt from: Wibias
Repo: lidge-jun/opencodex PR: 878
File: src/providers/quota.ts:111-135
Timestamp: 2026-08-03T17:05:39.608Z
Learning: In `src/codex/auth-api.ts`, `listCodexAuthAccounts(config, false)` is cache-backed but can perform upstream WHAM quota requests when the main-account cache exceeds `MAIN_CACHE_TTL` or a pool-account quota exceeds `POOL_CACHE_TTL`. It is not a guaranteed non-I/O snapshot API.

You are interacting with an AI system.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@github-actions[bot] Acknowledged. Pull request #1560 is ready for maintainer review.

You are interacting with an AI system.

@Wibias
Wibias merged commit ac58e0e into lidge-jun:dev Aug 12, 2026
31 of 34 checks passed

Wibias commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Thanks @luvs01 — merged. 🙏

This is a genuinely useful hardening change: it removes the last opt-in path that could persist caller-supplied Codex access/refresh credentials and identity metadata, so account creation now has one clear trust boundary through the existing OAuth flow. That reduces the risk of mismatched account identity, unsafe refresh-token handling, and partially trusted durable pool state, while keeping the supported add/reauth workflow intact.

The focused regressions and docs updates across all maintained locales made this especially easy to review with confidence. Cross-platform CI and React Doctor are green, and the final security review found no remaining P0–P3 issues. Thank you for the careful contribution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working maintainer-sponsored Maintainer sponsors this change to an auth, workflow, release, or dependency surface review-ready

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants