Skip to content

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

Description

@NathanFlurry

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions