Watch
0
0
Fork
You've already forked hyperhive
0

run the root check warn-only on hyperhive's own containers, per unit, not on the container@ template

This commit is contained in:
atlas 2026-10-28 23:37:59 +01:00
commit 24afc89ab3

View file

@ -19,6 +19,7 @@ let
;
})
hive
hiveWith
hiveWithController
runGroup
forceServiceConfigs
@ -73,6 +74,13 @@ let
gateway.openFirewall = true;
};
# A container the operator runs that hyperhive doesn't own, next to one it
# does (the classifier's).
withForeignContainer = hiveWith [ { containers.operator-box.config = { }; } ] {
deploy.bao.enable = true;
deploy.review-classifier.enable = true;
};
# On the store's host, which mints the runner's store identity.
withCi = hive {
deploy.bao.enable = true;
@ -1498,35 +1506,76 @@ let
&& (sc.ProtectKernelModules or false);
}
{
# Every `container@` instance starts through the template's drop-in, the
# agents' and the swarm services' alike, so a host with containers has it
# whether or not it runs a hive. A host with none has no `container@`
# unit and gets no drop-in. Only the rendered line is pinned: eval cannot
# show where systemd reads the file from. The misspelled name is the
# control that the lookup finds nothing when nothing is there.
name = "the container@ template drop-in runs the root check on every host with containers and on no other";
# Hyperhive's own declarative containers each run the root check from
# their own unit, warn-only. Every container in these fixtures is one of
# hyperhive's, so the names are read off the fixture: a container added
# without the check breaks the list, which is the point. The unit's own
# pre-start script is not a `hive-priv` entry, so the count is the check
# alone.
name = "every hyperhive container runs the root check warn-only from its own unit, and no hyperhive container is left out";
ok =
let
dropinText =
name: m:
checks =
m: name:
let
hits = lib.filter (p: (p.name or "") == name) m.systemd.packages;
pre = m.systemd.services."container@${name}".serviceConfig.ExecStartPre or [ ];
in
if builtins.length hits == 1 then (builtins.head hits).text else "";
runsCheck =
name: m:
let
want = "ExecStartPre=${m.services.hyperhive.c0re.package}/bin/hive-priv check-rootfs %i";
lines = lib.splitString "\n" (dropinText name m);
in
lib.elem (builtins.unsafeDiscardStringContext want) (map builtins.unsafeDiscardStringContext lines);
check = "hyperhive-container-rootfs-check";
builtins.filter (lib.hasInfix "hive-priv") (
map (p: builtins.unsafeDiscardStringContext (toString p)) pre
);
carries =
m: name:
checks m name == [
(builtins.unsafeDiscardStringContext "${m.services.hyperhive.c0re.package}/bin/hive-priv check-rootfs --warn-only ${name}")
];
names = lib.attrNames allLocal.containers;
in
runsCheck check allLocal
&& runsCheck check shared.servicesHere
&& !(runsCheck "${check}-misspelled" allLocal)
&& !(bare.systemd.units ? "container@.service")
&& !(runsCheck check bare);
names == [
"hive-forge"
"hive-matrix"
"swarm-attic"
"swarm-authelia"
"swarm-bao"
"swarm-builder"
"swarm-claude-login"
"swarm-grafana"
"swarm-nats"
"swarm-notify-router"
"swarm-otel"
"swarm-review-classifier"
"swarm-victorialogs"
"swarm-victoriametrics"
]
&& lib.all (carries allLocal) names
&& withCi.containers ? swarm-ci-runner
&& lib.all (carries withCi) (lib.attrNames withCi.containers)
# Control: a name with no unit finds nothing.
&& checks allLocal "swarm-nope" == [ ];
}
{
# The operator's other containers are not hyperhive's to touch: a
# `containers.<name>` it declares gets no check, while the classifier
# beside it does. The positive arm is what makes the absence mean
# something: the same lookup finds the classifier's.
name = "a container hyperhive does not declare gets no root check";
ok =
let
checks =
name:
builtins.filter (lib.hasInfix "hive-priv") (
map (p: builtins.unsafeDiscardStringContext (toString p)) (
withForeignContainer.systemd.services."container@${name}".serviceConfig.ExecStartPre or [ ]
)
);
in
lib.attrNames withForeignContainer.containers == [
"operator-box"
"swarm-bao"
"swarm-review-classifier"
]
&& lib.length (checks "swarm-review-classifier") == 1
&& lib.length (checks "swarm-bao") == 1
&& checks "operator-box" == [ ];
}
]
# Starting a unit that stays `active (exited)` is a no-op, so a timer aimed