# Cases for ../host-modules/lib/attic-root-facts.nix. Each case runs the script # against a stub `bao` over a store kept in files, and compares what the script # left in its directory and which leaves it read. set -uo pipefail failures=0 count=0 case="setup" fail() { echo "FAILED: $case: $*" >&2 failures=$((failures + 1)) } expect() { # count=$((count + 1)) if [ "$2" != "$3" ]; then fail "$1: got '$2', wanted '$3'"; fi } dir=$(mktemp -d) mkdir -p "$dir/bin" sed "s|@DIR@|$dir|g" "$SCRIPT" >"$dir/script.sh" calls=$dir/calls export DIR=$dir # `login` answers from LOGIN_FAIL. `kv get -field=value ` prints the file # kept for the path; a missing one is the store's "no value found" and DENY_READ # is a policy that grants nothing. Every call is logged. cat >"$dir/bin/bao" <>"$calls" case "\$1 \$2" in "login -method=cert") if [ "\${LOGIN_FAIL:-0}" = 1 ]; then echo "certificate refused" >&2; exit 2; fi echo store-token ;; "kv get") [ "\${BAO_TOKEN-}" = store-token ] || { echo "kv without the login's token" >&2; exit 97; } f="\$DIR/store/\$(printf '%s' "\$4" | tr / _)" if [ "\${DENY_READ:-0}" = 1 ]; then echo "permission denied" >&2; exit 2; fi [ -f "\$f" ] || { echo "No value found at \$4" >&2; exit 2; } cat "\$f" ;; *) echo "unexpected call: \$*" >&2; exit 98 ;; esac STUB chmod +x "$dir/bin/bao" export PATH="$dir/bin:$PATH" KEYLEAF=secret_swarm_hives_alpha_attic_public-key TOKENLEAF=secret_swarm_hives_alpha_attic_pull-token reset() { rm -rf "$dir/store" "$dir/attic" "$calls" mkdir -p "$dir/store" : >"$calls" } seed() { # printf '%s' "$1" >"$dir/store/$KEYLEAF" printf '%s' "$2" >"$dir/store/$TOKENLEAF" } # run [VAR=value…]: the script's exit status. run() { env "$@" bash "$dir/script.sh" >"$dir/out" 2>"$dir/err" } mode() { stat -c %a "$1" 2>/dev/null || echo missing; } ino() { stat -c %i "$1" 2>/dev/null || echo missing; } body() { cat "$1" 2>/dev/null || echo missing; } case="first run writes the key and the netrc, each 0600, in a 0700 directory" reset seed "swarm:S0VZ" "tok-1" run expect "exit" $? 0 expect "key" "$(body "$dir/attic/public-key")" "swarm:S0VZ" expect "netrc" "$(body "$dir/attic/netrc")" "machine cache.example password tok-1" expect "key mode" "$(mode "$dir/attic/public-key")" 600 expect "netrc mode" "$(mode "$dir/attic/netrc")" 600 expect "dir mode" "$(mode "$dir/attic")" 700 case="a second run with the same facts rewrites nothing" k=$(ino "$dir/attic/public-key") n=$(ino "$dir/attic/netrc") run expect "exit" $? 0 expect "key untouched" "$(ino "$dir/attic/public-key")" "$k" expect "netrc untouched" "$(ino "$dir/attic/netrc")" "$n" case="a rotated token replaces the netrc and leaves the key" seed "swarm:S0VZ" "tok-2" run expect "exit" $? 0 expect "netrc" "$(body "$dir/attic/netrc")" "machine cache.example password tok-2" expect "netrc mode" "$(mode "$dir/attic/netrc")" 600 expect "key untouched" "$(ino "$dir/attic/public-key")" "$k" case="a rotated key replaces the key file" seed "swarm:Tk9XCg" "tok-2" run expect "exit" $? 0 expect "key" "$(body "$dir/attic/public-key")" "swarm:Tk9XCg" case="only the hive's own leaves are read, after a login" expect "reads" "$(grep -c '^bao kv get' "$calls")" "$(grep -c '^bao kv get -field=value secret/swarm/hives/alpha/attic/' "$calls")" expect "login first" "$(head -1 "$calls")" "bao login -method=cert -token-only" expect "something was read" "$([ "$(grep -c '^bao kv get' "$calls")" -ge 2 ] && echo yes || echo no)" yes case="a store with no facts exits cleanly and creates nothing" reset run expect "exit" $? 0 expect "no key" "$(body "$dir/attic/public-key")" missing expect "no netrc" "$(body "$dir/attic/netrc")" missing case="one fact without the other creates nothing" reset printf '%s' "swarm:S0VZ" >"$dir/store/$KEYLEAF" run expect "exit" $? 0 expect "no key" "$(body "$dir/attic/public-key")" missing expect "no netrc" "$(body "$dir/attic/netrc")" missing # The failure cases start from a good state and an extra file in the directory. good() { reset seed "swarm:S0VZ" "tok-1" run touch "$dir/attic/other" } intact() { expect "key kept" "$(body "$dir/attic/public-key")" "swarm:S0VZ" expect "netrc kept" "$(body "$dir/attic/netrc")" "machine cache.example password tok-1" expect "other file kept" "$(body "$dir/attic/other")" "" } case="a store that refuses the login fails the run and removes nothing" good seed "swarm:NEW" "tok-new" run LOGIN_FAIL=1 expect "exit" $? 1 intact case="a store that refuses the read fails the run and removes nothing" good run DENY_READ=1 expect "exit" $? 1 intact case="a key with whitespace is refused and nothing changes" good seed "swarm:S0 VZ" "tok-new" run expect "exit" $? 1 intact case="a token with whitespace is refused and nothing changes" good seed "swarm:S0VZ" "tok new" run expect "exit" $? 1 intact case="a key without a name is refused and nothing changes" good seed "S0VZ" "tok-new" run expect "exit" $? 1 intact if [ "$failures" -ne 0 ]; then echo "$failures of $count checks failed" >&2 exit 1 fi echo "$count checks passed"