Skip to content

Seal the release summary sandbox: no toolchain roots or skills, only node - #2243

Merged
JacobStephens2 merged 2 commits into
mainfrom
issue-2230
Nov 15, 2026
Merged

JacobStephens2 merged 2 commits into
mainfrom
issue-2230

Conversation

@JacobStephens2

@JacobStephens2 JacobStephens2 commented Nov 15, 2026 •

Copy link
Copy Markdown
Owner

Summary

The release summary Session's sandbox used to bind every host toolchain root (~/.cargo, ~/.rustup, ~/.nvm and their env overrides) and the skills folder. That broke Spec #2054's promise of no host filesystem read access. It is now sealed. Other Sessions keep today's binds.

 pub(crate) struct Request<'a> {
-    pub skills_dir: &'a Path,
+    pub host: Host<'a>,   // Tools { skills_dir } | Sealed
 }

 prepare(request)
-  bind skills_dir; toolchains_into(home)
+  match request.host
+    Tools { skills_dir } => bind skills_dir; toolchains_into(home)   // Trials, Graders, Process sessions
+    Sealed               => node_into(harness binary)                // release summary
   ...
-  conceal_toolchain_credentials
+  if Tools: conceal_toolchain_credentials

node_into reads the Harness's #! line:

  • #!/abs/node: binds that one file read-only at that path.
  • #!/usr/bin/env node: binds only the resolved host node at its canonical path, with its directory first on PATH.
  • Anything else (native binary, other interpreter): binds nothing.

If node can't be resolved, prepare fails with Unavailable, so the existing fallback (patch plus GitHub generated notes) applies. The binds are never widened.

ADR 0013's exception and the manual are unchanged, as the issue's Decision asks.

Evidence

Execution evidence

Cause: src/release/summary.rs write built its sandbox with sandbox::prepare, which always called toolchains_into. That bound every existing toolchain root read-only, so the summary Harness could read anything under ~/.nvm.

  • Before (at ea4bd94f, with the issue's test added): cargo test --locked --test release -- release_summary_sandbox_binds_no_host_toolchain_directories
    thread 'native::release_summary_sandbox_binds_no_host_toolchain_directories' panicked at tests/release/native.rs:1581:5:
    summary Session read a host toolchain file: ... Host file readable ...
    test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 148 filtered out
    
    After: the same command:
    test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 148 filtered out; finished in 0.44s
    
  • npm-installed Harness: cargo test --locked --test release -- native::release_summary_ runs both release tests:
    test native::release_summary_sandbox_binds_only_node_for_an_npm_installed_harness ... ok
    test native::release_summary_sandbox_binds_no_host_toolchain_directories ... ok
    test result: ok. 2 passed; 0 failed
    
    If write is switched back to the old binds (Host::Tools), both tests fail.
  • Unit tests: cargo test --locked --bin thirdshift sandbox::tests gives 30 passed. This includes a_harness_names_node_only_in_its_interpreter_line and a_sealed_harness_binds_its_node_alone_or_fails; the second covers an unresolvable node failing with needs node.
  • Affected tests: scripts/affected-tests main selected the full suite.
    • On the first commit: PASS cargo test (774.60s).
    • After the review fixes: two unrelated tests failed intermittently, each in a different run, and pass on rerun:
      • experiments release::native_release_waits_for_leak_decisions_before_any_push failed with "Experiment is already running … lock acquisition failed"; it then passed 3 of 3 times.
      • process findings::fixing_dispatches_each_reproduced_finding_and_keeps_unreproduced_findings_private passed 2 of 3 times. It runs through sandbox::for_trial, which keeps the unchanged Host::Tools path.
    • Every other target in cargo test --locked --no-fail-fast passed.

Visual evidence

None: no UI changes.

Merge Danger

Door: two-way

Reverting restores the old binds.

Blast Radius: release-summaries

Only the release summary Session changes. Its worst case is a Harness whose node can't be resolved: release summaries then fall back to patch plus GitHub generated notes instead of a written summary. Trials, Graders and Process sessions use Host::Tools and are unchanged.

Unaddressed findings

Standards

Spec

None.

Review coverage: both reviewers read every changed file (src/release/summary.rs, src/sandbox.rs, tests/release/native.rs).

Closes #2230

Built with claude 2.1.314 · opus · default effort

Security review outcome

No unaddressed introduced findings.

…only node

The release summary Session promised no host filesystem read access, but the
shared sandbox bound ~/.cargo, ~/.rustup, ~/.nvm and the skills folder. A
sealed Host binds none of them, only the node an npm-installed Harness names
in its #! line; an unresolvable node fails the Session so the generated-notes
fallback applies.

Closes #2230
@JacobStephens2
JacobStephens2 merged commit 52ce095 into main Nov 15, 2026
28 checks passed
@JacobStephens2
JacobStephens2 deleted the issue-2230 branch November 15, 2026 03:32
@JacobStephens2 JacobStephens2 mentioned this pull request Nov 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Release summary sandbox can read host toolchain directories

1 participant