Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
147 commits
Select commit Hold shift + click to select a range
f0de6cd
refactor(deepnote): re-key notebook manager per (projectId, notebookI…
tkislan Jun 23, 2026
005accf
refactor(deepnote): render single notebook + serialize by metadata, d…
tkislan Jun 23, 2026
0ee7f53
feat(deepnote): split legacy multi-notebook files into single-noteboo…
tkislan Jun 23, 2026
8e27889
feat(deepnote): propagate project metadata across sibling files on disk
tkislan Jun 23, 2026
3995237
feat(deepnote): group the explorer by project and add a notebook stat…
tkislan Jun 24, 2026
3e16e20
refactor(deepnote): key the Jupyter server and environment per notebook
tkislan Jun 24, 2026
83d4e91
feat(deepnote): scope snapshots per notebook with a backward-compatib…
tkislan Jun 24, 2026
faa8432
feat(deepnote): run the init notebook per kernel from its sibling file
tkislan Jun 24, 2026
4a43a7d
fix(deepnote): satisfy lint and spell-check on the migration branch
tkislan Jun 24, 2026
f92d173
test(deepnote): use the real @deepnote/convert in unit tests instead …
tkislan Jun 24, 2026
6532d96
fix(deepnote): address code-review findings on the snapshot/serialize…
tkislan Jun 24, 2026
6d46725
fix(deepnote): exact snapshot lookup in the file watcher + close-canc…
tkislan Jun 26, 2026
21611db
refactor(deepnote): remove metadata propagation and project-level exp…
tkislan Jun 30, 2026
7814c6b
Merge origin/main into tk/single-notebook
tkislan Jun 30, 2026
663d31d
Revert unnecessary renamings
tkislan Jun 30, 2026
1643ef5
fix(deepnote): trim indented bullet content before stripping markdown
tkislan Jun 30, 2026
be64263
refactor(deepnote): import convert helpers directly, drop snapshotFil…
tkislan Jun 30, 2026
589845d
refactor(deepnote): update buildSnapshotPath to use object destructuring
tkislan Jun 30, 2026
3a910c1
test(deepnote): remove redundant subagent-written tests
tkislan Jun 30, 2026
dc0b2dd
Merge remote-tracking branch 'origin/main' into tk/single-notebook
tkislan Jul 1, 2026
ee38cf6
feat(deepnote): retire the split-away original as a .legacy backup
tkislan Jul 1, 2026
8c341e0
test(e2e): add multi-notebook split test with per-spec screenshots
tkislan Jul 1, 2026
c0cb36a
test(e2e): add single-notebook-open and init-notebook split/runner su…
tkislan Jul 1, 2026
9395179
test(e2e): add Explorer project-grouping suite
tkislan Jul 1, 2026
05fc076
fix(e2e): open the workspace folder reliably across multiple suites
tkislan Jul 1, 2026
4615f56
test(e2e): add active-notebook status bar suite
tkislan Jul 1, 2026
97e433a
test(e2e): add notebook-management command suite
tkislan Jul 1, 2026
7fba16e
test(e2e): add integrations UI suite
tkislan Jul 1, 2026
ebef08b
test(e2e): add project-rename fan-out suite
tkislan Jul 1, 2026
fc7c4eb
test(e2e): add init-only file edge-case suite
tkislan Jul 1, 2026
f38f3b0
test(e2e): add split-prompt safety suite
tkislan Jul 1, 2026
e6cfcda
test(e2e): add snapshots suite
tkislan Jul 1, 2026
892c625
test(e2e): add environment suite
tkislan Jul 1, 2026
af467d4
test(e2e): implement G2 — env delete stops a closed notebook's server
tkislan Jul 2, 2026
54b5592
fix(deepnote): honour files.enableTrash when deleting a notebook
tkislan Jul 2, 2026
683b87d
test(e2e): strengthen assertions flagged by review (F1-F3, F6-F7)
tkislan Jul 2, 2026
d82c185
docs(deepnote): trim redundant comments across the PR
tkislan Jul 2, 2026
743b1af
test(e2e): add file-watcher suite
tkislan Jul 2, 2026
f8065e1
refactor(deepnote): update file key handling and clean up comments
tkislan Jul 2, 2026
5502f34
test(deepnote): stub isServerRunning with sinon instead of manual rea…
tkislan Jul 2, 2026
81399f8
fix(deepnote): render init-only files as openable leaves and reveal t…
tkislan Jul 2, 2026
96f4b10
fix(deepnote): key the tree file caches by uri.toString() for cross-p…
tkislan Jul 2, 2026
54cc7e6
fix(deepnote): harden Jupyter import and report partial rename failures
tkislan Jul 2, 2026
ffc3ff8
fix(deepnote): clean up orphaned sibling files when a split write fails
tkislan Jul 2, 2026
c49d234
fix(deepnote): harden kernel and snapshot lifecycle
tkislan Jul 2, 2026
ac49c7d
fix(deepnote): mention notebook ID in the integrations error message
tkislan Jul 2, 2026
f9b4874
test(e2e): extract magic delays and dedup shared helpers
tkislan Jul 2, 2026
2bd8f3e
test(e2e): assert init-only file renders as an openable notebook leaf
tkislan Jul 3, 2026
8994093
fix(deepnote): unregister the old server handle only after a switch s…
tkislan Jul 3, 2026
9534176
fix(deepnote): resolve the init notebook for init-only leaf commands
tkislan Jul 3, 2026
cd0d8e2
fix(deepnote): implement getParent so Reveal in Explorer works
tkislan Jul 3, 2026
36fc854
fix(deepnote): report the accurate imported-notebook count on partial…
tkislan Jul 3, 2026
cc43096
test(e2e): use NOTEBOOK_NAME in the init-only delete toast assertion
tkislan Jul 3, 2026
854c6cb
docs(deepnote): trim comments in the latest review-fix changes
tkislan Jul 7, 2026
f5d7b08
docs: sweep comments across the full PR diff
tkislan Jul 8, 2026
b306773
chore: restore preLaunchTask in launch.json
tkislan Jul 8, 2026
d9c313e
chore(cspell): drop the PR's dictionary additions and reword instead
tkislan Jul 8, 2026
67ca8e7
docs: revert comment churn on unchanged code
tkislan Jul 8, 2026
14769f9
test(deepnote): type the server-starter test's private access through…
tkislan Jul 8, 2026
5c74813
test(deepnote): replace force casts with typed seams across the PR's …
tkislan Jul 8, 2026
a90c632
refactor(deepnote): shrink test mirrors — publicize helper, extract b…
tkislan Jul 9, 2026
951daf6
refactor(deepnote): extract ExecutionMetadataTracker from SnapshotSer…
tkislan Jul 9, 2026
ea42807
refactor(deepnote): extract IServerHandleRegistry from the kernel aut…
tkislan Jul 9, 2026
72677c4
test(deepnote): use deepStrictEqual for tracker summary assertions
tkislan Jul 9, 2026
ffd1bc7
test(deepnote): replace runtime-core inline mock with a typed mock mo…
tkislan Jul 11, 2026
aad512a
test(deepnote): drive unit tests through public seams, remove interna…
tkislan Jul 13, 2026
0f91bd7
chore(deepnote): server-config handle keying, canonical DeepnoteFile,…
tkislan Jul 13, 2026
951ba87
style(deepnote): reword 'unstubbed' comments to pass spell check
tkislan Jul 13, 2026
818bde0
Merge remote-tracking branch 'origin/main' into tk/single-notebook
tkislan Jul 13, 2026
ad5b594
refactor(deepnote): replace inline start function with direct serverS…
tkislan Jul 13, 2026
9dc85df
refactor(deepnote): unify tree item structure with extra property
tkislan Jul 13, 2026
f1d6627
chore(deepnote): remove unused DeepnoteKernelStatusIndicator
tkislan Jul 13, 2026
4a8f5ae
refactor(deepnote): replace notebook URI string conversion with getNo…
tkislan Jul 13, 2026
e936f59
refactor(deepnote): simplify DeepnoteInitNotebookRunner interface
tkislan Jul 13, 2026
9b9ece1
refactor(deepnote): import platform file helpers directly, drop re-ex…
tkislan Jul 13, 2026
b9086c1
refactor(deepnote): read snapshot files via readDeepnoteProjectFile
tkislan Jul 13, 2026
48a3098
test(deepnote): count e2e notebooks via schema parse instead of regex
tkislan Jul 13, 2026
f732f8f
refactor(deepnote): drop deprecated DeepnoteProject alias for Deepnot…
tkislan Jul 13, 2026
9d0a0fa
fix(deepnote): clone integrations per cached sibling to prevent share…
tkislan Jul 13, 2026
097d478
test(deepnote): assert exact notebook pair in snapshot save stubs
tkislan Jul 13, 2026
13af342
feat(deepnote): add .deepnote.env.yaml integrations file loader
tkislan Jul 14, 2026
baca484
feat(deepnote): merge .deepnote.env.yaml configs into SQL integration…
tkislan Jul 14, 2026
bc9e7e5
feat(deepnote): restart toolkit server when integration env files change
tkislan Jul 14, 2026
7843ac3
feat(deepnote): register env-file integrations services + add injecti…
tkislan Jul 14, 2026
1a23218
test(deepnote): add shared DeepnoteFile fixtures and adopt across tests
tkislan Jul 14, 2026
c46572e
refactor(deepnote): extract shared flushNotebookDocumentIfDirty guard
tkislan Jul 14, 2026
193c0c8
fix(deepnote): save open dirty notebooks before rename to prevent edi…
tkislan Jul 14, 2026
b7ec400
fix(deepnote): persist integration changes to every sibling file
tkislan Jul 14, 2026
19ab61a
fix(deepnote): roll back split side effects and report failures accur…
tkislan Jul 14, 2026
201f146
fix(deepnote): scope snapshot discovery to the notebook before the fi…
tkislan Jul 14, 2026
9689d5c
chore(deepnote): reword the split prompt to flag the legacy layout
tkislan Jul 14, 2026
2f3e1d7
fix(deepnote): keep Add Notebook from collapsing the tree and compoun…
tkislan Jul 15, 2026
9db519b
refactor(deepnote): inject DeepnoteTreeDataProvider into the explorer
tkislan Jul 15, 2026
bd84273
chore(deepnote): reword split test comment for spell check
tkislan Jul 15, 2026
9742682
test(deepnote): cover the open-dirty sibling in the project-rename e2e
tkislan Jul 15, 2026
c684269
fix(deepnote): give notebook tree items clearer icons and flag legacy…
tkislan Jul 15, 2026
470c4b8
fix(deepnote): harden env-file restart lifecycle (F1–F3)
tkislan Jul 15, 2026
f22af8c
refactor(deepnote): drop env-file restart prompt sequencing
tkislan Jul 15, 2026
7ac83eb
Merge origin/tk/single-notebook into tk/integrations-yaml-file
tkislan Jul 15, 2026
bb30c7e
refactor(deepnote): tidy env-file e2e comments + type the Cancellatio…
tkislan Jul 15, 2026
e94dff9
feat(deepnote): add local integration-env endpoint + live-refresher
tkislan Jul 16, 2026
26ae4d0
feat(deepnote): point toolkit at the local integration-env endpoint
tkislan Jul 16, 2026
f7fe532
refactor(deepnote): live-refresh integration env instead of restarting
tkislan Jul 16, 2026
9e54033
fix(deepnote): set toolkit project secret + validate endpoint token; …
tkislan Jul 16, 2026
61aba0d
style(deepnote): trim comments on the live env-refresh code
tkislan Jul 16, 2026
a881697
refactor(deepnote): rename IntegrationsEnvVarsEndpoint to UserpodApiE…
tkislan Jul 16, 2026
9f42ffb
fix(deepnote): address code-review findings for env-file integrations
tkislan Jul 17, 2026
14d4db1
Merge origin/main into tk/integrations-yaml-file
tkislan Jul 17, 2026
666d584
fix(deepnote): resolve lint and spell-check CI failures
tkislan Jul 17, 2026
2ed997c
fix(deepnote): reword dedup/unstarted instead of dictionary-ignoring …
tkislan Jul 17, 2026
a700a14
refactor(deepnote): inject env in file-config provider instead of esl…
tkislan Jul 17, 2026
1c6d81f
fix(deepnote): address verified code-review findings for env-file int…
tkislan Jul 18, 2026
07a001f
feat(deepnote): implement integration environment variable injection
tkislan Jul 27, 2026
1a2f039
Code comments cleanup
tkislan Jul 27, 2026
2cfc995
refactor(deepnote): add a web ISqlIntegrationEnvVarsProvider, drop @o…
tkislan Jul 28, 2026
bd47538
refactor(deepnote): drop @optional() from two node-only DI dependencies
tkislan Jul 28, 2026
807d14a
test(deepnote): mock INotebookKernelExecution instead of force-castin…
tkislan Jul 28, 2026
17ad214
test(deepnote): mock IUserpodApiEndpoints instead of hand-rolling a fake
tkislan Jul 28, 2026
5acfcf2
test(deepnote): stub ISqlIntegrationEnvVarsProvider instead of the we…
tkislan Jul 28, 2026
f377f11
test(deepnote): finish swapping the web provider for ts-mockito stubs
tkislan Jul 28, 2026
8b99637
refactor(deepnote): update integration detection to use structured input
tkislan Jul 28, 2026
af3fd66
refactor(deepnote): derive integration status in the UI
tkislan Jul 28, 2026
efe9595
test(deepnote): drive the env file watcher through mocked fs watchers
tkislan Jul 28, 2026
ec9eb19
Minor rename change
tkislan Jul 29, 2026
72a7d19
Merge remote-tracking branch 'origin/main' into tk/integrations-yaml-…
tkislan Jul 29, 2026
cda3156
refactor(deepnote): drop redundant SQL integration env var injection
tkislan Jul 29, 2026
b7dfdf5
fix(deepnote): surface a failed integration endpoint bind to the user
tkislan Jul 29, 2026
02aa582
feat(deepnote): support federated-auth integrations in .deepnote.env.…
tkislan Jul 29, 2026
aba5478
Proper typings for sql lsp connection utils, and remove unnecessary t…
tkislan Jul 29, 2026
6ca3a49
revert(deepnote): drop the authenticate action on federated cell fail…
tkislan Jul 29, 2026
e64b38b
Fix spell check
tkislan Jul 29, 2026
dc9c78f
Refactor SQL LSP connection tests to standardize field names and impr…
tkislan Jul 29, 2026
b2befeb
test(deepnote): cut redundant integration tests and share test fixtures
tkislan Jul 29, 2026
bbeb6c2
refactor(deepnote): simplify pgIntegrationYaml function using js-yaml
tkislan Jul 29, 2026
a473bcb
Minor code comment cleanup, and function renames
tkislan Jul 30, 2026
f21c2fe
fix(deepnote): update tests for getMergedIntegrationConfigs rename
tkislan Jul 30, 2026
d847797
Minor changes
tkislan Jul 30, 2026
3ecb15b
refactor(deepnote): remove the federated-auth orphaned token cleaner
tkislan Jul 30, 2026
ac9c4af
refactor(deepnote): streamline token deletion handling in Integration…
tkislan Jul 30, 2026
ec3ee88
feat(deepnote): show `.deepnote.env.yaml` integrations as read-only
tkislan Jul 30, 2026
00f55b7
fix(deepnote): resolve the notebook for Manage Integrations without f…
tkislan Jul 30, 2026
04e30c7
feat(deepnote): list file-declared integrations in the panel
tkislan Jul 30, 2026
82ee636
feat(deepnote): offer file-declared integrations on SQL blocks and re…
tkislan Jul 30, 2026
e6d24a1
docs(deepnote): correct the integrations specs for the current code
tkislan Jul 30, 2026
e81ee7d
fix(deepnote): share the env-file gate and clear stale diagnostics
tkislan Jul 30, 2026
dad3643
refactor(deepnote): read the env-file gate the way the rest of the ex…
tkislan Jul 31, 2026
08b799a
Summarize code comment
tkislan Jul 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@
"Unconfigured",
"unuse",
"unittests",
"userpod",
"Userpod",
"vegalite",
"venv",
"Venv",
Expand Down
18 changes: 18 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1649,6 +1649,12 @@
"description": "When enabled, outputs are saved to separate snapshot files in a 'snapshots' folder instead of the main .deepnote file.",
"scope": "resource"
},
"deepnote.integrations.envFile.enabled": {
"type": "boolean",
"default": true,
"description": "When enabled, integration credentials are also loaded from a '.deepnote.env.yaml' file (with 'env:' references resolved against '.env' and environment variables) next to the .deepnote file or at the workspace root.",
"scope": "resource"
},
"deepnote.experiments.enabled": {
"type": "boolean",
"default": true,
Expand Down Expand Up @@ -2703,6 +2709,7 @@
"clsx": "^2.1.1",
"cross-fetch": "^3.1.5",
"d3-format": "^3.1.0",
"dotenv": "^17.2.3",
"encoding": "^0.1.13",
"express": "^5.2.1",
"fast-deep-equal": "^2.0.1",
Expand Down
141 changes: 65 additions & 76 deletions specs/INTEGRATIONS_CREDENTIALS.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,28 +397,25 @@ Handles migration of legacy integration configurations to the new `@deepnote/dat

#### 2. **Integration Detector** (`integrationDetector.ts`)

Scans Deepnote projects to discover which integrations are used in SQL blocks.
Lists the integrations a Deepnote project declares, paired with the credentials stored for each.

**Detection Process:**

1. Retrieves the Deepnote project from `IDeepnoteNotebookManager`
2. Scans all notebooks in the project
3. Examines each code block for `metadata.sql_integration_id`
4. Maps Deepnote integration types to `DatabaseIntegrationType` using the project's integration list
5. Checks if each integration is configured (has credentials)
6. Returns a map of integration IDs to their status

**Integration Status:**

- `Connected`: Integration has valid credentials stored
- `Disconnected`: Integration is used but not configured
- `Error`: Integration configuration is invalid
2. Iterates the project's `integrations` roster (ids, names and types only — never credentials)
3. Skips entries whose type is not a configurable `DatabaseIntegrationType`
4. Reads each integration's config from `SecretStorage`, or `null` when nothing is stored
5. Appends `.deepnote.env.yaml` integrations the roster omits, so the panel lists what actually applies at
execution time; a failed lookup leaves the roster-only result rather than blocking the panel
6. Returns a map of integration IDs to their config and declared name/type

**Special Cases:**

- Excludes `deepnote-dataframe-sql` (internal DuckDB integration)
- Only processes code blocks with SQL integration metadata
- Uses project integration metadata to determine integration types
- Integrations configured in `.deepnote.env.yaml` have a `null` config here, since those configs are never
written through `SecretStorage`. They still resolve normally for kernel execution and SQL autocomplete, which
read the merged configs directly, and the panel marks them read-only rather than unconfigured (see below):
`IntegrationWebviewProvider` pairs the detection result with the file-configured ids.

#### 3. **Integration Manager** (`integrationManager.ts`)

Expand All @@ -427,10 +424,6 @@ Orchestrates the integration management UI and commands.
**Responsibilities:**

- Registers the `deepnote.manageIntegrations` command
- Updates VSCode context keys for UI visibility:
- `deepnote.hasIntegrations`: True if any integrations are detected
- `deepnote.hasUnconfiguredIntegrations`: True if any integrations lack credentials
- Handles notebook selection changes
- Opens the integration webview with detected integrations

**Command Flow:**
Expand All @@ -447,17 +440,35 @@ Provides the webview-based UI for managing integration credentials.
**Features:**

- Persistent webview panel (survives defocus)
- Real-time integration status updates
- Real-time updates as credentials are saved or cleared
- Configuration forms for each integration type
- Delete/reset functionality

**Connection Status:**

`IntegrationItem.tsx` derives the status pill from two inputs: `config` (the SecretStorage credentials the panel
can edit) and `isFileConfigured`, which `IntegrationWebviewProvider` computes from
`ISqlIntegrationEnvVarsProvider.getFileConfiguredIntegrationIds()`. That call returns ids only, so neither the
file's config nor its credentials ever reach the webview.

- **"Configured in file"** — `.deepnote.env.yaml` configures this id. Rendered with the connected styling, and
the Configure/Reset/Delete actions are hidden: the panel writes `SecretStorage` only and the file wins the
merge, so those edits would be silent no-ops at runtime. This holds even when SecretStorage also happens to
hold a config for the same id.
- **"Connected"** — SecretStorage holds credentials and no file config overrides them.
- **"Not Configured"** — neither layer configures the integration.

The separate federated-auth pill (BigQuery + `google-oauth`) is independent and tracks whether a refresh token
is stored. It is driven by `tokenStatus` alone, which the extension derives from its own candidate set, so the
Authenticate action stays available for file-configured integrations — exactly the rows that carry no `config`.

**Message Protocol:**

Extension → Webview:

```typescript
// Update integration list
{ type: 'update', integrations: IntegrationWithStatus[] }
{ type: 'update', integrations: DetectedIntegration[] }

// Show configuration form
{ type: 'showForm', integrationId: string, config: IntegrationConfig | null }
Expand Down Expand Up @@ -487,7 +498,7 @@ Main React component that manages the webview UI state.

**State Management:**

- `integrations`: List of detected integrations with status
- `integrations`: List of detected integrations with their stored configs
- `selectedIntegrationId`: Currently selected integration for configuration
- `selectedConfig`: Existing configuration being edited
- `message`: Success/error messages
Expand All @@ -501,7 +512,7 @@ Main React component that manages the webview UI state.
2. Panel shows configuration form overlay
3. User enters credentials
4. Panel sends save message to extension
5. Extension stores credentials and updates status
5. Extension stores credentials
6. Panel shows success message and refreshes list

**Delete Integration:**
Expand All @@ -511,7 +522,7 @@ Main React component that manages the webview UI state.
3. User clicks again to confirm
4. Panel sends delete message to extension
5. Extension removes credentials
6. Panel updates status to "Disconnected"
6. Panel clears the stored config, so the item offers "Configure" again

#### 6. **Configuration Forms**

Expand Down Expand Up @@ -678,55 +689,23 @@ DuckDB (internal):

**Integration Points:**

- Registered as an environment variable provider in the kernel environment service
- Called when starting a Jupyter kernel for a Deepnote notebook
- Environment variables are passed to the kernel process at startup
- Backs the loopback `userpod-api` endpoint (`userpodApiEndpoints.node.ts`), which serves the resolved credentials to `deepnote-toolkit` as `[{name, value}]`
- Queried per request rather than at kernel start, so a kernel always reads the credentials that are current at the moment it asks
- Fires `onDidChangeEnvironmentVariables` event when integration storage changes

#### 8. **SQL Integration Startup Code Provider** (`sqlIntegrationStartupCodeProvider.ts`)

Injects Python code into the kernel at startup to set environment variables.

**Why This Is Needed:**
Jupyter doesn't automatically pass all environment variables from the server process to the kernel process. This provider ensures credentials are available in the kernel's `os.environ`.

**Generated Code:**

```python
try:
import os
# [SQL Integration] Setting N SQL integration env vars...
os.environ['SQL_MY_POSTGRES_DB'] = '{"url":"postgresql://...","params":{},"param_style":"format"}'
os.environ['SQL_MY_BIGQUERY'] = '{"url":"bigquery://...","params":{...},"param_style":"format"}'
# [SQL Integration] Successfully set N SQL integration env vars
except Exception as e:
import traceback
print(f"[SQL Integration] ERROR: Failed to set SQL integration env vars: {e}")
traceback.print_exc()
```

**Execution:**

- Registered with `IStartupCodeProviders` for `JupyterNotebookView`
- Runs automatically when a Python kernel starts for a Deepnote notebook
- Priority: `StartupCodePriority.Base` (runs early)
- Only runs for Python kernels on Deepnote notebooks

### Toolkit Integration

#### 9. **How Credentials Are Exposed to deepnote-toolkit**
#### 8. **How Credentials Are Exposed to deepnote-toolkit**

The `deepnote-toolkit` Python package reads credentials from environment variables to execute SQL blocks.

**Flow:**

1. Extension detects SQL blocks in notebook
2. Extension retrieves credentials from secure storage
3. Extension converts credentials to JSON format
4. Extension injects credentials as environment variables (two methods):
- **Server Process**: Via `SqlIntegrationEnvironmentVariablesProvider` when starting Jupyter server
- **Kernel Process**: Via `SqlIntegrationStartupCodeProvider` when starting Python kernel
5. `deepnote-toolkit` reads environment variables when executing SQL blocks
1. Extension starts the Jupyter server with the integration endpoint env vars applied by `applyIntegrationEndpointEnv` (`DEEPNOTE_RUNTIME__ENV_INTEGRATION_ENABLED`, `DEEPNOTE_RUNTIME__RUNNING_IN_DETACHED_MODE`, `DEEPNOTE_RUNTIME__WEBAPP_URL`, `DEEPNOTE_RUNTIME__PROJECT_SECRET`, `DEEPNOTE_PROJECT_ID`) — no credentials are injected by the extension
2. At kernel init, `deepnote-toolkit`'s `set_integration_env()` calls the extension's loopback `userpod-api` endpoint at `DEEPNOTE_RUNTIME__WEBAPP_URL`, authenticating with the per-project bearer token in `DEEPNOTE_RUNTIME__PROJECT_SECRET`
3. The endpoint resolves the project's integrations via `SqlIntegrationEnvironmentVariablesProvider` — reading secure storage and converting the configs to `SQL_*` JSON values — and returns them as `[{name, value}]`
4. Toolkit sets the returned variables into the kernel's `os.environ`
5. `deepnote-toolkit` reads those environment variables when executing SQL blocks
6. Toolkit creates database connections using the credentials
7. Toolkit executes SQL queries and returns results

Expand Down Expand Up @@ -760,21 +739,31 @@ User → IntegrationPanel (UI)
### Execution Flow

```text
Deepnote server starts
→ applyIntegrationEndpointEnv()
→ Awaits UserpodApiEndpoints readiness, reads its loopback baseUrl
→ Resolves the project id from the .deepnote file
→ Sets DEEPNOTE_RUNTIME__* + DEEPNOTE_PROJECT_ID on the server process
→ Jupyter server process starts with those env vars (no credentials)

User executes SQL cell
→ Kernel startup triggered
→ SqlIntegrationEnvironmentVariablesProvider.getEnvironmentVariables()
→ Identifies Deepnote project from notebook resource
→ Retrieves project integrations from notebook manager
→ Fetches configured credentials from IntegrationStorage
→ Adds internal DuckDB integration
→ Calls getEnvironmentVariablesForIntegrations() from @deepnote/database-integrations
→ Converts configs to environment variable format
→ Generates SQL_* environment variables
→ Returns environment variables
→ Environment variables passed to Jupyter server process
→ SqlIntegrationStartupCodeProvider.getCode()
→ Generates Python code to set os.environ
→ Startup code executed in kernel
→ deepnote-toolkit set_integration_env()
→ GET {DEEPNOTE_RUNTIME__WEBAPP_URL}/userpod-api/{projectId}/integrations/environment-variables
Authorization: Bearer {DEEPNOTE_RUNTIME__PROJECT_SECRET}
→ UserpodApiEndpoints handles the request
→ Verifies the per-project bearer token
→ Finds the open deepnote notebook(s) for that project id
→ SqlIntegrationEnvironmentVariablesProvider.getEnvironmentVariables()
→ Retrieves project integrations from notebook manager
→ Fetches configured credentials from IntegrationStorage
→ Adds internal DuckDB integration
→ Calls getEnvironmentVariablesForIntegrations() from @deepnote/database-integrations
→ Converts configs to environment variable format
→ Generates SQL_* environment variables
→ Returns environment variables
→ Responds with [{name, value}]
→ Toolkit sets them into the kernel's os.environ
→ deepnote-toolkit reads os.environ['SQL_*']
→ Toolkit executes SQL query
→ Results returned to notebook
Expand Down
Loading
Loading