#!/usr/bin/env bash
# Proves buildbox-sshd-access serializes itself. Runs anywhere, as anyone: the lock is
# taken before the root check, so both branches are observable without touching a host.
set -uo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SCRIPT="$HERE/../host-config/bin/buildbox-sshd-access"
[ -x "$SCRIPT" ] || { echo "not executable: $SCRIPT" >&2; exit 2; }

WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT
LOCK="$WORK/lock"
# The forced non-root test identity below must be able to open only this disposable
# lock, so the test observes flock rather than filesystem permissions.
chmod 755 "$WORK"
: >"$LOCK"
chmod 666 "$LOCK"

pass=0; fail=0
ok()  { pass=$((pass+1)); printf 'ok   %s\n' "$1"; }
bad() { fail=$((fail+1)); printf 'FAIL %s\n' "$1"; }

# The forced non-root identity is test-only.  The uncontended assertion only needs to
# reach the root guard; running the converge itself would rewrite this machine's sshd
# configuration when CI happens to run as root.
run() {
  BUILDBOX_SSHD_ACCESS_LOCK="$LOCK" BUILDBOX_SSHD_ACCESS_LOCK_WAIT="$1" \
    BUILDBOX_SSHD_ACCESS_EFFECTIVE_UID=65534 "$SCRIPT" 2>&1
}

# (a) contended: a second run must give up rather than write the config underneath the first
exec 8>"$LOCK"
flock 8 || { echo "test could not take the lock" >&2; exit 2; }
out="$(run 1)"; rc=$?
[ "$rc" = 3 ] && ok "a contended run exits 3" || bad "contended run exited $rc, want 3"
case "$out" in
  *"another run held"*) ok "it says which lock it waited on and for how long" ;;
  *) bad "unhelpful contention message: $out" ;;
esac
exec 8>&-

# (b) uncontended: the lock is released with the holder and the next run proceeds past it.
# The forced non-root caller stops at the root check, which is proof it got through the lock.
out="$(run 1)"; rc=$?
[ "$rc" = 2 ] && ok "an uncontended run passes the lock and reaches the root check" \
  || bad "uncontended run exited $rc, want 2"
case "$out" in
  *"must run as root"*) ok "it failed for the right reason" ;;
  *) bad "wrong failure: $out" ;;
esac

printf '\n%d passed, %d failed\n' "$pass" "$fail"
[ "$fail" = 0 ]
