Files
matrix/deploy/lxc151-hookshot.sh
T
Lotus CIandClaude Opus 5.5 d9f023762e
Lint / JS (eslint) (push) Successful in 12s
Lint / Shell (shellcheck) (push) Successful in 13s
Lint / No secrets in webhook configs (push) Successful in 6s
Lint / Landing page is rendered (matrix (push) Successful in 5s
Lint / Python (ruff) (push) Successful in 6s
Lint / Secret scan (gitleaks) (push) Successful in 8s
Lint / Shell (shellcheck) (pull_request) Successful in 10s
Lint / JS (eslint) (pull_request) Successful in 8s
Lint / No secrets in webhook configs (pull_request) Successful in 5s
Lint / Python deps (pip-audit) (push) Successful in 41s
Lint / Landing page is rendered (matrix (pull_request) Successful in 4s
Lint / Python (ruff) (pull_request) Successful in 5s
Lint / Secret scan (gitleaks) (pull_request) Successful in 11s
Lint / Python deps (pip-audit) (pull_request) Successful in 56s
fix(livekit): graceful restart could restart LiveKit in the middle of a call
livekit-graceful-restart.sh decided "no active calls" by counting
established TCP connections on :7881 with `ss ... state established |
grep -c ESTAB`. Two bugs:

- With a `state` filter ss omits the State column, so `grep -c ESTAB`
  is always 0: the check never saw anything.
- :7881 is only LiveKit's ICE-TCP media fallback. Signalling is on
  :7880 and media is normally UDP.

Reproduced in a two-person call on the local stack: the old check
counted 0 and would have restarted. Now it waits while LiveKit's own
livekit_participant_total is above 0 or any signalling WebSocket on
:7880 is open, and also waits if the metrics can't be read.

The deploy hook now installs the script when it changes (it never
did, so edits to it never reached the server).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-11-03 00:25:58 -05:00

120 lines
5.2 KiB
Bash

#!/bin/bash
# Auto-deploy script for LXC 151 (matrix homeserver)
# Handles: hookshot transformation functions, livekit service file (graceful),
# voice-limit-guard (livekit policy sidecar), matrixbot
# Triggered by: Gitea webhook on push to main
set -euo pipefail
REPO_DIR="/opt/matrix-config"
LOG="/var/log/matrix-deploy.log"
CLONE_URL="https://code.lotusguild.org/LotusGuild/matrix.git"
ENV_FILE="/etc/matrix-deploy.env"
exec >> "$LOG" 2>&1
echo "=== $(date) === LXC151 deploy triggered ==="
# Load env (MATRIX_TOKEN, MATRIX_SERVER, MATRIX_ROOM)
if [ -f "$ENV_FILE" ]; then
# shellcheck source=/dev/null
source "$ENV_FILE"
fi
# Clone or pull
if [ ! -d "$REPO_DIR/.git" ]; then
git clone "$CLONE_URL" "$REPO_DIR"
else
cd "$REPO_DIR"
git fetch --all
PREV=$(git rev-parse HEAD)
git reset --hard origin/main
NEW=$(git rev-parse HEAD)
CHANGED=$(git diff --name-only "$PREV" "$NEW")
echo "Changed files: $CHANGED"
# Hookshot transforms
if echo "$CHANGED" | grep -q '^hookshot/'; then
echo "Deploying hookshot transforms..."
export MATRIX_TOKEN MATRIX_SERVER MATRIX_ROOM
bash "$REPO_DIR/hookshot/deploy.sh"
fi
# Livekit service file — graceful restart (never kill active calls)
if echo "$CHANGED" | grep -q '^systemd/livekit-server.service'; then
echo "livekit-server.service changed — staging graceful restart..."
cp "$REPO_DIR/systemd/livekit-server.service" /etc/systemd/system/livekit-server.service
systemctl daemon-reload
touch /run/livekit-restart-pending
echo "Restart pending — will apply when no active calls."
fi
# The graceful-restart check itself (run by livekit-graceful-restart.timer)
if echo "$CHANGED" | grep -q '^deploy/livekit-graceful-restart\.sh'; then
echo "Deploying livekit-graceful-restart.sh..."
bash -n "$REPO_DIR/deploy/livekit-graceful-restart.sh" \
&& install -m755 "$REPO_DIR/deploy/livekit-graceful-restart.sh" /usr/local/bin/livekit-graceful-restart.sh
fi
# Voice-limit / quality guard (fronts lk-jwt-service on :8070)
if echo "$CHANGED" | grep -qE '^livekit/voice-limit-guard\.py|^systemd/voice-limit-guard\.service'; then
echo "Deploying voice-limit-guard..."
# Validate syntax BEFORE swapping so a broken edit can never wedge token
# issuance (a syntax error would crash the guard and block all joins).
if python3 -m py_compile "$REPO_DIR/livekit/voice-limit-guard.py"; then
GUARD_DST="/opt/voice-limit-guard/voice-limit-guard.py"
GUARD_BAK="/opt/voice-limit-guard/voice-limit-guard.py.bak"
# Back up the last-known-good guard so a runtime-broken (but
# syntactically valid) deploy can self-heal — a dead guard breaks
# ALL new joins, so we must never leave it down.
[ -f "$GUARD_DST" ] && cp "$GUARD_DST" "$GUARD_BAK"
install -D -m644 "$REPO_DIR/livekit/voice-limit-guard.py" "$GUARD_DST"
if echo "$CHANGED" | grep -q '^systemd/voice-limit-guard\.service'; then
install -m644 "$REPO_DIR/systemd/voice-limit-guard.service" /etc/systemd/system/voice-limit-guard.service
systemctl daemon-reload
fi
# Restarting the guard only affects joins in a ~1s window (established
# calls talk directly to livekit-server); it does not drop calls.
# `|| true` so a non-zero restart can't abort the deploy under set -e.
systemctl restart voice-limit-guard || true
sleep 1
if systemctl is-active --quiet voice-limit-guard; then
echo "voice-limit-guard restarted successfully."
elif [ -f "$GUARD_BAK" ]; then
echo "ERROR: new voice-limit-guard failed to start — rolling back to last-known-good."
cp "$GUARD_BAK" "$GUARD_DST"
systemctl restart voice-limit-guard || true
sleep 1
if systemctl is-active --quiet voice-limit-guard; then
echo "voice-limit-guard rolled back and running."
else
echo "CRITICAL: voice-limit-guard down after rollback — manual intervention needed."
fi
else
echo "CRITICAL: voice-limit-guard failed to start and no backup to roll back to."
fi
else
echo "ERROR: py_compile failed on voice-limit-guard.py — skipping deploy."
fi
fi
# Matrixbot source files
if echo "$CHANGED" | grep -q '^matrixbot/'; then
echo "Deploying matrixbot changes..."
BOT_DIR="/opt/matrixbot"
BOT_FILES="bot.py callbacks.py commands.py config.py utils.py welcome.py wordle.py wordlist_answers.py wordlist_valid.py requirements.txt"
for f in $BOT_FILES; do
if [ -f "$REPO_DIR/matrixbot/$f" ]; then
cp "$REPO_DIR/matrixbot/$f" "$BOT_DIR/$f"
fi
done
systemctl restart matrixbot
sleep 2
if systemctl is-active --quiet matrixbot; then
echo "matrixbot restarted successfully."
else
echo "ERROR: matrixbot failed to restart."
fi
fi
fi
echo "=== $(date) === LXC151 deploy complete ==="