fix(runtime): withhold the history view and root anchor from runtimes - #932
Merged
Merged
Conversation
The workspace announces its mount table to sandboxed runtimes through the resolver attached at construction, and TypeScript filters that list (sandboxVisibleMounts): the history view is a shell surface rather than a place to put files, and the synthetic root anchor is a mount nobody asked for. Python handed the unfiltered Ops list, so a WASI guest preopened /.bash_history and every runtime reported a claim on the anchor -- while PrefixResolver's own docstring already promised the filtered behavior. PolicyContext.mounts follows the same resolver in both languages, so a policy now sees the same list too. Both withholds are pinned by a probe runtime in each language (the python pins verified red against the old wiring), plus a guard that an explicit root mount is still forwarded: withheld for being synthetic, never for being /. Also writes the session-blindness doctrine down on LanguageRuntime in both languages: the doors are the data plane and the name plane, and there is deliberately no session door -- a guest env write dies with the run and can neither trip nor bypass a pre_session rule. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
|
@codex review |
|
Codex Review: Didn't find any major issues. You're on a roll. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
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.
What
Python announced the unfiltered mount table to sandboxed runtimes; TypeScript filters it (
sandboxVisibleMounts). This PR ports the filter and pins it in both languages, and writes the runtime tier's session-blindness doctrine down onLanguageRuntime.The divergence
The workspace hands every
LanguageRuntimea resolver atattachtime — the mount prefixes a guest may see (WASI preopens one directory per mount;RuntimeVFS.prefixes()/mount_ofroute on them;PolicyContext.mountsis stamped from the same resolver).workspace.tssandboxVisibleMounts) withholds two prefixes, neither for being/: the history view (a shell surface, not a place to put files) and the synthetic root anchor (a mount nobody asked for — the workspace adds it so arg-less commands resolve). An explicit root mount is forwarded like any other prefix.self._ops.mount_prefixesunfiltered, so a WASI guest preopened/.bash_historyand every runtime reported a claim on the anchor.PrefixResolver's own docstring already promised "a sandbox-filtered list for the runtimes" — the docstring described TS, not Python.Changes
workspace.py: newWorkspace._sandbox_visible_mounts()(live read off the registry, mirroring TS), wired into the onePrefixResolverconstruction.PolicyContext.mountsfollows the same resolver in both languages, so policies now see the same list too.tests/workspace/test_runtime_binding.py: aResolverProberuntime captures the attached resolver; three pins — history withheld, synthetic anchor withheld, explicit root forwarded (guards against over-filtering). The two "withholds" pins were verified red against the old wiring.workspace.test.ts: the same three pins. TS behavior was already correct but had no direct test.language.py/language.ts: doctrine paragraph — the doors are the data plane (dispatch) and the name plane (resolver), and the list is complete on purpose: there is no session door. A guest env write lands on the guest's own copy and dies with the run, so guest code can neither trip nor bypass apre_sessionrule. A runtime that ever needs session state must take a gatedSessionView.What this PR deliberately does not do
This came out of a design review of how state planes reach the runtime tier (D4: "runtimes have no doors record"). The survey falsified the record:
attach(dispatch, resolver)already is the two doors — data plane and name plane — mirrored field-for-field across languages, withMountResolverdocumented as "the name-plane questions a runtime asks" and growth landing as protocol methods fed by injected sources, not signature changes. ARuntimeDoorsrecord would additionally have Python-only payload (the session/recorder re-bind exists only where guest calls cross threads; TS has no ambient capture at all), violating the parity it was meant to serve. What the survey did surface is this filter divergence, which is the PR.🤖 Generated with Claude Code