Uh oh!
There was an error while loading. Please reload this page.
feat(webapp): add multiple environment API key management - #4390
feat(webapp): add multiple environment API key management#4390carderne wants to merge 13 commits into
Conversation
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📜 Recent review details⏰ Context from checks skipped due to timeout. (20)
WalkthroughThis PR adds feature-flagged environment API key creation and revocation with RBAC-based presets, task scoping, expiration validation, persistence, telemetry, and audit crumbs. It updates API key listing and management UI with organization scoping, revoked-key filtering, status metadata, and creation or revocation dialogs. It adds public-token minting with scope and expiration validation and JWT signing. Authentication services now accept injectable dependencies. Tests and change notes cover the changes. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🦋 Changeset detectedLatest commit: 3952cbe The changes in this PR will be included in the next version bump. This PR includes changesets to release 27 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
6aba247 to
2579113Compare@trigger.dev/buildtrigger.dev@trigger.dev/core@trigger.dev/python@trigger.dev/react-hooks@trigger.dev/redis-worker@trigger.dev/rsc@trigger.dev/schema-to-json@trigger.dev/sdkcommit: |
2579113 to
dbca394Compared60d5a5 to
ba81e5eCompare
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
ca744a5 to
5f47b92Compare
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
A number passed to `expirationTime` is a Unix timestamp in seconds, not milliseconds as the JSDoc claimed. Following the old docs produced a token that effectively never expired. Also fail loudly when an additional API key reaches a local self-signing fallback. Those keys are not the environment's JWT signing material, so the token would never verify. Every endpoint that returns a public access token sets `x-trigger-jwt`, so this is unreachable today.
The API key policy methods are optional on the plugin-facing controller contract, so `Pick` over it yields optional members that these call sites would have to guard. Both already receive the LazyController singleton, which has substituted its fail-closed defaults, so point them at HostRbacController and keep the call sites guard-free.
Require both the global issuance switch and organization rollout flag before creating additional keys, while leaving existing credentials available for use and revocation. Show nullable creators and identify SDK v4.5.8 as the first compatible public-token version.
Record bounded outcomes for additional key creation, policy preparation, revocation, and public-token minting.
c91b01d to
b537812CompareNote GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
Observability mapAs of 18/100 over 412 measured of 428 entry points (base 18, no change) What this PR changed
FIX FIRST
AUDIT 3 of 50 sensitive mutations record an actor. 47 without one. What the score is made ofReport only, nothing here gates the merge. The rules and their reasons: internal-packages/observability-map/README.md. |
| <div className="mt-1 text-sm font-semibold text-text-bright"> | ||
| {preset?.label ?? "No restrictions"} |
There was a problem hiding this comment.
🟡 Key creation screen can claim a limited key grants unrestricted access
The permissions summary shown while creating a key falls back to the unrestricted description (PRESET_SCOPE_DETAILS.FULL_ACCESS at apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.apikeys/route.tsx:1011) whenever the chosen access level isn't in the hard-coded list, so a limited key is advertised as granting everything.
Impact: Someone creating a key can be told it has unrestricted access when it does not, leading to keys being created and trusted based on wrong information.
How an unlisted access preset ends up rendering the full-access summary
PRESET_SCOPE_DETAILS is a hard-coded map keyed by preset id (FULL_ACCESS, TRIGGER_ONLY, TASK_OPERATOR, ENVIRONMENT_OBSERVER, ENVIRONMENT_OPERATOR, DEPLOY_ONLY, ENV_VARS_ONLY), while the actual preset catalogue comes from the RBAC controller at runtime (rbac.apiKeyPresets, surfaced through the loader). When the controller returns a preset whose id is not in that map, ApiKeyScopePanel silently substitutes the FULL_ACCESS detail, which sets detail.admin = true; the panel then renders the amber admin box ("A single scope that grants everything below") and marks every capability row as "Full access", even though the header still shows the restricted preset's label.
This is reachable without a plugin adding new ids: defaultPresetId (route.tsx:584-587) picks the first available preset when FULL_ACCESS is unavailable, and that id may not appear in the radio groups rendered by PresetOptions, so the form can be submitted with a preset the user never explicitly picked while the panel described it as full access. Consider deriving the scope summary from data returned by the controller (e.g. describeApiKeyPolicy) instead of a client-side hard-coded map, or rendering an explicit "scopes unavailable" state for unknown preset ids rather than defaulting to full access.
Prompt for agents
In the API keys route (apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.apikeys/route.tsx), ApiKeyScopePanel resolves the capability summary from the hard-coded PRESET_SCOPE_DETAILS map and falls back to the FULL_ACCESS entry when the selected preset id is missing from that map. The preset catalogue is supplied at runtime by the RBAC controller (rbac.apiKeyPresets), so a preset id outside the hard-coded list — including the auto-selected defaultPresetId when FULL_ACCESS is unavailable — renders the 'admin' box and 'Full access' on every capability row for a key that is actually restricted. Fix by not defaulting unknown preset ids to the full-access detail: either drive the panel from data the controller can describe for the preset, or render a neutral 'scope details unavailable' state, and make sure the auto-selected default preset is always one that is actually rendered as a selectable option.
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Projects can create, inspect, expire, and revoke multiple API keys for each environment. Plaintext values are shown only at creation; stored credentials are hashed and the API keys page displays only an obfuscated suffix afterward.
Self-hosted installations support full-access additional keys by default. Authorization extensions can provide additional access presets and optional task selection. Additional keys can also mint scoped public access tokens through the Trigger.dev API without receiving the environment signing key.
Feature notes
_ak_keys.Deployment notes
Deploy the management UI and public-token endpoint with new key creation disabled. Enable creation for selected organizations after the authentication path and released SDK have been verified, then expand availability gradually.
Revoking an API key prevents new bearer requests and new token minting. Public tokens already minted by that key remain valid until their own expiration because they are signed by the environment signing key.
TODO
partially accept items before a validation or authorization error.
Follow-ups
_ak_key.