feat(integrations): Add support for federated auth integrations, starting with BigQuery#399
Conversation
Lay the foundation for BigQuery Google OAuth integration: DI symbols, shared type contracts, command/localization keys, and vendored @deepnote/blocks helpers required to generate federated SQL cell code without persisting access tokens. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Boot the federated-auth runtime: encrypted refresh-token storage with metadata-fingerprint stale detection, a Google OAuth strategy that owns its own verify callback, a session-less PKCE store, and a loopback flow that mints a refresh token via the user's browser. No access token is persisted — refresh is per-execution. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…xecution (M3) Each federated SQL cell now runs through a code generator that mints a fresh access token from Google before execution, defines it in a kernel-side variable via a silent prelude (store_history disabled), and references that variable from the cell's main Python — so the access token never lands in Jupyter's In[] history. Plumbs the generator through KernelProvider → NotebookKernelExecution → CellExecutionFactory → CellExecution as an optional dep so the web build degrades gracefully. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…d (M4) Wire the federated auth flow into reachable surfaces: a "Google OAuth" option on the BigQuery integration form, an Authenticate button with status pill in the integration list, a command that drives the loopback flow on desktop (and a clear "not supported" toast on web/remote), and all the localization plumbing. Stale tokens are cleared automatically when OAuth metadata changes, and federated integrations skip the kernel-startup env-var batch so the per-cell refresh path owns credential delivery. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add the two activation services that keep federated-auth state coherent across the extension host: a bridge that restarts kernels when a token changes (so the next cell starts with a clean os.environ) and an orphan cleaner that drops stored tokens for integrations that no longer exist. Also distinguish the misconfigured-OAuth-client error from the not-authenticated error in cell execution, so the user gets a clear "verify your credentials in integration settings" message rather than a generic re-auth prompt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The federated-auth code generator persists rotated refresh tokens during
cell preparation. That save was firing onDidChangeTokens, which the
kernel-restart bridge handled by queuing a kernel.restart() — landing
microseconds later while the very SQL cell that triggered the rotation
was still executing.
The new refresh token doesn't change anything the kernel sees: the
extension mints a fresh access token via the per-cell pre-execute on
every SQL block run, so there's no stale state to clear. Add a
{ silent: true } option to FederatedAuthTokenStorage.save() and use it
on the rotation path. Initial-auth and metadata-change saves keep
firing the event as before.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR implements federated authentication for BigQuery integrations in the VS Code Deepnote extension. It introduces OAuth-based token management with refresh logic, a loopback browser flow for acquiring credentials, SQL code generation that embeds fresh access tokens, and extension services that manage token lifecycle. The webview now displays token status and supports re-authentication. Cell execution conditionally runs a silent prelude to set connection context before executing federated SQL blocks. Kernel restarts are triggered when tokens change, and stale tokens are pruned when integrations are removed. Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #399 +/- ##
===========================
===========================
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 9
🤖 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 `@src/kernels/execution/cellExecution.federatedAuth.unit.test.ts`:
- Around line 217-225: Replace the multiple individual property assertions on
the first call with a single assert.deepStrictEqual comparing the full request
payload: build an expected object for the prelude (e.g., { code: prelude,
silent: true, store_history: false, allow_stdin: false, stop_on_error: true })
and call assert.deepStrictEqual(preludeContent, expectedPrelude); keep the
existing boolean check for preludeDispose if desired or include it in a second
deepStrictEqual against the full args tuple; do the same refactor for the second
call (calls[1] / its requestArgs/requestContent) referenced in the comment so
each payload comparison uses a single assert.deepStrictEqual rather than many
assert.strictEqual calls.
In `@src/kernels/execution/cellExecution.ts`:
- Around line 486-500: The current await of
kernelConnection.requestExecute(...).done ignores execute_reply content.status
so errors inside the federated prelude don't throw; change the call to capture
the reply (e.g., const reply = await
kernelConnection.requestExecute({...}).done), then inspect reply.content?.status
and if it equals "error" call logger.error with context including
federated.prelude and the reply content, and return
this.completedWithErrors(reply) (or an Error created from the reply) to stop
main execution; keep existing try/catch for transport exceptions around the same
kernelConnection.requestExecute call and use federated.prelude,
kernelConnection.requestExecute, this.completedWithErrors, and logger.error to
locate where to implement the check.
In
`@src/notebooks/deepnote/integrations/federatedAuth/federatedAuthInvariants.unit.test.ts`:
- Around line 10-13: The current conditional type distributes over the union
'accessToken' | 'expiresAt' causing a false negative; update the invariant to
test the union as a whole by using a non-distributive or aggregate check (for
example, use Extract<keyof FederatedAuthTokenEntry, Forbidden> extends never ?
true : never or wrap Forbidden in a tuple like [Forbidden] extends [keyof
FederatedAuthTokenEntry] ?) so that the test fails if any forbidden key is
present; change the AssertEntryOmitsForbidden definition that references
FederatedAuthTokenEntry and Forbidden accordingly and keep the rest of the
assertion (_entryShapeCheck and void usage) intact.
In
`@src/notebooks/deepnote/integrations/federatedAuth/federatedAuthKernelRestartBridge.node.unit.test.ts`:
- Line 83: Replace the repeated magic-number waits by extracting a named
constant and helper: add a top-of-module constant (e.g., const TEST_WAIT_MS =
10) and a small async helper function (e.g., async function waitMs(ms =
TEST_WAIT_MS) { return new Promise(resolve => setTimeout(resolve, ms)); }) and
then replace every occurrence of await new Promise((resolve) =>
setTimeout(resolve, 10)); in the tests with await waitMs(); so fixtures and
tests (references in federatedAuthKernelRestartBridge.node.unit.test.ts) use the
shared constant and helper to avoid duplication.
In
`@src/notebooks/deepnote/integrations/federatedAuth/federatedAuthOrphanedTokenCleaner.node.ts`:
- Around line 31-33: In FederatedAuthOrphanedTokenCleaner, the activate() method
is currently a no-op so any orphaned tokens present at startup are never
cleaned; update activate() to invoke the existing orphaned-token cleanup routine
used for integration-change events (call the exact method name in this class —
e.g., cleanOrphanedTokens(), runOrphanedTokenCleanup(), or similar) so cleanup
runs once on activation, await or handle the returned Promise if the cleanup is
async, and catch/log any errors so activation doesn't crash.
In `@src/notebooks/deepnote/integrations/integrationWebview.ts`:
- Around line 665-666: When deleting an integration, token cleanup
(tokenStorage.delete(integrationId)) must not be allowed to abort the overall
delete/reset flow if it fails; wrap the tokenStorage.delete(integrationId) calls
(the ones at/around where integrationStorage.delete(...) is called in
integrationWebview.ts) in a try/catch, log the error (or call process/project
logger) inside the catch, and do not rethrow so the in-memory and project state
transitions (the integrationStorage.delete and subsequent state updates) always
complete; apply the same pattern to both occurrences (the calls at the two
locations noted).
- Around line 50-52: The event callback passed to tokenStorage.onDidChangeTokens
calls this.updateWebview() without handling rejections, which can produce
unhandled promise rejections; change the callback so it consumes errors from
updateWebview (for example replace void this.updateWebview() with
this.updateWebview().catch(err => { /* handle or log the error */ }) or wrap the
call in an async IIFE with try/catch) so any rejection from updateWebview is
caught; reference tokenStorage.onDidChangeTokens and the updateWebview method
when making the change.
In
`@src/platform/notebooks/deepnote/sqlIntegrationEnvironmentVariablesProvider.ts`:
- Around line 110-116: The Promise.all call loading integration configs will
abort all work if any getIntegrationConfig rejects; change to per-item error
isolation by using Promise.allSettled over projectIntegrations.map(...) (or wrap
each await in try/catch inside the map) to collect only fulfilled results into
allConfigs, filter out rejected/undefined entries, and log the individual errors
(including integration.id) so one failing getIntegrationConfig call in
integrationStorage.getIntegrationConfig does not prevent returning other env
vars (including DuckDB).
In `@src/webviews/webview-side/integrations/BigQueryForm.tsx`:
- Around line 44-55: buildInitialConfig currently returns a blind clone of
existingConfig which can carry an unsupported authMethod into the form; change
it to clone the object (structuredClone(existingConfig)) then validate
existingConfig.authMethod against the supported set (e.g., 'service-account' and
'google-oauth') and if it's not supported, normalize it to a safe default (for
example 'service-account') and clear or reset any auth-specific fields (e.g.,
serviceAccountKey, oauthToken, oauthClientId/secrets) so the form doesn't start
in an invalid state; use the function buildInitialConfig and
createEmptyBigQueryConfig as anchors for where to perform this normalization.
🪄 Autofix (Beta)
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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 36bbea8e-d36e-4a6d-b50b-3de8abb8e3e5
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (41)
package.jsonpackage.nls.jsonsrc/kernels/execution/cellExecution.federatedAuth.unit.test.tssrc/kernels/execution/cellExecution.tssrc/kernels/kernelExecution.tssrc/kernels/kernelProvider.node.tssrc/messageTypes.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthCommandHandler.node.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthCommandHandler.node.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthCommandHandler.web.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthCommandHandler.web.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthInvariants.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthKernelRestartBridge.node.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthKernelRestartBridge.node.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthOrphanedTokenCleaner.node.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthOrphanedTokenCleaner.node.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthSqlBlockCodeGenerator.node.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthSqlBlockCodeGenerator.node.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthTokenStorage.node.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthTokenStorage.node.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/googleOAuthProvider.node.tssrc/notebooks/deepnote/integrations/federatedAuth/googleOAuthProvider.node.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/oauthLoopbackFlow.node.tssrc/notebooks/deepnote/integrations/federatedAuth/oauthLoopbackFlow.node.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/vendoredBlocksHelpers.tssrc/notebooks/deepnote/integrations/federatedAuth/vendoredBlocksHelpers.unit.test.tssrc/notebooks/deepnote/integrations/integrationWebview.tssrc/notebooks/deepnote/integrations/integrationWebview.unit.test.tssrc/notebooks/deepnote/integrations/types.tssrc/notebooks/serviceRegistry.node.tssrc/notebooks/serviceRegistry.web.tssrc/platform/common/constants.tssrc/platform/common/utils/localize.tssrc/platform/notebooks/deepnote/integrationTypes.tssrc/platform/notebooks/deepnote/sqlIntegrationEnvironmentVariablesProvider.tssrc/platform/notebooks/deepnote/sqlIntegrationEnvironmentVariablesProvider.unit.test.tssrc/webviews/webview-side/integrations/BigQueryForm.tsxsrc/webviews/webview-side/integrations/IntegrationItem.tsxsrc/webviews/webview-side/integrations/IntegrationList.tsxsrc/webviews/webview-side/integrations/IntegrationPanel.tsxsrc/webviews/webview-side/integrations/types.ts
The previous flow opened Google's `/authorize` directly from the extension's loopback URL, which works only for Desktop-app Google clients. Customers using a Web-application client (so the same client can be shared with the deepnote.com web product) can't register `http://127.0.0.1:<random-port>` redirect URIs, so the loopback hit `redirect_uri_mismatch`. Switch to a delegated flow: - Extension binds a random loopback port, externalizes it with `env.asExternalUri` (so SSH-remote / WSL / dev-container work), and opens `https://<deepnote.domain>/auth/bigquery/extension/start` with the loopback URL as `finalRedirect`. - deepnote.com performs the OAuth handshake using its already-registered `/auth/bigquery/google-oauth-callback` as Google's `redirect_uri`, then 302s the browser back to the loopback URL with the authorization `code` attached (or `error`+`error_description` on consent denial). - The extension exchanges the code directly with Google's `/token`, keeping the refresh token out of deepnote.com entirely. PKCE + state-nonce protect against code interception in transit. Removes the passport-google-oauth20 dependency from this path; the loopback server now exposes only `/auth/callback`. Token exchange is done with a new `exchangeAuthorizationCode` helper that mirrors the existing `fetchFreshAccessToken` shape and error taxonomy. Multi-window safety is automatic — each window's random port is the disambiguator, so the browser's redirect lands in exactly one window. `deepnote.domain` is now a `resource`-scoped setting so different workspace folders / notebook files can point at different hosts; the import client and the OAuth start URL both pass the active resource URI to the configuration lookup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…lementations Updated unit tests for FederatedAuth components to utilize new fake storage implementations for integration and token storage. This change simplifies the test setup and enhances clarity by removing unnecessary complexity related to manual state management. The tests now leverage the `createFakeIntegrationStorage` and `createFakeTokenStorage` functions, ensuring a more consistent and maintainable testing environment.
`@jupyterlab/services` resolves `IShellFuture.done` with the reply unconditionally and only rejects on transport/disposal errors. The federated prelude's `.done` was awaited but the reply was discarded, so a kernel that returned `content.status === 'error'` silently proceeded to the main execute against an unset `__deepnote_federated_sql_connection__*` global, surfacing a confusing `NameError` instead of the real cause. Capture the reply, check `content.status === 'error'`, and surface it as a `KernelError` via `completedWithErrors`. Add a unit test that resolves the prelude with an error reply and verifies the main execute is not called. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The form told users to create a 'Desktop app' OAuth client, but the federated-auth flow sends redirect_uri=https://deepnote.com/auth/bigquery/ google-oauth-callback to Google. That HTTPS redirect is only valid on a 'Web application' OAuth client; Desktop clients restrict redirects to localhost/custom-scheme. Users following the previous help would create the wrong client type and hit redirect_uri_mismatch on first authorize. Update both the l10n string and the in-form fallback to instruct users to create a 'Web application' client and add the deepnote.com callback to its authorized redirect URIs. Add a source-grep regression test that fails if either copy reverts to the old wording or drops the callback URL. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The test just read the form and localize.ts off disk and asserted the string contents — it didn't render the component, exercise any prop flow, or catch any behavior that a typo wouldn't catch. Locking in constants via source-grep is noise, not coverage. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rams The deepnote.com OAuth proxy start URL was emitting camelCase query parameters (clientId, codeChallenge, finalRedirect). OAuth 2.0 (RFC 6749) uses snake_case throughout (client_id, code_challenge, etc.), and the loopback callback already receives Google's snake_case (code, state, error_description), so the inbound and outbound wire formats should match. Only the URL keys change; the TypeScript params on buildExtensionStartUrl stay camelCase (TS convention). Tests updated to assert the snake_case wire format. Note: the deepnote.com server-side handler reading these params must be updated to match before this lands in production. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Updated the `IFederatedAuthSqlBlockCodeGenerator` interface to return a single string containing the connection JSON instead of an object with separate prelude and cellCode properties. Adjusted the `FederatedAuthSqlBlockCodeGenerator` implementation and related tests to reflect this change, ensuring that the access token is embedded directly in the execute call. This streamlines the code generation process for federated SQL blocks and enhances clarity in the execution flow.
The federated-auth OAuth flow was switched to a deepnote.com-proxied handshake in a2c8381, so the extension no longer drives Google's `/authorize` itself — the loopback server only reads `code`/`state` from a single callback URL and exchanges it via `fetch`. `passport` / `passport-google-oauth20` (+ their `@types`) are no longer imported anywhere; remove them from package.json and the lockfile. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… cell execution - Added a new error class `CellExecutionOutputError` to handle cases where an error message has already been written to the cell output. - Updated the `completedWithErrors` method in `CellExecution` to accept an options object for error handling, allowing for better control over how errors are written to cell output (append or replace). - Modified tests to assert the correct error type is caught and handled. - Enhanced error handling in `VSCodeNotebookController` to prevent duplicate error messages from being logged when a `CellExecutionOutputError` is encountered.
…ted-auth-big-query
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/webviews/webview-side/integrations/IntegrationItem.tsx (1)
8-14: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick winKeep props alphabetically ordered after adding
onAuthenticate.
onAuthenticatewas appended, but this interface/destructuring block should stay alphabetized to match repo ordering rules.Proposed reorder
export interface IIntegrationItemProps { integration: IntegrationWithStatus; + onAuthenticate: (integrationId: string) => void; onConfigure: (integrationId: string) => void; - onReset: (integrationId: string) => void; onDelete: (integrationId: string) => void; - onAuthenticate: (integrationId: string) => void; + onReset: (integrationId: string) => void; } export const IntegrationItem: React.FC<IIntegrationItemProps> = ({ integration, + onAuthenticate, onConfigure, - onReset, onDelete, - onAuthenticate + onReset }) => {As per coding guidelines: "Order method, fields and properties, first by accessibility and then by alphabetical order".
Also applies to: 57-63
🤖 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 `@src/webviews/webview-side/integrations/IntegrationItem.tsx` around lines 8 - 14, The IIntegrationItemProps interface and the props destructuring in the IntegrationItem component must be alphabetized: move onAuthenticate into the correct alphabetical position among integration, onConfigure, onDelete, onReset, etc., and reorder the corresponding destructured props in the IntegrationItem function to match; update both the IIntegrationItemProps declaration and the destructuring usage so property order is alphabetical (e.g., integration, onAuthenticate, onConfigure, onDelete, onReset).
🤖 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 `@src/kernels/errors/cellExecutionOutputError.ts`:
- Around line 1-2: This new file contains the Microsoft copyright header at the
top; remove the header lines so the file only contains the TypeScript code
(i.e., delete the leading comment block in
src/kernels/errors/cellExecutionOutputError.ts), leaving the existing exported
symbol(s) like CellExecutionOutputError and any imports/exports intact.
In `@src/kernels/execution/cellExecution.federatedAuth.unit.test.ts`:
- Around line 102-106: Test setup creates a CancellationTokenSource named
tokenSource and pushes it to disposables but it is never used or disposed;
either remove the unused tokenSource and its push from the setup block, or use
it in the tests (e.g., pass tokenSource.token to functions under test and call
tokenSource.cancel() in a test) and ensure you call tokenSource.dispose() (or
remove from disposables cleanup if you keep it) so CancellationTokenSource is
actually exercised and properly disposed; locate the tokenSource variable in the
setup function and update either its creation/push or add usage and disposal
accordingly.
In `@src/messageTypes.ts`:
- Around line 231-250: The block of new LocalizedMessages keys for BigQuery
federated-auth is not alphabetized; reorder the keys within the BigQuery
federated-auth section so they follow alphabetical order by property name (e.g.,
place integrationsAuthenticate, integrationsAuthenticating,
integrationsAuthenticationFailed, integrationsAuthenticationSucceeded,
integrationsBigQueryAuthMethodGoogleOauth, integrationsBigQueryAuthMethodLabel,
integrationsBigQueryAuthMethodServiceAccount, integrationsBigQueryClientIdLabel,
integrationsBigQueryClientIdPlaceholder, integrationsBigQueryClientSecretLabel,
integrationsBigQueryClientSecretPlaceholder,
integrationsBigQueryNotAuthenticated, integrationsBigQueryProjectLabel,
integrationsBigQueryProjectPlaceholder,
integrationsFederatedAuthNotSupportedInWeb, integrationsReauthenticate,
integrationsTokenStatusAuthenticated, integrationsTokenStatusDisconnected);
update the sequence around the identifiers mentioned
(integrationsBigQueryAuthMethodLabel,
integrationsBigQueryAuthMethodServiceAccount,
integrationsBigQueryAuthMethodGoogleOauth, integrationsBigQueryProjectLabel,
integrationsBigQueryProjectPlaceholder, integrationsBigQueryClientIdLabel,
integrationsBigQueryClientIdPlaceholder, integrationsBigQueryClientSecretLabel,
integrationsBigQueryClientSecretPlaceholder, integrationsAuthenticate,
integrationsReauthenticate, integrationsTokenStatusAuthenticated,
integrationsTokenStatusDisconnected, integrationsAuthenticating,
integrationsAuthenticationSucceeded, integrationsAuthenticationFailed,
integrationsBigQueryNotAuthenticated,
integrationsFederatedAuthNotSupportedInWeb) so the section follows alphabetical
ordering.
In `@src/notebooks/controllers/vscodeNotebookController.ts`:
- Around line 670-674: The catch blocks currently reassign the catch parameter
ex using WrappedError.unwrap(ex), which violates noCatchAssign; instead create a
new local (e.g., const unwrapped = WrappedError.unwrap(ex)) and use that for
subsequent instanceof checks and logging/rendering (replace uses of the
reassigned ex with unwrapped in the block where you check for
CellExecutionOutputError and any error rendering code). Ensure you do this for
all catch blocks in vscodeNotebookController.ts that call WrappedError.unwrap on
the catch parameter.
In
`@src/notebooks/deepnote/integrations/federatedAuth/federatedAuthTestHelpers.ts`:
- Around line 128-130: Introduce a top-of-module named constant (e.g.,
SETTLE_ASYNC_HANDLERS_DELAY_MS) and use it as the default timeout for
settleAsyncHandlers instead of the magic number 10; update the
settleAsyncHandlers function signature to default ms to that constant and
replace any inline uses of 10 for this helper with the new constant so the
intent and configuration are centralized.
In `@src/notebooks/deepnote/integrations/federatedAuth/vendoredBlocksHelpers.ts`:
- Around line 32-34: The escapePythonString function fails to escape carriage
returns; update escapePythonString to also replace '\r' with '\\r' (ensuring you
still first escape backslashes, then single quotes, then newlines and carriage
returns) so generated Python string literals won't break when value contains
'\r'.
In `@src/notebooks/deepnote/integrations/integrationWebview.ts`:
- Around line 36-57: The tokenStorageDisposables array (used to hold the
onDidChangeTokens subscription) is never disposed, causing a leak; add a cleanup
path by implementing a dispose() on the IntegrationWebviewProvider (or register
the provider with IDisposableRegistry) that iterates tokenStorageDisposables and
calls dispose() on each Disposable (and clears the array), and ensure
this.dispose() is invoked when the provider is torn down so the
IFederatedAuthTokenStorage.onDidChangeTokens subscription is unsubscribed.
- Around line 489-521: The tokenStorage.delete calls inside
invalidateStaleFederatedToken can throw and bubble up, breaking the caller's
saveConfiguration; wrap both delete invocations in a safe failure handler
(either a try/catch around the await this.tokenStorage.delete(integrationId)
calls or append .catch(err => { logger.warn(...); })) so deletion errors are
logged but do not reject the surrounding operation; adjust logging to include
the error and continue without rethrowing to ensure saveConfiguration can
proceed.
In
`@src/platform/notebooks/deepnote/sqlIntegrationEnvironmentVariablesProvider.ts`:
- Around line 14-20: Reorder imports so third-party package imports come before
local project imports: move the block importing DatabaseIntegrationConfig,
FederatedAuthMethod, getEnvironmentVariablesForIntegrations, and
isFederatedAuthMethod from '`@deepnote/database-integrations`' above the local
imports (the '../../common/*' and './*' imports) in
sqlIntegrationEnvironmentVariablesProvider (locate the import statements by
those symbol names) to follow the third-party/local grouping guideline.
---
Outside diff comments:
In `@src/webviews/webview-side/integrations/IntegrationItem.tsx`:
- Around line 8-14: The IIntegrationItemProps interface and the props
destructuring in the IntegrationItem component must be alphabetized: move
onAuthenticate into the correct alphabetical position among integration,
onConfigure, onDelete, onReset, etc., and reorder the corresponding destructured
props in the IntegrationItem function to match; update both the
IIntegrationItemProps declaration and the destructuring usage so property order
is alphabetical (e.g., integration, onAuthenticate, onConfigure, onDelete,
onReset).
🪄 Autofix (Beta)
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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: e109f31b-1a4a-4bbb-9158-99fd3e0b3815
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (49)
cspell.jsonpackage.jsonpackage.nls.jsonsrc/kernels/errors/cellExecutionOutputError.tssrc/kernels/execution/cellExecution.federatedAuth.unit.test.tssrc/kernels/execution/cellExecution.tssrc/kernels/execution/types.tssrc/kernels/kernelExecution.tssrc/kernels/kernelProvider.node.tssrc/messageTypes.tssrc/notebooks/controllers/vscodeNotebookController.tssrc/notebooks/deepnote/importClient.node.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthCommandHandler.node.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthCommandHandler.node.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthCommandHandler.web.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthCommandHandler.web.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthInvariants.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthKernelRestartBridge.node.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthKernelRestartBridge.node.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthOrphanedTokenCleaner.node.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthOrphanedTokenCleaner.node.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthSqlBlockCodeGenerator.node.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthSqlBlockCodeGenerator.node.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthTestHelpers.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthTokenStorage.node.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthTokenStorage.node.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/googleOAuthProvider.node.tssrc/notebooks/deepnote/integrations/federatedAuth/googleOAuthProvider.node.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/oauthLoopbackFlow.node.tssrc/notebooks/deepnote/integrations/federatedAuth/oauthLoopbackFlow.node.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/vendoredBlocksHelpers.tssrc/notebooks/deepnote/integrations/federatedAuth/vendoredBlocksHelpers.unit.test.tssrc/notebooks/deepnote/integrations/integrationWebview.tssrc/notebooks/deepnote/integrations/integrationWebview.unit.test.tssrc/notebooks/deepnote/integrations/types.tssrc/notebooks/deepnote/openInDeepnoteHandler.node.tssrc/notebooks/serviceRegistry.node.tssrc/notebooks/serviceRegistry.web.tssrc/platform/common/constants.tssrc/platform/common/utils/localize.tssrc/platform/notebooks/deepnote/integrationTypes.tssrc/platform/notebooks/deepnote/sqlIntegrationEnvironmentVariablesProvider.tssrc/platform/notebooks/deepnote/sqlIntegrationEnvironmentVariablesProvider.unit.test.tssrc/webviews/extension-side/dataframe/dataframeController.unit.test.tssrc/webviews/webview-side/integrations/BigQueryForm.tsxsrc/webviews/webview-side/integrations/IntegrationItem.tsxsrc/webviews/webview-side/integrations/IntegrationList.tsxsrc/webviews/webview-side/integrations/IntegrationPanel.tsxsrc/webviews/webview-side/integrations/types.ts
- Drop Microsoft header from new CellExecutionOutputError file. - Remove unused CancellationTokenSource in federated-auth test setup. - Extract settle-delay magic number into DEFAULT_SETTLE_DELAY_MS. - Tie IntegrationWebviewProvider's onDidChangeTokens subscription to IDisposableRegistry so it survives provider lifetime cleanly. - Make stale-token delete in invalidateStaleFederatedToken non-fatal so saveConfiguration still completes if deletion fails. - Reorder @deepnote/database-integrations import in sqlIntegrationEnvironmentVariablesProvider above local imports. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ted-auth-big-query
There was a problem hiding this comment.
♻️ Duplicate comments (1)
src/notebooks/deepnote/integrations/integrationWebview.ts (1)
506-527: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick winExtract the best-effort token-delete path.
These two branches now duplicate the same delete-and-warn flow already used elsewhere in the class. A small helper will keep cleanup behavior from drifting.
As per coding guidelines: "Extract duplicate logic into helper methods to prevent drift following DRY principle".
🤖 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 `@src/notebooks/deepnote/integrations/integrationWebview.ts` around lines 506 - 527, The two code paths in IntegrationWebviewProvider that call await this.tokenStorage.delete(integrationId).catch((err) => logger.warn(...)) should be consolidated into a small helper method (e.g., a private async handleStaleTokenDelete(integrationId: string, reason?: string)) that performs the delete and logs the same warn message on error and an optional info log for the reason; replace both occurrences (the early-delete branch and the fingerprint-change branch that compares newFingerprint !== stored.metadataFingerprint) with calls to this helper to centralize the delete-and-warn behavior.
🤖 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 `@src/notebooks/deepnote/integrations/integrationWebview.ts`:
- Around line 506-527: The two code paths in IntegrationWebviewProvider that
call await this.tokenStorage.delete(integrationId).catch((err) =>
logger.warn(...)) should be consolidated into a small helper method (e.g., a
private async handleStaleTokenDelete(integrationId: string, reason?: string))
that performs the delete and logs the same warn message on error and an optional
info log for the reason; replace both occurrences (the early-delete branch and
the fingerprint-change branch that compares newFingerprint !==
stored.metadataFingerprint) with calls to this helper to centralize the
delete-and-warn behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: bccc74c9-0c64-40db-8980-2a0fbe64f38e
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (7)
package.jsonsrc/kernels/errors/cellExecutionOutputError.tssrc/kernels/execution/cellExecution.federatedAuth.unit.test.tssrc/notebooks/deepnote/integrations/federatedAuth/federatedAuthTestHelpers.tssrc/notebooks/deepnote/integrations/integrationWebview.tssrc/notebooks/deepnote/integrations/integrationWebview.unit.test.tssrc/platform/notebooks/deepnote/sqlIntegrationEnvironmentVariablesProvider.ts
💤 Files with no reviewable changes (2)
- src/kernels/errors/cellExecutionOutputError.ts
- src/kernels/execution/cellExecution.federatedAuth.unit.test.ts
There was a problem hiding this comment.
♻️ Duplicate comments (1)
src/notebooks/deepnote/integrations/federatedAuth/vendoredBlocksHelpers.ts (1)
31-33:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winMissing
\rescape remains unaddressed.Carriage returns still aren't escaped. If
valuecontains\r, generated Python literals may break.Suggested fix
export function escapePythonString(value: string): string { - return `'${value.replaceAll('\\', '\\\\').replaceAll("'", "\\'").replaceAll('\n', '\\n')}'`; + return `'${value.replaceAll('\\', '\\\\').replaceAll("'", "\\'").replaceAll('\n', '\\n').replaceAll('\r', '\\r')}'`; }🤖 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 `@src/notebooks/deepnote/integrations/federatedAuth/vendoredBlocksHelpers.ts` around lines 31 - 33, The escapePythonString function currently does not escape carriage returns, which can break generated Python literals; update escapePythonString to also replace '\r' with '\\r' (e.g., add a .replaceAll('\r', '\\r') or equivalent step in the replacement chain inside the function) while keeping the existing backslash, single-quote and newline replacements intact so the function remains escapePythonString and preserves its other behaviors.
🤖 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 `@src/notebooks/deepnote/integrations/federatedAuth/vendoredBlocksHelpers.ts`:
- Around line 31-33: The escapePythonString function currently does not escape
carriage returns, which can break generated Python literals; update
escapePythonString to also replace '\r' with '\\r' (e.g., add a
.replaceAll('\r', '\\r') or equivalent step in the replacement chain inside the
function) while keeping the existing backslash, single-quote and newline
replacements intact so the function remains escapePythonString and preserves its
other behaviors.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 09f746a5-46b7-446b-8136-34aa50ac3c7f
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (2)
src/notebooks/deepnote/integrations/federatedAuth/vendoredBlocksHelpers.tssrc/notebooks/deepnote/integrations/integrationWebview.ts
💤 Files with no reviewable changes (1)
- src/notebooks/deepnote/integrations/integrationWebview.ts
Summary by CodeRabbit
New Features
Bug Fixes
Tests