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:
@@ -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
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user