rivet-dev / rivet-dev/dynamic-apps

Make agentOS runtime classifier content-based (match Linux exec semantics), not extension-based

Open
#275 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
1k
Forks
51
Avg merge
6m
Merged PRs (30d)
13

Description

Problem

The sidecar's JS-vs-WASM entrypoint classifier (resolve_javascript_command_entrypoint in crates/sidecar/src/execution.rs) decides which embedded runtime (V8 vs WASM) runs an agentOS package entrypoint by file extension: within the /opt/agentos package mount, .wasm → WASM, everything else → JavaScript.

This does not match Linux execve semantics, which classify by content (magic bytes / shebang), never by extension:

  • #! → run the named interpreter
  • \0asm (00 61 73 6d) → WebAssembly
  • \x7fELF → native ELF

The extension heuristic is only correct today because agentOS package bins happen to be exclusively JS or .wasm. It would misclassify an extensionless .wasm binary, or a non-JS script, that content sniffing would get right.

Why it is currently extension-based (context)

This was a deliberate shortcut taken while making /opt/agentos guest-native. The prior content-based path (resolve_javascript_command_entrypoint_innerload_executable_script_preview) reads the host filesystem, but guest-native tar-mounted package content is never materialized on the host — so the shebang read always failed and fell through to the WASM branch (the original misroute that surfaced as an ENOEXEC/wrong-runtime launch). Reading the bytes guest-native needs vm.kernel.read_file (&mut self), while the classifier chain is &VmState and the sibling child-process path (resolve_javascript_child_process_execution) is &self / &VmState — threading &mut cascades through several signatures. The extension rule avoided that cascade.

Note the kernel layer already IS content-based / Linux-faithful: resolve_spawn_commandparse_shebang_command (crates/kernel/src/kernel.rs) reads the file, parses the #! line, and returns ENOEXEC on a bad one. Only the sidecar's JS-vs-WASM pre-classification is extension-based.

Proposed fix

Classify by content via the kernel VFS instead of by extension:

  • leading bytes \0asm (00 61 73 6d) → WASM
  • leading #! → defer to the shebang interpreter (as the kernel already does)
  • otherwise → JS

This requires a guest-side read in the classifier — either thread &mut VmState through the classifier chain (and the child-process path), or add an immutable VFS "peek" that reads the first N bytes without requiring &mut.

Location

  • crates/sidecar/src/execution.rsresolve_javascript_command_entrypoint (the extension fast-path within the agentOS package mount) and its _inner shebang fallback, which currently reads the host path rather than the guest VFS.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in crates/sidecar/src/execution.rs at resolve_javascript_command_entrypoint and its _inner fallback, then read crates/kernel/src/kernel.rs around resolve_spawn_command and parse_shebang_command. Trace the classifier and child-process call signatures, including their VmState references, before choosing how guest VFS bytes can be inspected. Done means agentOS entrypoints classify \0asm, shebang, and other content consistently with the stated Linux semantics without relying on extensions.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.