Commit Graph

11 Commits

Author SHA1 Message Date
db4f517e44 #203: pin all third-party deploy images by digest
All checks were successful
CI / Lint, typecheck, test (pull_request) Successful in 5m32s
CI / Build container images (pull_request) Successful in 1m13s
CI / Auth e2e pack (pull_request) Successful in 8m22s
CI / Import/export fidelity gate (pull_request) Successful in 57s
CD / Build and push images (push) Successful in 16s
CD / Deploy to Test (push) Successful in 56s
CD / Smoke tests against Test (push) Successful in 1m24s
CD / Promote to Int (push) Successful in 52s
CI / Lint, typecheck, test (push) Successful in 5m36s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Successful in 8m3s
CI / Import/export fidelity gate (push) Successful in 57s
The four third-party images in the deploy compose (postgres, pandoc,
gotenberg — previously a floating MAJOR tag —, caddy) are now
name:tag@sha256 pins; the tag stays for readability, the digest decides
what runs. The pinned digests are exactly what the stages already run
(verified against the live containers' RepoDigests on ONE), so the next
recreation is byte-identical. A new early CI step fails on any
third-party compose image without a digest; compose.dev.yml is a local
convenience and deliberately exempt (its node helpers now follow the
#236 pin). Update + rollout procedure in deploy/stages.md — CD does not
sync stage composes, so the hand rollout to test/int/prod is part of
this issue's definition of done.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0168Ph5uBmHm8X28CSVpbpnJ
2026-07-31 05:13:13 +02:00
340f23fc51 Re-align the stage tables after the path change
All checks were successful
CD / Build and push images (push) Successful in 1m9s
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m11s
CD / Promote to Int (push) Successful in 10s
CI / Lint, typecheck, test (push) Successful in 4m17s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Successful in 5m58s
CI / Import/export fidelity gate (push) Successful in 48s
Release / Build release images and notes (push) Successful in 1m7s
Release / Release-candidate operations QA (push) Successful in 41s
Prod deploy / Deploy the released images to Prod (push) Successful in 16s
Prettier keeps the markdown table columns padded; the /srv/DOCKER
replace left them one character short. (Lesson re-learned: the lint
gate runs before every push, even for doc-only commits.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 12:53:11 +02:00
69e7b1406b Move the stage directories to /srv/DOCKER (host consolidation)
Some checks failed
CD / Build and push images (push) Successful in 1m9s
CI / Lint, typecheck, test (push) Failing after 1m11s
CI / Auth e2e pack (push) Has been skipped
CI / Import/export fidelity gate (push) Has been skipped
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m13s
CD / Promote to Int (push) Successful in 11s
ONE consolidated every Docker stack under /srv/DOCKER (BASEL
convention, tracked in stwaidele/infrastructure-one); the three
Dorfteich stages follow. Deploy targets in cd.yml (test/int) and
prod-deploy.yml plus the docs now point at /srv/DOCKER/dorfteich-<stage>.
Data lives in named volumes keyed by the unchanged compose project
name, so the directory move carries no data migration. The go-live
checklist's uptime-kuma path already lives under /srv/DOCKER — the doc
just catches up.

Deliberately committed together with the host-side move: this commit
must not deploy before the directories exist at the new path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 12:43:29 +02:00
6e56403102 Document runner capacity increase in the provisioning log
All checks were successful
CD / Promote to Int (push) Successful in 9s
CI / Lint, typecheck, test (push) Successful in 2m48s
CI / Auth e2e pack (push) Successful in 3m46s
CI / Import/export fidelity gate (push) Successful in 43s
CI / Build container images (push) Has been skipped
CD / Build and push images (push) Successful in 1m0s
CD / Deploy to Test (push) Successful in 11s
CD / Smoke tests against Test (push) Successful in 1m3s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1
2026-07-11 08:33:29 +02:00
514cdf5ead Move stages, runner and deploy target to dedicated host ONE
All checks were successful
CD / Build and push images (push) Successful in 3m45s
CI / Lint, typecheck, test (push) Successful in 3m39s
CI / Auth e2e pack (push) Successful in 3m43s
CI / Import/export fidelity gate (push) Successful in 43s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m12s
CD / Promote to Int (push) Successful in 10s
Gitea itself relocated to the dedicated Hetzner server ONE
(one.101010.cloud); this commit moves the rest of the delivery chain
along: cd.yml now deploys to one.101010.cloud (DEPLOY_HOST_KEY secret
rotated to ONE's host key), the act_runner one-dorfteich replaces
vps-dorfteich, and the stage/deployment docs describe the new topology
(Test/Int migrated with volumes; Prod joins on the same host at M8).
The Int promotion gate variable RUN_INT_DEPLOY was removed — the new
host has the capacity, so promote-int deploys again by default.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1
2026-07-11 08:05:36 +02:00
d4ebcfcfbe Add collaboration token issuance and connection authentication (#34)
All checks were successful
CD / Build and push images (push) Successful in 2m45s
CI / Lint, typecheck, test (push) Successful in 1m56s
CI / Auth e2e pack (push) Successful in 2m1s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m9s
CD / Promote to Int (push) Successful in 12s
The api mints a short-lived (60 s) HS256 JWT per page open after an interim
permission check; the collab server authenticates every connection with it
(ADR 0003/0007 — the only JWTs in the system).

- packages/shared: browser-safe token schema/types in `collab-token`, and the
  Node `crypto` sign/verify in `token-crypto` behind its own subpath export
  (`@dorfteich/shared/token-crypto`) so the web bundle never pulls in
  `node:crypto`. Only HS256 is produced/accepted; the signature is checked in
  constant time before any untrusted field is read.
- api: `GET /pages/:id/collab-token` (auth-required) returns
  {token, mode, expiresInSeconds}; `mode` is rw/ro via the interim access
  service; issuance is logged at debug level without the token value.
- collab: `onAuthenticate` verifies the token, checks the pageId matches the
  document name, stores {userId, mode} context, and enforces `ro` via
  Hocuspocus' read-only connection flag. Hocuspocus' own signal handling is
  disabled so index.ts remains the single shutdown owner.
- Shared COLLAB_TOKEN_SECRET env for api + collab (compose, dev overlay,
  .env.example, stage docs); a dev default keeps native dev/test/CI running.

Tests: shared token round-trip/rejection; api endpoint e2e (auth required,
claims, 404 for non-members/unknown ids); collab integration via
HocuspocusProvider (valid token connects; expired/tampered/mismatched-page/
wrong-secret rejected; read-only writes dropped, verified with two clients).

Closes #34

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 15:52:19 +02:00
8316c617d2 Add collaboration server skeleton (Hocuspocus) with health, container, and CI/CD (#33)
All checks were successful
CD / Build and push images (push) Successful in 2m36s
CI / Lint, typecheck, test (push) Successful in 1m50s
CI / Auth e2e pack (push) Successful in 1m58s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m13s
CD / Promote to Int (push) Successful in 11s
Bootstrap apps/collab as a Hocuspocus WebSocket server (ADR 0003):
- pino JSON logging (service=collab) and shared Zod env validation
  (collabEnvSchema); structured connection open/close logs.
- /healthz endpoint (process liveness + PostgreSQL ping) served via the
  onRequest hook, matching the container-internal path and the proxied
  /collab/healthz path; any WebSocket handshake is accepted for now
  (authentication arrives with #34, persistence with #35).
- Dockerfile (ESM workspace build) and a compose service on the frontend
  and internal networks with a healthcheck; dev overlay service and a new
  COLLAB_PORT variable.
- CD builds, pushes, and promotes the collab image; CI builds it on PRs;
  the smoke suite asserts /collab/healthz through the reverse proxy.
- deployment.md/stages.md: proxy routing, per-stage COLLAB_PORT, checklist.

Closes #33

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 14:53:44 +02:00
4dd452c0af Docs: warn that stage re-seeds must pass the password overrides
All checks were successful
CD / Build and push images (push) Successful in 40s
CI / Lint, typecheck, test (push) Successful in 1m22s
CI / Auth e2e pack (push) Successful in 1m42s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m5s
CD / Promote to Int (push) Successful in 10s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpQz6ypHJsLfMf4S6fyQEB
2026-07-05 21:03:43 +02:00
bef6d8e4dc Make stage mail + base URL configurable; seed password overrides
All checks were successful
CD / Build and push images (push) Successful in 1m49s
CI / Lint, typecheck, test (push) Successful in 1m15s
CI / Auth e2e pack (push) Successful in 1m41s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 7s
CD / Smoke tests against Test (push) Successful in 1m5s
CD / Promote to Int (push) Successful in 9s
- compose: pass APP_BASE_URL and SMTP_* through to the api container so
  stages can use a real relay (defaults still match the dev Mailpit
  overlay); document the new keys in .env.example and stages.md
- seed: FIXTURE_ADMIN_PASSWORD / FIXTURE_USER_PASSWORD env overrides so
  shared stages get non-public fixture passwords; credential is re-hashed
  on every run so re-seeding applies a changed password

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpQz6ypHJsLfMf4S6fyQEB
2026-07-05 10:42:32 +02:00
d675d69c21 Record stage provisioning completion
Some checks failed
CD / Build and push images (push) Failing after 5s
CD / Deploy to Test (push) Has been skipped
CD / Smoke tests against Test (push) Has been skipped
CD / Promote to Int (push) Has been skipped
CI / Lint, typecheck, test (push) Failing after 8s
CI / Build container images (push) Has been skipped
Test/Int directories, Caddy vhosts, deploy user, act_runner, and
registry access are live on the VPS; Gitea Actions is enabled
instance-wide. This commit doubles as the first full pipeline trigger.

Part of #9

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 00:12:59 +02:00
f870c3855d Document stage provisioning on the VPS
Some checks failed
CI / Lint, typecheck, test (push) Failing after 1m9s
CI / Build container images (push) Has been cancelled
deploy/stages.md walks through the Test/Int setup on 188.245.116.44:
stage directories and .env values, reverse-proxy vhosts (incl. the
/collab WebSocket route needed from M3), act_runner registration,
deploy user with per-stage SSH keys, and registry access. Root steps
are marked and executed together with the repo owner.

Part of #9

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 19:32:21 +02:00