feat(updates): check Gitea automatically and deploy on owner confirmation

Add owner-only update controls, a read-only SSH checker and independent systemd deployment services. Build before maintenance; back up code and database; restore on failed deployment. Preserve runtime configuration and gate business writes during the switch.
This commit is contained in:
WangShen007 committed 2026-10-24 07:26:41 +00:00
1 parent ed8dc01ed9
commit f3ad539998
28 files changed
+1346 -1

No files matched your search

+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -euo pipefail
umask 077
if [[ "$(id -u)" != 0 || "$#" != 1 ]]; then
printf 'Usage (root): %s /path/to/config.json\n' "$0" >&2
exit 1
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
python3 - "$1" <<'PY'
import json,re,sys
from pathlib import Path
from uuid import UUID
cfg=json.loads(Path(sys.argv[1]).read_text())
assert re.fullmatch(r'[0-9a-f]{40}',cfg['initial_revision']), 'Installed commit required'
assert cfg['owner_ids'], 'Deployment owner required'
for owner in cfg['owner_ids']:
UUID(owner)
for key in ('project_dir','ssh_key','known_hosts'):
assert Path(cfg[key]).exists(), f'Missing {key}'
assert Path(cfg['project_dir'],'backend/.env').exists()
assert Path(cfg['project_dir'],'deploy/local/.state/dashboard/config.js').exists()
assert cfg['repository'].startswith('ssh://'), 'Use authenticated SSH, not plain HTTP'
Path(cfg['state_dir']).mkdir(parents=True,exist_ok=True)
PY
install -d -m 700 /etc/replypier-updater
if [[ "$(realpath "$1")" != /etc/replypier-updater/config.json ]]; then
install -m 600 "$1" /etc/replypier-updater/config.json
else
chmod 600 /etc/replypier-updater/config.json
fi
install -d -m 755 /opt/replypier-updater
install -m 644 "${SCRIPT_DIR}"/updater/*.py /opt/replypier-updater/
install -m 644 "${SCRIPT_DIR}"/systemd/* /etc/systemd/system/
install -d -m 755 /etc/systemd/system/replypier-backend.service.d
cat > /etc/systemd/system/replypier-backend.service.d/update-recovery.conf <<'EOF'
[Unit]
Requires=replypier-update-recover.service
After=replypier-update-recover.service
EOF
python3 - <<'PY'
import sys
sys.path.insert(0,'/opt/replypier-updater')
from state import config,transaction
with transaction(config()):
pass
PY
systemctl daemon-reload
systemctl enable --now replypier-update-recover.service replypier-update-check.timer
printf '\nInstalled. Check manually: python3 /opt/replypier-updater/cli.py check\n'