fix(runtimed): unblock headless conda/uv kernels stuck on AwaitingTrust#2760
Draft
rgbkrk wants to merge 3 commits into
Draft
fix(runtimed): unblock headless conda/uv kernels stuck on AwaitingTrust#2760rgbkrk wants to merge 3 commits into
rgbkrk wants to merge 3 commits into
Conversation
The MCP `create_notebook` + dep flow could park a kernel in
`awaiting_trust` indefinitely when any explicit dep was missing from the
local allowlist. Headless callers (the nteract MCP gremlins, Claude
Code) have no way to click through a trust dialog, so the notebook just
sat there until the request timed out.
Three pieces:
- `DEFAULT_DATA_PACKAGES` now includes `numpy` and `scipy`. They were
the foundational deps the seed list missed; adding them closes the
most common case for fresh installs against both the `pypi` and
`conda` ecosystems. The pool-package hash includes the list, so
existing pool envs invalidate and rebuild on next daemon start.
- `CreateNotebook` auto-seeds the allowlist with the deps it was
handed. An MCP tool call that explicitly passes
`dependencies: ["pandas", ...]` is itself the consent event — by
the time bytes hit the daemon, the caller (or the Claude Code UI
approving the tool call) has already opted in. Notebooks loaded from
disk via `OpenNotebook` go nowhere near this code and still gate on
the regular trust dialog, so a sketchy dep like `canhazpassword`
pulled from a downloaded notebook is still surfaced for review.
- `runtime` info in MCP responses (`create_notebook`, `connect_notebook`,
etc.) now carries the `trust` block from `RuntimeState.trust` and,
when the kernel is parked at `AwaitingTrust`, a `next_action` hint
pointing to `manage_dependencies({trust: true})`. Tool schemas are
unchanged — only response shapes get richer.
Contributor
Codex review on #2760 caught that the seed helper was also running on the session-restore branch (cell_count > 0 at start). In that case the request's `dependencies` array is ignored, but the seed still read the doc and would have approved whatever the restored notebook declared — letting a CreateNotebook handshake silently grant trust to a persisted dep list the caller never opted into. Gate the seed on `freshly_created`: only true when `create_empty_notebook` actually populated the doc from the request deps. Restore paths fall back to the regular trust-dialog flow.
`test_config` was leaving `trusted_packages_db_path` at the
`DaemonConfig::default()` value, which points at the shared
`daemon_base_dir().join("trusted-packages.sqlite")`. Any test
that approved a dep (trust dialog OR the new `CreateNotebook`
auto-seed path) leaked rows across the whole suite. The
`test_untrusted_*` tests started false-passing on dev machines
and false-failing on CI depending on what ran before them.
Scope the db under each test's `TempDir`. Surfaces today as a
fix for the `test_untrusted_launch_and_sync_environment_are_daemon_rejected`
flake against the auto-trust seed, but the underlying gap predates
this PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Found via headless gremlin runs against the latest nightly: any MCP
create_notebookcall that included a dep missing from the local allowlist parked the kernel atawaiting_trustforever. Headless callers (nightly gremlins, Claude Code) have no way to click through a trust dialog, so the notebook just sat there until the request timed out.Three pieces of the fix.
Design decisions
Why
numpyandscipy— both are foundational deps for any data persona, but neither was in the seed list. On my machine the gremlin's request forconda + [pandas, numpy, matplotlib]failed because the audit log showed everypypi:*user-approval over the past month but zeroconda:*user-approvals — no one's ever clicked through a conda trust dialog, soconda:numpynever made it into the allowlist. Adding them toDEFAULT_DATA_PACKAGESseeds both ecosystems on daemon start. Pool envs already pullednumpytransitively viapandas/matplotlib, so the only meaningful install delta isscipy.Why auto-trust on
CreateNotebookdeps — when an MCP tool call passesdependencies: ["pandas", ...]explicitly, the tool call itself is the consent event. The Claude Code UI (or whatever MCP host) approves the tool invocation; by the time bytes hit the daemon the caller has already opted in to those deps.OpenNotebookgoes nowhere near this code — a downloaded notebook with a sketchy dep likecanhazpasswordstill surfaces through the regular trust dialog.Why a
next_actionhint instead of changing tool schemas — the existingmanage_dependenciestool already acceptstrust: trueto grant approval. The gremlin didn't reach for it because theawaiting_trustresponse was a dead end. Surfacing the trust state + remediation hint inruntime.trustandruntime.next_actionmakes the available path visible to any caller looking at the response. Tool descriptions are untouched, so no tool-cache update needed.Behavioral coverage
create_notebook+ explicit deps, no prior trustmcp_create_notebookcreate_notebook+ no depsNoDependenciesshort-circuit, no seedcreate_notebook+ already-approved depsON CONFLICT DO NOTHING)open_notebookof a downloaded.ipynbawaiting_trustuntil human approvesawaiting_trustruntime.trust+runtime.next_actionpointing atmanage_dependencies({trust: true})Pool env impact
DEFAULT_DATA_PACKAGESparticipates in the pool-package hash (expected_pool_package_hash). The const change invalidates existing pool envs; next daemon start rebuilds them with the new list.numpywas already a transitive dep ofpandas/matplotlib, so the practical install delta isscipy(~50MB per env).Test plan
cargo check -p runtimed -p runt-mcpcargo test -p runtimed --lib trusted_packages(10/10)cargo test -p runtimed --lib daemon(100/100)cargo test -p runtimed --lib notebook_sync_server(291/291, includes the two new auto-trust tests)cargo test -p runt-mcp --lib(120/120)Tests added
test_seed_trust_from_doc_metadata_promotes_to_trusted— populates the doc with explicit deps, calls the helper, verifies the trust check now resolves toTrusted.test_seed_trust_from_doc_metadata_skips_when_no_deps— empty dep list short-circuits viaNoDependenciesand doesn't write phantom rows to the allowlist.