AtlatestRepositoryapiary

apiary / tree / testsmoke.sh

1#!/usr/bin/env bash
2#
3# End-to-end smoke for apiary. Boots a throwaway enclave-server,
4# provisions a daviwil/admin user + leader-davos bot, then runs:
5#
6# 1. test/smoke-driver.sgl — exercises the live bridge path:
7# tool registration (both modes), connect, presence broadcast,
8# trusted-set filter, listen-peer mechanics, self-echo check.
9#
10# 2. The release `apiary` binary — boots it pointed at the
11# throwaway server, confirms it connects, lets it idle a few
12# seconds, then SIGTERMs it. Verifies clean exit.
14# Prerequisites:
15# - enclave-server built at $ENCLAVE_BIN (default:
16# ~/Projects/Code/sigil/enclave/build/dev/bin/enclave)
17# - apiary release bundle built at build/release/bin/apiary
18# (the script will build it if missing)
20set -u
21PORT=${PORT:-49669}
22ENCLAVE_REPO=${ENCLAVE_REPO:-$HOME/Projects/Code/sigil/enclave}
23ENCLAVE_BIN=${ENCLAVE_BIN:-$ENCLAVE_REPO/build/dev/bin/enclave}
24APIARY_REPO=${APIARY_REPO:-$(pwd)}
25APIARY_BIN=${APIARY_BIN:-$APIARY_REPO/build/release/bin/apiary}
26DB=${DB:-/tmp/apiary-smoke.db}
28if [ ! -x "$ENCLAVE_BIN" ]; then
29 echo "FATAL: enclave binary not found at $ENCLAVE_BIN" >&2
30 exit 1
31fi
33if [ ! -x "$APIARY_BIN" ]; then
34 echo "==> apiary release bundle missing; building it"
35 (cd "$APIARY_REPO" && \
36 sigil build apiary -c release --backend bytecode --force) \
37 || { echo "FATAL: apiary build failed"; exit 1; }
38fi
40SERVER_LOG=$(mktemp)
41SMOKE_LOG=$(mktemp)
42APIARY_LOG=$(mktemp)
43SERVER=
44APIARY_PID=
46cleanup() {
47 [ -n "${APIARY_PID:-}" ] && kill "$APIARY_PID" 2>/dev/null
48 [ -n "${SERVER:-}" ] && kill "$SERVER" 2>/dev/null
49 wait 2>/dev/null
50 rm -f "$SERVER_LOG" "$SMOKE_LOG" "$APIARY_LOG"
51 rm -f "$DB" "$DB-shm" "$DB-wal"
53trap cleanup EXIT
55echo "==> seeding DB at $DB"
56rm -f "$DB" "$DB-shm" "$DB-wal"
58DAVIWIL_PASS=admin
59ENCLAVE_DB_PATH="$DB" "$ENCLAVE_BIN" \
60 user add daviwil --password "$DAVIWIL_PASS" --role admin > /dev/null
62# Pre-create the ops-workers group so the Bug-A smoke check (which
63# spawns a worker without an explicit `groups` arg and verifies it
64# lands in APIARY_WORKER_GROUP) has a real group to land in.
65ENCLAVE_DB_PATH="$DB" "$ENCLAVE_BIN" \
66 group create ops-workers > /dev/null 2>&1 || true
68LEADER_OUT=$(ENCLAVE_DB_PATH="$DB" "$ENCLAVE_BIN" \
69 bot register leader-davos --owner daviwil --allow-services yes --auto-join "#hive")
70LEADER_TOKEN=$(echo "$LEADER_OUT" | grep -oE '[a-f0-9]{64}' | head -1)
71[ -z "$LEADER_TOKEN" ] && { echo "FATAL: no leader-davos token" >&2; exit 1; }
72echo " leader-davos token: ${LEADER_TOKEN:0:8}…(${#LEADER_TOKEN})"
74echo "==> starting enclave-server on :$PORT"
75ENCLAVE_LOG_LEVEL=warn ENCLAVE_PORT="$PORT" ENCLAVE_DB_PATH="$DB" \
76 "$ENCLAVE_BIN" serve > "$SERVER_LOG" 2>&1 &
77SERVER=$!
78sleep 2
79kill -0 "$SERVER" 2>/dev/null || \
80 { echo "FATAL: server died"; cat "$SERVER_LOG" >&2; exit 1; }
82# ============================================================
83# Phase 1: sigil-test driver against the live server
84# ============================================================
85echo "==> running test/smoke-driver.sgl"
86cd "$APIARY_REPO"
87APIARY_ENCLAVE_HOST=127.0.0.1 \
88APIARY_ENCLAVE_PORT="$PORT" \
89APIARY_ENCLAVE_TLS=no \
90APIARY_USER=leader-davos \
91APIARY_TOKEN="$LEADER_TOKEN" \
92APIARY_CHANNEL=#hive \
93APIARY_OWNER_NICK=daviwil \
94APIARY_REPORTS_TO=daviwil \
95APIARY_WORKER_GROUP=ops-workers \
96APIARY_SERVICES_TIMEOUT=8.0 \
97APIARY_DAVIWIL_PASS="$DAVIWIL_PASS" \
98sigil test test/smoke-driver.sgl > "$SMOKE_LOG" 2>&1
99SMOKE_EXIT=$?
101echo
102echo "==> driver output:"
103sed 's/^/ /' "$SMOKE_LOG"
105if [ "$SMOKE_EXIT" != "0" ] || ! grep -q "All tests passed" "$SMOKE_LOG"; then
106 echo
107 echo "DRIVER FAILED (exit=$SMOKE_EXIT)"
108 exit 1
109fi
111# ============================================================
112# Phase 2: rotate a fresh leader token (smoke driver consumed
113# auth state on the previous token), then run the release
114# `apiary` binary briefly. SIGTERM after a short idle.
115# ============================================================
116echo
117echo "==> rotating leader-davos token for the binary smoke"
118LEADER_OUT2=$(ENCLAVE_DB_PATH="$DB" "$ENCLAVE_BIN" \
119 bot rotate-token leader-davos)
120LEADER_TOKEN2=$(echo "$LEADER_OUT2" | grep -oE '[a-f0-9]{64}' | head -1)
121[ -z "$LEADER_TOKEN2" ] && { echo "FATAL: no rotated token" >&2; exit 1; }
123echo "==> launching apiary binary against the throwaway server"
124export APIARY_ENCLAVE_HOST=127.0.0.1
125export APIARY_ENCLAVE_PORT="$PORT"
126export APIARY_ENCLAVE_TLS=no
127export APIARY_USER=leader-davos
128export APIARY_TOKEN="$LEADER_TOKEN2"
129export APIARY_CHANNEL=#hive
130export APIARY_OWNER_NICK=daviwil
131export APIARY_REPORTS_TO=daviwil
132export APIARY_SERVICES_TIMEOUT=8.0
133export APIARY_MODE=leader
134# Drive the MCP loop with a fake initialize handshake so the bridge
135# kicks in (channel-wait-initialized! gates on the MCP `initialize`
136# request). Then keep stdin open via `tail -f` so the loop doesn't
137# return.
138INIT_JSON='{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smoke","version":"0.0"}}}'
139INITED_JSON='{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}'
140(printf '%s\n%s\n' "$INIT_JSON" "$INITED_JSON"; tail -f /dev/null) \
141 | "$APIARY_BIN" > "$APIARY_LOG" 2>&1 &
142APIARY_PID=$!
144# Wait up to 6s for "Apiary bridge connected" to appear.
145for _ in $(seq 1 60); do
146 if grep -q "Apiary bridge connected" "$APIARY_LOG"; then
147 break
148 fi
149 sleep 0.1
150done
152if ! grep -q "Apiary bridge connected" "$APIARY_LOG"; then
153 echo
154 echo "BINARY FAILED to connect"
155 echo "==> apiary log:"
156 sed 's/^/ /' "$APIARY_LOG"
157 exit 1
158fi
159echo " apiary bridge connected"
161# Idle briefly so any deferred goroutine crash surfaces.
162sleep 1
164# Send SIGTERM and verify the binary exits cleanly.
165kill -TERM "$APIARY_PID" 2>/dev/null
166wait "$APIARY_PID" 2>/dev/null
167APIARY_EXIT=$?
168APIARY_PID=
170echo
171echo "==> apiary log (tail):"
172tail -20 "$APIARY_LOG" | sed 's/^/ /'
174# Standard SIGTERM exit code on POSIX is 143 (128+15). Treat 0
175# and 143 as clean.
176if [ "$APIARY_EXIT" = "0" ] || [ "$APIARY_EXIT" = "143" ]; then
177 echo
178 echo "ALL CHECKS PASSED (apiary exit=$APIARY_EXIT)"
179 exit 0
180else
181 echo
182 echo "BINARY EXIT UNCLEAN (exit=$APIARY_EXIT)"
183 exit 1
184fi