keep the cache's key and pull token for hive-priv in a root-only directory
This commit is contained in:
parent
d241e64ab1
commit
b845630023
1 changed files with 519 additions and 22 deletions
177
nix/script-tests/attic-root-facts.sh
Normal file
177
nix/script-tests/attic-root-facts.sh
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
# 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() { # <description> <got> <want>
|
||||
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 <path>` 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" <<STUB
|
||||
#!$BASH
|
||||
echo "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() { # <key> <token>
|
||||
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"
|
||||
Loading…
Reference in a new issue