Skip to content

fix(execution): create-parent-aware WASI path resolution so wasm commands can create files#195

Merged
NathanFlurry merged 5 commits into
mainfrom
stack/fix-execution-create-parent-aware-wasi-path-resolution-so-wasm-commands-can-create-files-yxnnkzxw
Jul 2, 2026
Merged

fix(execution): create-parent-aware WASI path resolution so wasm commands can create files#195
NathanFlurry merged 5 commits into
mainfrom
stack/fix-execution-create-parent-aware-wasi-path-resolution-so-wasm-commands-can-create-files-yxnnkzxw

Conversation

@NathanFlurry

Copy link
Copy Markdown
Member

WASM commands could read but often not CREATE files: path_open(O_CREAT) and
path_create_directory picked the wrong guest mapping for cwd-relative and
absolute-descendant targets (e.g. git init writing /repo/.git/HEAD, shell
redirects like echo x > /tmp/r/a.txt), opening a host path whose parent did
not exist and surfacing WASI ENOENT.

  • wasi-module runner: create flows now resolve against a mapping whose parent
    actually exists (create-parent-aware cwd vs root disambiguation, absolute
    and root-relative variants); cwd preopen is keyed by the guest cwd mount
    instead of '.'.
  • git wasm shim: recursive 'git add .' (excluding .git), -q for init, -c
    overrides, rev-parse HEAD — enough for the init/add/commit/rev-parse flow.
  • Ecosystem git_init_commit bench gate now checks the real resolved commands
    dir instead of the stale registry/software/git/wasm path; row reports real
    numbers.
  • registry git wasmvm suite 19/19; new shell-redirect regression test.

Guest https.get to an in-guest TLS server failed with ERR_AGENTOS_NODE_SYNC_RPC:
the client upgrade leaves the rustls handshake incomplete (looping would deadlock
the guest thread that must service the server-side upgrade), so the first write
hit WouldBlock from the loopback transport and surfaced as a fatal sync-RPC error.

- Buffer plaintext writes on loopback TLS sockets while the handshake is pending
  (bounded 4 MiB, warn at 80%, typed error on overflow); the TLS reader thread
  drives the handshake with a short poll timeout, flushes the buffer on
  completion, enforces TLS_HANDSHAKE_TIMEOUT, and honors deferred shutdown.
- Interrupt flags on the loopback transport let a direct write reclaim the
  stream mutex from the reader without waiting out its poll.
- Bridge: https.createServer now actually upgrades accepted sockets to TLS
  (options were previously discarded); client secureConnect defers to a
  macrotask without double-starting the read pump; first-read wake scheduling
  no longer requires bench metrics to be enabled; localAddress/localPort flow
  through connect.
- New net/tls_loopback_get bench op (guest+node lanes, explicit unsupported
  native/wasm reasons) and engine support for unsupported-lane rendering.
- Regression tests: loopback https round-trip; pending-write buffer cap.
… sync-RPC wait

Any guest http2.createServer().listen() wedged the whole guest: Http2Server/
Http2Session._retain() issued a long-lived net.http2_*_wait sync RPC, and guest
sync-RPC servicing is serialized, so the in-flight wait starved every later RPC
(including the listen response the isolate was blocked on).

- _retain() now drives bounded net.http2_*_poll calls (wait_ms=0) on a timer
  loop and dispatches polled events through http2Dispatch; the loop stops on
  release/close/terminal events.
- New regression test: guest h2c listen -> request -> response round-trip.
- New net/http2_loopback_get matrix op (node + guest lanes, explicit
  unsupported native/wasm reasons) with body verification.
…ilesystem

Guest write-then-import failed: fs.writeFileSync goes through the process'
mapped host shadow (reconciled to the kernel only at exit), while module
resolution read vm.kernel directly — so files the running guest wrote were
invisible to import(), and resolution misses were negative-cached forever.

- Module resolution for live JS processes now reads through the process shadow
  first (same confined mapped-runtime open helpers as the fs RPCs), falling
  back to the kernel VFS.
- The session-thread direct module reader still answers host-dir hits first,
  but forwards misses to the sidecar instead of answering not-found locally.
- Negative resolution/package-json cache entries are kept only for stable
  node_modules paths, so retry-after-miss works for app paths while the
  node_modules hot path stays cached.
- Restored the fs/module_import_fresh matrix op and added a write-then-import
  regression test.
…ands can create files

WASM commands could read but often not CREATE files: path_open(O_CREAT) and
path_create_directory picked the wrong guest mapping for cwd-relative and
absolute-descendant targets (e.g. git init writing /repo/.git/HEAD, shell
redirects like echo x > /tmp/r/a.txt), opening a host path whose parent did
not exist and surfacing WASI ENOENT.

- wasi-module runner: create flows now resolve against a mapping whose parent
  actually exists (create-parent-aware cwd vs root disambiguation, absolute
  and root-relative variants); cwd preopen is keyed by the guest cwd mount
  instead of '.'.
- git wasm shim: recursive 'git add .' (excluding .git), -q for init, -c
  overrides, rev-parse HEAD — enough for the init/add/commit/rev-parse flow.
- Ecosystem git_init_commit bench gate now checks the real resolved commands
  dir instead of the stale registry/software/git/wasm path; row reports real
  numbers.
- registry git wasmvm suite 19/19; new shell-redirect regression test.
@NathanFlurry

Copy link
Copy Markdown
Member Author

Stack for rivet-dev/secure-exec

Get stack: forklift get 195
Push local edits: forklift submit
Merge when ready: forklift merge 195

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.

1 participant