Skip to content

v0.9.0

Latest

Choose a tag to compare

@github-actions github-actions released this 03 Sep 23:39
· 30 commits to main since this release
v0.9.0

A minor bump because one exit code changes. Everything else is a defect fix, and every one of them was
measured on this machine before and after.

One behaviour change

kern box --plan now exits non-zero when a profile it named cannot attach. It printed
cannot attach: no [[vcpu]] profile named 'nope' and exited 0, while the same command without
--plan exited 1. So kern box ... --plan && kern box ... walked on to a launch the preview had
already established could not happen, and a pipeline gating on the preview learned nothing from it.

The whole plan still prints and every broken profile is counted, so a configuration with three typos is
fixed in one pass rather than three. A script that reads the preview and ignores its exit code is
unaffected.

Fixed

A kern run that nobody capped said nothing, and one killed by the cap said nothing either.
A plain kern run is not uncapped: the scope it re-execs into carries MemoryMax=512M.
KERN_NO_SCOPE=1 skips that scope and the default goes with it, and both existing warnings were gated
on the caller having ASKED for a cap, so the case where nothing was typed printed nothing at all.
Measured, allocating 800 MiB against the default:

kern run                     killed, rc 137, with the OOM message
KERN_NO_SCOPE=1 kern run     ran to completion, rc 0, stderr EMPTY

and the process landed in whatever cgroup the caller happened to sit in. Separately, a workload the OOM
killer took exited 137 printing nothing: 137 is 128 + SIGKILL and SIGKILL has many senders, so on its
own it tells an operator nothing. Both now say what happened, and the OOM message is kept to what is
actually measurable: the killer fired in kern's cgroup subtree while the box ran, not which process it
took. The box's own cgroup is gone by then (--collect), and the wording says so rather than claiming
more.

An error that lists things reached the user as one run-on line. The scrub that strips control
characters from an error was stripping the newlines that made it a list:

$ kern volume rm a b
error: 2 volume(s) not removed:  no volume named 'a'  no volume named 'b'

Newlines survive now and every continuation line is indented, so a hostile value still cannot forge a
line at column 0 where kern's own error: and hint: prefixes live. Verified with an error: planted
inside a volume name: it comes out indented.

The seccomp allow-list generator promised to run cargo fmt and never ran it. --write left 623
changed lines on a file whose own header says DO NOT EDIT BY HAND, and turned the format check red.
Three places also pointed at the bare command, which only CHECKS, including the failure message the
check itself prints: following that message re-ran the check and changed nothing.

kern-sandbox 0.1.35 (PyPI and npm)

A FIFO the box planted could stall the host's read, or fake it. read_file/readFile opened
O_NOFOLLOW, which stops a symlink, and a symlink is not the only thing a box can leave at a name. A
box that runs mkfifo out.png made the host's read wait for a writer that never comes, with no timeout
and no way to interrupt it: the box decided how long the caller's call took. The write side is worse,
because opening a FIFO for writing blocks until a READER appears.

Adding O_NONBLOCK alone would have made it worse rather than better: a non-blocking read of a
writer-less FIFO returns zero bytes, so the call would have reported an EMPTY FILE where a pipe was
planted, turning a stall a caller can see into a wrong answer it cannot. Both halves ship: the open is
non-blocking, AND a descriptor that is not a regular file is refused, judged on the open descriptor
rather than on a path that can be swapped after the check.

Also: the MCP server's KERN_MCP_MEMORY_MB default of 1024 was sent on every call, and an explicit
flag beats a profile, so a vcpu: profile carrying its own memory= could never apply it. Unsetting
the variable did not help, because it fell back to the same default. 0 now means "send no --memory
at all".

Both package pages are rewritten. The PyPI page ran to 37,371 characters and opened on what kern
is; it is now 15,320 and opens on running AI-generated code in a real sandbox, one fresh box per call.
Nothing was dropped to get there: the LangChain shell-middleware section moved whole to
bindings/python/LANGCHAIN-SHELL.md. The npm page gets the same opening and a pointer to the MCP
server, which it had never mentioned.

Verified on the published binary

The four fixes above were re-run against the artifact attached to this release, not against a local
build: --plan exits 1 on a broken profile and 0 on a good one, volume rm prints its list on three
lines, KERN_NO_SCOPE=1 warns while a plain run stays silent, and a 900 MiB allocation against the
512 MiB default exits 137 WITH the reason.

1042 Rust, 348 Python and 67 Node tests.

curl -fsSL https://raw.githubusercontent.com/getkern/kern/main/install.sh | sh