Skip to content

Build-time Environment Reduction Plan

Build-time env enumeration (ENG D13 audit, full)

Section titled “Build-time env enumeration (ENG D13 audit, full)”
Env Var Name Service File:line Reference Category Source Notes
PUBLIC_* safe for image history Use --build-arg
PUBLIC_MARKETING_URL webapp apps/webapp/src/components/ConsentManager.astro:11 PUBLIC_* Hardcoded default (https://erpunlocked.com) Safe to expose in image
PUBLIC_POSTHOG_KEY webapp apps/webapp/src/components/chrome/AppChrome.astro:31 PUBLIC_* Cloud Build secret: erp-prod-posthog-key Safe to expose in image
PUBLIC_POSTHOG_HOST webapp apps/webapp/src/components/chrome/AppChrome.astro:32 PUBLIC_* Cloud Build secret: erp-prod-posthog-host Safe to expose in image
PUBLIC_APP_ENV webapp apps/webapp/src/components/chrome/AppChrome.astro:33 PUBLIC_* No hardcoded default (cast only; undefined if unset) Safe to expose in image
PUBLIC_EMAIL_ENABLED webapp apps/webapp/src/middleware/feature-flags.ts:190 PUBLIC_* Hardcoded default (false) Safe to expose in image
PUBLIC_OBSERVABILITY_TEST_ENABLED internal apps/internal/src/pages/observability.astro:12 PUBLIC_* Hardcoded default (false) Safe to expose in image
Non-PUBLIC* — per-row Notes are authoritative Secret-backed rows only: --mount=type=secret Not every row here needs a secret. DEV, MODE, PROD, NODE_ENV, SSR, AUTH_ENFORCEMENT_MODE and EMAIL_ENABLED are runtime-only or hardcoded — provisioning secrets for them is the over-provisioning this table exists to prevent.
E2E_FLAG_OVERRIDE_SECRET webapp apps/webapp/src/middleware/feature-flags.ts:13 non-PUBLIC Staging only — do NOT provision erp-prod-e2e-flag-override-secret DO NOT plumb into the production build. maybeApplyE2EOverride (feature-flags.ts:238) is dead in production solely because the secret is unset. Creating it arms a header that lets any caller who can forge it flip feature flags in prod.
FLAGSMITH_API_URL webapp apps/webapp/src/middleware/feature-flags.ts:20 non-PUBLIC Cloud Build secret: erp-prod-flagsmith-api-url MUST use --mount=type=secret
FLAGSMITH_ENVIRONMENT_KEY webapp apps/webapp/src/middleware/feature-flags.ts:23 non-PUBLIC Cloud Build secret: erp-prod-flagsmith-environment-key MUST use --mount=type=secret
FLAGSMITH_FALLBACK_FLAGS webapp apps/webapp/src/middleware/feature-flags.ts:177 non-PUBLIC Cloud Build secret: erp-prod-flagsmith-fallback-flags MUST use --mount=type=secret
DEV webapp apps/webapp/src/middleware/feature-flags.ts:61
apps/webapp/src/middleware/feature-flags.ts:195
apps/webapp/src/components/auth/AuthPerformanceMonitor.tsx:17
apps/webapp/src/middleware.ts:686
apps/webapp/src/pages/api/debug/env-check.ts:7
non-PUBLIC Runtime-only (Node.js built-in) Node.js built-in, no secret needed
MODE webapp apps/webapp/src/middleware/feature-flags.ts:142
apps/webapp/src/pages/admin/feature-flags/index.ts:58
apps/webapp/src/pages/erp/parts/auto-validate.ts:88
non-PUBLIC Runtime-only (Node.js built-in) Node.js built-in, no secret needed
PROD webapp apps/webapp/src/middleware/api-auth-enforcement.ts:22
apps/webapp/src/middleware.ts:79
apps/webapp/src/middleware.ts:287
apps/webapp/src/pages/orders/wherefour-submit.astro:21
apps/webapp/src/utils/encryption.ts:13
non-PUBLIC Runtime-only (Node.js built-in) Node.js built-in, no secret needed
NODE_ENV webapp apps/webapp/src/middleware.ts:686 non-PUBLIC Runtime-only (Node.js built-in) Node.js built-in, no secret needed
SSR webapp apps/webapp/src/utils/encryption.ts:13
apps/webapp/src/utils/encryption.ts:18
non-PUBLIC Runtime-only (Astro built-in) Astro built-in, no secret needed
ENCRYPTION_KEY webapp apps/webapp/src/utils/encryption.ts:14
apps/webapp/src/utils/encryption.ts:19
non-PUBLIC Cloud Build secret: erp-prod-encryption-key MUST use --mount=type=secret
AUTH_ENFORCEMENT_MODE webapp apps/webapp/src/middleware/api-auth-enforcement.ts:22 non-PUBLIC Hardcoded default (log) Runtime-only flag, no secret needed
RESEND_API_KEY webapp apps/webapp/src/actions/index.ts:8
apps/webapp/src/pages/api/contact.ts:14
non-PUBLIC Cloud Build secret: erp-prod-resend-api-key MUST use --mount=type=secret
INBOX_ROUTING_SECRET webapp apps/webapp/src/pages/api/emails/bulk-actions/internal.ts:39 non-PUBLIC Cloud Build secret: erp-prod-inbox-routing-secret MUST use --mount=type=secret
EMAIL_ENABLED webapp apps/webapp/src/middleware/feature-flags.ts:188 non-PUBLIC Hardcoded default (false) Runtime-only flag, no secret needed
CLERK_PUBLISHABLE_KEY internal apps/internal/src/middleware.ts:27 non-PUBLIC Cloud Build secret: erp-prod-clerk-publishable-key MUST use --mount=type=secret

PUBLIC_* (safe for –build-arg): 6 variables

  • PUBLIC_MARKETING_URL
  • PUBLIC_POSTHOG_KEY
  • PUBLIC_POSTHOG_HOST
  • PUBLIC_APP_ENV
  • PUBLIC_EMAIL_ENABLED
  • PUBLIC_OBSERVABILITY_TEST_ENABLED

Non-PUBLIC, secret-backed (must use –mount=type=secret): 8 variables

  • E2E_FLAG_OVERRIDE_SECRET — staging only; do NOT provision erp-prod-e2e-flag-override-secret (see the table row and “Deliberately NOT provisioned” below)
  • FLAGSMITH_API_URL
  • FLAGSMITH_ENVIRONMENT_KEY
  • FLAGSMITH_FALLBACK_FLAGS
  • ENCRYPTION_KEY
  • RESEND_API_KEY
  • INBOX_ROUTING_SECRET
  • CLERK_PUBLISHABLE_KEY

Non-PUBLIC, runtime-only (no secret needed): 7 variables

  • DEV, MODE, PROD, NODE_ENV (Node.js built-ins)
  • SSR (Astro built-in)
  • AUTH_ENFORCEMENT_MODE, EMAIL_ENABLED (runtime flags)

8 + 7 = the 15 non-PUBLIC rows in the table above. Counting all 15 as secret-backed is what produced the earlier “13” and is the over-provisioning this document exists to prevent.

Existing secrets (likely to exist):

  • erp-prod-clerk-publishable-key

New secrets needed:

  • erp-prod-flagsmith-api-url
  • erp-prod-flagsmith-environment-key
  • erp-prod-flagsmith-fallback-flags
  • erp-prod-encryption-key
  • erp-prod-resend-api-key
  • erp-prod-inbox-routing-secret

Deliberately NOT provisioned: erp-prod-e2e-flag-override-secret. maybeApplyE2EOverride (apps/webapp/src/middleware/feature-flags.ts:238) is dead in production solely because E2E_FLAG_OVERRIDE_SECRET is unset there. Creating it arms a header that flips feature flags for anyone who can forge it. Staging only.

  • erp-prod-posthog-key
  • erp-prod-posthog-host

Checked: 2026-05-22
Method: gcloud secrets list --project=ordermatic-prod --filter="name:erp-prod-*"
Result: GCP access not available from this environment
Follow-up: Manual verification required by team with GCP access

Action needed: Team with ordermatic-prod project access should verify these secrets exist in Secret Manager before implementing build-time changes.

  1. Dockerfile Impact: The 8 secret-backed non-PUBLIC variables must be passed via --mount=type=secret in Cloud Build, not as build args. The other 7 non-PUBLIC variables are runtime-only and need no secret at all — do not mount them.
  2. Performance Impact: Two separate wins, not one. The 7 runtime-only variables leave build-time handling entirely. The 8 secret-backed ones still have to be readable during the build — that is what Note 1 mounts them for — but move off --build-arg, so they stop landing in image history. Layer-size and build-time savings come from the first group; the second is a security change that is size-neutral.
  3. Security: Proper secret management is required to avoid exposing sensitive configuration in image history
  4. Testing: All runtime-only behavior should be tested after the build-time changes