Watch
0
0
Fork
You've already forked hyperhive
0

swarm-nats: test that the server's rendered config carries the callout xkey

`checks.script-test-nats-render-config` runs the queue server's
`ExecStartPre` render against a scratch runtime directory: a fetched key
lands in `auth_callout.xkey` and the wrapper includes the fragment, and
a missing or malformed key file fails the start and writes no config.

module-eval only sees the render as a store path, so dropping `xkey`
from the template, or its substitution, passed every check while the
server would have run unsealed.
This commit is contained in:
atlas 2026-10-05 22:13:59 +02:00 • committed by mara
commit 6c4a459773
3 changed files with 116 additions and 0 deletions

View file

@ -39,6 +39,12 @@ in
inherit pkgs self nixosSystem;
inherit (pkgs) lib;
};
# Executes the queue server's config render, which `module-eval-nats-authelia`
# only sees as a store path: the callout xkey it writes is a build output.
script-test-nats-render-config = import ./script-tests/nats-render-config.nix {
inherit pkgs self nixosSystem;
inherit (pkgs) lib;
};
module-eval-nats-tls = import ./module-eval/nats-tls.nix {
inherit pkgs self nixosSystem;
inherit (pkgs) lib;

View file

@ -0,0 +1,50 @@
# `checks.script-test-nats-render-config` — runs the queue server's
# `ExecStartPre`, ../host-modules/swarm-nats.nix's `renderConfig`, which writes
# the callout xkey into the config `nats-server` reads. The cases are in
# ./nats-render-config.sh.
#
# What runs is the rendered script. The one edit is its runtime directory,
# moved under the build directory because the sandbox has no writable
# `/var/lib`.
{
pkgs,
lib,
self,
nixosSystem,
}:
let
inherit
(import ../module-eval/lib.nix {
inherit
pkgs
lib
self
nixosSystem
;
})
hive
;
queue = hive {
deploy.nats.enable = true;
deploy.nats.autoGenerateCallout = false;
deploy.nats.calloutUserPublicKey = "UTESTUSERPUBKEYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
deploy.nats.calloutIssuerPublicKey = "ATESTISSUERPUBKEYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
deploy.nats.calloutUserSeedFile = "/run/secrets/nats-user.seed";
deploy.nats.calloutIssuerSeedFile = "/run/secrets/nats-issuer.seed";
deploy.nats.authPackage = pkgs.emptyDirectory;
deploy.nats.authBaoClientCertFile = "/etc/pki/nats-auth.pem";
deploy.nats.authBaoClientKeyFile = "/etc/pki/nats-auth-key.pem";
};
in
pkgs.runCommand "hyperhive-script-test-nats-render-config"
{
# `removePrefix` keeps the string context, and with it the script's store
# path among this check's inputs. The `+` is systemd's, not the path's.
RENDER = lib.removePrefix "+" queue.containers.swarm-nats.config.systemd.services.nats.serviceConfig.ExecStartPre;
nativeBuildInputs = [ pkgs.jq ];
}
''
${pkgs.bash}/bin/bash ${./nats-render-config.sh}
touch "$out"
''

View file

@ -0,0 +1,60 @@
# Cases for ./nats-render-config.nix. Each case gets a fresh runtime directory,
# runs the rendered script against it, and asserts on the exit code and the
# config files left behind.
set -uo pipefail
failures=0
count=0
fail() {
echo "FAILED: $case: $*" >&2
failures=$((failures + 1))
}
# The shape the script checks for, X and 55 base32 characters.
key=XAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
setup() {
case=$1
dir=$(mktemp -d)
rt=$dir/rt
mkdir "$rt"
if ! sed "s|^d=.*|d=$rt|" "$RENDER" >"$dir/render"; then
echo "cannot read the rendered script $RENDER" >&2
exit 1
fi
chmod +x "$dir/render"
if ! grep -qxF "d=$rt" "$dir/render"; then fail "the rewrite did not reach the script's runtime directory"; fi
}
go() {
count=$((count + 1))
"$dir/render" >"$dir/out" 2>"$dir/err"
rc=$?
}
setup "a fetched key is rendered into auth_callout.xkey, and the server's config includes it"
printf '%s' "$key" >"$rt/callout-xkey.pub"
go
if [ "$rc" -ne 0 ]; then fail "exit $rc: $(cat "$dir/err")"; fi
if ! jq -e --arg k "$key" '.authorization.auth_callout.xkey == $k' "$rt/callout.conf" >/dev/null; then
fail "callout.conf does not carry the key as auth_callout.xkey"
fi
if ! grep -qxF 'include "callout.conf"' "$rt/nats.conf"; then fail "nats.conf does not include callout.conf"; fi
setup "with no key file the start fails and writes no config"
go
if [ "$rc" -eq 0 ]; then fail "exited 0"; fi
if [ -e "$rt/callout.conf" ] || [ -e "$rt/nats.conf" ]; then fail "a config was written"; fi
setup "a file that is not a public xkey fails the start and writes no config"
printf '%s' "not-a-key" >"$rt/callout-xkey.pub"
go
if [ "$rc" -eq 0 ]; then fail "exited 0"; fi
if [ -e "$rt/callout.conf" ] || [ -e "$rt/nats.conf" ]; then fail "a config was written"; fi
if [ "$failures" -ne 0 ]; then
echo "script-test-nats-render-config: $failures of $count cases broke" >&2
exit 1
fi
echo "$count cases hold in script-test-nats-render-config"