# Temporarily deploy BFF/frontend and shorten the role lifetime. Always restore it. rotation() ( exec 9> "$STATE/bootstrap.lock" flock -n 9 || fail 'Another local bootstrap or rotation check is running' vault database/roles/bff | jq '.data' > "$WORK/original-role" compose ps --services --status running > "$WORK/running" workers='' restore() { touch "$WORK/stop" for pid in $workers; do wait "$pid" || true; done restore_failed=0 vault database/roles/bff POST < "$WORK/original-role" >/dev/null || { echo 'ERROR: restore BFF role TTL manually' >&2; restore_failed=1; } for service in frontend bff; do if ! grep -qx "$service" "$WORK/running"; then compose stop "$service"; compose rm -f "$service"; fi done return "$restore_failed" } trap restore EXIT trap 'exit 130' INT trap 'exit 143' TERM jq '.+{default_ttl:"12s",max_ttl:"24s"}' "$WORK/original-role" | vault database/roles/bff POST >/dev/null compose up -d --no-deps --force-recreate --wait --wait-timeout 90 bff frontend export_ca https -f https://localhost:5126/ > "$WORK/index" grep -q flutter_bootstrap "$WORK/index" || fail 'Frontend bundle is not served' https -f https://localhost:5126/settings > "$WORK/route" cmp -s "$WORK/index" "$WORK/route" || fail 'Frontend route fallback failed' https -f https://localhost:5126/api/v1/health >/dev/null process=$(compose exec -T bff pidof service) for worker in 1 2 3 4; do ( while [ ! -f "$WORK/stop" ]; do # 43 characters passes syntax validation, executes a Mongo transaction/read, # and returns invalid-token without creating users or sending email. token=$(openssl rand -hex 22 | cut -c1-43) code=$(printf '{"token":"%s"}' "$token" | https -o "$WORK/body-$worker" -w '%{http_code}' \ -H 'Content-Type: application/json' -H 'Origin: https://localhost:5126' \ -H 'X-Auth-Transport: cookie' -H 'X-CSRF-Protection: 1' --data-binary @- \ https://localhost:5126/api/v1/accounts/verification/confirm) || code=0 if [ "$code" = 400 ] && grep -q 'Verification is invalid or already used' "$WORK/body-$worker"; then echo ok >> "$WORK/results-$worker" else echo fail >> "$WORK/results-$worker"; fi sleep 0.03 done ) & workers="$workers $!" done count=0; attempt=0 while [ "$attempt" -lt 40 ]; do sleep 1 [ "$(compose exec -T bff pidof service)" = "$process" ] || fail 'BFF restarted during rotation' compose logs --no-color bff > "$WORK/logs" count=$(grep -c 'Database pool replaced without restarting service' "$WORK/logs" || true) [ "$count" -lt 3 ] || break attempt=$((attempt+1)) done touch "$WORK/stop" for pid in $workers; do wait "$pid"; done workers='' [ "$count" -ge 3 ] || fail 'Three pool rotations were not observed' cat "$WORK"/results-* > "$WORK/results" ! grep -q fail "$WORK/results" || fail 'Unexpected HTTP responses during rotation' count=$(wc -l < "$WORK/results") [ "$count" -ge 100 ] || fail 'Insufficient rotation traffic' echo "PASS: three real Vault rotations, unchanged BFF PID, $count transaction-backed HTTP requests, zero failures" )