# Cases for ./agent-backend-env.nix. Each case gets a fresh runtime directory, # credentials directory, operator's file and store, runs the unit's script under # the unit's `UMask=0077` with a clean environment, and asserts on the exit # code, the output, the files left behind and the `bao` calls made. set -uo pipefail failures=0 count=0 fail() { echo "FAILED: $case: $*" >&2 failures=$((failures + 1)) } leaf=secret/swarm/agents/a1/backend-env login_call="login -method=cert -token-only" get_call="kv get -field=env $leaf" # setup setup() { case=$1 dir=$(mktemp -d) rt=$dir/rt creds=$dir/creds log=$dir/bao.log kv=$dir/kv earlier=$dir/earlier.env mkdir -m 0700 "$rt" mkdir "$creds" "$kv" printf cert >"$creds/hive-agent-bao-cert" printf key >"$creds/hive-agent-bao-key" : >"$log" if ! sed -e "s|/run/hive-agent-backend-env/|$rt/|g" -e "s|$EARLIER_FILE|$earlier|g" \ "$UNIT_SCRIPT" >"$dir/script"; then echo "cannot read the rendered script" >&2 exit 1 fi chmod +x "$dir/script" if grep -q '/run/' "$dir/script"; then fail "the script still names /run after the rewrite"; fi if ! grep -qF "$earlier" "$dir/script"; then fail "the rewrite did not reach the operator's file"; fi login_rc=0 deny_read= deny_write= race= stored=$kv/$(printf '%s' "$leaf" | tr / _) } go() { count=$((count + 1)) ( umask 0077 cd "$dir" || exit 99 exec env -i \ PATH="$FAKE_BAO_BIN:$UNIT_PATH" \ BAO_ADDR="$UNIT_BAO_ADDR" \ BAO_CLIENT_CERT="$creds/hive-agent-bao-cert" \ BAO_CLIENT_KEY="$creds/hive-agent-bao-key" \ CREDENTIALS_DIRECTORY="$creds" \ FAKE_BAO_LOG="$log" \ FAKE_BAO_KV="$kv" \ FAKE_BAO_LOGIN_RC="$login_rc" \ FAKE_BAO_DENY_READ="$deny_read" \ FAKE_BAO_DENY_WRITE="$deny_write" \ FAKE_BAO_RACE="$race" \ "$dir/script" ) >"$dir/out" 2>"$dir/err" rc=$? } expect_rc() { if [ "$rc" != "$1" ]; then fail "exit $rc, expected $1; stderr: $(<"$dir/err")"; fi } expect_err() { if ! grep -qF -- "$1" "$dir/err"; then fail "stderr lacks '$1'; stderr: $(<"$dir/err")"; fi } expect_out() { if ! grep -qF -- "$1" "$dir/out"; then fail "stdout lacks '$1'; stdout: $(<"$dir/out")"; fi } # expect_calls ... — the exact `bao` argument lines, in order. expect_calls() { local want want=$(printf '%s\n' "$@") if [ "$(<"$log")" != "${want%$'\n'}" ]; then fail "bao calls were '$(<"$log")', expected '$*'"; fi } expect_no_calls() { if [ -s "$log" ]; then fail "bao was called: $(<"$log")"; fi } # expect_same — byte for byte, trailing newlines included. expect_same() { if [ ! -e "$1" ]; then fail "$1 missing" return fi if ! printf '%s' "$2" | cmp -s - "$1"; then fail "$1 holds '$(<"$1")', expected '$2'"; fi } expect_no_file() { if [ -e "$1" ]; then fail "$1 left behind"; fi } # The operator's file, kept to compare after the run. put_earlier() { printf '%s' "$1" >"$earlier" chmod 0600 "$earlier" earlier_inode=$(stat -c %i "$earlier") } expect_earlier_untouched() { expect_same "$earlier" "$1" if [ "$(stat -c %i "$earlier")" != "$earlier_inode" ]; then fail "the operator's file was replaced"; fi } # A leaf holding before the run. put_leaf() { printf '%s' "$1" >"$stored" } expect_leaf() { expect_same "$stored" "$1" } file_text=$'ANTHROPIC_API_KEY=k-file\nANTHROPIC_BASE_URL=http://x\n' setup "no store identity delivered" : >"$creds/hive-agent-bao-cert" put_earlier "$file_text" go expect_rc 0 expect_err "has no store identity" expect_no_calls expect_no_file "$rt/env" setup "a store holding nothing is seeded from the file, bytes unchanged, and the store's value is used" put_earlier "$file_text" go expect_rc 0 expect_calls "$login_call" "$get_call" "kv put -cas=0 $leaf env=@$earlier" "$get_call" expect_leaf "$file_text" expect_same "$rt/env" "$file_text" expect_earlier_untouched "$file_text" if [ "$(stat -c %a "$rt/env")" != 600 ]; then fail "env is mode $(stat -c %a "$rt/env"), expected 600"; fi expect_no_file "$rt/env.new" expect_no_file "$rt/bao.err" setup "a file with no final newline is seeded exactly" put_earlier 'ANTHROPIC_API_KEY=k-file' go expect_rc 0 expect_leaf 'ANTHROPIC_API_KEY=k-file' expect_same "$rt/env" 'ANTHROPIC_API_KEY=k-file' expect_earlier_untouched 'ANTHROPIC_API_KEY=k-file' setup "a value in the store wins over the file and is not written back to it" put_earlier "$file_text" put_leaf $'ANTHROPIC_API_KEY=k-bao\n' go expect_rc 0 expect_calls "$login_call" "$get_call" expect_leaf $'ANTHROPIC_API_KEY=k-bao\n' expect_same "$rt/env" $'ANTHROPIC_API_KEY=k-bao\n' expect_earlier_untouched "$file_text" setup "an unchanged store value leaves the file in place" put_leaf "$file_text" printf '%s' "$file_text" >"$rt/env" chmod 0600 "$rt/env" before=$(stat -c %i "$rt/env") go expect_rc 0 expect_out "is unchanged" expect_same "$rt/env" "$file_text" if [ "$(stat -c %i "$rt/env")" != "$before" ]; then fail "the unchanged env was replaced"; fi setup "a changed store value replaces the file in place" put_leaf $'ANTHROPIC_API_KEY=k-new\n' printf old >"$rt/env" chmod 0600 "$rt/env" go expect_rc 0 expect_out "fetched this agent's backend environment" expect_same "$rt/env" $'ANTHROPIC_API_KEY=k-new\n' expect_no_file "$rt/env.new" setup "no file and nothing in the store writes nothing" go expect_rc 0 expect_out "no file to create it from" expect_calls "$login_call" "$get_call" expect_no_file "$rt/env" expect_no_file "$stored" setup "an empty file is never stored" put_earlier "" go expect_rc 0 expect_calls "$login_call" "$get_call" expect_no_file "$rt/env" expect_no_file "$stored" setup "nothing in the store leaves an env fetched earlier alone" printf kept >"$rt/env" chmod 0600 "$rt/env" go expect_rc 0 expect_same "$rt/env" kept setup "a store that refuses the login with a file in place changes nothing and fails the unit" put_earlier "$file_text" login_rc=2 go expect_rc 1 expect_err "did not accept this agent's certificate login" expect_err "no such host" expect_calls "$login_call" expect_no_file "$rt/env" expect_no_file "$stored" expect_earlier_untouched "$file_text" setup "a lost race reads back the winner's value and keeps the file" put_earlier "$file_text" race=$'ANTHROPIC_API_KEY=k-winner\n' go expect_rc 0 expect_calls "$login_call" "$get_call" "kv put -cas=0 $leaf env=@$earlier" "$get_call" expect_err "could not create $leaf" expect_leaf $'ANTHROPIC_API_KEY=k-winner\n' expect_same "$rt/env" $'ANTHROPIC_API_KEY=k-winner\n' expect_earlier_untouched "$file_text" setup "a policy that refuses the create leaves the file to carry the agent" put_earlier "$file_text" deny_write=1 go expect_rc 0 expect_calls "$login_call" "$get_call" "kv put -cas=0 $leaf env=@$earlier" "$get_call" expect_err "permission denied" expect_err "holds no usable env" expect_no_file "$rt/env" expect_no_file "$stored" expect_earlier_untouched "$file_text" setup "a leaf that exists but holds no env is not overwritten" put_earlier "$file_text" put_leaf "" go expect_rc 0 expect_calls "$login_call" "$get_call" expect_err "holds no usable env" expect_leaf "" expect_no_file "$rt/env" setup "a leaf without the env field is not overwritten" put_earlier "$file_text" put_leaf "x" printf other >"$stored.field" go expect_rc 0 expect_calls "$login_call" "$get_call" expect_leaf "x" expect_no_file "$rt/env" setup "a refused read fails the unit and writes nothing" put_earlier "$file_text" deny_read=1 go expect_rc 1 expect_err "could not read $leaf" expect_err "permission denied" expect_calls "$login_call" "$get_call" expect_no_file "$rt/env" expect_earlier_untouched "$file_text" # `UMask=0077` makes every file the script creates 0600; a stale leftover of a # stopped run must not block the next. setup "leftovers of a stopped run do not block the fetch" put_leaf $'ANTHROPIC_API_KEY=k-bao\n' printf stale >"$rt/env.new" printf stale >"$rt/bao.err" go expect_rc 0 expect_same "$rt/env" $'ANTHROPIC_API_KEY=k-bao\n' expect_no_file "$rt/env.new" expect_no_file "$rt/bao.err" # The control: the stub's create-only answer is what the lost-race and # refused-create cases lean on, so show it refuses a second create. setup "the stub refuses a create over an existing leaf" put_leaf kept printf x >"$dir/x" ( PATH="$FAKE_BAO_BIN:$PATH" BAO_TOKEN=s.fake FAKE_BAO_LOG=$log FAKE_BAO_KV=$kv \ bao kv put -cas=0 "$leaf" env=@"$dir/x" ) >/dev/null 2>"$dir/err" if [ $? -eq 0 ]; then fail "the stub took a second create"; fi expect_leaf kept if [ "$failures" -gt 0 ]; then echo "script-test-agent-backend-env: $failures failed assertions over $count runs" >&2 exit 1 fi echo "script-test-agent-backend-env: $count runs, all assertions hold"