diff --git a/.gitea/workflows/deploy-backoffice.yml b/.gitea/workflows/deploy-backoffice.yml index c795ed7..fd2a73a 100644 --- a/.gitea/workflows/deploy-backoffice.yml +++ b/.gitea/workflows/deploy-backoffice.yml @@ -17,10 +17,20 @@ jobs: deploy: runs-on: [self-hosted, homelab] steps: + # Plain git clone instead of actions/checkout@v4: that action is + # Node.js-based, and this runner deliberately has no Node toolchain + # (host-mode jobs run directly on the homelab, kept minimal). Auth is + # via the DEPLOY_TOKEN Actions secret (repo is private); the token is + # stripped from the stored remote URL right after cloning. - name: Checkout - uses: actions/checkout@v4 - with: - ref: ${{ inputs.ref }} + env: + DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }} + run: | + set -euo pipefail + find . -mindepth 1 -delete + git clone --depth 1 --branch "${{ inputs.ref }}" \ + "http://${DEPLOY_TOKEN}@172.24.0.2:3000/BPPP/smb-online.git" . + git remote set-url origin http://172.24.0.2:3000/BPPP/smb-online.git # Only db/ and app/ — never touch secrets/ or .env, which live only on # the host and aren't in the repo. diff --git a/TODO.md b/TODO.md index 001ab47..89287a6 100644 --- a/TODO.md +++ b/TODO.md @@ -66,24 +66,36 @@ Follow-ups (not yet done — all need you, not more code): - [ ] Your call, no rush: encrypt `credentials.secret` at rest (e.g. pgcrypto) instead of plaintext if the dashboard is ever exposed more broadly than Caddy basic-auth + host security. -## Deploy pipeline — trigger from the Gitea UI +## Deploy pipeline — trigger from the Gitea UI — DONE 2026-07-15 (backoffice only) **Goal:** stop hand-running scp/ssh/docker-compose-build for every change (that's how the -credentials feature above shipped). `git.mivanchenko.de` (Gitea, already the `origin` remote for -every repo here, running alongside the other homelab containers) supports **Gitea Actions** — -workflows in `.gitea/workflows/` that run on a self-hosted runner and can be started with a -manual "Run workflow" button in the repo UI, not just on push. -- [ ] Register a Gitea Actions runner (can run directly on the homelab host, or in its own - container with the Docker socket mounted so it can `docker compose build`/`up -d`). -- [ ] `.gitea/workflows/deploy.yml`: `workflow_dispatch` trigger (the UI button), optionally also - on push to `main`. Steps: checkout → sync changed paths to `/home/mivanchenko/smb-crm/` (and - whichever other `deploy/*` groups changed) → apply any pending SQL migrations → `docker compose - build` + `up -d --no-deps ` for just the affected Compose group(s) → hit `/healthz` - (or the equivalent) to confirm before declaring success. -- [ ] Needs real secrets in Gitea's repo/runner secrets store (SSH deploy key or a runner already - on the host, `CRM_API_TOKEN`, etc.) — **your call** on which, since it's a homelab access - decision. -- [ ] Once trustworthy, this replaces the manual migration step described in the credentials - section above and the `new-client.sh` → scp → ssh flow in `deploy/clients/README.md`. +credentials feature above originally shipped). Gitea Actions is now enabled on +`git.mivanchenko.de`, with a self-hosted runner (`homelab-runner`, labels `self-hosted`/ +`homelab`) running natively on the homelab host as the `act-runner` systemd service (survives +reboots). `.gitea/workflows/deploy-backoffice.yml` is a `workflow_dispatch`-only job (manual +"Run workflow" button — deliberately not on push, since triggering it = deploying) that syncs +`backoffice/db` + `backoffice/app`, re-applies the idempotent schema, rebuilds/restarts +`smb-crm`, and health-checks it. +- [x] Runner registered — runs directly on the host with the same `docker`/filesystem access the + operator already has, so no SSH deploy key was needed for the runner itself. +- [x] Fixed along the way: the runner-token generator needs `docker exec -u git gitea …` (Gitea + refuses to run as root, `docker exec` defaults to root); the runner is registered against + Gitea's internal container IP (`http://172.24.0.2:3000`), not `git.mivanchenko.de`, because the + homelab can't reach its own public hostname (NAT hairpin) — `https://git.mivanchenko.de` calls + from the host itself just hang. +- [x] First real run failed twice, both fixed: (1) `actions/checkout@v4` needs Node.js, which the + intentionally-minimal host-mode runner doesn't have — replaced with a plain `git clone`; + (2) the repo is private, so that clone needs auth — added a `DEPLOY_TOKEN` Gitea Actions secret + (a `read:repository,write:repository`-scoped token under the admin account, stored only in + Gitea's encrypted secret store, stripped from the cloned workspace's `git remote` right after + checkout). +- [ ] **Needs you:** actually press "Run workflow" once in the Gitea UI (Actions tab → + Deploy backoffice (smb-crm)) as the real end-to-end test — I deliberately didn't mint a Gitea + API token to test-trigger it myself (that would've left a stray write-scoped credential behind). +- [ ] Extend the same pattern to the other `deploy/*` groups (`booking/`, `smb-demos/`, + `clients//`) — straightforward once the backoffice one is confirmed working, since + they're all simpler (mostly just `docker compose up -d`, no DB migration step). +- [ ] Once you're adding collaborators: anyone with **write** access to this repo can trigger a + deploy. Worth being deliberate about who gets write vs. read/PR-only access — **your call**. ## Other - [ ] Harden n8n auth: compose still has deprecated `N8N_BASIC_AUTH_*` with password `password`