feat/one-api
needs attentionviewing older commit215cd2d · incrementalpre-PRreviewed 2026-07-27 17:04 UTC3H · 6M · 5L- Purpose
- Ship machine and service API credentials for the Batu public API, establishing the auth foundation required for SOC 2 readiness and external integrations.
- Goal
- Complete one-table API key system (customer bk_ + Batu sk_ credentials), JWT token exchange with ES256, scope enforcement gate, and the first compliance artifact documenting the implemented controls.
- Sub-goals
- SG-1: ApiKey entity — one table, kind discriminator, scrypt hashing
- SG-2: Token exchange — POST /v1/auth/token, ES256 JWT, timing equalization
- SG-3: Service key variant — platform-scoped, no org, same table
- SG-4: Meta gate — one enforcement point for credential class + scope on every route
- SG-5: Compliance narrative — first SOC 2 / ISO 27001 artifact
- What
- This commit adds docs/security/access-control-narrative.md (294 lines) — the first compliance document for the branch. Prior commits implemented the full API key + service key stack.
- Why
- SOC 2 CC6 and ISO 27001 A.5/A.8 require documented access control controls. The narrative captures the as-implemented state including known gaps (§9 L1-L7), establishing an auditable baseline.
- Areas
- domains/core/src/api-key/+727−33apps/platform/src/api/+383−28packages/api/src/+407−37docs/security/+294−0.claude/rules/+81−6packages/database/+53−5.github/workflows/+30−2
- Blast
- ~35 files across 7 areas, +1975/-111 lines (excluding the 13k-line Drizzle snapshot)
Findings · 14
correctness3
Display prefix described as 8 chars; stored prefix is 11 (bk_+8)
docs/security/access-control-narrative.md
§4.2 'Non-disclosure in logs' says 'non-secret 8-character display prefix are bound as database parameters.' PREFIX_DISPLAY_LENGTH=11 in api-key.lib.ts — prefix is `bk_` (3) + 8 random chars = 11 total.
CHECK constraint description captures only half the invariant
docs/security/access-control-narrative.md
§3 writes kind='service' ⇒ org_id IS NULL. Actual constraint is biconditional; omits that non-service keys MUST have an org.
scrypt params cited as explicit config; they are Node.js defaults
docs/security/access-control-narrative.md
security3
§4.3 JWKS claim misrepresents the verification trust path
docs/security/access-control-narrative.md
The JWKS endpoint exists for external consumers. Internal verification (verifyBatuJwt) reads BATU_JWT_PUBLIC_KEY_PEM from an env var. Rotation boundary is a redeploy, not a JWKS TTL.
§3 'by construction' framing not scoped to public surface
docs/security/access-control-narrative.md
Combined rotation + revocation exposure window (25h) not stated
docs/security/access-control-narrative.md
conventions1
§6 event-type list uses leading-dot shorthand
docs/security/access-control-narrative.md
`.rotated`, `.revoked`, `.deleted` look like sub-paths; should be full standalone identifiers.
tests1
§5.3 & §8 overstate IDOR test: not in CI, probe is one-directional
docs/security/access-control-narrative.md
Test requires RUN_INTEGRATION=true + DB env; no CI workflow sets this. Also probes only from org-A, not symmetrically from each org.
improvement6
Stale argon2id comments in schema contradict the doc's scrypt claim
docs/security/access-control-narrative.md
packages/database/src/schema/api-keys.ts lines 9 and 94 say 'argon2id hash' — the implementation and this doc correctly say scrypt. Must be fixed in same PR.
§6 Request-stage RLS gate doesn't apply to machine credentials
docs/security/access-control-narrative.md
Machine credentials use service-role DB (no RLS). Exclusion from key-creation is application-layer authz, not RLS.
§8 'Authentication outcomes' evidence claim underspecified
docs/security/access-control-narrative.md
Failed-auth paths return silent 401 with no visible structured log entry in the handler code. Auditor will request log schema.
L2/L3 retirement has no owner, date, or tracking reference
docs/security/access-control-narrative.md
§2 system boundary omits EventBridge/SQS outbox delivery path
docs/security/access-control-narrative.md
§3 automated test claim lacks file reference
docs/security/access-control-narrative.md
History · 47 commits
- 82bb5b9blockedincremental5H · 5M · 4L2026-08-12 01:48
- 90aa3d5needs attentionincremental1H · 5M · 3L2026-08-11 19:37
- 29d19a0needs attentionincremental1H · 5M · 9L2026-08-11 17:41
- 9bd8a0cneeds attentionfull0H · 5M · 9L2026-08-11 02:14
- 62ec3f7needs attentionincremental2H · 5M · 6L2026-08-10 22:51
- f93bca9needs attentionincremental2H · 5M · 8L2026-08-10 17:51
- 052db6fneeds attentionincremental1H · 3M · 4L2026-08-09 21:13
- 45699caneeds attentionincremental0H · 7M · 11L2026-08-09 17:44
- b843d8aneeds attentionincremental1H · 7M · 9L2026-08-09 04:05
- e1757b8needs attentionincremental0H · 3M · 6L2026-08-05 02:11
- 7a762faneeds attentionincremental2H · 5M · 5L2026-08-05 01:25
- 3300a60needs attentionincremental2H · 4M · 7L2026-08-04 19:06
- 0c8a7f5needs attentionincremental0H · 4M · 9L2026-08-04 18:15
- 345f42eneeds attentionincremental2H · 6M · 9L2026-08-04 17:28
- 8338a9aneeds attentionincremental5H · 14M · 14L2026-08-04 00:33
- 41be4c3needs attentionincremental0H · 5M · 7L2026-08-03 23:49
- 5ed593dneeds attentionincremental1H · 6M · 6L2026-08-03 21:32
- b333e25needs attentionincremental4H · 9M · 8L2026-08-03 21:00
- 5642cccneeds attentionincremental2H · 3M · 2L2026-08-03 20:17
- 73b0b39needs attentionincremental3H · 10M · 13L2026-07-31 18:29
- b19852eneeds attentionincremental0H · 1M · 5L2026-07-29 05:04
- 3845205needs attentionincremental3H · 6M · 4L2026-07-29 04:47
- eb8eb50needs attentionincremental0H · 1M · 2L2026-07-29 03:03
- f4720a3needs attentionincremental6H · 8M · 7L2026-07-29 02:54
- f8d341ablockedincremental2H · 2M · 5L2026-07-29 00:00
- a7f1a64needs attentionincremental2H · 8M · 8L2026-07-28 18:41
- 738b60bblockedincremental3H · 6M · 5L2026-07-28 00:46
- 2c248b6needs attentionincremental8H · 12M · 8L2026-07-27 23:23
- 1346cc0needs attentionincremental2H · 8M · 6L2026-07-27 20:15
- 0716018needs attentionincremental2H · 11M · 12L2026-07-27 19:22
- 215cd2dneeds attentionincremental3H · 6M · 5L2026-07-27 17:04current
- ec46958needs attentionincremental0H · 3M · 5L2026-07-27 16:51
- de7b337blockedincremental4H · 9M · 14L2026-07-27 06:36
- b1bb9c0needs attentionincremental1H · 2M · 4L2026-07-27 05:09
- 4701d11needs attentionincremental0H · 4M · 3L2026-07-27 04:44
- e1626c4needs attentionincremental3H · 9M · 10L2026-07-27 03:21
- 195f198needs attentionincremental3H · 3M · 3L2026-07-25 01:22
- 42c7358safeincremental0H · 0M · 0L2026-07-22 20:46
- 85b9018needs attentionincremental0H · 1M · 6L2026-07-21 23:51
- a7b2a9aneeds attentionincremental0H · 9M · 12L2026-07-21 18:49
- c2ee0daneeds attentionincremental4H · 7M · 7L2026-07-21 02:17
- e8ffa5eneeds attentionincremental4H · 7M · 5L2026-07-21 01:33
- a2d2a54needs attentionincremental2H · 7M · 3L2026-07-21 00:51
- 576fbd6needs attentionfull1H · 6M · 7L2026-07-21 00:35
- d3465e8needs attentionincremental1H · 7M · 10L2026-07-21 00:23
- dc794a7needs attentionincremental0H · 5M · 5L2026-07-20 23:46
- 9082773needs attentionfull1H · 3M · 3L2026-07-20 23:13