[quality] test: executed coverage for the Justfile VM recipes — _rootful_load_image, _build-bib, _run-vm - #377
kubestellar-hive[bot] wants to merge 1 commit into
Conversation
Add tests/unit/justfile-vm-recipes_test.bats, covering the three Justfile recipes that carried the whole disk/ISO image pipeline with zero executed coverage: _rootful_load_image, _build-bib and _run-vm. The recipes run against a sandbox copy of the Justfile with podman, sudo, chown, jq, ss, xdg-open, sleep and the nested just invocations stubbed on PATH, so no container starts, no privilege is escalated and no network is touched. Covered decisions: - _rootful_load_image: the sudo/root short-circuit, skipping the copy when root storage already holds the image, podman image scp when the IDs differ, the TMPDIR staging directory and its cleanup, and the pull fallback when podman inspect cannot resolve the image. - _build-bib: the --type/--use-librepo/--rootfs argv, the read-only /config.toml mount, the shared host container storage, the target image reference, the BIB_IMAGE override and the digest-pinned default, the privileged/unconfined run flags, artifact relocation into output/ with staging-directory removal, and which steps escalate via sudo. - _run-vm: build-on-missing dispatch, the iso vs non-iso image-file mapping, loopback port selection including walking past bound ports, the KVM/TPM/GPU/sizing flags and the ephemeral qemu invocation. One test is a characterization test rather than a guard: _build-bib ends with sudo chown -R $USER:$USER under set -u, so it aborts after the image is already built whenever USER is undefined. That defect is filed separately; the test is labelled so whoever fixes it knows to update it. No production file is modified. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: sec-check[bot] <sec-check[bot]@users.noreply.github.com>
|
Important Held for human review by the hive's ACMM level gate. This PR was opened by the "quality" agent while Hive policy required a human checkpoint for that agent. Non-outreach agents are held at ACMM L3–L5; the Hive will automatically remove the |
hanthor
left a comment
There was a problem hiding this comment.
Thank you for this one — I went in expecting a vacuous bot-authored test PR and it is the opposite. I mutation-tested your assertions against the real recipes and they are genuinely load-bearing. Ten single-line breakages of Justfile, nine killed:
$ cd <worktree at 49b2dd6>
$ for each mutant: sed -i ... Justfile && bats tests/unit/justfile-vm-recipes_test.bats
rootfs btrfs -> ext4 -> not ok 6 passes the requested type and the fixed librepo/btrfs flags
drop :ro on the config mount -> not ok 7 mounts the requested config read-only at /config.toml
drop --privileged from bib -> not ok 11 runs the builder privileged with an unconfined label
label=type:unconfined_t -> disable -> not ok 11
port=8006 -> 9006 -> not ok 19, 20, 22
output/bootiso/install.iso -> boot.iso -> not ok 17 maps the iso type to output/bootiso/install.iso
drop --device=/dev/kvm -> not ok 21 requests KVM, TPM, GPU and the documented VM sizing
CPU_CORES=4 -> 2 -> not ok 21
hardcode args="--type qcow2 " -> not ok 7
One survivor only: adding :ro to the shared /var/lib/containers/storage mount (which would break a real bib run) passes all 22, because test 8 matches the mount as a substring. Worth tightening to an exact -v <path>:<path> token if you touch the file again, but that is a nit.
The blocking problem is that the _rootful_load_image block is not hermetic — it reads the ambient $UID instead of pinning it, so three of your 22 tests fail outright when the suite runs as root:
$ id -u
0
$ bats tests/unit/justfile-vm-recipes_test.bats
1..22
ok 1 _rootful_load_image: short-circuits under sudo without inspecting podman
ok 2 _rootful_load_image: skips the copy when root storage already has the image
not ok 3 _rootful_load_image: copies user storage to root when the IDs differ
not ok 4 _rootful_load_image: routes the copy through a TMPDIR it cleans up
not ok 5 _rootful_load_image: pulls into root storage when the image is unknown locally
ok 6 .. ok 22
The cause is unambiguous — --print-output-on-failure shows the recipe never reaches the code under test:
$ bats --print-output-on-failure -f "copies user storage to root" tests/unit/justfile-vm-recipes_test.bats
# + [[ -n '' ]]
# + [[ 0 -eq 0 ]]
# + echo 'Already root or running under sudo, no need to load image from user podman.'
# + exit 0
_rootful_load_image short-circuits on "${UID}" -eq "0" (Justfile:252), and tests 3, 4 and 5 stub podman/just but never arrange for a non-root $UID, so they assert against a recipe that exited at line 5. .github/workflows/unit-tests.yml runs on ubuntu-latest as an unprivileged user, so CI is green and this is invisible there — but it fails for anyone running the suite in a container, a rootful dev shell, or under sudo bats, which is a normal thing to do in a repo whose recipes are about rootful podman.
Worse than the three red tests is test 2, skips the copy when root storage already has the image. It asserts only negatives:
! grep -q 'podman image scp' "${JUST_LOG}"
! grep -q 'podman pull' "${JUST_LOG}"
Under root the recipe short-circuits before touching podman at all, so JUST_LOG is empty and both negatives hold trivially. It reports ok while testing nothing:
$ bats -f "skips the copy when root storage" tests/unit/justfile-vm-recipes_test.bats
1..1
ok 1 _rootful_load_image: skips the copy when root storage already has the image
That is a test that goes green in exactly the environment where its premise is false, which is the failure mode this PR exists to prevent elsewhere.
Bash makes $UID readonly, so you cannot simply export a fake one. Two workable directions: either skip the four _rootful_load_image non-short-circuit cases when [ "$(id -u)" -eq 0 ] — explicit and honest — or add a positive assertion to test 2 (that podman inspect was actually called, e.g. grep -q 'inspect -t image' "${PODMAN_LOG}") so it cannot pass vacuously, and let 3/4/5 skip. I would take both: the skip guard stops the red, the positive assertion stops the silent green.
Everything else checks out. Disjointness is real — I merged #366, #368, #371, #373 and this PR onto be4b0eb in one worktree and all five merged cleanly with no new failures attributable to this file; the only cross-PR breakage in that tree is iso/iso.toml kickstart ref matches the canonical vendor and name, which is the known #366/#368 semantic conflict and nothing to do with you. Your characterization test 14 for the USER: unbound variable defect is correctly flagged in place and I agree it belongs in #374 rather than here. Baseline for the record: bats tests/unit on the merge-base be4b0eb gives 195 ok / 1 not ok (build: does not add a build secret when GITHUB_TOKEN is unset, a pre-existing failure caused by GITHUB_TOKEN being set in my environment, not by anything here); with this PR, 197 ok / 1 not ok plus the three above.
Fix the hermeticity and I am happy to approve — the assertion content is some of the better test work I have reviewed in this repo.
Generated by Claude Code
Test Improvement
Adds
tests/unit/justfile-vm-recipes_test.bats(22 tests) — executedcoverage for the three Justfile recipes that had none:
_rootful_load_image(Justfile:247-277),_build-bib(
Justfile:288-315) and_run-vm(Justfile:352-391).These three carry the whole disk/ISO image pipeline:
build-qcow2,build-raw,build-iso,rebuild-*,run-vm-*and thebuild-vm/run-vmaliases are all thin dispatchers onto them. Until now a regression in any of
their decisions only surfaced when a maintainer ran a real 15-25 minute image
build.
No production file is modified. The only file this PR adds or changes is
tests/unit/justfile-vm-recipes_test.bats.How it runs
Against a sandbox copy of the Justfile, with
podman,sudo,chown,jq,ss,xdg-open,sleepand the recipes' own nestedjustinvocations stubbedon PATH — the same harness shape as
tests/unit/justfile-build_test.bats. Nocontainer starts, no privilege is escalated, no network is touched. The real
justis resolved before PATH is shadowed so the tests drive the real binarywhile the recipes' internal
just sudoif .../just build-<type> ...calls hitthe stub and are asserted on.
What is asserted
_rootful_load_image— theSUDO_USER/UIDshort-circuit (must not touchpodman at all); skipping the copy when root storage already holds the image;
podman image scp <uid>@localhost::img:tag root@localhost::img:tagwhen the IDsdiffer; the
TMPDIR=staging directory and that it does not survive the recipe;the
podman pullfallback whenpodman inspectcannot resolve the image._build-bib—--type <type> --use-librepo=True --rootfs=btrfs; theread-only
/config.tomlbind mount of the requested config; the shared/var/lib/containers/storagemount; thetarget:tagreference; theBIB_IMAGEoverride and the digest-pinned default;
--privilegedwith--security-opt label=type:unconfined_t; artifact relocation intooutput/withthe staging directory removed; and that escalation is limited to the container
run and the artifact move/chown.
_run-vm— build-on-missing dispatch and the no-rebuild path; theisospecial case (
output/bootiso/install.iso) versusoutput/<type>/disk.<type>;loopback port selection including walking past ports
ssreports as bound;--device=/dev/kvm,TPM=Y,GPU=Y,CPU_CORES=4,RAM_SIZE=8G,DISK_SIZE=64G; and the ephemeraldocker.io/qemux/qemuinvocation.One characterization test, flagged as such
_build-bib: currently aborts with "USER: unbound variable" when USER is undefinedpins a live defect, not a desired behavior._build-bibends withsudo chown -R $USER:$USER output/underset -u, so in any environment thatdoes not define
USERthe recipe fails after the image is already built,leaving
output/owned by root. That is filed separately as #374 with the exactone-line replacement; whoever applies it should update this single test to assert
the new
chownargv. The test comment says so in place.Verification
Related Issue
Closes #376
Not related to #374 beyond the note above — that issue needs a
Justfilechangethis PR deliberately does not make.
Disjointness
This PR touches exactly one file,
tests/unit/justfile-vm-recipes_test.bats,which does not exist on
main. Checked against every open finpilot PR:#344 owns
tests/unit/justfile-shell-sources_test.bats(shell-sources/lintrecipes), #353 and #373 own
tests/unit/justfile-build_test.bats(thebuildrecipe), #368 owns
tests/unit/image-identity_test.bats. #369 and #373 modifyJustfile; this PR does not, and its assertions do not depend on thesudoifinternals #369 changes or on the
SHA_HEAD_SHORTbuild arg #373 removes.Filed by quality agent (hold-gated mode). Human review required.
— hive: agent=quality backend=copilot model=claude-opus-5