-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathenv.ts
More file actions
65 lines (63 loc) · 3.57 KB
/
Copy pathenv.ts
File metadata and controls
65 lines (63 loc) · 3.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// Normalised environment-mode predicates.
//
// Centralising `NODE_ENV` interpretation avoids the drift that the
// PR #84 senior-review caught: three call sites (`auth.ts`, `app.ts`,
// `server.ts`) each did `process.env.NODE_ENV === 'production'`, which
// silently fell through to dev behaviour on `"Production"` (uppercase),
// `"production "` (trailing space from hand-edited compose env-files),
// or `"prod"` (operator abbreviation). The auth-guard PR existed
// because that exact failure mode had already happened in production,
// so leaving each call site to re-derive the check would have shipped
// the same bug shape it set out to close.
//
// `isProduction()` uses the conservative interpretation: only an
// explicit, known-safe-for-dev-fallback `NODE_ENV` value escapes
// production handling. Anything else — including unrecognised values
// like `"prod"`, `"staging"`, `"qa"` — is treated as production.
// Rationale: an unrecognised value is almost certainly an operator
// typo for "production" or a parallel-to-production environment
// (staging, QA), both of which should require the strong API key.
// Silently treating them as dev was the exact failure mode this
// helper was extracted to close.
//
// The dev safelist intentionally stays short. Each token must have a
// load-bearing caller in this repo — a Dockerfile, compose file, npm
// script, vitest/Node default, or framework convention that actually
// sets it. If you add an entry, name the caller in the comment below.
// Round 2 cut `'local'` (no caller found); round 3's review cut `'dev'`
// and `'testing'` for the same reason — both had imagined-not-verified
// citations in an earlier comment. A safelist entry without a verified
// caller is dead code that invites the next maintainer to expand the
// dev-fallback surface "because it's already a pattern."
//
// Currently in the safelist:
// * `''` — NODE_ENV unset; the implicit dev workflow when an operator
// runs `npm run dev` (see `backend/package.json`'s `dev` script:
// `tsx watch src/server.ts`, no env override).
// * `'development'` — Node's standard sentinel, the value
// `dotenv/config` and most Node frameworks recognise. Set by
// `docker-compose.yml`'s `backend` service for the dev compose
// topology (verified at the time of writing).
// * `'test'` — vitest's default `NODE_ENV` (Vitest documents this:
// "If NODE_ENV is not set, Vitest sets it to 'test' by default").
// The backend's entire 60-test suite runs under this value. Also
// set explicitly by `tests/ui/docker-compose.ui.yml`'s backend
// service so the Playwright stack picks up the dev-CORS fallback
// (production CORS only allows `https://highfive.schutera.com`
// and would block the homepage container's `http://localhost:6173`
// origin). Narrowing this safelist requires updating the UI
// compose first.
//
// `process.env` is read each call rather than captured at module load
// because the test suite manipulates env vars between cases via
// `vi.resetModules()` + dynamic `import()`. Per-call `process.env`
// access is cheap (Node maintains it as a normal object), so calling
// `isProduction()` from a hot path is fine. The asymmetry with
// `auth.ts`'s once-at-load `ENV_KEY` capture is intentional: the
// key value is policy (set once at deploy time), the env-mode is
// runtime context (test suite flips it between cases).
const DEV_ENV_TOKENS: ReadonlySet<string> = new Set(['', 'development', 'test']);
export function isProduction(): boolean {
const normalised = (process.env.NODE_ENV ?? '').trim().toLowerCase();
return !DEV_ENV_TOKENS.has(normalised);
}