feat(oauth): support importing Google Antigravity accounts from Cockpit Tools JSON (#1076) - #1077
feat(oauth): support importing Google Antigravity accounts from Cockpit Tools JSON (#1076)#1077agentHits wants to merge 4 commits into
Conversation
Review readiness checklistThis PR is kept in draft until every requirement below is fulfilled. The tickable checklist has been added to your PR description — tick all four boxes there.
3/4 boxes ticked. This PR stays in draft until every box above is ticked. |
|
✅ PR quality gates passed This pull request now targets The title was left unchanged. The draft is owned by the checklist message below. |
|
📝 WalkthroughWalkthroughThis PR adds batch OAuth account import support. The API validates and processes account payloads, the CLI accepts file or inline JSON, and the provider workspace provides a Cockpit JSON import form with result reporting and account refresh. ChangesOAuth account import
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant ProviderAuthPanel
participant OAuthAccountRoutes
participant OAuthCredentials
User->>ProviderAuthPanel: Paste account JSON and submit
ProviderAuthPanel->>OAuthAccountRoutes: POST /api/oauth/accounts/import
OAuthAccountRoutes->>OAuthCredentials: Refresh and save credentials
OAuthCredentials-->>OAuthAccountRoutes: Return per-account results
OAuthAccountRoutes-->>ProviderAuthPanel: Return import and failure counts
ProviderAuthPanel-->>User: Display results and refresh accounts
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@gui/src/components/provider-workspace/ProviderAuthPanel.tsx`:
- Around line 292-365: Replace the hardcoded import UI strings in
ProviderAuthPanel, including the JSON placeholder, import result sentence,
“Import JSON”, and “Import JSON (Cockpit)”, with appropriate t(...) lookups. Add
matching translation keys and values to the GUI locale files, preserving
interpolation for imported and failed counts in the result message.
- Around line 287-295: Update the placeholder attribute on the import JSON
textarea in ProviderAuthPanel to use a JSX expression containing a valid
JavaScript string, preserving the example JSON text and its inner quotes.
In `@src/cli/account-extended.ts`:
- Around line 353-410: The cmdImport CLI flow lacks regression coverage for its
argument validation, provider validation, inline and file JSON inputs, API
errors, and JSON output. Add focused Bun/account CLI tests invoking cmdImport
through the account command path, covering invalid argument counts, non-OAuth
providers, successful inline JSON import, successful file-based JSON import,
non-200 API responses, and --json output; assert the relevant return values, API
payloads, and console output while reusing existing test helpers and fixtures.
In `@src/server/management/oauth-account-routes.ts`:
- Around line 395-433: Restrict account import to google-antigravity at both
boundaries: in the account import route around provider validation and the batch
loop, reject any other provider with a clear 400 response before iterating; in
ProviderAuthPanel, render the import action only when item.name is
google-antigravity so the GUI matches the management API behavior.
- Around line 384-392: Update the account-entry handling around the
rawBody/accounts array parsing to preserve every submitted array element instead
of filtering non-record values out. Track totalCount from the original input
array length, emit a failed per-account result for each non-record entry, and
continue normal processing for valid records; add a test covering a mixed
valid-and-invalid batch.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: db59e0f4-ce49-4fec-bb58-ae3cbe1f9932
📒 Files selected for processing (5)
gui/src/components/provider-workspace/ProviderAuthPanel.tsxsrc/cli/account-extended.tssrc/cli/account.tssrc/server/management/oauth-account-routes.tstests/oauth-accounts-api.test.ts
| placeholder="[{\"email\":\"user@gmail.com\",\"refresh_token\":\"1//...\"}]" | ||
| disabled={importBusy} | ||
| style={{ fontFamily: "var(--font-mono, monospace)", fontSize: 12 }} | ||
| /> | ||
| {importResult && ( | ||
| <div className="muted faint" style={{ fontSize: 12, marginTop: 4 }}> | ||
| Imported {importResult.imported} account(s), {importResult.failed} failed. | ||
| </div> | ||
| )} | ||
| <div style={{ display: "flex", gap: 8, marginTop: 8 }}> | ||
| <button | ||
| type="button" | ||
| className="btn btn-primary btn-sm" | ||
| disabled={importBusy || !importJsonText.trim()} | ||
| onClick={async () => { | ||
| const text = importJsonText.trim(); | ||
| if (!text) return; | ||
| setImportBusy(true); | ||
| setImportResult(null); | ||
| try { | ||
| let parsed: unknown; | ||
| try { | ||
| parsed = JSON.parse(text); | ||
| } catch { | ||
| setImportResult({ imported: 0, failed: 1 }); | ||
| return; | ||
| } | ||
| const res = await fetch(`${apiBase}/api/oauth/accounts/import`, { | ||
| method: "POST", | ||
| headers: { "Content-Type": "application/json" }, | ||
| body: JSON.stringify({ | ||
| provider: item.name, | ||
| accounts: Array.isArray(parsed) ? parsed : (parsed as { accounts?: unknown })?.accounts ?? parsed, | ||
| }), | ||
| }); | ||
| if (res.ok) { | ||
| const data = (await res.json()) as { importedCount?: number; failedCount?: number }; | ||
| setImportResult({ imported: data.importedCount ?? 0, failed: data.failedCount ?? 0 }); | ||
| if ((data.importedCount ?? 0) > 0) { | ||
| setImportJsonText(""); | ||
| void authHandlers.onRetryAccounts?.(item.name); | ||
| } | ||
| } else { | ||
| setImportResult({ imported: 0, failed: 1 }); | ||
| } | ||
| } catch { | ||
| setImportResult({ imported: 0, failed: 1 }); | ||
| } finally { | ||
| setImportBusy(false); | ||
| } | ||
| }} | ||
| > | ||
| {importBusy ? t("pws.saving") : "Import JSON"} | ||
| </button> | ||
| <button | ||
| type="button" | ||
| className="btn btn-ghost btn-sm" | ||
| onClick={() => { setImportingJson(false); setImportJsonText(""); setImportResult(null); }} | ||
| > | ||
| {t("common.cancel")} | ||
| </button> | ||
| </div> | ||
| </div> | ||
| ) : ( | ||
| <div style={{ display: "flex", gap: 8, marginTop: 8 }}> | ||
| {loggedIn && ( | ||
| <button type="button" className="btn btn-ghost btn-sm" | ||
| onClick={() => void authHandlers.onLogin(item.name, true)} disabled={busy || Boolean(switchingAccountId)}> | ||
| {t("pws.addAccount")} | ||
| </button> | ||
| )} | ||
| <button type="button" className="btn btn-ghost btn-sm" | ||
| onClick={() => setImportingJson(true)} disabled={busy || Boolean(switchingAccountId)}> | ||
| Import JSON (Cockpit) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Move import UI text into locale files.
Lines 292, 298, 344, and 365 hardcode user-visible placeholder, result, and button text. Use t(...) keys and add the translations to the locale files. This includes "Import JSON", "Import JSON (Cockpit)", and the import result sentence.
As per path instructions, GUI user-visible strings must use i18n locale files rather than hardcoded text.
🧰 Tools
🪛 Biome (2.5.6)
[error] 292-292: unexpected token \
(parse)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@gui/src/components/provider-workspace/ProviderAuthPanel.tsx` around lines 292
- 365, Replace the hardcoded import UI strings in ProviderAuthPanel, including
the JSON placeholder, import result sentence, “Import JSON”, and “Import JSON
(Cockpit)”, with appropriate t(...) lookups. Add matching translation keys and
values to the GUI locale files, preserving interpolation for imported and failed
counts in the result message.
Source: Path instructions
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2f79feacb1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return usage("Error: account import only applies to OAuth providers (such as google-antigravity)"); | ||
| } | ||
|
|
||
| let jsonText = input; |
There was a problem hiding this comment.
Avoid accepting credential JSON on the command line
When input is not an existing file, the command parses that argv value as JSON; for the advertised <file-or-json> path this means a refresh_token can be supplied directly on the command line, exposing it via shell history and process listings. This is a new credential-handling path, so require a file or stdin (-) instead of accepting raw secret JSON in argv.
AGENTS.md reference: AGENTS.md:L218-L224
Useful? React with 👍 / 👎.
| if (provider === "google-antigravity") { | ||
| const creds = await refreshAntigravityToken(refreshToken); | ||
| if (inputEmail && !creds.email) creds.email = inputEmail; | ||
| await saveCredential(provider, creds, { preserveIdentityless: true }); |
There was a problem hiding this comment.
Reject imports without a discovered CCA project
When refreshAntigravityToken() returns an access/refresh pair but cannot discover or onboard a Cloud Code Assist project, this still saves the credential and reports it as imported. The Antigravity adapter later requires provider.project and throws, so the just-imported account appears successful but cannot serve requests; mirror the login flow by treating missing creds.projectId as a failed import.
Useful? React with 👍 / 👎.
| const invalidToken = await fetch(new URL("/api/oauth/accounts/import", server.url), { | ||
| method: "POST", headers: { "Content-Type": "application/json" }, | ||
| body: JSON.stringify([ | ||
| { email: "bad@example.com", refresh_token: "invalid-token" } |
There was a problem hiding this comment.
Keep the import API test offline
This validation case uses a non-empty refresh_token, so the new import handler proceeds into refreshAntigravityToken() and makes a real call to Google's OAuth token endpoint before returning the expected failed result. In CI/offline runs or during Google outages the unit test can wait for the token-request timeout or fail for the wrong reason; stub the refresh/fetch path or use a missing-token payload for local validation.
Useful? React with 👍 / 👎.
| } | ||
| }} | ||
| > | ||
| {importBusy ? t("pws.saving") : "Import JSON"} |
There was a problem hiding this comment.
Use i18n keys for import UI copy
The new import controls render visible English directly in JSX (Imported ..., Import JSON, Import JSON (Cockpit)), so localized dashboards get untranslated copy and lint:i18n should reject the component. Add locale keys in all gui/src/i18n/*.ts modules and render these strings via t(...).
AGENTS.md reference: gui/AGENTS.md:L14-L18
Useful? React with 👍 / 👎.
| if (provider === "google-antigravity") { | ||
| const creds = await refreshAntigravityToken(refreshToken); | ||
| if (inputEmail && !creds.email) creds.email = inputEmail; | ||
| await saveCredential(provider, creds, { preserveIdentityless: true }); |
There was a problem hiding this comment.
Upsert the provider row after a successful import
ocx account import google-antigravity ... is accepted even on a fresh config because the CLI classifies public OAuth provider names as OAuth, but this handler only writes the credential store. Unlike the normal login path, it never upserts and saves config.providers[provider], so a successful import can leave the account present in auth.json but with no routable provider card or model route until the user performs a separate provider-add/login operation.
Useful? React with 👍 / 👎.
| } | ||
| } | ||
| } | ||
| return 0; |
There was a problem hiding this comment.
Return failure when every CLI import entry fails
When the import API returns HTTP 200 with { ok: false, importedCount: 0, failedCount: ... } for revoked or invalid refresh tokens, the CLI still prints the result and exits 0 here. Scripts and users will treat a completely failed import as successful; check the response ok/counts and return a non-zero status when no account was imported.
Useful? React with 👍 / 👎.
| <button type="button" className="btn btn-ghost btn-sm" | ||
| onClick={() => setImportingJson(true)} disabled={busy || Boolean(switchingAccountId)}> | ||
| Import JSON (Cockpit) |
There was a problem hiding this comment.
Hide Cockpit import on unsupported OAuth providers
This button is rendered for every OAuth provider's Accounts tab, but the management handler only imports google-antigravity and returns per-entry failures for Anthropic, xAI, Kimi, Kiro, Cursor, etc. Users can paste sensitive Cockpit JSON into a provider that can never accept it; gate the control to the provider the endpoint actually supports or make the endpoint support the same set the UI exposes.
AGENTS.md reference: gui/AGENTS.md:L9-L10
Useful? React with 👍 / 👎.
| const set = getAccountSet(provider); | ||
| const identity = creds.accountId ?? creds.email; | ||
| const activeAcc = set?.accounts.find(a => (a.credential.accountId ?? a.credential.email) === identity); | ||
| results.push({ email: creds.email ?? inputEmail, accountId: activeAcc?.id, status: "imported" }); |
There was a problem hiding this comment.
Mask imported account emails in the management response
Successful and failed import results serialize creds.email/inputEmail verbatim, while the existing OAuth account-list/status surfaces mask account emails before returning them. In the dashboard and CLI this exposes full Google account identifiers for every imported or failed row; return masked emails (or omit them and use the account id) before serializing the result.
Useful? React with 👍 / 👎.
| if (provider === "google-antigravity") { | ||
| const creds = await refreshAntigravityToken(refreshToken); | ||
| if (inputEmail && !creds.email) creds.email = inputEmail; | ||
| await saveCredential(provider, creds, { preserveIdentityless: true }); |
There was a problem hiding this comment.
Preserve refresh-token-only batch imports
For Cockpit rows that omit email (or for Google refresh responses that do not include an id token/email), creds.accountId and creds.email remain undefined before saveCredential(). The store's identityless path replaces the active slot instead of appending, so a batch of refresh-token-only entries can report every row as imported while only the last credential survives; require an identity for import or store these rows under a stable refresh-derived account id.
Useful? React with 👍 / 👎.
…om Cockpit Tools JSON (lidge-jun#1076)
…dge-jun#1076) - Restrict account import route and GUI import button to google-antigravity - Preserve totalCount and handle non-object elements gracefully in import loop - Add i18n translation keys (pws.importJson, pws.importJsonCockpit, pws.importResultSummary) across all 6 locales - Fix JSX placeholder string syntax in ProviderAuthPanel - Update CLI EXTENDED_USAGE and add tests for cmdImport
2f79fea to
8f1a74e
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@gui/src/i18n/en.ts`:
- Around line 1007-1010: Fix the malformed pws.addAccount and
pws.importResultSummary entries in gui/src/i18n/en.ts lines 1007-1010,
gui/src/i18n/ja.ts lines 955-958, gui/src/i18n/de.ts lines 1456-1459,
gui/src/i18n/ko.ts lines 1483-1486, gui/src/i18n/ru.ts lines 997-1000, and
gui/src/i18n/zh.ts lines 1476-1479: restore each locale’s specified
pws.addAccount value and remove the duplicated trailing literal from
pws.importResultSummary. Then run bun x tsc --noEmit to verify all catalogs
type-check.
In `@src/server/management/oauth-account-routes.ts`:
- Around line 379-459: Add a maximum batch-size validation for accountEntriesRaw
before the import loop, using a limit such as 100 entries. Return a 400 JSON
error when the limit is exceeded, while preserving the existing empty-array
validation and normal processing for batches within the limit.
- Around line 425-443: In the import flow around refreshAntigravityToken and
saveCredential, reject credentials unless both creds.accountId and creds.email
are present. For identity-less results, add a failed result with an appropriate
error, increment failedCount, and continue before saveCredential; only valid
credentials should be saved, reported as imported, and counted in importedCount.
In `@tests/cli-account.test.ts`:
- Around line 1358-1379: The cmdImport test still lacks coverage for file-based
JSON input and non-200 API failures. Extend the existing “ocx account import
validates inputs and outputs results” test by creating a temporary valid JSON
file and importing it via its path, then configure one mocked endpoint response
with a non-200 status and assert a non-zero exit code plus the expected “Error:
…” apiError output; use the existing temp-file and mock-server utilities.
In `@tests/oauth-accounts-api.test.ts`:
- Around line 179-229: Add a regression case to “POST import validates provider
and accounts payload” covering two imported accounts without email (or one
missing email alongside an existing active account), and assert the response
does not report success for the identity-less entry. Keep the test focused on
the collision fix in the import route and preserve the existing validation
assertions.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 9443c477-18ae-4ba2-818e-0c10829de902
📒 Files selected for processing (12)
gui/src/components/provider-workspace/ProviderAuthPanel.tsxgui/src/i18n/de.tsgui/src/i18n/en.tsgui/src/i18n/ja.tsgui/src/i18n/ko.tsgui/src/i18n/ru.tsgui/src/i18n/zh.tssrc/cli/account-extended.tssrc/cli/account.tssrc/server/management/oauth-account-routes.tstests/cli-account.test.tstests/oauth-accounts-api.test.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8f1a74e0b0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "pws.addAccount": | ||
| "pws.importJson": "Import JSON", |
There was a problem hiding this comment.
The new locale keys were inserted between pws.addAccount's key and value, so the parser sees a property with no value followed by another key; the same malformed pattern is present in every locale file, which makes the GUI i18n modules fail to parse and blocks the dashboard build. Split pws.addAccount back into its own key/value and add the import keys as separate entries in each locale file.
AGENTS.md reference: gui/AGENTS.md:L15-L18
Useful? React with 👍 / 👎.
| const res = await fetch(`${apiBase}/api/oauth/accounts/import`, { | ||
| method: "POST", | ||
| headers: { "Content-Type": "application/json" }, | ||
| body: JSON.stringify({ | ||
| provider: item.name, | ||
| accounts: Array.isArray(parsed) ? parsed : (parsed as { accounts?: unknown })?.accounts ?? parsed, | ||
| }), |
There was a problem hiding this comment.
Gate Cockpit imports with the OAuth risk warning
When a user imports Google Antigravity JSON from the Accounts tab, this direct POST stores a high-risk OAuth refresh token without going through the existing dashboard warning path (requestLoginOAuth checks oauthTosRisk(provider), and google-antigravity is classified as high risk). Route this import action through the same acknowledgement modal before sending/saving the tokens so users cannot bypass the warning just by using the new import path.
Useful? React with 👍 / 👎.
| <textarea | ||
| className="input" | ||
| rows={4} | ||
| value={importJsonText} | ||
| onChange={e => setImportJsonText(e.target.value)} | ||
| placeholder='[{"email":"user@gmail.com","refresh_token":"1//..."}]' | ||
| disabled={importBusy} | ||
| style={{ fontFamily: "var(--font-mono, monospace)", fontSize: 12 }} | ||
| /> |
There was a problem hiding this comment.
Add an accessible label to the import textarea
The new JSON paste textarea has no associated label or aria-label; the placeholder is only an example and is not a durable accessible name, so screen-reader users cannot tell what the field is for once focused or populated. Add a localized visible label or aria-label for the Cockpit JSON input.
AGENTS.md reference: gui/AGENTS.md:L31-L33
Useful? React with 👍 / 👎.
| let importedCount = 0; | ||
| let failedCount = 0; | ||
|
|
||
| for (const rawItem of accountEntriesRaw) { |
There was a problem hiding this comment.
For a large Cockpit export or accidental JSON array with many objects, this unbounded loop calls refreshAntigravityToken once per entry, and each call can spend up to the OAuth request timeout before moving to the next. A single management request can therefore consume proxy resources and issue hundreds or thousands of Google token requests; reject or cap batches before entering the refresh loop.
Useful? React with 👍 / 👎.
…e account identity (lidge-jun#1076) - Restore pws.addAccount string across all 6 locale files (en, ru, zh, de, ja, ko) - Enforce maximum 100-account limit for batch imports on POST /api/oauth/accounts/import - Require account identity (email or accountId) before persisting imported credentials - Add CLI file-based JSON import test coverage
- Add non-empty statements to catch blocks in ProviderAuthPanel.tsx and cli-account.test.ts - Ensure deterministic PR hygiene checks pass cleanly
There was a problem hiding this comment.
♻️ Duplicate comments (2)
tests/cli-account.test.ts (1)
1379-1397: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd the still-missing non-200 API error-handling case for
cmdImport.This test now covers file-based JSON import (Lines 1379-1397), closing half of a prior review request. The other half — a mocked endpoint returning a non-200 status, asserting a non-zero exit code and
Error: ...output — is still not present in this file.Extend the existing "ocx account import validates inputs and outputs results" test group with a case that configures the mock
/api/oauth/accounts/importendpoint to return a non-200 status for one request, then assertsrun(...)returns a non-zerocodeand stdout/stderr contains the expectedapiErrortext.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/cli-account.test.ts` around lines 1379 - 1397, Extend the existing “ocx account import validates inputs and outputs results” test group with a cmdImport case that configures the mocked /api/oauth/accounts/import endpoint to return a non-200 response, then invokes run with import arguments and asserts a non-zero exit code plus output containing the expected apiError text prefixed by Error:. Keep the existing successful file-import test unchanged.gui/src/components/provider-workspace/ProviderAuthPanel.tsx (1)
287-295: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMove the remaining hardcoded JSON placeholder into the locale files.
Line 292 still hardcodes the example JSON string shown in the textarea placeholder. A prior review comment asked for this text, along with the button and result text, to move into locale files. The button and result text (
pws.importJson,pws.importJsonCockpit,pws.importResultSummary) now uset(...), but the placeholder does not.Add a
pws.importJsonPlaceholderkey to all six locale catalogs and use it here instead of the literal string.As per path instructions, "GUI dashboard... Check that GUI state changes stay consistent with the management API responses and that user-visible strings go through the i18n locale files rather than hardcoded text."
♻️ Proposed fix
- placeholder='[{"email":"user@gmail.com","refresh_token":"1//..."}]' + placeholder={t("pws.importJsonPlaceholder")}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@gui/src/components/provider-workspace/ProviderAuthPanel.tsx` around lines 287 - 295, Move the textarea placeholder in ProviderAuthPanel from the hardcoded JSON string to the i18n system by adding the pws.importJsonPlaceholder key with the same value to all six locale catalogs, then replace the literal placeholder in the import JSON textarea with t("pws.importJsonPlaceholder").Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@gui/src/components/provider-workspace/ProviderAuthPanel.tsx`:
- Around line 287-295: Move the textarea placeholder in ProviderAuthPanel from
the hardcoded JSON string to the i18n system by adding the
pws.importJsonPlaceholder key with the same value to all six locale catalogs,
then replace the literal placeholder in the import JSON textarea with
t("pws.importJsonPlaceholder").
In `@tests/cli-account.test.ts`:
- Around line 1379-1397: Extend the existing “ocx account import validates
inputs and outputs results” test group with a cmdImport case that configures the
mocked /api/oauth/accounts/import endpoint to return a non-200 response, then
invokes run with import arguments and asserts a non-zero exit code plus output
containing the expected apiError text prefixed by Error:. Keep the existing
successful file-import test unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: ff500fda-ee23-42be-a3d1-ce8daf8cb4ec
📒 Files selected for processing (10)
gui/src/components/provider-workspace/ProviderAuthPanel.tsxgui/src/i18n/de.tsgui/src/i18n/en.tsgui/src/i18n/ja.tsgui/src/i18n/ko.tsgui/src/i18n/ru.tsgui/src/i18n/zh.tssrc/server/management/oauth-account-routes.tstests/cli-account.test.tstests/oauth-accounts-api.test.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 29463aa149
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } catch (err) { | ||
| void err; | ||
| setImportResult({ imported: 0, failed: 1 }); | ||
| return; |
There was a problem hiding this comment.
When the pasted JSON is malformed, this catch reduces the error to the same count-only summary used for any other failure, and the later non-OK response path does the same. In those cases users only see “0 imported, 1 failed” and cannot tell whether to fix JSON syntax, choose a different provider, or retry a server-side failure; store and render a localized validation/error message from JSON.parse or the response body instead.
AGENTS.md reference: gui/AGENTS.md:L31-L33
Useful? React with 👍 / 👎.
| failedCount++; | ||
| continue; | ||
| } | ||
| await saveCredential(provider, creds, { preserveIdentityless: true }); |
There was a problem hiding this comment.
Upgrade legacy identityless accounts on import
Because imports now require an account identity, passing preserveIdentityless: true disables the store’s legacy-upgrade path for an existing active Google Antigravity credential that was saved without email/accountId. In that case importing the same Cockpit account appends a second active row instead of upgrading the stale identityless slot, leaving a duplicate, selectable credential behind; omit this option for identity-bearing imports.
Useful? React with 👍 / 👎.
|
Maintainer triage (code-level, against
Minor: misindented |
|
Closing this draft — closest of the batch to landing, and the token refresh validation is done right. Blockers: (1) refresh tokens are accepted via argv, which leaks into shell history and process listings — take them via file path or stdin only; (2) the GUI change ships without the required screenshot evidence; (3) credential import is a security-sensitive surface and needs a maintainer-sponsored review pass. Please reopen with file/stdin-only input and the GUI evidence; this one we would like to take. |
Summary
Fixes #1076.
Adds support for batch importing Google Antigravity / Gemini accounts exported from Cockpit Tools (or any valid JSON array containing
emailandrefresh_token).Key Changes
API Endpoint (
POST /api/oauth/accounts/import):[ { "email": "user@gmail.com", "refresh_token": "1//..." } ]google-antigravityprovider to align with available token discovery capabilities.refreshAntigravityTokento validate credentials, decode user email, and discover Cloud Code AssistprojectId.auth.jsonprovider account pool.importedCount,failedCount, detailed per-account results).CLI Integration (
ocx account import <provider> <file-or-json>):Web UI Integration (
ProviderAuthPanel.tsx):google-antigravityand JSON input area underProviders -> Google Antigravity -> Accounts.en,ru,zh,de,ja,ko).Automated Tests (
tests/oauth-accounts-api.test.ts&tests/cli-account.test.ts):cmdImportvalidation, and API execution.Verification
Ran
bun test --preload ./tests/preload.ts tests/oauth-accounts-api.test.ts tests/cli-account.test.tsandbun run typecheck:71 pass, 0 failtsc --noEmitpassed with 0 errors.Review readiness checklist
This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:
Summary by CodeRabbit