# `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