Configuration And Secrets
Configuration changes are cross-cutting. A single value can touch app env parsing, Docker builds, GitHub Actions, Pulumi outputs, runtime parameter stores, smoke tests, and operator runbooks.
Use this page when adding, renaming, removing, or changing the meaning of:
- App environment variables.
- Frontend build arguments.
- Backend runtime settings.
- i18n runtime or build settings.
- GitHub Actions variables or secrets.
- Pulumi config keys, Pulumi secret config keys, Pulumi outputs, or deployment contract fields.
- SSM runtime parameter references.
- CI, Playwright, smoke, or local
.envvalues.
Principle
Section titled “Principle”Environment names are allowed to appear in more than one place only when each place enforces a different boundary.
Good duplication:
- App env schemas prove the process can parse the value it consumes.
.env.examplefiles teach local developers what they need to provide.- Workflow manifests describe which values GitHub owns and which values GitHub must not own.
- Deployment contracts describe sanitized cloud facts that routine deployment code can consume without direct Pulumi access or guessing provider resources.
- Deployed-dev validators catch drift before AWS, SSM, Docker, or runtime hosts are involved.
- Runtime parameter inventories describe the operator-facing names and value kinds.
Bad duplication:
- Mirroring Pulumi outputs into GitHub environment variables because it is convenient.
- Adding a runtime secret to GitHub when the host should read it from SSM.
- Adding
NEXT_PUBLIC_*values to runtime SSM parameters even though they are browser-bundled build inputs. - Repeating a value in docs without a validator, parser, fixture, or operational checklist that keeps it honest.
Docs explain the contract. Code-owned schemas, manifests, fixtures, scripts, Pulumi outputs, deployment contracts, and validators enforce it.
Classify First
Section titled “Classify First”Before editing files, answer these questions:
- Who consumes it: frontend browser, frontend server, backend, i18n package, deploy workflow, Pulumi, runtime host, tests, smoke checks, or an operator?
- When is it needed: build time, runtime, deploy time, preview time, test time, or local development only?
- How visible is it: public, restricted public, non-secret internal config, or secret?
- Who owns the source of truth: repo default,
.envfile, GitHub environment, Pulumi config, deployment contract, SSM runtime parameter, CI setup, or operator action? - What should fail if it is missing: local boot, image build, preflight, deploy contract, runtime render, smoke, or a live cloud validation step?
If those answers are fuzzy, document the intended boundary before wiring the value into code.
Source Boundaries
Section titled “Source Boundaries”| Source | Use For | Do Not Use For |
|---|---|---|
| App env schemas | Values the running process actually reads. | Cloud resource discovery or workflow governance. |
.env.example / .env.shared | Local development discoverability and safe defaults. | Real secrets or deployed cloud facts. |
| GitHub environment variables | Deploy bootstrap and governance values. | App runtime config, cloud facts, Pulumi outputs, or repo-derived defaults. |
| GitHub environment secrets | Deploy credentials or tokens GitHub itself must use. | App runtime secrets that should stay at the runtime host boundary. |
| Pulumi stack config | Stack choices and infrastructure-owned config. | App values that should vary through runtime parameters. |
| Pulumi secret config | Infrastructure-owned secrets or restricted public provider config. | Plain app runtime secrets that do not belong in infrastructure state. |
| Pulumi state backend profile | Infra-operator state storage, locks, history, backups, and passphrase. | Routine app/docs CD inputs or deployment contract artifact storage. |
| Pulumi outputs | Infra-operator source facts that can be projected into deploy contracts. | Routine app/docs CD inputs, plaintext secrets, or values GitHub can derive from the checkout. |
| Deployment contracts | Sanitized non-secret cloud facts for routine app/docs CD. | Pulumi state, raw provider subtrees, secret values, or infrastructure backend details. |
| SSM runtime parameters | Deployed app runtime config and runtime secrets. | Frontend browser build inputs or deploy bootstrap credentials. |
| Docker build args | Frontend build-time values, especially browser-visible NEXT_PUBLIC_* | Backend runtime secrets or values intended to change without a rebuild. |
| CI / Playwright injected env | Test runner setup and hermetic smoke values. | Production or deployed-dev source-of-truth registries. |
Smallest Surface Set
Section titled “Smallest Surface Set”Do not update every possible file by default. Update the surfaces that own the boundary you classified.
| Boundary | Common Files Or Contracts |
|---|---|
| Backend runtime env | apps/wavemap-back-end/src/env.ts |
| Frontend browser env | apps/wavemap-front-end/src/env/client.ts |
| Frontend server-only env | apps/wavemap-front-end/src/env/server.ts |
| Shared i18n env | packages/i18n/src/env/client.ts, packages/i18n/src/env/server.ts |
| GitHub workflow vocabulary | infra/environments/deployed-dev/workflow-env.contract.json |
| Deployed-dev runtime parameters | infra/operations/src/deployed-dev/runtime-config-contract.ts |
| Deployed-dev deployment facts | Deployment contracts, Pulumi outputs before projection, and infra/environments/deployed-dev/fixtures/runtime-deploy.outputs.valid.json when no-cloud deploy checks consume the shape. |
| Host env rendering | Runtime env render helpers and the runtime deployment source that maps grouped parameters into backend, frontend, and Postgres env files. |
| Testing and smoke setup | CI workflow env setup, Playwright runtime setup, smoke helpers, and Testing only when the verification command or expected config contract changes. |
| Operator procedures | Runbooks only when the changed value affects a repeated operator decision, live recovery path, readiness check, or mutation gate. |
Local development .env.example files should change when a developer needs to provide a new local value. Real local
secrets still stay out of git.
Deployed-Dev Runtime Boundary
Section titled “Deployed-Dev Runtime Boundary”Deployed dev keeps workflow bootstrap, cloud facts, and app runtime config separate:
- GitHub Actions reads the sanitized deployment contract, runtime parameter references, image tags, and deploy metadata.
- GitHub Actions sends SSM command payloads that reference parameter paths.
- The runtime host reads
/wavemap/dev/runtime/*from SSM Parameter Store. - The runtime host renders backend, frontend, and Postgres env files locally.
- Frontend
NEXT_PUBLIC_*values are browser build inputs, not runtime SSM parameters.
Pulumi outputs and deployment contracts should expose parameter names and value kinds, not plaintext secret values. SSM
metadata checks should validate names and String / SecureString types without decrypting values.
See Deployed Dev Environment for the environment shape and Runtime Config Readiness for the operator procedure.
Runtime config does not currently have a separate operations page. Keep cross-cutting source-ownership rules here, keep the deployed-dev environment shape in Deployed Dev Environment, and keep repeated live operator steps in Runbooks. Split out a dedicated operations page only when rotation, multi-environment promotion, or inventory lifecycle work grows beyond the runbook.
Secret Handling
Section titled “Secret Handling”- Never commit real secret values.
- Never print secret values in scripts, workflow summaries, logs, fixtures, or docs.
- Treat
NEXT_PUBLIC_*values as browser-visible, even when the backing value is a restricted provider key. - Keep deployed app runtime secrets out of GitHub environment secrets unless there is a documented temporary bridge.
- GitHub Actions must not decrypt or log
SecureStringruntime parameters. - Prefer presence, name, type, and path validation over value validation for secrets.
- Redacted placeholders such as
[required-secret]are acceptable in no-cloud plans and docs.
Verification
Section titled “Verification”Run the narrowest command that proves the changed boundary first, then widen only as needed.
Common deployed-dev checks:
pnpm wavemap -- deploy dev frontend-build-inputspnpm wavemap -- deploy dev runtime-parameterspnpm wavemap -- deploy dev runtime-config planpnpm wavemap -- deploy dev runtime-config populatepnpm wavemap -- deploy dev runtime-config checkpnpm wavemap -- deploy dev runtime-config livepnpm wavemap -- deploy dev runtime-envpnpm wavemap -- deploy dev contractspnpm wavemap -- deploy dev preflightCommon repo checks:
pnpm verify:scriptspnpm verify:github-actionspnpm verify:i18npnpm -C apps/wavemap-front-end lintpnpm -C apps/wavemap-back-end testUse the app or package parser, lint, or test command when the change is local to one consumer. Use
pnpm wavemap -- deploy dev contracts when the value crosses the deployed-dev workflow, build, or runtime boundary. Use
pnpm wavemap -- deploy dev preflight before handing off a deployed-dev contract slice.
Rename Or Remove
Section titled “Rename Or Remove”Treat renames and removals as migrations:
- Remove the old parser entry only after all runtime, render, build, and workflow paths stop supplying it.
- Keep compatibility aliases only when an active deployment or migration needs them.
- Update docs and fixtures in the same slice so no-cloud checks fail on stale names.
- Prefer failing early in preflight over discovering a missing value on the runtime host.
Examples
Section titled “Examples”New frontend browser build value:
- Add or update the frontend client env schema.
- Decide whether it is public or restricted public.
- Add the Docker build arg and deploy build-input resolver coverage.
- Update the workflow environment manifest if it is part of deployed-dev build vocabulary.
- Keep it out of runtime SSM unless the server also consumes a separate non-
NEXT_PUBLIC_*runtime value.
New backend runtime secret:
- Add the backend env schema entry.
- Add a
SecureStringruntime parameter reference under the appropriate group. - Add a redacted placeholder in the runtime config population plan.
- Add it to runtime inventory docs or runbooks when an operator must create or verify it.
- Verify with
runtime-parameters,runtime-config plan,runtime-config check, and thencontracts.
New Pulumi-owned cloud fact:
- Emit it as a non-secret Pulumi output.
- Keep provider-specific details under
provider.awsuntil a provider-neutral consumer exists. - Add it to the no-cloud fixture only if deploy scripts or validators consume it.
- Do not mirror it into GitHub environment variables.