From e9104cdc449ef2bc7bb7338f5ad73c8c8d56f8fb Mon Sep 17 00:00:00 2001 From: DEV-bot Date: Sat, 28 Feb 2026 15:04:06 +0000 Subject: [PATCH] fix(staging): prevent app/schema drift on failed deploy (refs #130 #90) --- infra/staging/README.md | 4 ++- infra/staging/deploy_staging.sh | 43 +++++++++++++++++++++------------ 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/infra/staging/README.md b/infra/staging/README.md index 68e7824..3c02b82 100644 --- a/infra/staging/README.md +++ b/infra/staging/README.md @@ -22,7 +22,9 @@ Forventet: - service er active - healthz returnerer JSON med ok=true -Efter deploy vil scriptet også verificere at `DB_ENGINE` ikke er `django.db.backends.sqlite3` før migrations køres. +Efter deploy validerer scriptet, at `DB_ENGINE` ikke er `django.db.backends.sqlite3` før migrations køres. + +Deploy-scriptet bruger en release-candidate mappe og promoverer først til `/opt/wpp-staging/app` efter succesfuld `migrate`. Det reducerer schema/code drift ved afbrudte deploys (issue #130) og understøtter release-readiness gate (issue #90). ## Deploy (canonical execution context) Deploy skal altid køres via Proxmox host over SSH (ikke fra lokal coder-shell med direkte sudo pct). diff --git a/infra/staging/deploy_staging.sh b/infra/staging/deploy_staging.sh index 5704af1..fcc142a 100755 --- a/infra/staging/deploy_staging.sh +++ b/infra/staging/deploy_staging.sh @@ -9,19 +9,25 @@ PROXMOX_HOST="${PROXMOX_HOST:-proxmox-lan}" echo "[deploy] host=${PROXMOX_HOST} CT_ID=${CT_ID} REF=${REF_NAME}" echo "[deploy] extracting source + installing deps + migrate + restart" -ssh "${PROXMOX_HOST}" "sudo -n /usr/sbin/pct exec ${CT_ID} -- bash -lc \"set -euo pipefail -mkdir -p /opt/wpp-staging/releases/src -cd /opt/wpp-staging/releases -curl -fsSL \\\"${ARCHIVE_URL}\\\" -o app.tar.gz -rm -rf src && mkdir src -tar -xzf app.tar.gz -C src --strip-components=1 -rm -rf /opt/wpp-staging/app/* -cp -a src/. /opt/wpp-staging/app/ -# Ensure deploy artifact copied as root does not leave app tree non-writable for wpp. -chown -R wpp:wpp /opt/wpp-staging/app -# Staging must not run on SQLite (issue #133). Remove bundled sqlite artifact. -rm -f /opt/wpp-staging/app/db.sqlite3 -cd /opt/wpp-staging/app +ssh "${PROXMOX_HOST}" sudo -n /usr/sbin/pct exec "${CT_ID}" -- bash -s -- "${ARCHIVE_URL}" <<'REMOTE' +set -euo pipefail + +ARCHIVE_URL="$1" +RELEASES_DIR=/opt/wpp-staging/releases +CANDIDATE_DIR="${RELEASES_DIR}/src" +APP_DIR=/opt/wpp-staging/app + +mkdir -p "${CANDIDATE_DIR}" +cd "${RELEASES_DIR}" +curl -fsSL "${ARCHIVE_URL}" -o app.tar.gz +rm -rf "${CANDIDATE_DIR}" && mkdir -p "${CANDIDATE_DIR}" +tar -xzf app.tar.gz -C "${CANDIDATE_DIR}" --strip-components=1 + +# Ensure deploy artifact copied as root does not leave candidate tree non-writable for wpp. +chown -R wpp:wpp "${CANDIDATE_DIR}" +# Staging must not run on SQLite (issue #133). Remove bundled sqlite artifact from candidate. +rm -f "${CANDIDATE_DIR}/db.sqlite3" +cd "${CANDIDATE_DIR}" # Load staging env before any manage.py call (issue #133 follow-up). ENV_LOADED=0 @@ -48,9 +54,16 @@ fi runuser -u wpp -- python3 -m venv .venv runuser -u wpp -- .venv/bin/pip install -U pip >/dev/null runuser -u wpp -- .venv/bin/pip install -r requirements.txt >/dev/null -runuser -u wpp -- .venv/bin/python manage.py shell -c \"from django.conf import settings; import sys; engine = settings.DATABASES['default']['ENGINE']; print(f'DB_ENGINE={engine}'); sys.exit(0 if engine != 'django.db.backends.sqlite3' else 1)\" +runuser -u wpp -- .venv/bin/python manage.py shell -c "from django.conf import settings; import sys; engine = settings.DATABASES['default']['ENGINE']; print(f'DB_ENGINE={engine}'); sys.exit(0 if engine != 'django.db.backends.sqlite3' else 1)" runuser -u wpp -- .venv/bin/python manage.py migrate --noinput + +# Promote candidate only after migrations succeed (issue #130): avoid code/schema drift after failed deploy. +rm -rf "${APP_DIR}"/* +cp -a "${CANDIDATE_DIR}"/. "${APP_DIR}/" +chown -R wpp:wpp "${APP_DIR}" + systemctl restart wpp-staging.service -curl -fsS http://127.0.0.1:8000/healthz\"" +curl -fsS http://127.0.0.1:8000/healthz +REMOTE echo "[deploy] OK: staging deploy complete for CT ${CT_ID} (${REF_NAME})"