diff --git a/nix/checks.nix b/nix/checks.nix index d9bf8011..a7c24d60 100644 --- a/nix/checks.nix +++ b/nix/checks.nix @@ -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; diff --git a/nix/script-tests/nats-render-config.nix b/nix/script-tests/nats-render-config.nix new file mode 100644 index 00000000..1b42143e --- /dev/null +++ b/nix/script-tests/nats-render-config.nix @@ -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" + '' diff --git a/nix/script-tests/nats-render-config.sh b/nix/script-tests/nats-render-config.sh new file mode 100644 index 00000000..0a592969 --- /dev/null +++ b/nix/script-tests/nats-render-config.sh @@ -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"