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 |
Summary
Section titled “Summary”Environment Variables by Category
Section titled “Environment Variables by Category”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.
Required Cloud Build Secrets
Section titled “Required Cloud Build Secrets”Existing secrets (likely to exist):
erp-prod-clerk-publishable-key
New secrets needed:
erp-prod-flagsmith-api-urlerp-prod-flagsmith-environment-keyerp-prod-flagsmith-fallback-flagserp-prod-encryption-keyerp-prod-resend-api-keyerp-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-keyerp-prod-posthog-host
Secret Verification Status
Section titled “Secret Verification Status”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.
Implementation Notes
Section titled “Implementation Notes”- Dockerfile Impact: The 8 secret-backed non-PUBLIC variables must be passed via
--mount=type=secretin 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. - 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. - Security: Proper secret management is required to avoid exposing sensitive configuration in image history
- Testing: All runtime-only behavior should be tested after the build-time changes