Repository navigation
feat(admin): internal bot users with short-lived token minting - #8088
Conversation
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryThe incremental change updates the setup-smoke assertion to the current Files Reviewed (1 file changed since prior review; 15 unchanged PR files carried forward)
Previous Review Summaries (3 snapshots, latest commit 72ea686)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit 72ea686)Status: No Issues Found | Recommendation: Merge Executive SummaryThe incremental change fixes the last finding: every refusal fixture now carries a valid pepper and asserts the specific refusal message, so each case fails only on the condition it names. No new issues in the changed test. Overview
Files Reviewed (1 file changed since prior review)
The other 14 PR files are unchanged since commit Previous review (commit 8107a94)Status: 1 Issue Found | Recommendation: Address before merge Executive SummaryThe previous findings are fixed at HEAD; one remaining test-quality gap leaves the new blocked-bot rejection assertions unable to fail for the condition they target. Overview
Issue Details (click to expand)SUGGESTION
Files Reviewed (7 files)
Fix these issues in Kilo Cloud Previous review (commit 2e6628e)Status: 7 Issues Found | Recommendation: Address before merge Executive SummaryThe token mint's auth, eligibility, and JWT claims are sound, but a non-UUID Overview
Issue Details (click to expand)WARNING
SUGGESTION
Files Reviewed (16 files)
Reviewed by deepseek-v4.1-flash-1017 · Input: 38.7K · Output: 4.2K · Cached: 289.9K Review guidance: REVIEW.md from base branch |
Summary
Internal workloads such as the bouncer watch and the auto-routing benchmark currently call the gateway with tokens for a personal user. They then share that user's per-user gateway rate limit with everything else the user does. This PR lets each workload run as its own dedicated internal bot user, which gets its own limit.
/admin/internal-bot-users(Users section of the admin sidebar). It listsbot-internal-*users with their org and role. A form creates a user from a slug, a display name and an organization id.ensureInternalBotUserinapps/web/src/lib/bot-users/bot-user-service.ts. The per-org product bots and internal bots now share oneinsertBotUserinsert:is_bot, a randomapi_token_pepper, theproviderHashsafety identifiers, abot_stripe_*customer id, and auto top-up off. The id isbot-internal-<slug>(slug^[a-z0-9][a-z0-9-]{0,40}$) and the email is<slug>-internal-bot@kilocode.internal. The user is added to the org asmember. Running it again reuses the existing user and membership and never duplicates them. An existing non-bot row with the same id is refused.POST /api/internal/bot-tokenmints a one-hour token for an internal bot.Authorization: Bearer <BOT_TOKEN_MINT_SECRET>, compared withtimingSafeEqual. If the secret is unset or empty, the endpoint returns 401.{ userId, organizationId }. Both fields are required.bot-internal-prefix are eligible. They must also haveis_bot, no block, a non-empty pepper, and an owner or member role in the org. This keeps humans and the per-org product bots (bot-code-review-*, ...) out.kilo-apiandkilo-gatewayaudiences,tokenPurpose: 'delegated-workload', and{ tokenSource: 'internal-bot', organizationId, organizationRole }. The legacy branch is used while the family flag is off.BOT_TOKEN_MINT_SECRETis declared inconfig.servernext toMCP_CATALOG_TOKEN_SECRET, the other single-purpose mint secret. It is documented inENVIRONMENT.mdand.env.local.example, anddocs/token-issuance-policy.mdgets a row for the new issuer.Flag key
The modern token shape is gated by a new resource-token family,
internal-bot, which maps toINTERNAL_BOT_RESOURCE_TOKENS_ENABLED. The repo already gives each producer family its own default-off flag behindSHARED_RESOURCE_TOKENS_ENABLED(cloud-agent-next,chat,benchmark, ...), so this follows that pattern. Reusingbenchmarkwould couple unrelated workloads, such as the bouncer watch, to the benchmark's rollout. While the flag is off, the endpoint issues the legacy shape, and the eligibility rules apply in both modes. Set the flag in production to issue the modern shape.There is no generic admin audit-log table, only
kiloclaw_admin_audit_logsfor KiloClaw. Everyadmin.*tRPC call already emits anadmin_accessevent throughadminProcedure, so this PR adds no separate audit write.Verification
apps/webJest:src/app/api/internal/bot-token/route.test.ts(mocked DB, matching the existing internal-mint tests) andsrc/lib/bot-users/bot-user-service.test.ts(real Postgres) pass.is_bot=false;blocked_atorblocked_reasonset; a null or blank pepper; a missing membership; abilling_managerrole. The rejection cases run in both token modes.packages/web-sharedconfig.server.resource-tokens.test.tspasses with the new family.apps/webtypecheck, oxlint and oxfmt are clean.Deploy notes
Nothing calls the endpoint until
BOT_TOKEN_MINT_SECRETis set in the web environment. Before any workload switches to it, create the bot users (for examplebot-internal-bouncer-watchandbot-internal-benchmark) from the new admin page.Also in this PR
apps/web/tests/setup-smoke/profile.spec.tswaits for the profile card's current title, "Platform routing mode". An earlier change onmainrenamed the card, so the setup smoke fails onmaintoo.