123set -euo pipefail45script_dir="$(CDPATH='' cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"6repo_dir="$(CDPATH='' cd -- "$script_dir/../.." && pwd -P)"7temp_parent="${TMPDIR:-/tmp}"8temp_parent="${temp_parent%/}"9temp_root="$(mktemp -d "$temp_parent/sigil-auth-probe.XXXXXX")"1011host_pid=""12cleanup() {13 local status=$?14 trap - EXIT INT TERM HUP15 if [[ -n "$host_pid" ]] && kill -0 "$host_pid" 2>/dev/null; then16 kill -TERM "$host_pid" 2>/dev/null || true17 wait "$host_pid" 2>/dev/null || true18 fi19 case "$temp_root" in20 "$temp_parent"/sigil-auth-probe.??????) rm -rf -- "$temp_root" ;;21 esac22 exit "$status"23}24trap cleanup EXIT INT TERM HUP2526die() {27 printf 'authenticated probe proof failed: %s\n' "$*" >&228 exit 129}3031wait_for_ready() {32 local deadline=$((SECONDS + 30))33 while (( SECONDS < deadline )); do34 grep -Fxq 'status=ready' "$host_log" 2>/dev/null && return 035 kill -0 "$host_pid" 2>/dev/null || return 136 sleep 0.137 done38 return 139}4041wait_for_log_count() {42 local literal="$1"43 local expected="$2"44 local deadline=$((SECONDS + 15))45 local observed46 while (( SECONDS < deadline )); do47 observed="$(grep -Fc -- "$literal" "$host_log" 2>/dev/null || true)"48 [[ "$observed" -ge "$expected" ]] && return 049 kill -0 "$host_pid" 2>/dev/null || return 150 sleep 0.151 done52 return 153}5455cd "$repo_dir"56if [[ -f "${HOME}/.cargo/env" ]]; then57 # shellcheck source=/dev/null58 source "${HOME}/.cargo/env"59fi60cargo build --locked -p sigil-host --bins6162target_root="${CARGO_TARGET_DIR:-$repo_dir/target}"63case "$target_root" in64 /*) ;;65 *) target_root="$repo_dir/$target_root" ;;66esac67host_bin="$target_root/debug/sigil"68probe_bin="$target_root/debug/sigil-probe"69ffmpeg_bin="$(command -v ffmpeg)"70[[ -x "$host_bin" && -x "$probe_bin" ]] || die 'host/probe binaries are missing'71[[ -x "$ffmpeg_bin" ]] || die 'ffmpeg is unavailable'7273export XDG_RUNTIME_DIR="$temp_root/xdg"74install -d -m 0700 "$XDG_RUNTIME_DIR"75host_identity="$temp_root/host.key"76probe_identity="$temp_root/probe.key"77host_config="$temp_root/host.toml"78invitation="$temp_root/probe.goq-invite"79host_log="$temp_root/host.log"80first_log="$temp_root/first.log"81reconnect_log="$temp_root/reconnect.log"82compat_log="$temp_root/compat.log"83replay_log="$temp_root/replay.log"8485"$host_bin" identity init --output "$host_identity" >"$temp_root/host-identity.log"86"$host_bin" identity init --output "$probe_identity" >"$temp_root/probe-identity.log"87host_node_id="$(sed -n 's/^node_id=//p' "$temp_root/host-identity.log")"88probe_node_id="$(sed -n 's/^node_id=//p' "$temp_root/probe-identity.log")"89[[ -n "$host_node_id" && -n "$probe_node_id" ]] || die 'identity output is incomplete'9091printf '%s\n' \92 "identity_path = \"$host_identity\"" \93 "state_path = \"$temp_root/state\"" \94 'source = "test-pattern"' \95 'width = 1280' \96 'height = 800' \97 'framerate = 60' \98 'codec = "h264"' \99 'input_mode = "log"' \100 "ffmpeg_path = \"$ffmpeg_bin\"" \101 >"$host_config"102chmod 0600 "$host_config"103"$host_bin" config check --config "$host_config" >/dev/null104105RUST_LOG='info,sigil::server=debug' "$host_bin" serve \106 --config "$host_config" \107 --max-runtime-seconds 90 \108 >"$host_log" 2>&1 &109host_pid=$!110wait_for_ready || {111 sed -n '1,160p' "$host_log" >&2 || true112 die 'configured host did not become ready'113}114"$host_bin" invitation create \115 --config "$host_config" \116 --peer "$probe_node_id" \117 --pointer-keyboard \118 --output "$invitation" \119 >/dev/null120121"$probe_bin" \122 --node-id "$host_node_id" \123 --identity "$probe_identity" \124 --invitation "$invitation" \125 --frames 1 \126 >"$first_log"127wait_for_log_count 'MoQ control client released' 1 \128 || die 'first authenticated session did not drain'129130"$probe_bin" \131 --node-id "$host_node_id" \132 --identity "$probe_identity" \133 --frames 1 \134 >"$reconnect_log"135wait_for_log_count 'MoQ control client released' 2 \136 || die 'ticket-free session did not drain'137138"$probe_bin" \139 --node-id "$host_node_id" \140 --identity "$probe_identity" \141 --media-v3 \142 --frames 1 \143 >"$compat_log"144wait_for_log_count 'media v3 client released' 1 \145 || die 'grouped-v3 session did not drain'146147for proof_log in "$first_log" "$reconnect_log" "$compat_log"; do148 grep -Fxq 'probe=ok' "$proof_log" || die "probe evidence is missing from $proof_log"149 grep -Fxq 'sequence_gaps=0' "$proof_log" || die "sequence gap in $proof_log"150 awk -F= '$1 == "input_ack_micros" && $2 ~ /^[0-9]+$/ { found=1 } END { exit !found }' \151 "$proof_log" || die "input acknowledgment is missing from $proof_log"152done153grep -Fxq 'transport=iroh-moq' "$first_log" || die 'first transport is not upstream MoQ'154grep -Fxq 'transport=iroh-moq' "$reconnect_log" || die 'reconnect transport is not upstream MoQ'155grep -Fxq 'transport=grouped-v3' "$compat_log" || die 'compatibility transport is not grouped-v3'156157if "$probe_bin" \158 --node-id "$host_node_id" \159 --identity "$probe_identity" \160 --invitation "$invitation" \161 --frames 4 \162 >"$replay_log" 2>&1; then163 die 'redeemed invitation replay was accepted'164fi165grep -Fq 'host rejected control stream: Portal peer is not authorized' "$replay_log" \166 || {167 sed -n '1,80p' "$replay_log" >&2 || true168 die 'redeemed invitation replay returned the wrong rejection'169 }170enrollment="$($host_bin enrollment show --config "$host_config")"171grep -Fxq 'enrollment=active' <<<"$enrollment" || die 'probe enrollment is not active'172grep -Fxq "peer_node_id=$probe_node_id" <<<"$enrollment" \173 || die 'enrollment belongs to the wrong peer'174grep -Fxq 'grants=view,pointer-keyboard' <<<"$enrollment" \175 || die 'enrollment grants changed'176177printf 'authenticated_probe_proof=ok\n'178printf 'invitation_redemption=ok\n'179printf 'ticket_free_reconnect=ok\n'180printf 'grouped_v3_reconnect=ok\n'181printf 'invitation_replay=rejected\n'