Retarget deploy pipeline to POS and guard against cross-service clobber
Deploy Ladill POS / deploy (push) Successful in 24s
Deploy Ladill POS / deploy (push) Successful in 24s
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 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e5d2b84388
commit
57862acb47
@@ -1,4 +1,4 @@
|
|||||||
name: Deploy Ladill Mini
|
name: Deploy Ladill POS
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -10,7 +10,7 @@ permissions:
|
|||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: deploy-mini
|
group: deploy-pos
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -19,10 +19,27 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
NODE_ROOT: /tmp/ladill-node-22-r1
|
NODE_ROOT: /tmp/ladill-node-22-r1
|
||||||
NODE_VERSION: "22.14.0"
|
NODE_VERSION: "22.14.0"
|
||||||
RELEASE_ARCHIVE: /tmp/ladill-mini-release-${{ gitea.run_id }}-${{ gitea.run_attempt }}.tgz
|
RELEASE_ARCHIVE: /tmp/ladill-pos-release-${{ gitea.run_id }}-${{ gitea.run_attempt }}.tgz
|
||||||
WORKSPACE: /tmp/${{ gitea.repository_owner }}-mini-${{ gitea.run_id }}-${{ gitea.run_attempt }}
|
WORKSPACE: /tmp/${{ gitea.repository_owner }}-pos-${{ gitea.run_id }}-${{ gitea.run_attempt }}
|
||||||
LADILL_APP_ROOT: /var/www/ladill-mini
|
LADILL_APP_ROOT: /var/www/ladill-pos
|
||||||
steps:
|
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
|
- name: Checkout
|
||||||
shell: bash {0}
|
shell: bash {0}
|
||||||
run: |
|
run: |
|
||||||
@@ -78,7 +95,7 @@ jobs:
|
|||||||
- name: Deploy release
|
- name: Deploy release
|
||||||
shell: bash {0}
|
shell: bash {0}
|
||||||
env:
|
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: |
|
run: |
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
: "${LADILL_APP_ROOT:?Set LADILL_APP_ROOT}"
|
: "${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"
|
NGINX_SCRIPT="/var/www/ladill.com/current/deployment/setup-service-subdomain-nginx.sh"
|
||||||
fi
|
fi
|
||||||
if [ ! -f "$NGINX_SCRIPT" ]; then
|
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
|
exit 0
|
||||||
fi
|
fi
|
||||||
if sudo -n bash "$NGINX_SCRIPT" mini --app /var/www/ladill-mini/current; then
|
if sudo -n bash "$NGINX_SCRIPT" pos --app /var/www/ladill-pos/current; then
|
||||||
echo "nginx vhost updated for mini.ladill.com"
|
echo "nginx vhost updated for pos.ladill.com"
|
||||||
else
|
else
|
||||||
echo "WARN: nginx vhost step skipped (deploy user cannot sudo) — vhost must already be provisioned"
|
echo "WARN: nginx vhost step skipped (deploy user cannot sudo) — vhost must already be provisioned"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -12,7 +12,42 @@ Standalone **in-store register** at `pos.ladill.com`. Charges via Ladill Pay (`s
|
|||||||
|
|
||||||
## Deploy
|
## 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 <service>-worker:*` name
|
||||||
|
|
||||||
|
A **guard step** in `deploy.yml` enforces `basename(LADILL_APP_ROOT) == <repo name>` 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
|
```bash
|
||||||
php artisan migrate --force
|
php artisan migrate --force
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@
|
|||||||
# Fast on-host release deploy (same model as climpme/web/deploy/deploy.sh).
|
# Fast on-host release deploy (same model as climpme/web/deploy/deploy.sh).
|
||||||
set -Eeuo pipefail
|
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"
|
RELEASES_DIR="$APP_ROOT/releases"
|
||||||
SHARED_DIR="$APP_ROOT/shared"
|
SHARED_DIR="$APP_ROOT/shared"
|
||||||
CURRENT_LINK="$APP_ROOT/current"
|
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
|
(cd "$CURRENT_LINK" && php artisan queue:restart) || true
|
||||||
fi
|
fi
|
||||||
if command -v supervisorctl >/dev/null 2>&1; then
|
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
|
fi
|
||||||
|
|
||||||
log "Cleaning old releases"
|
log "Cleaning old releases"
|
||||||
|
|||||||
Reference in New Issue
Block a user