fix(env): the documented Compose deploy could not boot #163

Merged
whitlocktech merged 1 commits from fix/env-example-secret-enc-key into main 2026-08-24 16:31:14 +00:00
Member

The defect

.env.example — the file docker-compose.yml actually reads — never listed SECRET_ENC_KEY. utils/secretBox.js resolves the key at require time and throws SECRET_ENC_KEY must be set in production, so following README Option A exactly produces a container that crash-loops before it ever listens:

Error: SECRET_ENC_KEY must be set in production
    at resolveKey (/app/server/src/utils/secretBox.js:24:11)
    at Object.<anonymous> (/app/server/src/model/emailConfig/emailConfig.model.js:7:19)

It was easy to miss because the variable is documented in two places a Compose operator never opens: server/.env.example, which is what local development copies, and the README's environment-variable reference table. Only the file the deployment reads was missing it.

Reproduced, then verified

Against the published image, not a working tree:

  1. cp .env.example .env, fill in what the README's list names, docker compose up -d → crash loop on the error above.
  2. With this change, the same procedure reaches listening on http://0.0.0.0:3000, seeds the first admin, and /api/health answers {"status":"ok"}.

The change

  • .env.example gains SECRET_ENC_KEY beside JWT_SECRET, documenting what it encrypts, that production refuses to start without it, and that changing it later orphans every stored secret rather than re-encrypting them.
  • README Option A's "set at least" list gains SECRET_ENC_KEY and BOT_INTERNAL_KEY. Both are refused-at-boot in production, and BOT_INTERNAL_KEY is required even on a deployment that runs no bot — precisely the case the list omitted.

No code changes; the boot-time refusal is correct behaviour and stays as it is.

How it was found

While writing the runicgateway.com installation docs (runicgateway.com#10), whose quickstart is checked against this file on every build. Merging this will turn that PR's checkQuickstart red by design — the check fails the moment the variable appears here, so the note calling it an upstream omission cannot outlive the defect. A one-line follow-up on that branch clears it.


AI-assisted: written with Claude Code (Opus 5).

🤖 Generated with Claude Code

## The defect `.env.example` — the file `docker-compose.yml` actually reads — never listed **`SECRET_ENC_KEY`**. `utils/secretBox.js` resolves the key at require time and throws `SECRET_ENC_KEY must be set in production`, so following README Option A exactly produces a container that **crash-loops before it ever listens**: ``` Error: SECRET_ENC_KEY must be set in production at resolveKey (/app/server/src/utils/secretBox.js:24:11) at Object.<anonymous> (/app/server/src/model/emailConfig/emailConfig.model.js:7:19) ``` It was easy to miss because the variable *is* documented in two places a Compose operator never opens: `server/.env.example`, which is what local development copies, and the README's environment-variable reference table. Only the file the deployment reads was missing it. ## Reproduced, then verified Against the **published image**, not a working tree: 1. `cp .env.example .env`, fill in what the README's list names, `docker compose up -d` → crash loop on the error above. 2. With this change, the same procedure reaches `listening on http://0.0.0.0:3000`, seeds the first admin, and `/api/health` answers `{"status":"ok"}`. ## The change - **`.env.example`** gains `SECRET_ENC_KEY` beside `JWT_SECRET`, documenting what it encrypts, that production refuses to start without it, and that changing it later **orphans every stored secret** rather than re-encrypting them. - **README Option A's "set at least" list** gains `SECRET_ENC_KEY` and `BOT_INTERNAL_KEY`. Both are refused-at-boot in production, and `BOT_INTERNAL_KEY` is required *even on a deployment that runs no bot* — precisely the case the list omitted. No code changes; the boot-time refusal is correct behaviour and stays as it is. ## How it was found While writing the runicgateway.com installation docs (runicgateway.com#10), whose quickstart is checked against this file on every build. **Merging this will turn that PR's `checkQuickstart` red by design** — the check fails the moment the variable appears here, so the note calling it an upstream omission cannot outlive the defect. A one-line follow-up on that branch clears it. --- AI-assisted: written with Claude Code (Opus 5). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
wtclaude added 1 commit 2026-08-24 16:20:13 +00:00
fix(env): the documented Compose deploy could not boot
All checks were successful
PR Checks / client-build (pull_request) Successful in 30s
PR Checks / bot-tests (pull_request) Successful in 31s
PR Checks / server-tests (pull_request) Successful in 2m32s
c43e092248
`.env.example` — the file docker-compose.yml actually reads — never listed
SECRET_ENC_KEY. `utils/secretBox.js` resolves the key at require time and throws
`SECRET_ENC_KEY must be set in production`, so following README Option A exactly
produces a container that crash-loops before it ever listens.

It was easy to miss because the variable IS documented in two places that a
Compose operator never opens: `server/.env.example`, which is what local
development copies, and the README's environment-variable reference table. Only
the file the deployment reads was missing it.

Reproduced against the published image with a clean `cp .env.example .env`, then
verified the fix the same way: fill in the values the README names and
`docker compose up -d` reaches `listening on http://0.0.0.0:3000` and
`/api/health` → `{"status":"ok"}`.

- `.env.example` gains SECRET_ENC_KEY, beside JWT_SECRET, with what it encrypts,
  that production refuses to start without it, and that changing it later
  orphans every stored secret rather than re-encrypting them.
- README's Option A "set at least" list gains SECRET_ENC_KEY and
  BOT_INTERNAL_KEY. Both are refused-at-boot in production, and BOT_INTERNAL_KEY
  is required even on a deployment that runs no bot, which is exactly the case
  the list omitted.

Found while writing the runicgateway.com installation docs, whose quickstart is
checked against this file on every build.

Co-Authored-By: Claude <noreply@anthropic.com>
whitlocktech approved these changes 2026-08-24 16:31:06 +00:00
whitlocktech merged commit 3bca112502 into main 2026-08-24 16:31:14 +00:00
whitlocktech deleted branch fix/env-example-secret-enc-key 2026-08-24 16:31:15 +00:00
Sign in to join this conversation.
No description provided.