rotate: 6 service-API drivers (mongo, npm, gcp, twilio, flyio, k8s)

Each driver is real-service code only (no test awareness; tests inject just an
HTTPClient/Bin), following the established patterns:

- mongo: in-place changeUserPassword over the old connection; no secret on argv
  (host/db on the URI, both passwords on stdin, output scrubbed).
- npm:   create token -> /-/whoami -> delete-by-key; blob records the key.
- gcp:   service-account KEY rotation; mints an RS256 JWT signed with the SA's
  own private key (crypto/rsa, stdlib) to self-auth the IAM create/verify/delete.
- twilio: API Key create -> get -> delete, Basic auth (KeySid/secret).
- flyio: GraphQL — a managing token mints/deletes the rotated deploy token.
- k8s:   create a service-account-token Secret, await the populated token,
  verify against the SA, delete the old Secret (invalidates the old token).

All 6 register their honest proof level (MOCK-ONLY) in proofs.go +
ROTATION-PROOFS.md; mongo/npm/k8s are LIVE-VM candidates pending real-target VM
POCs. Emulators enforce credential validity (gcp verifies the JWT signature),
tests assert Verify(old) fails after revoke + a secret-leak canary.

Full suite: 103 green, -race clean on rotate/sink/vault.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
leetcrypt
2026-06-18 15:57:59 -07:00
parent b415c43bff
commit 35f19c007a
15 changed files with 2776 additions and 2 deletions
+35
View File
@@ -264,6 +264,41 @@ service + re-run — zero driver code changes (the drivers contain no test aware
Full suite after the batch: **82 green**, `-race` clean on rotate/sink/vault.
## Service-API batch 2 — 6 drivers (mongo, npm, gcp, twilio, flyio, k8s), 2026-06-18
Six more rotation drivers, each **real-service code only** (no test awareness; tests inject
just an `HTTPClient`/`Bin`), validated against protocol-enforcing emulators:
- **mongo** (in-place DB) — `changeUserPassword` over the OLD authenticated connection is
itself the cutover; `RevokeOld` is a no-op. NO secret on argv: the URI handed to `mongosh`
carries host/db only, both passwords go in on stdin, captured output is scrubbed. Fake
`mongosh` stub authenticates against a state-file password → proves old password dies.
- **npm** (provider-API create→verify→revoke) — `POST /-/npm/v1/tokens` (Bearer old) →
`/-/whoami` (Bearer new) → `DELETE …/tokens/token/<key>`. Blob records the token `key=`
for deletion; degrades to guided when absent.
- **gcp** (provider-API, service-account KEY) — mints an **RS256 JWT signed with the SA's own
private key** (`crypto/rsa`, stdlib, no new dep), exchanges it for an access token, then
`CreateServiceAccountKey` → GET serviceAccount (verify) → `DeleteServiceAccountKey`. The
emulator **verifies the JWT signature** against the key's public key, so the test proves
genuine signing, not a stub. SA JSON round-trips base64-wrapped in the one-line blob.
- **twilio** (provider-API) — `POST …/Keys.json` (Basic old) → GET key (Basic new) →
`DELETE …/Keys/<sid>.json`. Basic-auth username=KeySid, password=secret.
- **flyio** (provider-API, GraphQL) — a **managing token** mints/deletes the **deploy token**
(the rotated value) via `createLimitedAccessToken` / `deleteLimitedAccessToken`; verify
runs the app query as the new deploy token. Same "auth rotates a value" shape as ghactions.
- **k8s** (provider-API) — creates a new `kubernetes.io/service-account-token` Secret, waits
for the controller to populate `.data.token`, GETs the SA to verify, then DELETEs the old
Secret (which invalidates the old token).
**All 6 are MOCK-ONLY** — honestly, because they were proven only against emulators. mongo,
npm and k8s are LIVE-VM *candidates* (real MongoDB / a throwaway npm registry / a k3s cluster
would promote them with zero driver-code change), but per the standing rule a driver is only
LIVE-VM after the *real target* validates the cutover, so they stay MOCK-ONLY until those VM
POCs run. Each emulator enforces credential validity and the tests assert `Verify(old)` fails
after revoke, plus a leak canary (no token/secret/`PRIVATE KEY` in Identity/Source/Location).
Full suite after batch 2: **103 green**, `-race` clean on rotate/sink/vault.
## Summary
- Harness result: **31/31 PASS**, including the global secret-leak canary (no CANARY
+23 -2
View File
@@ -53,6 +53,12 @@ stops a mock-only driver from ever being mistaken for a live one.
| `cloudflare` | `httptest` emulator | no self-host |
| `ghactions` | `httptest` emulator (holds the libsodium box keypair, decrypts the sealed PUT) | no self-host |
| `gitlab` | `httptest` emulator | GitLab CE too heavy for the VM |
| `mongo` | fake-`mongosh` shell stub (auths against a state file) | real-MongoDB VM POC not yet run |
| `npm` | `httptest` registry emulator | real registry never hit |
| `gcp` | `httptest` IAM emulator (verifies the driver's RS256 JWT against the key's public key) | no self-host |
| `twilio` | `httptest` emulator (Basic-auth Keys resource) | no self-host |
| `flyio` | `httptest` GraphQL emulator | no self-host |
| `k8s` | `httptest` apiserver emulator (token-Secret create/delete) | real k3s POC not yet run |
## What the MOCK-ONLY emulators actually prove
@@ -67,7 +73,22 @@ protocol so the test exercises the driver's true cutover logic:
on `PUT` **decrypts the sealed value** and stores the plaintext; the test asserts the
decrypted value equals the new value the driver put in the rebuilt blob — proving the
sealed-box encryption is correct, not simulated.
- **npm / twilio / k8s** — each emulator enforces credential validity (a token/key
authenticates only while it exists) and the test asserts `Verify(old)` fails after
`RevokeOld` — proving the create→verify→revoke cutover really happened, old credential
dead, new one alive.
- **gcp** — the emulator **verifies the RS256 JWT signature** the driver mints against the
public key recorded for the key's `kid`; it only issues an access token for a JWT that
actually verifies, and `DELETE` removes the key — so the test proves real service-account
self-auth (genuine `crypto/rsa` signing) *and* the cutover (revoked key can no longer mint
a token).
- **flyio** — a managing token mints/deletes the deploy token over GraphQL; the deploy token
authenticates the app query only while it exists, so the test proves the managing-token →
deploy-token rotation and that the revoked deploy token stops working.
- **mongo** — the fake `mongosh` authenticates `db.auth` against a password held in a state
file and only `changeUserPassword` updates it; the test proves the in-place cutover (old
password rejected after rotation). No password ever reaches `mongosh`'s argv.
Promoting any of these to LIVE-VM only requires standing up the real service (a self-hosted
GitLab CE / a real Cloudflare token / a throwaway GitHub repo) and re-running the same
driver against it — no driver code changes.
GitLab CE / a real Cloudflare token / a throwaway GitHub repo / a real MongoDB / a real npm
registry / a k3s cluster) and re-running the same driver against it — no driver code changes.