Support mTLS clustering on the repl testing.

This commit is contained in:
Kalzu Rekku committed 2026-10-26 12:38:02 +02:00
1 parent 74049b47f3
commit ff16548585
1 file changed
+67 -21
Executable → Regular
+67 -21
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# ============================================================================== # ==============================================================================
# repl-test.sh: Integration harness for Records API & Replication # repl-test.sh: Integration harness for Records API & Replication (mTLS)
# Starts Primary (:3000), Replica (:3001), and Dashboard (:8080). # Starts Primary (:3000), Replica (:3001), and Dashboard (:8080).
# ============================================================================== # ==============================================================================
set -euo pipefail set -euo pipefail
@@ -12,7 +12,7 @@ WORK="${WORK:-$ROOT_DIR/repl-test}"
PRIMARY_PORT="${PRIMARY_PORT:-3000}" PRIMARY_PORT="${PRIMARY_PORT:-3000}"
REPLICA_PORT="${REPLICA_PORT:-3001}" REPLICA_PORT="${REPLICA_PORT:-3001}"
DASHBOARD_PORT="${DASHBOARD_PORT:-8080}" DASHBOARD_PORT="${DASHBOARD_PORT:-8080}"
TOKEN="${TOKEN:-change-me}" # Matches index.html default TOKEN="${TOKEN:-change-me}" # Replication bearer token
CORS_ORIGIN="${CORS_ORIGIN:-http://127.0.0.1:$DASHBOARD_PORT}" CORS_ORIGIN="${CORS_ORIGIN:-http://127.0.0.1:$DASHBOARD_PORT}"
START_DASHBOARD="${START_DASHBOARD:-1}" START_DASHBOARD="${START_DASHBOARD:-1}"
@@ -66,7 +66,6 @@ rm -rf "$WORK"
mkdir -p "$WORK/primary" "$WORK/replica" mkdir -p "$WORK/primary" "$WORK/replica"
# Schema allows "msg" and "message", requiring integer "version" # Schema allows "msg" and "message", requiring integer "version"
# This aligns with index.html tests and manual curl inputs.
for d in primary replica; do for d in primary replica; do
cat > "$WORK/$d/config.json" <<'EOF' cat > "$WORK/$d/config.json" <<'EOF'
{ {
@@ -93,8 +92,9 @@ start_node() {
wait_up() { wait_up() {
local name=$1 port=$2 local name=$1 port=$2
for _ in $(seq 1 50); do for _ in $(seq 1 60); do
if curl -sf "http://127.0.0.1:$port/api/now" >/dev/null 2>&1; then # Note: -k used since cluster cert is generated on boot
if curl -k -sf "https://127.0.0.1:$port/api/now" >/dev/null 2>&1; then
return 0 return 0
fi fi
sleep 0.1 sleep 0.1
@@ -107,17 +107,56 @@ wait_up() {
exit 1 exit 1
} }
# --- Launch Cluster --- # ==============================================================================
echo -e "\033[1;32m==> Starting Primary on :$PRIMARY_PORT\033[0m" # 1. Launch Primary (Cluster CA & Server Cert generated automatically)
# ==============================================================================
echo -e "\033[1;32m==> Starting Primary on :$PRIMARY_PORT (HTTPS/mTLS)...\033[0m"
start_node primary "$PRIMARY_PORT" APP_ROLE=primary start_node primary "$PRIMARY_PORT" APP_ROLE=primary
wait_up "primary" "$PRIMARY_PORT" wait_up "primary" "$PRIMARY_PORT"
echo -e "\033[1;32m==> Starting Replica on :$REPLICA_PORT\033[0m" # ==============================================================================
# 2. Test Dynamic Discovery: Retrieve Cluster Public CA
# ==============================================================================
echo -e "\n\033[1;34m==> Testing dynamic discovery: Fetching Cluster Public CA...\033[0m"
ca_resp=$(curl -k -sf "https://127.0.0.1:$PRIMARY_PORT/api/cluster/ca")
if echo "$ca_resp" | grep -q 'BEGIN CERTIFICATE'; then
echo -e " \033[1;32m✔ Cluster CA certificate downloaded successfully.\033[0m"
else
echo -e " \033[1;31m✖ Failed to retrieve Cluster CA.\033[0m"
exit 1
fi
# ==============================================================================
# 3. Mint Short-Lived Join Token via Primary
# ==============================================================================
echo -e "\n\033[1;34m==> Minting short-lived Join Token from Primary...\033[0m"
token_resp=$(curl -k -sf -X POST "https://127.0.0.1:$PRIMARY_PORT/api/cluster/tokens" \
-H 'Content-Type: application/json' \
-d '{"ttl_secs": 120}')
if command -v jq >/dev/null 2>&1; then
JOIN_TOKEN=$(echo "$token_resp" | jq -r '.token')
else
JOIN_TOKEN=$(echo "$token_resp" | grep -o '"token":"[^"]*' | cut -d'"' -f4)
fi
echo -e " \033[1;32m✔ Obtained one-time join token: $JOIN_TOKEN\033[0m"
# ==============================================================================
# 4. Launch Replica (Bootstraps mTLS identity using the Join Token)
# ==============================================================================
echo -e "\n\033[1;32m==> Starting Replica on :$REPLICA_PORT (Dynamic Join Enrollment)...\033[0m"
start_node replica "$REPLICA_PORT" \ start_node replica "$REPLICA_PORT" \
APP_ROLE=replica \ APP_ROLE=replica \
APP_PRIMARY_URL="http://127.0.0.1:$PRIMARY_PORT" APP_PRIMARY_URL="https://127.0.0.1:$PRIMARY_PORT" \
APP_JOIN_TOKEN="$JOIN_TOKEN"
wait_up "replica" "$REPLICA_PORT" wait_up "replica" "$REPLICA_PORT"
# Verify credentials were saved to replica's SQLite database
if [[ -f "$WORK/replica/messages.db" ]]; then
echo -e " \033[1;32m✔ Replica enrolled and saved mTLS credentials in SQLite.\033[0m"
fi
# --- Launch Dashboard (if available) --- # --- Launch Dashboard (if available) ---
if [[ "$START_DASHBOARD" -eq 1 && -f "$ROOT_DIR/dashboard.py" ]]; then if [[ "$START_DASHBOARD" -eq 1 && -f "$ROOT_DIR/dashboard.py" ]]; then
if check_port "$DASHBOARD_PORT"; then if check_port "$DASHBOARD_PORT"; then
@@ -129,20 +168,24 @@ if [[ "$START_DASHBOARD" -eq 1 && -f "$ROOT_DIR/dashboard.py" ]]; then
fi fi
fi fi
# --- Write Smoke Test Records --- # ==============================================================================
echo -e "\n\033[1;34m==> Writing 3 test records to Primary\033[0m" # 5. Write Smoke Test Records to Primary
# ==============================================================================
echo -e "\n\033[1;34m==> Writing 3 test records to Primary via HTTPS\033[0m"
for i in 1 2 3; do for i in 1 2 3; do
curl -s -X POST "http://127.0.0.1:$PRIMARY_PORT/api/records" \ curl -k -s -X POST "https://127.0.0.1:$PRIMARY_PORT/api/records" \
-H 'Content-Type: application/json' \ -H 'Content-Type: application/json' \
-d "{\"data\":{\"version\":1,\"msg\":\"hello $i\"}}" >/dev/null -d "{\"data\":{\"version\":1,\"msg\":\"hello $i\"}}" >/dev/null
echo " Record #$i written" echo " Record #$i written"
done done
# --- Await Replication Sync --- # ==============================================================================
echo -e "\n\033[1;34m==> Verifying replica sync...\033[0m" # 6. Await Replica mTLS Sync
# ==============================================================================
echo -e "\n\033[1;34m==> Verifying replica mTLS sync stream...\033[0m"
caught_up=0 caught_up=0
for _ in $(seq 1 40); do for _ in $(seq 1 40); do
status_output=$(curl -s "http://127.0.0.1:$REPLICA_PORT/api/replication/status" || true) status_output=$(curl -k -s "https://127.0.0.1:$REPLICA_PORT/api/replication/status" || true)
if echo "$status_output" | grep -q '"last_applied_seq":3'; then if echo "$status_output" | grep -q '"last_applied_seq":3'; then
caught_up=1 caught_up=1
break break
@@ -151,14 +194,17 @@ for _ in $(seq 1 40); do
done done
if [[ $caught_up -eq 1 ]]; then if [[ $caught_up -eq 1 ]]; then
echo -e "\033[1;32m✔ SUCCESS: Replica caught up to seq 3!\033[0m" echo -e "\033[1;32m✔ SUCCESS: Replica caught up to seq 3 over mTLS!\033[0m"
else else
echo -e "\033[1;31m✖ WARNING: Replica did not reach seq 3 in time.\033[0m" echo -e "\033[1;31m✖ WARNING: Replica did not reach seq 3 in time.\033[0m"
echo "Replica Status Output: $status_output"
fi fi
# --- Verify Read-Only Guard on Replica --- # ==============================================================================
# 7. Verify Read-Only Safety Guard on Replica
# ==============================================================================
echo -e "\n\033[1;34m==> Testing Replica read-only safety guard:\033[0m" echo -e "\n\033[1;34m==> Testing Replica read-only safety guard:\033[0m"
http_code=$(curl -s -o /dev/null -w "%{http_code}" -X POST "http://127.0.0.1:$REPLICA_PORT/api/records" \ http_code=$(curl -k -s -o /dev/null -w "%{http_code}" -X POST "https://127.0.0.1:$REPLICA_PORT/api/records" \
-H 'Content-Type: application/json' \ -H 'Content-Type: application/json' \
-d '{"data":{"version":1,"msg":"should fail"}}') -d '{"data":{"version":1,"msg":"should fail"}}')
@@ -172,9 +218,9 @@ fi
cat <<EOF cat <<EOF
====================================================================== ======================================================================
Cluster is healthy and running: Cluster is healthy and running over mTLS:
- Primary API: http://127.0.0.1:$PRIMARY_PORT - Primary API: https://127.0.0.1:$PRIMARY_PORT
- Replica API: http://127.0.0.1:$REPLICA_PORT - Replica API: https://127.0.0.1:$REPLICA_PORT
- Web Dashboard: http://127.0.0.1:$DASHBOARD_PORT - Web Dashboard: http://127.0.0.1:$DASHBOARD_PORT
- Logs Dir: $WORK/ - Logs Dir: $WORK/