WasmSandbox::run_impl calls prepare_for_run before entering the guest, and in 0.7.0 that is clear_output_files:
pub fn prepare_for_run(&mut self) -> Result<()> {
self.clear_output_files()
}
So the only directory a guest may write to, output_dir mounted at /output with DirPerms::MUTATE, is emptied on the way into every run. A file the host places there before the first run is deleted before guest code sees it, and a file the guest creates is deleted by the next run. input_dir is read-only, so it cannot serve a workload that reads, edits and deletes its inputs.
Reproduced with the published Python SDK, hyperlight-sandbox 0.7.0 with backend-wasm 0.7.0 and python-guest 0.7.0, on Windows 11 x86-64 with WHP and CPython 3.13:
import os, pathlib, tempfile
from hyperlight_sandbox import Sandbox
d = tempfile.mkdtemp()
pathlib.Path(d, "staged.txt").write_text("hello from the host")
sb = Sandbox(output_dir=d)
r = sb.run("print(open('/output/staged.txt').read())")
print(r.stderr.strip().splitlines()[-1], os.listdir(d))
sb.run("open('/output/made-by-guest.txt', 'w').write('x')")
print(os.listdir(d))
r = sb.run("import os; print(os.path.exists('/output/made-by-guest.txt'))")
print(r.stdout.strip(), os.listdir(d))
FileNotFoundError: [Errno 44] No such file or directory: '/output/staged.txt' []
['made-by-guest.txt']
False []
I understand the clear is deliberate: it is where the cached quota accounting is reset, and a run should not inherit a previous run's leftovers by default. I am not asking for the default to change.
What I am asking for is an opt-in policy, selected at build time and off by default, under which prepare_for_run leaves the mutable directory alone. Two properties matter more than the spelling:
- Quotas are reconciled from disk, not from the cache. With preservation on, the file count and byte totals must be recomputed from the real directory before guest entry, so a host-staged file counts against the limits and an over-quota directory fails the run before the guest starts rather than after it has partly written.
- Reset stays explicit. Snapshot restore or a dedicated reset call is where the directory is cleared under this policy, so an integrator can still return a sandbox to a known state on purpose. Preservation changes what happens on entry, not what restore means.
A SandboxBuilder option such as .preserve_output_files(true), exposed on the Python Sandbox constructor beside output_dir, would be enough. If you would rather express it as a file-lifetime enum, that also works for us.
Alternatives I considered and would rather not ship: copying inputs in through a hidden guest prelude, which invents a second file lifecycle the runtime does not validate; staging to the read-only input_dir, which cannot be edited or deleted by the guest; and a privately patched native wheel, which leaves the published dependency set uninstallable. Happy to contribute the change if the shape is agreed.
WasmSandbox::run_implcallsprepare_for_runbefore entering the guest, and in 0.7.0 that isclear_output_files:So the only directory a guest may write to,
output_dirmounted at/outputwithDirPerms::MUTATE, is emptied on the way into every run. A file the host places there before the first run is deleted before guest code sees it, and a file the guest creates is deleted by the next run.input_diris read-only, so it cannot serve a workload that reads, edits and deletes its inputs.Reproduced with the published Python SDK,
hyperlight-sandbox0.7.0 with backend-wasm 0.7.0 and python-guest 0.7.0, on Windows 11 x86-64 with WHP and CPython 3.13:I understand the clear is deliberate: it is where the cached quota accounting is reset, and a run should not inherit a previous run's leftovers by default. I am not asking for the default to change.
What I am asking for is an opt-in policy, selected at build time and off by default, under which
prepare_for_runleaves the mutable directory alone. Two properties matter more than the spelling:A
SandboxBuilderoption such as.preserve_output_files(true), exposed on the PythonSandboxconstructor besideoutput_dir, would be enough. If you would rather express it as a file-lifetime enum, that also works for us.Alternatives I considered and would rather not ship: copying inputs in through a hidden guest prelude, which invents a second file lifecycle the runtime does not validate; staging to the read-only
input_dir, which cannot be edited or deleted by the guest; and a privately patched native wheel, which leaves the published dependency set uninstallable. Happy to contribute the change if the shape is agreed.