Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rivet-dev/secure-exec
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.3.1
Choose a base ref
...
head repository: rivet-dev/secure-exec
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.3.2
Choose a head ref
  • 6 commits
  • 55 files changed
  • 2 contributors

Commits on Jun 25, 2026

  1. fix(runtime): strip module shebang, stream large http responses, reje…

    …ct oversized vm.fetch by content-length (#130)
    
    - v8-runtime: strip a leading #!shebang in build_module_source so the patched
      Claude agent SDK (which begins with #!/usr/bin/env node) parses in guest V8
      instead of SyntaxError-crashing the adapter on session/new (host Node strips
      it; the guest loader did not).
    - v8-bridge: ServerResponseBridge streams a single res.end(body) to the
      connection socket in bounded slices (incremental byteLength) instead of
      buffering the whole body + its serialize/transmit copies, which tripped the
      isolate heap-limit OOM guard on multi-MB responses. Socket-backed path only;
      loopback http unchanged.
    - sidecar: vm.fetch rejects a response whose declared Content-Length exceeds
      VM_FETCH_BUFFER_LIMIT_BYTES before stalling on a body it cannot stream through
      the bounded kernel socket buffer; keeps the per-VM configured-limit payload
      check intact.
    - limits-inventory: classify DEFAULT_HEAP_LIMIT_MB (policy) and
      MAX_V8_USERLAND_CODE_BYTES (invariant).
    
    Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
    NathanFlurry and claude authored Jun 25, 2026
    Configuration menu
    Copy the full SHA
    2eb88d8 View commit details
    Browse the repository at this point in the history
  2. fix(sidecar): shadow-walk skip + bound undici pool to stop the net-br…

    …idge leak (#128)
    
    Three native-sidecar fixes behind long-lived VM latency/stall.
    
    1) Read-side shadow-tree re-walk
    Read-side guest fs ops (Exists/Stat/Lstat/ReadFile/Pread) reconcile the host
    shadow tree into the kernel VFS, re-reading+re-writing EVERY file on EVERY op
    (O(whole tree), super-linear). Add an rsync-style (size,mode,mtime) lstat skip for
    unchanged files. Test read_side_ops_skip_unchanged_shadow_files: warm read over an
    unchanged 800-file tree >4x cheaper than cold (cold=22.7s, warm=28ms debug).
    
    2) EventEmitter shim: spurious MaxListenersExceededWarning
    ensureEventEmitterInitialized() defaulted _maxListenersWarned but not
    _maxListeners, so emitters that acquire _events outside our ctor (undici's
    Client/Pool/Agent) had _maxListeners=undefined and 'total <= undefined' warned on
    the FIRST listener. Default _maxListeners so the threshold is meaningful.
    
    3) undici client-per-request leak (the real net-bridge leak)
    The bridge's UndiciAgent was created with an UNBOUNDED per-origin pool. Requests
    that overlap while clients are still connecting each find every client kNeedDrain
    and spawn a fresh Client+socket -- and for HTTPS the LLM path is HTTP/2 (ALPN), so
    each spawn is a whole new h2 session. The synchronous bridge reads widen that
    connect window (the #122 per-payload macrotask yield only helps h1 same-socket
    reuse, nothing for the h2 connect-window herd). Over a long many-call turn the
    abandoned clients accumulate connect/close/drain/error/finish/readable/end/
    terminated listeners without bound -> http2 degradation -> 'Request was aborted.'
    Bound connections (6, browser-like; h2 multiplexes within each) so excess requests
    queue on existing clients instead of spawning new ones.
    
    Test keepalive_no_listener_leak now drives CONCURRENT requests (the trigger) and
    asserts the host-side connection count stays bounded: 160 requests over 6
    connections with the cap vs 16 (2x concurrency) without it. A process.on('warning')
    handler surfaces any MaxListenersExceededWarning to stderr (the warning alone is
    insufficient -- leaked listeners spread across per-client emitters).
    
    Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
    NathanFlurry and claude authored Jun 25, 2026
    Configuration menu
    Copy the full SHA
    1225be9 View commit details
    Browse the repository at this point in the history
  3. fix(execution): size the wasm runner V8 heap so warmup stops OOMing (#…

    …129)
    
    The wasm runner isolate is started with JavascriptExecutionLimits::default(), so
    its V8 heap falls back to isolate::DEFAULT_HEAP_LIMIT_MB (128 MiB -- the per-GUEST
    isolate budget). But the runner is trusted infrastructure that must compile the
    WASI runtime + the guest's wasm module (e.g. bash.wasm) into its own heap before
    the guest runs, and that routinely exceeds 128 MiB. The near-heap-limit guard then
    terminates the isolate with an uncatchable, message-less exception, so warmup dies
    and surfaces as the opaque 'WebAssembly warmup exited with status 1 (Error: null)'
    (ERR_AGENTOS_NODE_SYNC_RPC). A clean release hits this too.
    
    Size the runner heap explicitly (default 2048 MiB, operator-tunable via
    AGENTOS_WASM_RUNNER_HEAP_LIMIT_MB) instead of leaving it on the per-guest default.
    This does NOT weaken guest isolation: the guest module's memory/fuel/stack stay
    bounded separately, Rust-side, from request.limits. The value is a V8 heap ceiling
    (heap_limits(0, cap)), committed only as used.
    
    Unit test wasm_runner_heap_limit_defaults_and_honors_operator_override covers the
    default (> 128), a positive override, and zero/non-numeric fallback.
    
    Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
    NathanFlurry and claude authored Jun 25, 2026
    Configuration menu
    Copy the full SHA
    02564e2 View commit details
    Browse the repository at this point in the history
  4. fix: plug twelve runtime memory leaks across sidecar, kernel, VFS, V8 (

    …#131)
    
    A leak audit of the VM runtime found tracking maps/registries populated on
    create but released only on a happy-path teardown (skipped on error '?' or
    never), plus per-timer threads with no cancellation. Each fix releases on
    every termination path; each ships a fast safeguard-firing test.
    
    sidecar:
    - dispose_vm_internal removes per-VM tracking on every exit path (VM removed
      before the fallible teardown half; cleanup runs unconditionally, error
      surfaced after) and the dispose_session/remove_connection loops attempt
      every item and aggregate errors instead of '?'-ing out (H1).
    - extension_process_output_buffers cleared on VM disposal, not just on
      successful handoff (M6).
    - disposed sessions are now untracked from the stdio active_sessions set (M5).
    - loopback-TLS endpoints remove their own registry entry on Drop instead of
      relying on the lazy retain() sweep (L4).
    - new additive Extension::on_session_disposed hook, fired on
      DisposeReason::ConnectionClosed, so extensions (e.g. ACP) can free
      per-session state on client disconnect (enables agent-os H4).
    sidecar-browser: vms/contexts maps cleared on every dispose path (H1).
    execution: bridge/kernel timer threads are delay-capped and cancellable via a
      generation check + clear-on-teardown, so guest timers can't exhaust OS
      threads or outlive their session (H2, M3).
    v8-runtime: VM_CONTEXTS slots evicted on context finalize, not only on error,
      so reused isolates don't hit MAX_VM_CONTEXTS (M1); pending promise-resolver
      Globals reset before the isolate is dropped on every run_event_loop exit
      (Shutdown/abort), fixing the leak and a V8 lifetime-contract violation (M2).
    kernel: socket ids allocated only after the backlog check passes, so a
      full-backlog connect failure no longer consumes an id (M4).
    vfs: rename rolls back staged snapshot entries on copy/rename failure (L2);
      InMemoryMetadataStore gains delete_snapshot() and a real gc() that reclaims
      unreferenced blocks (L3).
    
    L1 (bounded, documented Box::into_raw isolate handle) intentionally left as-is.
    
    Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
    NathanFlurry and claude authored Jun 25, 2026
    Configuration menu
    Copy the full SHA
    f183ed2 View commit details
    Browse the repository at this point in the history

Commits on Jun 26, 2026

  1. Configuration menu
    Copy the full SHA
    1f13c36 View commit details
    Browse the repository at this point in the history
  2. fix(sidecar): classify new limit constants, tolerate stale sidecar re…

    …sponses, fix service-test build (#133)
    
    Fixes surfaced while syncing agent-os against latest secure-exec main:
    
    1. limits: classify DEFAULT_WASM_RUNNER_HEAP_LIMIT_MB (#129) and MAX_TIMER_DELAY_MS
       (#131) — both added without inventory entries, so limits_audit failed on main.
    2. sidecar: accept_sidecar_response drops a stale sidecar_response with no matching
       pending request (UnmatchedResponse) or already completed (DuplicateResponse)
       instead of failing the whole sidecar — a per-VM callback can be answered by the
       host after that VM is disposed on the shared sidecar process. Real protocol
       violations stay fatal.
    3. tests: re-export crate::EventSinkTransport into the source-included service test
       crate (#132 added the use in src/service.rs without the matching test re-export,
       breaking 'cargo test -p secure-exec-sidecar --test service' compilation).
    
    Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
    NathanFlurry and claude authored Jun 26, 2026
    Configuration menu
    Copy the full SHA
    d8a4435 View commit details
    Browse the repository at this point in the history
Loading