Watch
0
0
Fork
You've already forked hyperhive
0

module-eval: set the hive-controller option only in tests that need a hive

The shared `hive` fixture turned `deploy.hive-controller.enable` on for
every eval test. It is now off by default; `hiveWithController` turns it
on, and the fixtures whose claims read the hive tier (hive-c0re, the
queue-agent credential, the hive leaf, `deploy.hive-controller.*`, or an
absence that is only meaningful with a hive present) use it.

glue-nats-auth-bao-identity.nix still read the renamed
`services.hyperhive.enable`, which printed the "Obsolete option" trace
six times per CI run. The term is dropped: the pairing is gated on the
queue and the minted PKI, as its sibling glue-nats-bao-identity.nix is.
This commit is contained in:
atlas 2026-10-05 02:27:33 +02:00 • committed by mara
commit ea63b0d150
10 changed files with 47 additions and 31 deletions

View file

@ -18,12 +18,13 @@ let
;
})
hive
hiveWithController
runGroup
;
# The store, plus a placed bootstrap token: the only shape in which the
# granter's own role can be written at all.
baoGrantHere = hive {
baoGrantHere = hiveWithController {
deploy.bao.enable = true;
deploy.bao.bootstrapTokenFile = "/run/secrets/bao-bootstrap.token";
};
@ -91,7 +92,7 @@ let
# rather than one per reader: the claim they are *separate* principals is
# only testable where all of them render at once — that is the deployment in
# which two of them sharing a leaf would be invisible.
baoGrantWithConsumers = hive {
baoGrantWithConsumers = hiveWithController {
deploy.bao.enable = true;
deploy.bao.bootstrapTokenFile = "/run/secrets/bao-bootstrap.token";
deploy.grafana.enable = true;
@ -109,7 +110,7 @@ let
# The store with none of the readers beside it. Grafana and the collector are
# simply off; the queue reader renders on any host holding
# its leaf, which ./glue-bao-tls.nix mints here, so that leaf is taken away.
baoGrantNoReaders = hive {
baoGrantNoReaders = hiveWithController {
deploy.bao.enable = true;
deploy.bao.bootstrapTokenFile = "/run/secrets/bao-bootstrap.token";
deploy.bao.queueAgentClientCertFile = lib.mkForce null;
@ -126,7 +127,7 @@ let
# Every reader against a store it does not run, each with a leaf placed by
# hand. The deployment in which there is no local policy unit to wait for.
baoRemoteReaders = hive {
baoRemoteReaders = hiveWithController {
deploy.grafana.enable = true;
deploy.swarm-otel.enable = true;
deploy.bao.clientCertFile = "/etc/pki/bao-client.pem";

View file

@ -18,12 +18,13 @@ let
;
})
hive
hiveWithController
runGroup
;
# The store and a service that reads from it, versus the store alone. The
# pair is what makes the reader's absence arm mean anything.
baoWithMatrix = hive {
baoWithMatrix = hiveWithController {
deploy.bao.enable = true;
deploy.matrix.enable = true;
};
@ -38,7 +39,7 @@ let
# hive, so an operator placing leaves by hand places one for it as well as
# the hive's own. Naming only `clientCertFile` here would leave the unit
# unrendered — which is what the arms below would then be asserting about.
baoRemoteReader = hive {
baoRemoteReader = hiveWithController {
deploy.matrix.enable = true;
deploy.bao.clientCertFile = "/etc/pki/bao-client.pem";
deploy.bao.clientKeyFile = "/etc/pki/bao-client-key.pem";
@ -50,14 +51,14 @@ let
# store nor a hand-placed leaf. The absence arm for the matrix-ctl cases below
# needs it, and defining it here rather than importing keeps each group's
# fixture set its own, as ./lib.nix asks.
matrixNoBaoIdentity = hive { deploy.matrix.enable = true; };
matrixNoBaoIdentity = hiveWithController { deploy.matrix.enable = true; };
# 🩸 The hand-configured remote reader that named the hive's leaf and stopped.
# `baoRemoteReader` above is the same deployment done right; this one holds
# the hive's own leaf, so it demonstrably reads the store, and is missing the
# queue reader's pair. Without the refusal it would render no queue reader
# and say nothing — which is what the refusal arms below are about.
baoRemoteReaderMissingLeaves = hive {
baoRemoteReaderMissingLeaves = hiveWithController {
deploy.matrix.enable = true;
deploy.bao.clientCertFile = "/etc/pki/bao-client.pem";
deploy.bao.clientKeyFile = "/etc/pki/bao-client-key.pem";
@ -65,7 +66,7 @@ let
# The same omission on a hive that does NOT run a homeserver: the queue
# refusal checks only the hive's own toggle.
remoteReaderNoMatrixMissingLeaves = hive {
remoteReaderNoMatrixMissingLeaves = hiveWithController {
deploy.bao.clientCertFile = "/etc/pki/bao-client.pem";
deploy.bao.clientKeyFile = "/etc/pki/bao-client-key.pem";
};

View file

@ -18,6 +18,7 @@ let
;
})
hive
hiveWithController
runGroup
baoNames
baoStream
@ -26,9 +27,9 @@ let
swarmServiceEnables
;
allLocal = hive { deploy.singleHostSwarm = true; };
allLocal = hiveWithController { deploy.singleHostSwarm = true; };
bare = hive { };
bare = hiveWithController { };
# The same stub with the central toggle (`deploy.hive-controller.enable`)
# off. Paired with `bare` below to pin the defaults that do not read it:
@ -44,7 +45,7 @@ let
# Every hive defaults the agents' queue address to the queue's name, so the
# only hive without one is a hive told to have none.
noAgentQueue = hive { deploy.hive-controller.queue.agentNatsUrl = null; };
noAgentQueue = hiveWithController { deploy.hive-controller.queue.agentNatsUrl = null; };
# On the forge's host: the runner is refused anywhere else.
withCi = hive {
@ -487,7 +488,7 @@ let
refusedHiveName =
extra:
lib.any (a: !a.assertion && lib.hasInfix "services.hyperhive.hiveName to be set" a.message)
(hive ({ hiveName = null; } // extra)).assertions;
(hiveWithController ({ hiveName = null; } // extra)).assertions;
in
refusedHiveName { }
&& refusedHiveName {
@ -504,7 +505,7 @@ let
name = "a missing swarm.domain is refused on a hive and on a swarm-service host, and a host enabling nothing evaluates";
ok =
let
noDomain = extra: hive ({ swarm.domain = null; } // extra);
noDomain = extra: hiveWithController ({ swarm.domain = null; } // extra);
refusedSwarmDomain =
extra:
lib.any (

View file

@ -21,26 +21,26 @@ let
nixosSystem
;
})
hive
hiveWithController
runGroup
;
# Every service on one host, so the store's granting unit renders the role
# this leaf is issued through.
allLocal = hive {
allLocal = hiveWithController {
deploy.singleHostSwarm = true;
};
# The same host with the role's lifetime moved, so a threshold that is a
# number of its own shows up as one that did not move with it.
shortTtl = hive {
shortTtl = hiveWithController {
deploy.singleHostSwarm = true;
deploy.bao.servicesPkiLeafTtlHours = 48;
};
# Fronting none of the swarm's names, reading a store it does not run,
# with the reader identity and the hive's own identity placed by hand.
noService = hive {
noService = hiveWithController {
deploy.bao.clientCertFile = "/etc/pki/bao-client.pem";
deploy.bao.clientKeyFile = "/etc/pki/bao-client-key.pem";
deploy.bao.serverCaFile = "/etc/pki/bao-ca.pem";
@ -50,7 +50,7 @@ let
noSvcFetch = noService.systemd.services.swarm-services-cert.script;
# The same hive with no store identity at all.
noIdentity = hive { };
noIdentity = hiveWithController { };
noIdFetch = noIdentity.systemd.services.swarm-services-cert.script;
# The `want_svc=0` branch of a rendered script, up to the `fi` that closes it (the

View file

@ -24,7 +24,7 @@
# a certificate needs something that *runs* it. A case needing a rendered
# file must stub what it drags in (`deploy.swarm-ui.package = pkgs.emptyDirectory`).
#
# `hive`/`agent`/`agentWith` builders, the shared cross-group helpers, and
# `hive`/`hiveWithController`/`agent`/`agentWith` builders, the shared cross-group helpers, and
# the `runGroup` derivation builder live in ./lib.nix; each file below
# defines only the fixtures and cases its own cluster needs.
{
@ -59,7 +59,6 @@ let
# just one level down. `recursiveUpdate` merges nested attrsets
# all the way down instead.
services.hyperhive = lib.recursiveUpdate {
deploy.hive-controller.enable = true;
hiveName = "h1";
swarm.domain = "t.local";
swarm.hives.h1.domain = "h1.t.local";
@ -68,6 +67,13 @@ let
];
}).config;
# `hive` with the hive-controller tier on (hive-c0re, the agent containers,
# `deploy.hive-controller.*`). Only a fixture whose claim reads that tier
# takes this; every other claim is about the swarm services and evaluates
# without a hive on the host.
hiveWithController =
extra: hive (lib.recursiveUpdate { deploy.hive-controller.enable = true; } extra);
# The other half of the tree. `nix/agent-modules/` is evaluated by nothing
# else in this suite — every fixture above is a host — so a rendered
# container config was only ever read by a real deploy. Same entry point
@ -206,6 +212,7 @@ let
in
{
inherit hive;
inherit hiveWithController;
inherit agent;
inherit agentWith;
inherit baoNames;

View file

@ -18,6 +18,7 @@ let
;
})
hive
hiveWithController
runGroup
;
@ -30,11 +31,11 @@ let
# The same hive with the identity taken away, which separates "a homeserver
# is deployed" from "this host can authenticate to the store".
matrixNoBaoIdentity = hive { deploy.matrix.enable = true; };
matrixNoBaoIdentity = hiveWithController { deploy.matrix.enable = true; };
# A hive host that does not run the homeserver: its hive-c0re reaches the
# homeserver across the network.
matrixElsewhere = hive { };
matrixElsewhere = hiveWithController { };
cases = [
{
# Absence arm, and what makes the one above able to fail: with no leaf

View file

@ -19,6 +19,7 @@ let
;
})
hive
hiveWithController
runGroup
bridgePorts
;
@ -28,7 +29,7 @@ let
# Every service on one host. The queue, the store and every in-tree client of the queue
# are all here, so the scan below reads each of them.
allLocal = hive {
allLocal = hiveWithController {
deploy.singleHostSwarm = true;
};
@ -58,11 +59,13 @@ let
deploy.swarm-controller.baoClientCertFile = "/var/lib/swarm-controller/bao-client.pem";
deploy.swarm-controller.baoClientKeyFile = "/var/lib/swarm-controller/bao-client-key.pem";
};
remote = hive (lib.recursiveUpdate remoteSecrets { deploy.swarm-controller.enable = true; });
remote = hiveWithController (
lib.recursiveUpdate remoteSecrets { deploy.swarm-controller.enable = true; }
);
# The same hive given its status secret by hand, which is what turns
# publishing on away from the IdP's host.
remotePublishing = hive (
remotePublishing = hiveWithController (
lib.recursiveUpdate remoteSecrets {
deploy.hive-controller.statusPublish.clientSecretFile = "/var/lib/secrets/hive-h1.secret";
}

View file

@ -18,6 +18,7 @@ let
;
})
hive
hiveWithController
runGroup
;
@ -80,7 +81,7 @@ let
# The store and a service that reads from it, versus the store alone. The
# pair is what makes the reader's absence arm mean anything.
baoWithMatrix = hive {
baoWithMatrix = hiveWithController {
deploy.bao.enable = true;
deploy.matrix.enable = true;
};

View file

@ -18,6 +18,7 @@ let
;
})
hive
hiveWithController
runGroup
bridgePortsOrNone
swarmServiceEnables
@ -90,7 +91,7 @@ let
# The swarm's shared services hosted HERE without the all-local mode — a
# services box with hives elsewhere, the shape ./host-modules/
# swarm-required-services.nix documents the switch for.
swarmServicesHere = hive { deploy.allSwarmServices = true; };
swarmServicesHere = hiveWithController { deploy.allSwarmServices = true; };
# Same, with one of those services placed on another host. Every derivation
# in that module is `mkDefault` so this stays expressible.
@ -105,7 +106,7 @@ let
upstream = "https://example.invalid/tool";
dest = "mirrors/tool";
};
controllerWithMirrors = hive {
controllerWithMirrors = hiveWithController {
deploy.swarm-controller.enable = true;
deploy.forgejo.enable = true;
deploy.forgejo.mirrors = [ aMirror ];
@ -428,7 +429,7 @@ let
# which is what keeps "asserted by whoever needs it" from being a
# setting the operator cannot turn off.
name = "an explicit gateway.enable = false wins over the modules asserting it";
ok = !(hive { gateway.enable = false; }).services.nginx.enable;
ok = !(hiveWithController { gateway.enable = false; }).services.nginx.enable;
}
{
name = "declared forge mirrors reach the swarm-controller, not hive-c0re";