Skip to content

v0.5.3

Choose a tag to compare

@github-actions github-actions released this 22 Aug 23:24
· 1737 commits to main since this release

Upgrade if you run test suites or MCP servers through nvx. Two long-standing problems on Windows made contained commands leave processes behind forever.

Test runners and tool runners no longer hang

A contained command could not read a subprocess's output as it was produced. It blocked before the child process even existed, with no error — so every contained npx vitest or npx playwright run left a process wedged until someone found and killed it. On the development machine 17 had accumulated, some stuck for 13 hours.

Windows builds piped output out of named pipes, and a sandboxed process is not allowed to create one. nvx now creates them outside the sandbox and the contained side only opens them, which Windows does permit. Output streams as it is produced, stdout and stderr stay separate, and exit codes come through.

Two limits, both stated rather than discovered: writing to a contained child's input is not supported, and beyond 8 children capturing output at once the output arrives when each stream ends rather than as it is produced. nvx prints a warning the first time that happens.

nvx stops when the program that started it stops

An MCP server that ignores end-of-input kept running after its client went away, and nvx kept waiting on it, holding a sandbox open. They accumulated at about one a minute until Windows ran out of memory. nvx now leaves when its input has hung up and the program that started it has exited — both, because a finished shell pipeline looks like the first on its own, and a deliberately detached command looks like the second.

Sandbox leftovers clean themselves up

Abandoned sandbox profiles used to wait for nvx cleanup, which nobody ran; 91 had built up. Each run now reclaims a few afterwards, skipping any still in use. nvx cleanup still exists for reclaiming everything at once.

nvx audit

A local record of the security decisions nvx made, and — with NVX_TRACE=1 — of what each command did: whether it was contained, why not when it was not, exit code, duration, warnings. Nothing is sent anywhere. Command arguments are not recorded, only a subcommand nvx recognises, because argv is where tokens and private paths live.

Read it as what nvx recorded about its own runs. Anything running as you can append to that file, including your own uncontained code, so it is not evidence against someone who already runs code on your machine.

Honesty note: macOS does not contain filesystem reads

The Seatbelt profile allows reads, so a contained install on macOS can read ~/.ssh, ~/.aws and ~/.npmrc. This is deliberate — the dynamic linker needs to read system libraries whose locations vary by macOS version, and a strict read allowlist stops processes launching — but README, SECURITY.md and PRODUCT.md all stated the Windows behaviour as the product's behaviour. That is corrected on main (after this tag): on macOS nvx contains writes and egress, not credential reads.

macOS also remains unverified at runtime. The profile's text is asserted by tests; no macOS hardware has been observed enforcing it.

Everything above is Windows-only unless stated. Upgrading is a binary replacement; no state migration.

Full Changelog: v0.5.2...v0.5.3