Commit Graph
3 Commits
Author SHA1 Message Date
JakeBreath d9c1e9e521 Add CI and manual image publishing workflows
CI / Frontend build & lint (push) Failing after 4m59s
CI / Backend tests (push) Successful in 12m54s
- .gitea/workflows/ci.yml: on every push/PR, run Django checks + the full
  backend suite against MariaDB/Redis services and the frontend
  lint/type-check/build. Runs on the nitro-ci runner (ubuntu-latest).
- .gitea/workflows/publish.yml: manual dispatch; multi-arch build+push of
  both images as :latest and :<short-sha> with GIT_HASH baked in.
- push_*.sh: non-interactive registry login for CI (REGISTRY_USER/
  REGISTRY_TOKEN) and a PLATFORMS override.
2026-09-22 22:32:37 -05:00
JakeBreath b96c311235 Fix cross-origin staging URLs, e621 UA format and IQDB queue stalls
The dev Vite proxy rewrites the request Host to 127.0.0.1:8000, so the
backend's absolute signed file URLs pointed at a different origin than the
SPA (localhost:5173). Images tolerated it, but the auth'd fetch that reads
the staging blob for IQDB was blocked ('Cross-Origin Request Blocked') and
every similarity check died before reaching e621.

apiUrl() now keeps API-built absolute URLs on the page's origin whenever the
SPA is in same-origin mode (dev proxy, deploy nginx) and leaves them
absolute when an explicit backend URL is configured. All consumers use it:
staging previews and the bulk modal, library cards, optimizer (range sniff +
worker), IQDB card, delete page, similar page.

e621 identification now follows the documented 'App/version (developer)'
form: server-side requests send 'J621/<hash> (JakeBreath)' and the browser
_client gets the same string, with the hash baked into the frontend image
(GIT_HASH build arg; guarded at runtime so the dev server still works).

IQDB stalls: requests now time out after 20s (a hung fetch used to block the
serialized e621 queue forever), and all checks run through one serial drain
so repeated 'Check similarity' clicks can no longer start overlapping runs
that re-download the same staging blobs. Auth/rate-limit/timeout/network
failures stop the queue with the reason and a retry button instead of
grinding through the rest.

Verified live: staged file URL is same-origin through the proxy and fetches
200 through it.
2026-09-19 00:30:42 -05:00
JakeBreath 8ebda6ab20 Docker deployment (2 images, 3 composes, Tailscale funnels) + committed security suite
Test suite (the manual audit harness, now a real test):
- backend/apps/core/tests/test_security.py: 20 transactional tests across
  guest visibility, object ownership, staged-upload/similarity privacy,
  staff role boundaries, deletion rules, encrypted credentials, throttling
  and the download allowlist. Uses temp media folders and clears cache.
  Needs a one-time GRANT on test_j621 (documented in the module + README).

Images (deploy/J621-Frontend, deploy/J621-Backend, repo root as context):
- Frontend: node build -> static nginx with SPA fallback, asset caching and
  an internal health endpoint.
- Backend: gunicorn + whitenoise (admin static collected at build), ffmpeg
  for video thumbnails, migrations applied on start, GIT_HASH build arg so
  the shell's version pill shows the commit.

Composes (distinct project names so they coexist with the dev stack):
- compose.yml (both), compose.frontend.yml, compose.backend.yml.
- A shared nginx proxy service is the only entry point (no host nginx, no
  published host ports): /api,/admin,/static,/health -> backend, everything
  else -> SPA; both upstreams resolve at request time so one config serves
  all variants.
- A Tailscale sidecar per compose shares the nginx network namespace;
  serve.default/frontend/backend.json use funnel ports 443 and 8443 only
  (10000 is the remaining allowance) with ${TS_CERT_DOMAIN} substitution.

Registry: push_frontend.sh / push_backend.sh / push_all.sh build multi-arch
images and push :latest + :<sha> to the Gitea registry, following the
existing Packs-site pattern.

Docs: deploy/README.md + .env.example, ROADMAP section 6 updated,
AGENTS.md deployment and test notes.

Verified: all three composes validate, both nginx configs pass nginx -t,
both images build, the combined stack boots against real MariaDB/Redis
(migrations applied, /health ok, whitenoise serving admin static, env=prod,
git hash baked in), the proxy serves the SPA and routes /api, and
manage.py test apps.core.tests passes 20/20.
2026-09-18 00:51:29 -05:00