Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/nix/module-eval/snapshot-store.nix
atlas 7b50ae57e4 snapshot store: test the sender deadlines and the receiver bounds
open_stream takes its deadlines as parameters so the tests can use short
ones. The header-write test connects to a peer that holds the connection
without reading and sends a header larger than any loopback buffer; the
connect deadline is tested through the shared bounded helper with a
future that never completes, since a connect that hangs is not
reproducible without the network. The module-eval case asserts the
unit's RuntimeMaxSec and that the receiver script reads its header with
a timeout.
2026-10-16 11:45:58 +02:00

102 lines
3.3 KiB
Nix

# `checks.module-eval-snapshot-store` — see ./lib.nix for the shared
# rationale (why this suite exists, naming convention, "evaluates not
# executes").
#
# The snapshot store's receiver socket: where it listens, that it can bind
# before the mesh interface is up, that it refuses a wildcard, and that a
# silent or stalled transfer is bounded.
{
pkgs,
lib,
self,
nixosSystem,
}:
let
inherit
(import ./lib.nix {
inherit
pkgs
lib
self
nixosSystem
;
})
hive
runGroup
;
# Bare hive: the store and the mesh it needs, nothing else.
store = hive {
deploy.wireguard.enable = true;
deploy.wireguard.address = "10.100.0.1/24";
snapshotStore.enable = true;
snapshotStore.port = 51822;
};
# The same with a wildcard where the mesh address goes.
storeOnWildcard = hive {
deploy.wireguard.enable = true;
deploy.wireguard.address = "0.0.0.0/24";
snapshotStore.enable = true;
};
# The IPv6 wildcard.
storeOnWildcardV6 = hive {
deploy.wireguard.enable = true;
deploy.wireguard.address = "::/64";
snapshotStore.enable = true;
};
unit = store.systemd.services."swarm-snapshot-store@";
moduleSource = builtins.readFile ../host-modules/swarm-snapshot-store.nix;
socket = store.systemd.sockets.swarm-snapshot-store.socketConfig;
refusedAsWildcard =
m:
lib.any (
a: !a.assertion && lib.hasInfix "refuses a wildcard listen address" a.message
) m.assertions;
cases = [
{
# The wg-hive address does not exist when sockets.target binds, so
# without FreeBind the bind fails with EADDRNOTAVAIL and the receiver
# never listens. The unit still renders and evaluates either way, which
# is why only a rendered-config check can see it.
name = "the receiver socket may bind before the mesh interface has its address";
ok = socket.FreeBind or false == true;
}
{
# The bare IP and the configured port: the prefix length on
# `deploy.wireguard.address` must not leak into the listen address.
name = "the receiver socket listens on the mesh address and the configured port";
ok = socket.ListenStream == "10.100.0.1:51822";
}
{
# The control for the case below: it is the wildcard that trips the
# assertion, not the store being on.
name = "a mesh address on the store raises no wildcard refusal";
ok = !(refusedAsWildcard store);
}
{
# A wildcard bind is an unauthenticated remote write into agent state.
name = "a wildcard mesh address, IPv4 or IPv6, is refused";
ok = refusedAsWildcard storeOnWildcard && refusedAsWildcard storeOnWildcardV6;
}
{
# Without it a stalled `btrfs receive` holds a root instance forever.
name = "the receiver unit has a runtime ceiling";
ok = unit.serviceConfig.RuntimeMaxSec or null == "6h";
}
{
# The script is a store path, so its text is not evaluable without
# building it; the module source is the nearest thing to read. A
# silent peer must not hold the root instance past the header read.
name = "the receiver script bounds its header read";
ok = lib.hasInfix "read -r -t \${toString headerTimeoutSeconds} keyword agent" moduleSource;
}
];
in
runGroup "snapshot-store" cases