# Secret Management Runbook

**Status:** Stub — populate as part of Phase 1.F.12
**Owner:** Platform team
**Source pattern:** [`learning_ai_notes/docs/runbooks/SECRET_MANAGEMENT.md`](../../../../../learning_ai_notes/docs/runbooks/SECRET_MANAGEMENT.md) (commit `bcad7d3`)

---

## Purpose

This runbook documents how secrets flow from **Azure KeyVault → env → process** for
tracker-web (Next.js client/server) and the platform-service backend it proxies, and
how to rotate them safely.

---

## Secret Inventory

| Secret                              | Used by                                   | Storage                                 | Rotation cadence                                     |
| ----------------------------------- | ----------------------------------------- | --------------------------------------- | ---------------------------------------------------- |
| `JWT_SECRET`                        | platform-service + tracker-web API routes | KeyVault `bytelyst-jwt-secret`          | Quarterly                                            |
| `TRACKER_MEK_ID_<PRODUCTID>`        | tracker-service field encryption          | KeyVault per-product MEK keys           | Quarterly (see [MEK_ROTATION.md](./MEK_ROTATION.md)) |
| `POSTHOG_KEY`                       | tracker-web client-side telemetry         | KeyVault `tracker-posthog-key`          | On compromise only                                   |
| `COSMOS_CONNECTION_STRING`          | platform-service Cosmos client            | KeyVault `bytelyst-cosmos-conn`         | On compromise only                                   |
| `VALKEY_PASSWORD`                   | platform-service session/cache            | KeyVault `bytelyst-valkey-password`     | Quarterly                                            |
| `TURNSTILE_SECRET` (Phase 1.4)      | tracker-web public submission CAPTCHA     | KeyVault `tracker-turnstile-secret`     | On compromise only                                   |
| `GITHUB_WEBHOOK_SECRET` (Phase 3.3) | tracker-service inbound webhook HMAC      | KeyVault `tracker-gh-webhook-secret`    | On compromise only                                   |
| `GITEA_WEBHOOK_SECRET` (Phase 3.3)  | tracker-service inbound webhook HMAC      | KeyVault `tracker-gitea-webhook-secret` | On compromise only                                   |
| Agent API keys (Phase 3.1)          | end-user-managed; stored hashed in Cosmos | Cosmos `apikeys` collection             | User-managed                                         |

---

## Resolution Path

```
KeyVault  →  Docker build args (NEXT_PUBLIC_*)  →  baked into next-build
         ╲
          →  docker-compose env_file       →  process.env at runtime
              ↘
               systemd EnvironmentFile      →  process.env at runtime
```

- **Build-time secrets** (`NEXT_PUBLIC_*`) are baked into the Next.js standalone build via
  Dockerfile `ARG` + `ENV` (Phase 1.C.3 / 1.2). Once baked they are visible in client JS;
  only put truly public-safe values here.
- **Runtime secrets** flow via docker-compose `env_file` or systemd `EnvironmentFile` so
  they are not visible in client bundles.
- **No secret ever** appears in `git`, `.env.example`, log lines, or container `inspect`
  output.

---

## Rotation Procedure

> **TODO** — adapt full procedure from `learning_ai_notes/docs/runbooks/SECRET_MANAGEMENT.md`
> once tracker-service ships secret-aware deployment in Phase 1.F.

1. **Create new secret version in KeyVault**
2. **Update env source** (docker-compose `.env`, systemd unit, or CI/CD secret store)
3. **Rolling restart** affected services
4. **Verify** — `pnpm run smoke:local` passes against rotated stack
5. **Revoke previous secret version** in KeyVault after 24 h soak

---

## On Suspected Compromise

1. **Immediately revoke** the suspected secret in KeyVault
2. **Rotate** all dependent secrets in the same blast radius
3. **Force-revoke** all JWT tokens (bump `JWT_SECRET` → all sessions invalidated)
4. **Audit** access logs since suspected compromise window
5. **File a tracker bug** type `chore`, label `security`, priority `critical`

---

## PII Scrubbing Rule

Per Phase 1.F.10: emails, names, and any field marked `pii: true` in the schema must NEVER
appear as plaintext in:

- Log lines (use `@bytelyst/logger` redaction map)
- Telemetry events sent to PostHog
- Error messages bubbled to clients
- Webhook delivery logs (Phase 3.4 / 3.5)

---

_See [`MEK_ROTATION.md`](./MEK_ROTATION.md) for field-level encryption key rotation specifically._
