Add Forgejo deploy workflow and update deploy docs
Some checks failed
Deploy / deploy (push) Failing after 13s

This commit is contained in:
mattie726 2026-08-25 23:19:09 -07:00 committed by Barely Removable
parent 8a2651ec87
commit 0757e95ad3
3 changed files with 79 additions and 27 deletions

View file

@ -0,0 +1,28 @@
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# The job container only sees its own checkout — the live app lives
# at /mnt/user/appdata/card-grader on the host, bind-mounted into
# this container at the same path (see runner container.options) so
# `docker compose`'s relative volume paths resolve against the real
# host directory rather than an ephemeral one. `data/` holds the
# production DB and photos and must survive every deploy.
- name: Sync source to deploy path
run: |
rsync -a --delete \
--exclude='.git' \
--exclude='data' \
./ /mnt/user/appdata/card-grader/
- name: Rebuild and restart
working-directory: /mnt/user/appdata/card-grader
run: docker compose up -d --build

1
.gitignore vendored
View file

@ -2,3 +2,4 @@ grades.db
data/ data/
__pycache__/ __pycache__/
*.pyc *.pyc
.DS_Store

View file

@ -76,37 +76,60 @@ copies of the repo (local Mac, server) are kept in sync by committing on
both sides. There is currently no automated push-to-deploy path connected — both sides. There is currently no automated push-to-deploy path connected —
see below. see below.
**Pending: restricted git-push deploy.** A setup script **Superseded approach, fully torn down: git-shell restricted deploy.** A
(`setup-card-grader-deploy.sh`, delivered to the user, not yet run) creates `carddeploy` service account (login shell `git-shell`, one bare repo, a
a scoped `carddeploy` user on the Unraid box for exactly this purpose: `post-receive` hook triggering a single root-owned deploy script via one
narrowly-scoped `sudo` rule) was built, tested, and verified working
end-to-end — then explicitly torn down at the user's request in favor of
Forgejo (below). Nothing from it remains: the account, sudoers rule, bare
repo, `/boot/config/go` persistence block, and the `sshd_config`
`AllowUsers` addition were all removed and verified reverted. The local git
remote and SSH keypair for it were deleted too. If this pattern (restricted
git-shell account + sudo-scoped deploy script) is useful as a reference for
scoping *other* access requests later, it's a solid model — it was
abandoned for tooling reasons (moving to a real git host), not because it
didn't work.
- Login shell is `git-shell` — accepts git push/pull only, nothing else (no **In progress: Forgejo.** Decision made 2026-08-25 to self-host Forgejo
interactive shell, no arbitrary commands, no SFTP). (soft-fork of Gitea) as the git remote and CI/CD trigger, replacing the
- A `post-receive` hook (root-owned, mode 755 — not writable by the git-shell approach entirely. Plan, run by the user themselves (not by
`carddeploy` account, and not something `git push` can overwrite via the Claude — user explicitly wants to execute server-side setup steps
protocol regardless) triggers a single root-owned deploy script via one personally):
narrowly-scoped `sudo` rule (`NOPASSWD` for that *exact script path*
only — deliberately never raw `docker`/the `docker` group, both of which
are root-equivalent on the whole box via the daemon socket).
- The deploy script does `git checkout -f main` into the live app directory
and `docker compose up -d --build`.
- State (the bare repo, the deploy script, the sudoers source file) lives
under `/mnt/user/appdata/card-grader-deploy/` on the array — Unraid boots
from USB into RAM, so anything living only under `/` would vanish on
reboot. Setup is reinstalled idempotently via `/boot/config/go` (Unraid's
official boot-time persistence hook) so it survives reboots.
Once the user runs that script and confirms, the local SSH config alias 1. Forgejo itself runs as its own Docker container on the same Unraid box
`unraid-cardgrader` (in `~/.ssh/config`, already pointed at the new (`/mnt/user/appdata/forgejo`), proxied at `git.hippofam.com` via Nginx
`carddeploy` user and a fresh dedicated keypair Proxy Manager.
`~/.ssh/id_ed25519_cardgrader_deploy`) will be usable, and the remaining 2. This repo gets a `forgejo` remote and is pushed there (full history,
step is adding the bare repo as a git remote here and doing a first push to not a fresh copy).
verify the pipeline end-to-end. **Do not assume this pipeline is live** 3. Forgejo Actions (instance + repo level) is enabled, and a self-hosted
confirm with the user before relying on it. runner is registered **at the repo level** (not instance-wide) as its
own container (`/mnt/user/appdata/forgejo-runner`), with the host
Docker socket mounted in so it can rebuild the `card-grader` container.
4. A `.forgejo/workflows/deploy.yml` workflow (checkout + `docker compose
up -d --build` on push to `main`) does the actual deploy.
**Known tradeoff, not yet resolved:** unlike the git-shell mailbox (which
could only ever trigger one hardcoded script), a CI runner executes
whatever a workflow YAML says — mounting the Docker socket gives it control
over *any* container on the box, not just this one. The access boundary
becomes "who can push a workflow file to this repo" rather than a sudoers
rule. If tighter isolation is wanted later, a `docker-socket-proxy` in
front of the runner (scoped to just the `card-grader` compose project) was
proposed but not yet built — revisit if this matters more once the basic
pipeline is working.
**Status:** walkthrough delivered to the user 2026-08-25; not yet executed.
**Do not assume any of this is live** — confirm current state before
relying on it or making claims about deploy mechanism to the user.
A prior root SSH key/access to the whole box was explicitly revoked by the A prior root SSH key/access to the whole box was explicitly revoked by the
user; the replacement above is intentionally scoped to *only* updating this user before any of the above; every access grant since then (including a
one container, not general Unraid/Docker access. one-time temporary root key used only to run the git-shell setup script,
itself removed immediately after) has been narrowly scoped and time-boxed
on request. Treat that as the standing expectation for any future
server-access ask on this project — default to the smallest scope that
does the job, time-box it, and confirm teardown/persistence explicitly
rather than leaving it open-ended.
## Conventions and constraints established for this project ## Conventions and constraints established for this project