rotate: Vercel token + SendGrid API-key drivers (create→verify→revoke)
Two more provider-API rotation drivers for the vibe-coder credential surface, both following the create-new → verify → revoke-old pattern with the self-contained blob form <provider>://<host>/?id=&secret=. - vercel: POST /v3/user/tokens mints a new bearer; Verify lists tokens and asserts the new id is present; RevokeOld DELETEs the old token by id. - sendgrid: clones the old key's scopes (GET /v3/api_keys/<id>) onto the new key so rotation is a faithful replacement, not a privilege downgrade; Verify is a GET /v3/scopes auth proof; RevokeOld DELETEs the old key by id. Both ship Bearer-enforcing httptest emulators that prove a real cutover (old credential dead, new alive after RevokeOld) plus a leak check. Recorded as MOCK-ONLY in proofs.go + docs/ROTATION-PROOFS.md (no self-host). go build/vet clean; 77 rotate tests pass, -race clean. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+14
-5
@@ -69,6 +69,8 @@ stops a mock-only driver from ever being mistaken for a live one.
|
||||
| `twilio` | `httptest` emulator (Basic-auth Keys resource) | no self-host |
|
||||
| `flyio` | `httptest` GraphQL emulator | no self-host |
|
||||
| `resend` | `httptest` emulator (Bearer `/api-keys` resource) | no self-host |
|
||||
| `vercel` | `httptest` emulator (Bearer `/v3/user/tokens` resource) | no self-host |
|
||||
| `sendgrid` | `httptest` emulator (Bearer `/v3/api_keys` resource, scope clone + `/v3/scopes` auth proof) | no self-host |
|
||||
|
||||
## What the MOCK-ONLY emulators actually prove
|
||||
|
||||
@@ -83,11 +85,18 @@ 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 / resend** — 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. (Resend additionally proves `Verify(new)` by listing keys with the
|
||||
new Bearer token and asserting the new id is present — auth success *and* the key exists.)
|
||||
- **npm / twilio / resend / vercel** — each emulator enforces credential validity (a
|
||||
token/key authenticates only while it exists) and the test asserts the old credential is
|
||||
dead after `RevokeOld` while the new one still authenticates — proving the
|
||||
create→verify→revoke cutover really happened. (Resend and Vercel additionally prove
|
||||
`Verify(new)` by listing keys/tokens with the new Bearer token and asserting the new id
|
||||
is present — auth success *and* the credential exists.)
|
||||
- **sendgrid** — the emulator enforces Bearer validity *and* records each key's scopes; the
|
||||
driver clones the old key's scopes onto the new one (`GET /v3/api_keys/<id>` → reuse on
|
||||
`POST /v3/api_keys`) so rotation is a faithful replacement, not a privilege downgrade. The
|
||||
test asserts the minted key carries the seeded scopes, that `Verify(new)` (a `GET /v3/scopes`
|
||||
auth proof) succeeds, and that the old key stops authenticating after `RevokeOld` while the
|
||||
new key still does — old key dead, new one alive with the same scopes.
|
||||
- **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
|
||||
|
||||
Reference in New Issue
Block a user