# Pathrule Pattern: Secrets & Environment Management (1.0.0)
# ::pathrule:package:secrets-env-management

### [RULE] Never commit plaintext secrets  (path: /)
<!-- scope: project | priority: high | strict -->

No file containing a live secret may be committed, and `.gitignore` must block every plaintext env file before the first commit.

- Add `.env`, `.env.*`, and `.env.local` to `.gitignore`; track only `.env.example` with placeholder values.
- Commit secrets only when encrypted at rest, for example a `dotenvx`-encrypted `.env` or a `sops`-encrypted file where the decryption key lives outside the repo.
- Run `gitleaks` as a pre-commit hook and in CI so a staged secret is blocked before it reaches the remote.
- If a secret is ever pushed, treat it as compromised: rotate it immediately, then scrub history. Removing the commit is not enough.

---

### [RULE] Keep server secrets out of the client bundle  (path: /src)
<!-- scope: folder | priority: high | advisory -->

Anything bundled for the browser is public, so server secrets must never be referenced from client-reachable modules.

- Read secrets only in server code (route handlers, server actions, API layers, background jobs), never in components that ship to the client.
- Expose values to the client only through an intentional public prefix such as `NEXT_PUBLIC_`, `VITE_`, or `PUBLIC_`, and assume anything prefixed that way is world-readable.
- Validate the full env at startup with a typed schema (for example `zod`) so a missing or misnamed secret fails fast instead of surfacing as a runtime `undefined`.
- Never log a secret value or echo it into an error message, response body, or analytics event.

---

### [MEMORY] Secret storage tiers: local, CI, production  (path: /)

Secrets flow through three tiers, and each has a distinct source of truth so no plaintext credential is shared by hand.

- Local: developers keep an uncommitted `.env.local`, or pull from the team store with a CLI such as `doppler run`, `infisical run`, or `vault`. Share new keys via the store, never over chat.
- CI: the pipeline authenticates with GitHub OIDC to mint a short-lived cloud role instead of holding static keys. Vercel and similar platforms issue OIDC tokens with roughly a 60-minute TTL, so the long-lived key never exists in the environment.
- Production: a managed store (AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager, or the platform env UI) injects values at runtime. Prefer Vault dynamic secrets, which mint per-request credentials with a built-in TTL and auto-revoke, so there is nothing to rotate.

See /.github/workflows for the OIDC pipeline wiring and /src for the runtime read and validation rules.

---

### [MEMORY] Rotation and least-privilege defaults  (path: /)

Every credential is scoped narrowly and has a known expiry, so a leak has a small blast radius and a short window.

- Issue a distinct key per service or consumer; never share one key across apps, which makes revocation surgical instead of a fleet-wide outage.
- Grant least privilege: scope each key to the exact resources and actions it needs, read-only where possible.
- Set a rotation policy. Prefer dynamic or OIDC short-lived credentials so rotation is automatic; for unavoidable static keys, schedule rotation (for example AWS Secrets Manager rotation for RDS) and alert before expiry.
- Keep audit logging on at the store so every access (who, when, what) is traceable, and revoke immediately on offboarding or suspected exposure.

---

### [SKILL] secrets-env-management-review  (path: /)

---
name: secrets-env-management-review
description: Review checklist for any change that touches secrets, env vars, CI credentials, or config. Run before merging to confirm no credential leaks into git, logs, or the client bundle.
---

# Secrets & environment management review

- [ ] No plaintext secret is added to a tracked file; `.env`, `.env.*`, and `.env.local` are in `.gitignore`.
- [ ] Only `.env.example` (placeholder values) or an encrypted env file (`dotenvx`/`sops`, key stored outside the repo) is committed.
- [ ] `gitleaks` runs as a pre-commit hook and in CI, and the diff passes a secret scan.
- [ ] Secrets are read server-side only; nothing sensitive is exposed via a public prefix (`NEXT_PUBLIC_`, `VITE_`, `PUBLIC_`).
- [ ] Env is validated at startup with a typed schema so missing or misnamed vars fail fast.
- [ ] No secret value is logged, returned in a response, or sent to analytics.
- [ ] CI authenticates via OIDC for short-lived cloud roles instead of storing long-lived static keys.
- [ ] Production reads secrets from a managed store with runtime injection, not a baked-in build artifact.
- [ ] Each new credential is least-privilege, distinct per consumer, and has a rotation policy or short TTL.
- [ ] Any previously exposed secret has been rotated, not just deleted from history.
