Skip to content

v0.16.0 — Sandbox access: API keys + quotas (G19d)

Choose a tag to compare

@omercelikdev omercelikdev released this 27 Jul 21:16

Sandbox access (G19d, ADR 0011)

The fourth vertical of the integration sandbox: hand out per-consumer API keys so external teams can hit a tenant's mock surface without knowing anything about hosts or headers.

API keys — --sandbox-auth

  • POST /__admin/apikeys issues an mfk_… token (256-bit CSPRNG) shown exactly once — afterwards only a 12-character display prefix is stored and listed. At rest: salted SHA-256, verified in constant time.
  • A key presented as X-Api-Key: mfk_… or Authorization: Bearer mfk_… selects the key's tenant ahead of the host/header chain. No credentials → everything resolves exactly as before; an invalid or revoked key is an honest 401, never a silent fall-through to another tenant.
  • A sandbox key is not admin authentication — /__admin/* refuses it on both carriers.
  • Keys survive restarts on every persistence backend (file root-dir, LiteDB, Postgres, Redis).

Quotas

  • Optional quotaPerHour per key: fixed hourly window, exact under parallel load — N requests across the budget never admit more than the budget.
  • Counted responses carry X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-Reset; past the budget the caller gets a realistic 429 with Retry-After. usedThisHour is visible in the key listing.

Validation

No oracle exists for sandbox keys, so per the established precedent: 10 unit tests (constant-time verification, pinned hash format, exact window boundaries on a test clock, 8×50 parallel admits exactly 100 of a 100 budget, persistence round-trips) + 5 wire self-tests against a restarted real host (tenant isolation with two keys, admin refusal, an exact parallel 429 boundary, restart survival). Stryker on the new pure logic: 28/29 killed, the lone survivor analyzed as an equivalent mutant in docs/parity/g19-sandbox.md.

Docs: CLI flags · Admin API

Full change: #213

🤖 Generated with Claude Code