Record the check-writing gotchas from the microvm host work #34

Merged
vnprc merged 1 commit from agent/shell-nix-check-gotchas into master 2026-07-30 08:11:59 +01:00
Member

Five gotchas found while writing the allod/nexus microvm host checks (allod/nexus#24), all of the kind that turns a check into one that cannot fail.

Two shell ones, in shell.md's existing "a guard that cannot be shown to fail does not count" family: ls <dangling-symlink> exits 0, so an access probe ending in ls <link> passes whether or not the target exists; and rm -f exits 0 on an absent path, so it cannot show that a deletion was denied. Both were found by an isolation fixture reporting two attacks as successful when the boundary was in fact closed — the probe, not the boundary, was wrong.

Three Nix ones, in nix.md:

  • lib.escapeShellArg leaves a shell-safe string unquoted, so a check grepping generated shell for '<path>' passes or fails on nixpkgs' quoting optimisation rather than on the generator. With unquoted needles, "this path must not appear" also stops working as a substring check, because every derived path carries its root as a prefix — set comparison over the extracted argument list is the replacement.
  • NixOS renders ExecStart=<script> with a trailing space when there are no arguments, so a $-anchored extraction silently matches nothing; and a unit defined with script keeps its payload in a separate unit-script-* derivation.
  • builtins.tryEval does not catch abort, and nixpkgs aborts on a group name over 31 characters. A mutation fixture that trips it takes the whole check down rather than recording an outcome, and an assertion meant to give that input a friendlier diagnostic can never be the reported one.

The nix flake check memory note gains a clarification: exposing a second host system costs nothing by default, because Nix omits systems it cannot build and says which. The OOM risk is per-configuration.

Risk

R0. Documentation only, in the topic files that already own these subjects.

Validation

Every statement was measured while writing allod/nexus#24: the two shell behaviours directly on this VM's coreutils, the escaping and trailing-space behaviours against the rendered artefacts that first failed on them, the abort behaviour by a fixture that took a check down with it, and the flake-check omission from nix flake check's own output.

Five gotchas found while writing the `allod/nexus` microvm host checks (allod/nexus#24), all of the kind that turns a check into one that cannot fail. Two shell ones, in `shell.md`'s existing "a guard that cannot be shown to fail does not count" family: `ls <dangling-symlink>` exits 0, so an access probe ending in `ls <link>` passes whether or not the target exists; and `rm -f` exits 0 on an absent path, so it cannot show that a deletion was denied. Both were found by an isolation fixture reporting two attacks as successful when the boundary was in fact closed — the probe, not the boundary, was wrong. Three Nix ones, in `nix.md`: - `lib.escapeShellArg` leaves a shell-safe string unquoted, so a check grepping generated shell for `'<path>'` passes or fails on nixpkgs' quoting optimisation rather than on the generator. With unquoted needles, "this path must not appear" also stops working as a substring check, because every derived path carries its root as a prefix — set comparison over the extracted argument list is the replacement. - NixOS renders `ExecStart=<script> ` with a trailing space when there are no arguments, so a `$`-anchored extraction silently matches nothing; and a unit defined with `script` keeps its payload in a separate `unit-script-*` derivation. - `builtins.tryEval` does not catch `abort`, and nixpkgs aborts on a group name over 31 characters. A mutation fixture that trips it takes the whole check down rather than recording an outcome, and an assertion meant to give that input a friendlier diagnostic can never be the reported one. The `nix flake check` memory note gains a clarification: exposing a second host system costs nothing by default, because Nix omits systems it cannot build and says which. The OOM risk is per-configuration. ## Risk R0. Documentation only, in the topic files that already own these subjects. ## Validation Every statement was measured while writing allod/nexus#24: the two shell behaviours directly on this VM's coreutils, the escaping and trailing-space behaviours against the rendered artefacts that first failed on them, the `abort` behaviour by a fixture that took a check down with it, and the flake-check omission from `nix flake check`'s own output.
vnprc approved these changes 2026-07-30 08:11:41 +01:00
vnprc force-pushed agent/shell-nix-check-gotchas from df1e16713a to c424108ebc 2026-07-30 08:11:48 +01:00 Compare
vnprc merged commit c424108ebc into master 2026-07-30 08:11:59 +01:00
vnprc deleted branch agent/shell-nix-check-gotchas 2026-07-30 08:11:59 +01:00
Sign in to join this conversation.
No description provided.