From 89979385575a7f95f499d9b6337597da03df5ecc Mon Sep 17 00:00:00 2001 From: damocles Date: Fri, 14 Aug 2026 03:45:01 +0200 Subject: [PATCH] nix: cover the hive-ci container's unit merge in module-eval --- nix/module-eval.nix | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/nix/module-eval.nix b/nix/module-eval.nix index 5b017afe..fb37f0b9 100644 --- a/nix/module-eval.nix +++ b/nix/module-eval.nix @@ -62,6 +62,22 @@ let allLocal = hive { enableAllLocalDefaults = true; }; bare = hive { }; + withCi = hive { swarm.forge.ci.enable = true; }; + + # A priority collision is a property of the *option*, not + # of the merged value's interior — nix throws the moment the value is + # demanded at all, so `seq`-ing each `serviceConfig` value to WHNF is + # both necessary and sufficient. `deepSeq` over-specifies this: it keeps + # walking *into* the resulting value after the merge already succeeded, + # and a package/derivation-shaped value's `override`/`overrideAttrs` + # self-reference sends it into nixpkgs' fixpoint machinery and blows the + # stack (measured — this is not a hypothetical). + forceCiServiceConfigs = + let + svcs = withCi.containers.hive-ci.config.systemd.services; + vals = lib.concatMap (s: builtins.attrValues (s.serviceConfig or { })) (builtins.attrValues svcs); + in + builtins.foldl' (acc: v: builtins.seq v acc) true vals; # Each case: a name stating the property, and `ok`. cases = [ @@ -100,6 +116,17 @@ let ok = !(builtins.hasAttr "= /.well-known/matrix/client" bare.services.nginx.virtualHosts."_".locations); } + { + # main got eval-borked twice by this exact class of bug (once on the + # unit's `Restart` key, once on `RestartSec`) — a nixpkgs bump to + # `gitea-actions-runner.nix` adds a plain `serviceConfig.*` + # definition that collides with one of ours, and nix refuses to + # merge two plain definitions at *host* eval. No other check + # instantiates a host with `containers.hive-ci` actually enabled, so + # the collision only surfaces on operator deploy, not in CI. + name = "the CI container's unit definitions merge without a priority collision"; + ok = forceCiServiceConfigs; + } ]; bad = builtins.filter (c: !c.ok) cases;