Skip to content

Develop - #12

Merged
krlex merged 10 commits into
mainfrom
develop
Oct 7, 2026
Merged

krlex merged 10 commits into
mainfrom
develop

Conversation

@krlex

@krlex krlex commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Motivation

Changes

Testing

  • Existing tests pass locally
  • New tests added (where applicable)
  • Manual verification documented above

Notes for reviewers

Checklist

  • Commits are signed with a real name and email
  • CHANGELOG.md updated (under ## [Unreleased])
  • Documentation updated (README / docs/ / Pages) if behavior changed
  • No secrets, credentials, or internal hostnames committed

krlex added 10 commits August 11, 2026 14:05
nginx terminates TLS and refuses to start when the certificate it is
configured with is missing. nginx/ssl/ ships empty (just a .gitkeep), and
nothing in the compose path puts anything there, so a clean

    git clone && cp .env.example .env && docker compose up -d

left nginx in a restart loop with nothing serving on 80 or 443 -- the whole
stack was up and unreachable. The instructions for producing a certificate
exist, but in README-prod.md, which the quickstart never sends you to.

Generate a self-signed pair on first start when nginx/ssl/ is empty, and
say so loudly in the log. A certificate that is already there is never
touched, so this changes nothing for an operator who supplies a real one.
.env.example pinned 2026.07.0, which predates 0cb32fe. On that image the
node registers as `control` instead of the requested `hybrid`, and the
`default` queue is created as a Kubernetes container group. On Compose
there is no Kubernetes, so project updates fail with

    unknown work type kubernetes-incluster-auth

and every job launched afterwards sits in `pending` forever. The env var
asking for a hybrid node was simply ignored.

2026.07.1 is not a fix either: it was published for the backend only, so
pinning it makes the frontend image unresolvable. 2026.07.2-rc1 is the
lowest tag that exists for both images and contains the fix.

Also add FORAIL_TLS_CN for the generated certificate.
Two things the Quick Start asserted were not true on a clean machine.

It said every service should report healthy after `docker compose up -d`;
nginx could not, because no certificate existed. And it never mentioned
that job execution is off by default -- so a reader who followed it exactly
got an API and a UI where projects never sync and jobs never leave
`pending`, with nothing pointing at why.

Say where the UI is and how to log in, describe the self-signed
certificate, and document FORAIL_TASK_PRIVILEGED together with the reason
it defaults to off.
…-on-a-clean-machine

The quickstart could not work on a clean machine
Tested on a compose stack (2026.07.2-rc1), the documented procedure
did not work at any step:

- `docker compose exec postgres /scripts/backup.sh` fails: the scripts
  are mounted into forail-task at /etc/forail/, not into postgres.
- backup.sh piped pg_dump into gzip without pipefail, so a failed dump
  still produced a "backup" and exit 0.
- restore.sh psql-loaded a plain dump into the live database: 1,868
  "already exists" errors, nothing replaced (data written after the
  backup survived), "Restore complete." and exit 0. Worse, the dump's
  setval() calls did run, moving sequences back below existing ids, so
  the next inserts failed with duplicate keys and forail-init could no
  longer start.
- Nothing recorded which FORAIL_SECRET_KEY a backup belongs to; restored
  under another key, every credential is unreadable.

backup.sh: pg_dump custom format, written under a temporary name and
renamed only when complete, pipefail, mode 0600, plus a .meta file with
the Forail version, last migration and a fingerprint of the secret key.

restore.sh: refuses without --yes, refuses while other sessions are
connected (forail-web/forail-task must be stopped; it runs in a one-off
`docker compose run --rm --no-deps forail-task` container), refuses on a
secret-key mismatch unless told otherwise. It restores into a new
database and swaps it in by renaming, so a failure changes nothing and
the previous database stays available until dropped. pg_restore --clean
is not an option: it cannot drop the partitioned event tables. Old
.sql.gz backups still restore.

scripts/test-backup-restore.sh runs the round trip against a running
stack: marker data and an encrypted credential, backup, a later write,
restore refused while running, restore, then checks the marker is back,
the later write is gone, the secret decrypts and new writes succeed.
It passes on a fresh 2026.07.2-rc1 stack.

Also verified by hand: backup on 2026.07.2-rc1, upgrade to an image
built from current backend develop work; forail-init applied 0211 and
0212, all data and job history present, credentials decrypt.
The README told operators to run ./scripts/backup.sh and restore.sh on the host, where neither pg_dump nor the database credentials are. Give the commands that actually work -- backup in forail-task, restore in a one-off container with the writers stopped -- and say plainly that the database backup is useless without FORAIL_SECRET_KEY. The full procedure, upgrade and rollback are in the Administrator Handbook.
Compose and .env.example default to the 2026.10.0 images; changelog for everything since 2026.06.0. Not tagged.
…estores

Backup/restore that actually restores, with a round-trip test
@krlex
krlex merged commit 3ebb71a into main Oct 7, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant