app: scaffold echolot-app + core-protocol — client spine verified live vs fmr
Multi-module Android app, built bottom-up from a verifiable core. core-protocol is pure Kotlin/JVM (no Android SDK): SPKI-pinned control plane (enroll/profile/session over HttpsURLConnection — API-1 compatible, hostname verification off, trust is the pin), HKDF-SHA256 session keys, ELT1 UDP data plane (HMAC gate, ECHO+observation, MTU probe) — byte-compatible with the Go server. Unit tests incl. the RFC 5869 HKDF vector (key derivation provably matches the server). LiveServerTest + scripts/test-fmr.sh prove the client end-to-end against the deployed fmr server: profile (8 caps), session, ECHO rtt~11ms with the observation block returning our observed NAT port, MTU 1400->1400, observations. Live test self-skips without ECHOLOT_LIVE_*. Two client bugs caught live: java.net.http hostname verification (→ HttpsURLConnection, also the Android-minSdk-26 choice) and ECHO padding needed for the observation to survive anti-amplification. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
b229eeb674
commit
3520eabd21
@@ -0,0 +1,44 @@
|
||||
#!/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
|
||||
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} ..."
|
||||
TOKEN=$(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"])')
|
||||
|
||||
echo "· enrolling over ${CTL_URL} ..."
|
||||
CRED=$(curl -sk -X POST "${CTL_URL}/v1/enroll" -H "Authorization: Bearer ${TOKEN}" \
|
||||
| python -c 'import json,sys;print(json.load(sys.stdin)["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}"
|
||||
echo "· running LiveServerTest ..."
|
||||
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}" \
|
||||
./gradlew :core-protocol:test --tests '*LiveServerTest*' --info --rerun-tasks --console=plain \
|
||||
2>&1 | grep -E "profile:|session:|echo |mtu probe|observations bytes|LiveServerTest|BUILD|FAIL|PASS" || true
|
||||
Reference in New Issue
Block a user