#!/usr/bin/env bash # Fast, sandboxed selftests for the auth checkpoint (M19). # # No Docker, no network, no real credentials: every case runs against # fixture files via PI_AUTH_FILE. The suite asserts the core safety # property: credential MATERIAL from fixtures never reaches auth.sh or # agent.sh output. set -uo pipefail cd "$(dirname "$0")/.." SANDBOX="$(mktemp -d)" trap 'rm -rf "$SANDBOX"' EXIT PASS=0 FAIL=0 # Status colors: terminal-only, NO_COLOR-respecting; plain when piped. if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then C_OK=$'\033[0;32m'; C_FAIL=$'\033[0;31m'; C_RESET=$'\033[0m' else C_OK=""; C_FAIL=""; C_RESET="" fi check() { if [ "$2" = "0" ]; then PASS=$((PASS+1)); echo "${C_OK}OK${C_RESET} $1"; else FAIL=$((FAIL+1)); echo "${C_FAIL}FAIL${C_RESET} $1"; fi } SECRET="SK-TEST-DO-NOT-PRINT-9f2b" TOKEN="ACCESS-TOKEN-SHOULD-NOT-PRINT" ENVVAL="ENVVAL-SHOULD-NOT-PRINT" mkdir -p "$SANDBOX/creds" "$SANDBOX/empty" printf '{"anthropic":{"type":"oauth","access":"%s"},"zai":{"type":"api_key","key":"%s"}}' "$TOKEN" "$SECRET" > "$SANDBOX/creds/auth.json" printf '{}' > "$SANDBOX/creds/auth.work.json" printf '{}' > "$SANDBOX/creds/auth.personal.json" # status: missing credential file -> exit 3 (config missing for a read) OUT="$(PI_AUTH_FILE="$SANDBOX/creds/absent.json" scripts/auth.sh status 2>"$SANDBOX/err.txt")"; RC=$? [ "$RC" -eq 3 ] && grep -q "credential file not found" "$SANDBOX/err.txt" \ && check "status on missing credential file exits 3" 0 || check "status on missing credential file exits 3" 1 # status: happy path — providers sorted with credential types OUT="$(PI_AUTH_FILE="$SANDBOX/creds/auth.json" scripts/auth.sh status 2>&1)"; RC=$? [ "$RC" -eq 0 ] \ && printf '%s\n' "$OUT" | grep -q ' anthropic type=oauth source=auth\.json' \ && printf '%s\n' "$OUT" | grep -q ' zai type=api_key source=auth\.json' \ && check "status lists providers with credential types" 0 || check "status lists providers with credential types" 1 # the core safety property: fixture secret material never reaches output printf '%s\n' "$OUT" | grep -q "$SECRET" \ && check "api key material never reaches output" 1 || check "api key material never reaches output" 0 printf '%s\n' "$OUT" | grep -q "$TOKEN" \ && check "oauth token material never reaches output" 1 || check "oauth token material never reaches output" 0 # status: unparseable file -> exit 2 printf 'not json' > "$SANDBOX/creds/broken.json" PI_AUTH_FILE="$SANDBOX/creds/broken.json" scripts/auth.sh status >/dev/null 2>&1; RC=$? [ "$RC" -eq 2 ] && check "unparseable credential file exits 2" 0 || check "unparseable credential file exits 2" 1 # status: symlinked credential file -> exit 4 (must be a regular file) ln -s "$SANDBOX/creds/auth.json" "$SANDBOX/creds/link.json" PI_AUTH_FILE="$SANDBOX/creds/link.json" scripts/auth.sh status >/dev/null 2>&1; RC=$? [ "$RC" -eq 4 ] && check "symlinked credential file exits 4" 0 || check "symlinked credential file exits 4" 1 # status: env-side names are informational — name shown, value never OUT="$(FAKE_TEST_API_KEY=$ENVVAL PI_AUTH_FILE="$SANDBOX/creds/auth.json" scripts/auth.sh status 2>&1)" printf '%s\n' "$OUT" | grep -q "FAKE_TEST_API_KEY" \ && check "env-side credential names reported" 0 || check "env-side credential names reported" 1 printf '%s\n' "$OUT" | grep -q "$ENVVAL" \ && check "env var values never reach output" 1 || check "env var values never reach output" 0 # accounts: empty directory -> (none), exit 0 OUT="$(PI_AUTH_FILE="$SANDBOX/empty/auth.json" scripts/auth.sh accounts 2>&1)"; RC=$? [ "$RC" -eq 0 ] && printf '%s\n' "$OUT" | grep -q "(none)" \ && check "accounts with no named files reports none" 0 || check "accounts with no named files reports none" 1 # accounts: listing with active marker OUT="$(PI_AUTH_FILE="$SANDBOX/creds/auth.work.json" scripts/auth.sh accounts 2>&1)"; RC=$? [ "$RC" -eq 0 ] && printf '%s\n' "$OUT" | grep -q '^ work <- active (PI_AUTH_FILE)$' \ && printf '%s\n' "$OUT" | grep -q '^ personal$' \ && check "accounts lists files and marks the active one" 0 || check "accounts lists files and marks the active one" 1 # accounts: missing directory -> exit 3 PI_AUTH_FILE="$SANDBOX/nodir/auth.json" scripts/auth.sh accounts >/dev/null 2>&1; RC=$? [ "$RC" -eq 3 ] && check "accounts on missing directory exits 3" 0 || check "accounts on missing directory exits 3" 1 # agent.sh --auth: missing account file refuses before any container work scripts/agent.sh researcher --auth nope /dev/null 2>"$SANDBOX/err.txt"; RC=$? [ "$RC" -eq 4 ] && grep -q "no credential file for auth account 'nope'" "$SANDBOX/err.txt" \ && check "agent --auth with missing account file refuses (exit 4)" 0 || check "agent --auth with missing account file refuses (exit 4)" 1 # agent.sh --auth: invalid account name refuses scripts/agent.sh researcher --auth "bad~name" /dev/null 2>"$SANDBOX/err.txt"; RC=$? [ "$RC" -eq 4 ] && grep -q "invalid auth account name" "$SANDBOX/err.txt" \ && check "agent --auth with invalid account name refuses" 0 || check "agent --auth with invalid account name refuses" 1 echo echo "selftest: $PASS passed, $FAIL failed" [ "$FAIL" -eq 0 ]