Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.1 KiB
JOURNAL — phase nixenv (Builder)
2026-06-17 — M1: single-source the harness runtime env
Why this design
The phase plan §2 wants ONE definition of "what's needed to run a recipe test", referenced from
three places, so DEFECT-3 (a dep present for one path, missing for another) becomes structurally
impossible. I put the single source in nix/modules/packages.nix because it is the existing
"shared pkgs" overlay module already imported by both host configs — so pkgs.ccciRuntimeTools
and pkgs.cc-ci-run are reachable from every module/host without a fragile cross-module let.
Three overlay defs:
ccciPyEnv(let-bound, internal) —python3.withPackages [pytest playwright], the ONLY pyEnv now.ccciRuntimeTools(overlay attr) — the union tool set.cc-ci-run(overlay attr) —writeShellApplicationwithruntimeInputs = [ccciPyEnv] ++ ccciRuntimeTools.
Consumers:
harness.nix→environment.systemPackages = [ pkgs.cc-ci-run ](installs the entrypoint).nightly-sweep.nix→ wrapper execscc-ci-run(same binary the Drone pipeline runs), so pyEnv + tooling + PLAYWRIGHT env are identical to the Drone path by construction. Dropped: the duplicate pyEnv, the parallelruntimeInputstool list, and the DEFECT-3export PATH=/run/current-system/sw/bin…prepend — git-lfs/bash/util-linux/openssl now come from cc-ci-run's runtimeInputs.- both host
configuration.nix→systemPackages = pkgs.ccciRuntimeTools ++ [ pkgs.openssh ].
Why the union is a superset (nothing dropped)
- old cc-ci-run:
abra docker git coreutils util-linux⊂ set. - old sweep:
bash abra docker git curl jq gnused gnugrep gnutar coreutils util-linux procps⊂ set; its host-PATH-derived git-lfs/openssl are now EXPLICIT in the set. - old host PATH:
curl git jq(+ git-lfs on hetzner only) ⊂ set;opensshkept as host-only add. - pyEnv (python3+pytest+playwright) + playwright browsers (via PLAYWRIGHT_BROWSERS_PATH) preserved.
Additions vs any single prior list:
git-lfs,openssl(plan §2). Thecc-cihost GAINS git-lfs, killing the one-off hetzner-only divergence — both host configs now byte-identical.
Why writeShellApplication makes this work
writeShellApplication emits export PATH="<runtimeInputs>:$PATH" (confirmed on the live wrapper).
So cc-ci-run's full tool set is the PATH prefix regardless of caller. Under Drone the inherited
suffix is /run/current-system/sw/bin:/run/wrappers/bin; under the sweep it's the systemd-minimal
PATH — but the harness tools all resolve from the shared prefix either way, which is the parity the
plan wants. The host systemPackages reference is the belt-and-suspenders path for direct
.drone.yml shell-outs (abra --version, docker info) that don't go through cc-ci-run.
buildEnv collision watch (resolved)
Worry: adding coreutils/util-linux/procps/bash/gnu* to host systemPackages could collide with the
NixOS base requiredPackages. It did not — base requiredPackages are lowPrio, so the normal-prio
additions override cleanly. Both #cc-ci and #cc-ci-hetzner built with no collision error.
Note on other modules' tool lists
backupbot/docker-prune/drone/proxy/warm-keycloak.nix still list gnused/gnugrep/etc. in their OWN
runtimeInputs — those are independent reconcile-service scripts, never part of the harness/recipe
-test env, never part of the DEFECT-3 divergence. Single-sourcing is scoped to the harness env
(pyEnv + recipe-test tooling consumed by cc-ci-run / sweep / host PATH), which is now packages.nix only.
Verification (local, dirty tree needs ?submodules=1 — secrets/ is a submodule)
nixos-rebuild build --flake '.?submodules=1#cc-ci-hetzner'→ builtnixos-system-…dhmpm232….nixos-rebuild build --flake '.?submodules=1#cc-ci'→ built OK.- cc-ci-run store
zxlx9jnylh7la5m48bsqb1wfm5l9r0bd; PATH carries all 15 tools incl git-lfs-3.6.1 + openssl-3.3.3. - sweep wrapper
gh02w1kc…execs the SAMEzxlx9j…/bin/cc-ci-run. - cc-ci host sw/bin now lists git-lfs + openssl (was missing git-lfs pre-refactor).
grep -rn withPackages nix/→ 1 hit (packages.nix:17).