From e73beb20df29a9b5df55d1cb52edec0f9134cda1 Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Tue, 13 Oct 2026 08:31:51 +0200 Subject: [PATCH] Remove upgrade and older-build text from the README (closes #520) The schema comes from 001_schema.sql, edited in place before 1.0, so the README's upgrade procedure, downgrade note, BIND_ADDRESS upgrade note and remarks about what older builds wrote are removed. The description of the SQL schema files moves to a new Schema subsection under Database Architecture, the health check command moves to Version stamping, and the section is renamed Backup and Restore. The sentences on session timestamps, file modes and the retention clamp now say only what the code does. Model: opus-5-5 --- README.md | 87 +++++++++++++++++-------------------------------------- 1 file changed, 26 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index 1e4b4b9..cbdcc85 100644 --- a/README.md +++ b/README.md @@ -465,10 +465,7 @@ idle timestamp is rewritten at most once per tenth of the idle window rather than on every request, which means a session may expire up to 10% early relative to the user's true last request, but never late. -Both clocks are anchored by timestamps stored in the session cookie. Sessions -issued before this feature existed carry neither, so they are treated as -expired: upgrading to a build that has it logs every existing session out once, -and those users sign in again. +Both clocks are anchored by timestamps stored in the session cookie. #### Invalid values abort startup @@ -702,11 +699,11 @@ app as that user. `webhooker.db` holds target configuration in plaintext — bearer tokens, API keys, Slack webhook URLs — along with the session encryption key, so webhooker creates every SQLite file it owns `0600`: each database and both of its `-wal` -and `-shm` sidecars, across all three tiers. Files an earlier build left `0644` -are tightened when they are opened. The directory's `0750` is defence in depth — -it stops other local users listing the directory and learning your webhook UUIDs -from the `events-{uuid}.db` filenames — not the barrier protecting the -credentials. +and `-shm` sidecars, across all three tiers. Any of them found at another mode +is set to `0600` when the database is opened. The directory's `0750` is defence +in depth — it stops other local users listing the directory and learning your +webhook UUIDs from the `events-{uuid}.db` filenames — not the barrier protecting +the credentials. ### Running under upaas @@ -918,7 +915,7 @@ replaces the `max-age` it stored, so to end the policy sooner, set a short `HSTS_MAX_AGE` such as `1s` and keep it until returning browsers have picked it up, or have a reverse proxy send `max-age=0`. -## Backup, Restore, and Upgrades +## Backup and Restore ### What to back up @@ -1071,60 +1068,14 @@ beside it, or wait until there are none. 4. Start the service. The container gives the directory and the restored files to the `webhooker` user before the app starts, whoever restored them (see - [Running with Docker](#running-with-docker)). Each restored database gets any - of its SQL migrations it has not had as it is opened (see - [Upgrades](#upgrades)). - -### Upgrades - -**Back up before every upgrade.** Each kind of database file has its schema in -SQL files built into the binary, one directory per kind under -`internal/db/migrations/`. In each, `000_migration.sql` creates the -`schema_migrations` table, which records the number of every file the database -has had, and `001_schema.sql` holds the whole schema. Opening a database runs, -in one transaction, every file in its directory that `schema_migrations` does -not list: - -- `main/` for the main database, on connect — settings, users, API keys, - webhooks, entrypoints and targets -- `events/` for each event database, when it is lazily opened — events, - deliveries, delivery results and their running totals -- `archive/` for each archive database, on every open and reopen - -There are no down migrations. - -Upgrade procedure: - -1. Stop the service. -2. Back up `DATA_DIR` using one of the procedures above. -3. Pull the new image and start it. -4. Confirm `database migrations completed` in the logs before putting traffic - back on it. -5. Confirm the new build is the one running: - `curl -s http://host:8080/.well-known/healthcheck` reports the version it was - stamped with (see [Version stamping](#version-stamping)). - -**Upgrading past the introduction of `BIND_ADDRESS`:** earlier versions always -bound every interface. **Container deployments are unaffected** — the image -ships `ENV BIND_ADDRESS=0.0.0.0`, so a `docker run` or Compose service that -worked before still works with nothing changed. - -A **bare binary** is the case that changes: the listener now binds `127.0.0.1` -unless `BIND_ADDRESS` says otherwise, so a deployment that relied on reaching it -from another host becomes unreachable until it sets the address the proxy -connects to. Check the `bindAddress` field of the startup log to see what a -running process bound. See [Bind address](#bind-address). - -**Downgrade is unsupported.** Once a newer binary has migrated the files there -is no way to move them back. The only supported way back to an older version is -restoring the pre-upgrade backup, which discards everything received since that -backup was taken. + [Running with Docker](#running-with-docker)). ### Version stamping The binary reports its version at `/.well-known/healthcheck` (the `version` field), in the UI footer, and in the startup log line (`msg=starting`, `version=...`). It is also the Sentry release name, as `webhooker-{version}`. +`curl -s http://host:8080/.well-known/healthcheck` shows which build is running. The value is stamped in at build time by the linker; it is not read from a file at runtime, so it identifies the build itself. @@ -1583,8 +1534,7 @@ The cap is not arbitrary: the reaper computes its cutoff as a `time.Duration`, an int64 nanosecond count, and a longer period overflows it. An overflowed cutoff lands in the future, where it matches every row, so the sweep would delete every event the webhook has instead of none. The reaper also clamps the -value it is given, so a row written by an older version cannot trigger that -either. +value it reads to the cap, so no stored value can trigger that either. #### Entrypoint @@ -1967,7 +1917,7 @@ and application state: - **APIKeys** — programmatic access credentials On first startup the main database is created from its SQL files (see -[Upgrades](#upgrades)), a session encryption key is generated and stored, and an +[Schema](#schema)), a session encryption key is generated and stored, and an `admin` user is created. **Per-Webhook Event Databases** (`{DATA_DIR}/events-{webhook_uuid}.db`) — each @@ -2164,6 +2114,21 @@ The database uses the though CGO is required at build time due to the transitive `mattn/go-sqlite3` dependency from `gorm.io/driver/sqlite`. +#### Schema + +Each kind of database file has its schema in SQL files built into the binary, +one directory per kind under `internal/db/migrations/`. In each, +`000_migration.sql` creates the `schema_migrations` table, which records the +number of every file the database has had, and `001_schema.sql` holds the whole +schema. Opening a database runs, in one transaction, every file in its directory +that `schema_migrations` does not list: + +- `main/` for the main database, on connect — settings, users, API keys, + webhooks, entrypoints and targets +- `events/` for each event database, when it is lazily opened — events, + deliveries, delivery results and their running totals +- `archive/` for each archive database, on every open and reopen + ### Request Flow ```