Part of #525. Make the BYOK AI review (shipped in #652) actually usable end-to-end by maintainers — backend.
Context (how it works today)
- Free default → Cloudflare Workers AI (
env.AI). BYOK advisory write-up → a direct Worker→provider call (api.anthropic.com / api.openai.com) with the maintainer's key; the consensus blocker always stays on free Workers AI.
- Keys are stored AES-256-GCM-encrypted in our D1
repository_ai_keys (never in the repo — a GitHub App can't read repo Actions secrets). Set today only via the internal-token route POST /v1/internal/repos/:owner/:repo/ai-key, so there is no self-serve path for maintainers.
.gittensory.yml gate.aiReview supports only mode + byok.
Scope (backend)
Invariants
Key encrypted at rest, never returned/logged/surfaced; consensus blocking remains Workers-AI-only + confirmed-contributor-gated; all public AI output through sanitizePublicComment.
Part of #525. Make the BYOK AI review (shipped in #652) actually usable end-to-end by maintainers — backend.
Context (how it works today)
env.AI). BYOK advisory write-up → a direct Worker→provider call (api.anthropic.com/api.openai.com) with the maintainer's key; the consensus blocker always stays on free Workers AI.repository_ai_keys(never in the repo — a GitHub App can't read repo Actions secrets). Set today only via the internal-token routePOST /v1/internal/repos/:owner/:repo/ai-key, so there is no self-serve path for maintainers..gittensory.yml gate.aiReviewsupports onlymode+byok.Scope (backend)
.gittensory.yml gate.aiReviewacceptsprovider(anthropic|openai) +model(string), config-as-code; key stays out of the yml. Thread throughRepositorySettings(aiReviewProvider/aiReviewModel) + DB migration + zod +resolveEffectiveSettings.provideracts as a consistency guard (mismatch → skip BYOK, fall back to Workers AI); ymlmodeloverrides the stored/default model.POST/GET/DELETE /v1/repos/:owner/:repo/ai-key, gated to repo owners/admins/maintainers (collaborator-permission or installation-owner check). GET returns only{configured, provider, last4, model}.Invariants
Key encrypted at rest, never returned/logged/surfaced; consensus blocking remains Workers-AI-only + confirmed-contributor-gated; all public AI output through
sanitizePublicComment.