chore(framework): canonize Vault-as-SSOT + ESO-default secrets policy #519

Merged
jason.woltje merged 3 commits from chore/canonize-vault-secrets-policy into main 2026-06-11 19:07:01 +00:00
Owner

Summary

This PR encodes the Vault-as-source-of-truth + ESO-default secrets policy as binding framework rules, effective for all future agent work across all Mosaic projects.

Operator decision: Jason approved this wording via Discord on 2026-05-22.

Files updated

File Duplicate path Change
guides/VAULT-SECRETS.md packages/mosaic/framework/guides/VAULT-SECRETS.md Expanded with 4 new sections (decision matrix, ESO bridge example, Direct-Vault opt-in, forbidden patterns)
guides/BOOTSTRAP.md packages/mosaic/framework/guides/BOOTSTRAP.md Added "Secrets Bootstrap" required subsection with checklist
packages/mosaic/framework/defaults/STANDARDS.md (single copy in repo) Added ### Secrets handling (HARD RULE) under Non-Negotiables

Duplicate-path sync note

The framework files exist at two paths in this repo and must stay in sync:

  • guides/ <-> packages/mosaic/framework/guides/
  • packages/mosaic/framework/defaults/STANDARDS.md is the single canonical copy (no root-level defaults/ dir exists in this repo)

All pairs are md5-equal after this commit. Future maintainers: always edit both paths when modifying these files.

Policy summary (verbatim from STANDARDS.md)

  • Vault is the canonical source-of-truth for every secret in every environment. No exceptions.
  • For k8s workloads: External Secrets Operator -> k8s Secret -> env var is the default read path. No Vault client in app code.
  • Direct-Vault is opt-in only, justified per-app by a documented dynamic-secrets requirement.
  • ${VAR:-default} fallback syntax is forbidden for required values in deploy configs. Use ${VAR:?VAR is required}.
  • .env files in production deployment paths are forbidden.
  • App startup must validate required secrets via schema (zod/pydantic/equivalent) and exit non-zero on missing values.
  1. CI lint implementation: Add lint rules to the CI pipeline (.woodpecker/) that catch the forbidden patterns listed in VAULT-SECRETS.md - Forbidden Patterns -- specifically: untagged ${VAR:-default} in deploy configs, vault kv calls in app source, hardcoded credential patterns, and .env files in production paths. Initially in warning mode, then error mode per Jason's staged-rollout plan.
  2. Staged rollout: Warning mode first (log violations, do not fail build) -> Error mode after teams have had time to remediate existing violations.
  3. Existing project audit: Run the forbidden-patterns check against all current repos and open remediation issues for violations found.

Review requirement

DO NOT MERGE without operator approval. This policy binds every future agent session and every Mosaic project. Jason should review the verbatim wording before this lands on main.

## Summary This PR encodes the Vault-as-source-of-truth + ESO-default secrets policy as binding framework rules, effective for all future agent work across all Mosaic projects. **Operator decision:** Jason approved this wording via Discord on 2026-05-22. ## Files updated | File | Duplicate path | Change | |---|---|---| | `guides/VAULT-SECRETS.md` | `packages/mosaic/framework/guides/VAULT-SECRETS.md` | Expanded with 4 new sections (decision matrix, ESO bridge example, Direct-Vault opt-in, forbidden patterns) | | `guides/BOOTSTRAP.md` | `packages/mosaic/framework/guides/BOOTSTRAP.md` | Added "Secrets Bootstrap" required subsection with checklist | | `packages/mosaic/framework/defaults/STANDARDS.md` | _(single copy in repo)_ | Added `### Secrets handling (HARD RULE)` under Non-Negotiables | ## Duplicate-path sync note The framework files exist at two paths in this repo and must stay in sync: - `guides/` <-> `packages/mosaic/framework/guides/` - `packages/mosaic/framework/defaults/STANDARDS.md` is the single canonical copy (no root-level `defaults/` dir exists in this repo) All pairs are md5-equal after this commit. Future maintainers: always edit both paths when modifying these files. ## Policy summary (verbatim from STANDARDS.md) - Vault is the canonical source-of-truth for every secret in every environment. No exceptions. - For k8s workloads: External Secrets Operator -> k8s Secret -> env var is the default read path. No Vault client in app code. - Direct-Vault is opt-in only, justified per-app by a documented dynamic-secrets requirement. - `${VAR:-default}` fallback syntax is forbidden for required values in deploy configs. Use `${VAR:?VAR is required}`. - `.env` files in production deployment paths are forbidden. - App startup must validate required secrets via schema (zod/pydantic/equivalent) and exit non-zero on missing values. ## Recommended follow-up (subsequent PRs) 1. **CI lint implementation:** Add lint rules to the CI pipeline (`.woodpecker/`) that catch the forbidden patterns listed in `VAULT-SECRETS.md - Forbidden Patterns` -- specifically: untagged `${VAR:-default}` in deploy configs, `vault kv` calls in app source, hardcoded credential patterns, and `.env` files in production paths. Initially in warning mode, then error mode per Jason's staged-rollout plan. 2. **Staged rollout:** Warning mode first (log violations, do not fail build) -> Error mode after teams have had time to remediate existing violations. 3. **Existing project audit:** Run the forbidden-patterns check against all current repos and open remediation issues for violations found. ## Review requirement **DO NOT MERGE without operator approval.** This policy binds every future agent session and every Mosaic project. Jason should review the verbatim wording before this lands on main.
jason.woltje force-pushed chore/canonize-vault-secrets-policy from e88a89f34d to f6b901dbca 2026-06-11 18:21:12 +00:00 Compare
jason.woltje merged commit b79e9f32c6 into main 2026-06-11 19:07:01 +00:00
jason.woltje deleted branch chore/canonize-vault-secrets-policy 2026-06-11 19:07:02 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#519