From 57862acb47f2656b815720dd6ba1a1b64674f0e7 Mon Sep 17 00:00:00 2001 From: isaacclad Date: Tue, 23 Jun 2026 23:16:00 +0000 Subject: [PATCH] Retarget deploy pipeline to POS and guard against cross-service clobber The pipeline was copied from Ladill Mini and still deployed into /var/www/ladill-mini, so the first POS push overwrote mini.ladill.com. Retarget every mini reference to pos (app root, archive/workspace names, concurrency group, nginx subdomain, supervisor worker), add a guard step that fails the run unless basename(LADILL_APP_ROOT) matches the repo name, and document the incident + a forking checklist in DEPLOY.md. Co-Authored-By: Claude Opus 4.8 --- .gitea/workflows/deploy.yml | 35 ++++++++++++++++++++++++++--------- DEPLOY.md | 37 ++++++++++++++++++++++++++++++++++++- deploy/deploy.sh | 4 ++-- 3 files changed, 64 insertions(+), 12 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index ab0d5b0..e09958f 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -1,4 +1,4 @@ -name: Deploy Ladill Mini +name: Deploy Ladill POS on: push: @@ -10,7 +10,7 @@ permissions: contents: read concurrency: - group: deploy-mini + group: deploy-pos cancel-in-progress: true jobs: @@ -19,10 +19,27 @@ jobs: env: NODE_ROOT: /tmp/ladill-node-22-r1 NODE_VERSION: "22.14.0" - RELEASE_ARCHIVE: /tmp/ladill-mini-release-${{ gitea.run_id }}-${{ gitea.run_attempt }}.tgz - WORKSPACE: /tmp/${{ gitea.repository_owner }}-mini-${{ gitea.run_id }}-${{ gitea.run_attempt }} - LADILL_APP_ROOT: /var/www/ladill-mini + RELEASE_ARCHIVE: /tmp/ladill-pos-release-${{ gitea.run_id }}-${{ gitea.run_attempt }}.tgz + WORKSPACE: /tmp/${{ gitea.repository_owner }}-pos-${{ gitea.run_id }}-${{ gitea.run_attempt }} + LADILL_APP_ROOT: /var/www/ladill-pos steps: + - name: Guard deploy target + # Refuse to deploy if this workflow was copied from another service + # without retargeting LADILL_APP_ROOT. The app dir basename MUST match + # the repo name (ladill-pos -> /var/www/ladill-pos), otherwise a copied + # pipeline would clobber a sibling service. See DEPLOY.md "Forking this pipeline". + shell: bash {0} + run: | + set -Eeuo pipefail + REPO_NAME="${{ gitea.repository }}"; REPO_NAME="${REPO_NAME##*/}" + APP_DIR_NAME="$(basename "$LADILL_APP_ROOT")" + if [ "$REPO_NAME" != "$APP_DIR_NAME" ]; then + echo "FATAL: repo '$REPO_NAME' != deploy target '$APP_DIR_NAME' (LADILL_APP_ROOT=$LADILL_APP_ROOT)." >&2 + echo "Refusing to deploy — a mis-targeted workflow would overwrite another service. Retarget deploy.yml env." >&2 + exit 1 + fi + echo "Guard OK: $REPO_NAME -> $LADILL_APP_ROOT" + - name: Checkout shell: bash {0} run: | @@ -78,7 +95,7 @@ jobs: - name: Deploy release shell: bash {0} env: - LADILL_RELEASE_ARCHIVE: /tmp/ladill-mini-release-${{ gitea.run_id }}-${{ gitea.run_attempt }}.tgz + LADILL_RELEASE_ARCHIVE: /tmp/ladill-pos-release-${{ gitea.run_id }}-${{ gitea.run_attempt }}.tgz run: | set -Eeuo pipefail : "${LADILL_APP_ROOT:?Set LADILL_APP_ROOT}" @@ -93,11 +110,11 @@ jobs: NGINX_SCRIPT="/var/www/ladill.com/current/deployment/setup-service-subdomain-nginx.sh" fi if [ ! -f "$NGINX_SCRIPT" ]; then - echo "WARN: setup-service-subdomain-nginx.sh not found — configure mini.ladill.com vhost manually" + echo "WARN: setup-service-subdomain-nginx.sh not found — configure pos.ladill.com vhost manually" exit 0 fi - if sudo -n bash "$NGINX_SCRIPT" mini --app /var/www/ladill-mini/current; then - echo "nginx vhost updated for mini.ladill.com" + if sudo -n bash "$NGINX_SCRIPT" pos --app /var/www/ladill-pos/current; then + echo "nginx vhost updated for pos.ladill.com" else echo "WARN: nginx vhost step skipped (deploy user cannot sudo) — vhost must already be provisioned" fi diff --git a/DEPLOY.md b/DEPLOY.md index fb68ade..34ab974 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -12,7 +12,42 @@ Standalone **in-store register** at `pos.ladill.com`. Charges via Ladill Pay (`s ## Deploy -Same release model as Mini/Merchant — see `deploy/deploy.sh`. +Same release model as Mini/Merchant — see `deploy/deploy.sh`. Pushing to `main` +triggers `.gitea/workflows/deploy.yml` on the host `deploy` runner, which builds a +release and deploys into `/var/www/ladill-pos`. + +## ⚠️ Forking this pipeline (read before copying to a new service) + +This workflow was bootstrapped by copying Mini's. **If you copy `.gitea/workflows/deploy.yml`, +`deploy/deploy.sh`, or `DEPLOY.md` to a new service, retarget EVERY `mini`/`pos` reference**, +or the new repo's pipeline will deploy its code on top of the service you copied from. + +Things that must match the new service (search for the old slug and replace all): + +- `deploy.yml`: `name:`, `concurrency.group`, `RELEASE_ARCHIVE`, `WORKSPACE`, + `LADILL_APP_ROOT`, the nginx step subdomain (`pos --app /var/www/ladill-pos/current`) +- `deploy.sh`: `APP_ROOT` default and the `supervisorctl restart -worker:*` name + +A **guard step** in `deploy.yml` enforces `basename(LADILL_APP_ROOT) == ` and +fails the run on a mismatch — keep repo name and app dir name identical (`ladill-pos` → +`/var/www/ladill-pos`). + +> **Incident 2026-06-24:** the initial POS pipeline still pointed at `/var/www/ladill-mini`, +> so the first POS push overwrote mini.ladill.com (POS code + a stray `create_pos_tables` +> migration against the `ladill_mini` DB). Remediated by repointing mini's `current` symlink +> to the last genuine Mini release and dropping the 4 stray `pos_*` tables. The guard step +> above exists to make this impossible to repeat. + +## Server prerequisites (one-time, as root) + +Done for `pos.ladill.com`; replicate for any new service: + +1. MySQL: `CREATE DATABASE ladill_pos` + user `ladill_pos@127.0.0.1` (`ALL` on its own db; + `SELECT` on `ladill_merchant` + `ladilldb` for commerce links) +2. `/var/www/ladill-pos/{releases,shared}` owned `deploy:www-data` +3. `shared/.env` (mode 640, `deploy:www-data`) with generated `APP_KEY`, DB creds, and the + integration keys from the monolith (see "Platform wiring") +4. nginx vhost via `deployment/setup-service-subdomain-nginx.sh pos --app /var/www/ladill-pos/current` ```bash php artisan migrate --force diff --git a/deploy/deploy.sh b/deploy/deploy.sh index 47fca9d..0c65e1e 100755 --- a/deploy/deploy.sh +++ b/deploy/deploy.sh @@ -2,7 +2,7 @@ # Fast on-host release deploy (same model as climpme/web/deploy/deploy.sh). set -Eeuo pipefail -APP_ROOT="${LADILL_APP_ROOT:-/var/www/ladill-mini}" +APP_ROOT="${LADILL_APP_ROOT:-/var/www/ladill-pos}" RELEASES_DIR="$APP_ROOT/releases" SHARED_DIR="$APP_ROOT/shared" CURRENT_LINK="$APP_ROOT/current" @@ -236,7 +236,7 @@ if [ -L "$CURRENT_LINK" ] && [ -f "$CURRENT_LINK/artisan" ]; then (cd "$CURRENT_LINK" && php artisan queue:restart) || true fi if command -v supervisorctl >/dev/null 2>&1; then - supervisorctl restart ladill-mini-worker:* 2>/dev/null || true + supervisorctl restart ladill-pos-worker:* 2>/dev/null || true fi log "Cleaning old releases"