Skip to content

Commit a02ad0e

Browse files
s3rot0n1nclaude
andcommitted
fix: require SUPPRESSION_HASH_KEY in the self-host Compose setup
The API refuses to boot without SUPPRESSION_HASH_KEY, but the root .env.example and docker-compose.yml never mentioned it, so the documented `docker compose up` path crash-looped. List it in .env.example, make Compose fail fast with a clear message when it is missing, and ignore the root .env that the self-host steps create with every secret in it. A config test asserts every secret checkConfig requires is listed and enforced, so the next required variable can't be forgotten the same way. Fixes #32 Co-Authored-By: Claude Opus 5.5 <[email protected]>
1 parent 1cc9b0b commit a02ad0e

4 files changed

Lines changed: 41 additions & 1 deletion

File tree

‎.env.example‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
POSTGRES_PASSWORD=
44
BETTER_AUTH_SECRET=
55
PIXEL_SIGNING_SECRET=
6-
# Generate this one with: openssl rand -base64 32
6+
# Generate these with: openssl rand -base64 32
77
ESP_CREDENTIALS_ENCRYPTION_KEY=
8+
SUPPRESSION_HASH_KEY=
89

910
# The initial account and its default team are created by the one-shot init
1011
# service. Its API key is shown exactly once in `docker compose logs init`.

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Secrets (copied from .env.example for self-hosting)
2+
.env
3+
14
# Dependencies
25
node_modules/
36
.npmrc
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { readFileSync } from "node:fs";
2+
import path from "node:path";
3+
import { describe, expect, it } from "vitest";
4+
5+
// Secrets `checkConfig` in `index.ts` refuses to boot without. The Compose
6+
// self-host path builds `DB_CONNECTION_STRING` itself, so it is not listed.
7+
// Keep in sync when `checkConfig` gains a new required variable.
8+
const REQUIRED_SECRETS = [
9+
"BETTER_AUTH_SECRET",
10+
"PIXEL_SIGNING_SECRET",
11+
"ESP_CREDENTIALS_ENCRYPTION_KEY",
12+
"SUPPRESSION_HASH_KEY",
13+
];
14+
15+
// Tests run with this package (`apps/api`) as cwd; see `test/db.ts`.
16+
const repoRoot = path.resolve(process.cwd(), "../..");
17+
const read = (file: string) => readFileSync(path.join(repoRoot, file), "utf8");
18+
19+
describe("self-host configuration", () => {
20+
const envExample = read(".env.example");
21+
const compose = read("docker-compose.yml");
22+
23+
it.each(REQUIRED_SECRETS)("lists %s in the root .env.example", (name) => {
24+
expect(envExample).toMatch(new RegExp(`^${name}=`, "m"));
25+
});
26+
27+
it.each(REQUIRED_SECRETS)(
28+
"makes docker compose fail fast without %s",
29+
(name) => {
30+
expect(compose).toContain(
31+
`${name}: \${${name}:?Set ${name} in .env}`,
32+
);
33+
},
34+
);
35+
});

‎docker-compose.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ services:
4444
BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET:?Set BETTER_AUTH_SECRET in .env}
4545
PIXEL_SIGNING_SECRET: ${PIXEL_SIGNING_SECRET:?Set PIXEL_SIGNING_SECRET in .env}
4646
ESP_CREDENTIALS_ENCRYPTION_KEY: ${ESP_CREDENTIALS_ENCRYPTION_KEY:?Set ESP_CREDENTIALS_ENCRYPTION_KEY in .env}
47+
SUPPRESSION_HASH_KEY: ${SUPPRESSION_HASH_KEY:?Set SUPPRESSION_HASH_KEY in .env}
4748
SUPER_ADMIN_EMAIL: ${SUPER_ADMIN_EMAIL:?Set SUPER_ADMIN_EMAIL in .env}
4849
API_PUBLIC_URL: ${API_PUBLIC_URL:-http://localhost:4000}
4950
WEB_CLIENT: ${WEB_CLIENT:-http://localhost:3000}

0 commit comments

Comments
 (0)