#!/usr/bin/env bash # SPDX-FileCopyrightText: 2026 Echolot contributors # SPDX-License-Identifier: GPL-3.0-or-later # # Runs core-protocol's LiveServerTest against the deployed fmr server: mints an # enrollment token over SSH (admin is localhost-only), enrolls over the public # control plane, computes the SPKI pin from the served cert, and hands the # whole lot to the Gradle test. Proves the Kotlin client talks to the real # server over the wire. # # Usage: JAVA_HOME=... echolot-app/scripts/test-fmr.sh [gradle-task] [test-filter] # e.g. ... test-fmr.sh :core-engine:test '*LiveGrantedTest*' set -euo pipefail SSH_HOST="${ECHOLOT_SSH:-claude-echolot}" CTL_HOST="${ECHOLOT_CTL_HOST:-fmr-1.echo-lot.app}" CTL_PORT="${ECHOLOT_CTL_PORT:-8443}" UDP_PORT="${ECHOLOT_UDP_PORT:-8442}" CTL_URL="https://${CTL_HOST}:${CTL_PORT}" echo "· minting enrollment token on ${SSH_HOST} ..." MINTED=$(ssh -o BatchMode=yes "$SSH_HOST" \ 'curl -s -X POST http://127.0.0.1:8444/admin/enroll-tokens') TOKEN=$(printf '%s' "$MINTED" | python -c 'import json,sys;print(json.load(sys.stdin)["token"])') # The server also returns the whole §2.1 bootstrap link. LiveEnrollmentTest redeems that link, # which is what proves the Go side and the Kotlin side agree on its encoding — a disagreement # there yields a pin wrong by one character, which fails much later and looks like anything but. ENROLL_URI=$(printf '%s' "$MINTED" \ | python -c 'import json,sys;print(json.load(sys.stdin).get("enroll_uri",""))') echo "· enrolling over ${CTL_URL} ..." # A second token, because the one above is single-use and may be spent by LiveEnrollmentTest. TOKEN2=$(ssh -o BatchMode=yes "$SSH_HOST" \ 'curl -s -X POST http://127.0.0.1:8444/admin/enroll-tokens' \ | python -c 'import json,sys;print(json.load(sys.stdin)["token"])') CRED=$(curl -sk -X POST "${CTL_URL}/v1/enroll" -H "Authorization: Bearer ${TOKEN2}" \ -H "X-Echolot-App-Version: 0.2.0" \ | python -c 'import json,sys;d=json.load(sys.stdin);print(d.get("device_credential") or d["credential"])') echo "· computing SPKI pin from served cert ..." PIN=$(echo | openssl s_client -connect "${CTL_HOST}:${CTL_PORT}" 2>/dev/null \ | openssl x509 -pubkey -noout \ | openssl pkey -pubin -outform der 2>/dev/null \ | openssl dgst -sha256 -binary | openssl base64) echo "· pin=${PIN}" TASK="${1:-:core-protocol:test}" FILTER="${2:-*LiveServerTest*}" echo "· running ${TASK} ${FILTER} ..." cd "$(dirname "$0")/.." ECHOLOT_LIVE_URL="$CTL_URL" \ ECHOLOT_LIVE_PIN="$PIN" \ ECHOLOT_LIVE_CRED="$CRED" \ ECHOLOT_LIVE_UDP="${CTL_HOST}:${UDP_PORT}" \ ECHOLOT_LIVE_TARGET="${ECHOLOT_LIVE_TARGET:-fmr}" \ ECHOLOT_ENROLL_URI="$ENROLL_URI" \ ./gradlew "$TASK" --tests "$FILTER" --info --rerun-tasks --console=plain \ 2>&1 | grep -E "profile:|capabilities:|session:|echo |primed|mtu probe|downtrain|big_send|largest|observations bytes|link:|parsed:|enrolled:|refused|Live[A-Za-z]*Test|BUILD|FAIL|PASS|^e:" || true