deploy.builder.enable defaults on under deploy.allSwarmServices (mkDefault), where the host has the builder's store identity pair, as for the review classifier. An explicit false still wins.
133 lines
5.3 KiB
Nix
133 lines
5.3 KiB
Nix
# `checks.module-eval-builder` — see ./lib.nix for the shared rationale (why
|
|
# this suite exists, naming convention, "evaluates not executes"). The swarm
|
|
# builder's container, its default and its queue and IdP registrations; its
|
|
# store grants are in ./bao-grants.nix beside every other principal's.
|
|
{
|
|
pkgs,
|
|
lib,
|
|
self,
|
|
nixosSystem,
|
|
}:
|
|
let
|
|
inherit
|
|
(import ./lib.nix {
|
|
inherit
|
|
pkgs
|
|
lib
|
|
self
|
|
nixosSystem
|
|
;
|
|
})
|
|
hive
|
|
hiveWithController
|
|
runGroup
|
|
;
|
|
|
|
bare = hiveWithController { };
|
|
|
|
# On the store's host, which mints the builder's store identity.
|
|
withBuilder = hive {
|
|
deploy.bao.enable = true;
|
|
deploy.builder.enable = true;
|
|
};
|
|
|
|
servicesHere = hiveWithController { deploy.allSwarmServices = true; };
|
|
# Short-circuits on `assertion`, so only a failing one has its message read.
|
|
refusedWithoutIdentity =
|
|
m:
|
|
lib.any (a: !a.assertion && lib.hasInfix "deploy.builder.enable requires" a.message) m.assertions;
|
|
|
|
natsHere = hive {
|
|
swarm.nats.enable = true;
|
|
swarm.nats.authPackage = pkgs.emptyDirectory;
|
|
};
|
|
|
|
autheliaHere = hive {
|
|
deploy.bao.enable = true;
|
|
deploy.authelia.enable = true;
|
|
};
|
|
|
|
container = withBuilder.containers.swarm-builder;
|
|
inner = container.config;
|
|
svc = inner.systemd.services.swarm-builder;
|
|
env = svc.environment;
|
|
|
|
cases = [
|
|
{
|
|
name = "the swarm builder's container exists only where its host enables it";
|
|
ok = !(bare.containers ? swarm-builder) && withBuilder.containers ? swarm-builder;
|
|
}
|
|
{
|
|
# The store's host mints the builder's leaf, so the switch needs no
|
|
# manual identity step: the pair is set and the module's identity
|
|
# assertion, which nothing else reads in this fixture, passes. `nats` is
|
|
# the control that the switch is on.
|
|
name = "hosting the shared services turns the builder on, with its store identity";
|
|
ok =
|
|
servicesHere.services.hyperhive.deploy.builder.enable
|
|
&& servicesHere.containers ? swarm-builder
|
|
&& servicesHere.services.hyperhive.deploy.bao.builderClientCertFile != null
|
|
&& servicesHere.services.hyperhive.deploy.bao.builderClientKeyFile != null
|
|
&& !(refusedWithoutIdentity servicesHere)
|
|
&& servicesHere.services.hyperhive.deploy.bao.enable
|
|
&& servicesHere.services.hyperhive.deploy.nats.enable;
|
|
}
|
|
{
|
|
# A config PR is unreviewed input to an evaluation: the container keeps
|
|
# its own netns, and reaches the host's nix daemon through its socket
|
|
# alone, with no daemon of its own racing the bind.
|
|
name = "the builder's container has its own netns and builds only through the host's daemon socket";
|
|
ok =
|
|
container.privateNetwork
|
|
&& inner.services.hyperhive.swarmContainer.privateNetwork
|
|
&& container.bindMounts."/nix/var/nix/daemon-socket".hostPath == "/nix/var/nix/daemon-socket"
|
|
&& !inner.systemd.services.nix-daemon.enable
|
|
&& !inner.systemd.sockets.nix-daemon.enable
|
|
&& inner.systemd.globalEnvironment.NIX_REMOTE == "daemon";
|
|
}
|
|
{
|
|
# The daemon holds its store leaf, handed in by nspawn without a copy on
|
|
# disk; the forge token is read per build and reaches only `git`.
|
|
name = "the builder loads only its store leaf, runs as a dynamic user and carries no token in its unit";
|
|
ok =
|
|
lib.elem "builder-bao-key" svc.serviceConfig.LoadCredential
|
|
&& env.BAO_CLIENT_KEY == "/run/credentials/swarm-builder.service/builder-bao-key"
|
|
&& env.SWARM_BUILDER_OIDC_CLIENT_ID == "swarm-builder"
|
|
&& lib.elem "--load-credential=builder-bao-key:/var/lib/swarm-bao-pki/builder-key.pem" container.extraFlags
|
|
&& svc.serviceConfig.DynamicUser
|
|
&& !(lib.any (lib.hasSuffix "TOKEN") (lib.attrNames env));
|
|
}
|
|
{
|
|
# The check builds on the sources a hive on this host would render into
|
|
# its meta flake, so a green check means the same base.
|
|
name = "the builder builds on the hyperhive and nixpkgs this host's hives use";
|
|
ok =
|
|
env.SWARM_BUILDER_HYPERHIVE_FLAKE == withBuilder.services.hyperhive.c0re.hyperhiveFlake
|
|
&& env.SWARM_BUILDER_NIXPKGS_FLAKE == withBuilder.services.hyperhive.c0re.nixpkgsFlake
|
|
&& lib.hasSuffix "-check-flake" env.SWARM_BUILDER_CHECK_FLAKE
|
|
&& env.SWARM_BUILDER_CONFIG_ORG == "agent-configs"
|
|
&& env.SWARM_BUILDER_FORGE_URL == "https://${withBuilder.services.hyperhive.swarm.forge.domain}";
|
|
}
|
|
{
|
|
# The responder denies a client id it does not know, and a NATS denial
|
|
# arrives as a timeout.
|
|
name = "the queue's responder grants the builder's client its subject";
|
|
ok = lib.hasInfix "--builder-client swarm-builder" natsHere.containers.swarm-nats.config.systemd.services.swarm-nats-auth.serviceConfig.ExecStart;
|
|
}
|
|
{
|
|
name = "the builder's client is registered as a machine, and the publisher carries its secret";
|
|
ok =
|
|
let
|
|
c = lib.findFirst (
|
|
c: c.id == "swarm-builder"
|
|
) null autheliaHere.services.hyperhive.swarm.authelia.oidc.clients;
|
|
in
|
|
c != null
|
|
&& c.kind == "machine"
|
|
&& lib.hasInfix "secret/swarm/services/swarm-builder/oidc/client" (
|
|
autheliaHere.systemd.services.swarm-secret-publish.script
|
|
);
|
|
}
|
|
];
|
|
in
|
|
runGroup "builder" cases
|