feat(api): add API-provisionable service accounts#9399
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (14)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (10)
📝 WalkthroughWalkthroughService-account provisioning now supports transactional creation of workspace-scoped bot identities through a management command and workspace-owner API endpoint, with role validation, one-time token delivery, response-log redaction, authentication attribution, and contract documentation. ChangesService Account Provisioning
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Admin
participant ServiceAccountAPIEndpoint
participant ServiceAccountCreateSerializer
participant create_service_account
participant APITokenLogMiddleware
Admin->>ServiceAccountAPIEndpoint: POST service-account request
ServiceAccountAPIEndpoint->>ServiceAccountCreateSerializer: validate payload
ServiceAccountAPIEndpoint->>create_service_account: provision account and token
create_service_account-->>ServiceAccountAPIEndpoint: ServiceAccount result
ServiceAccountAPIEndpoint-->>Admin: HTTP 201 with one-time token
ServiceAccountAPIEndpoint->>APITokenLogMiddleware: mark response for redaction
APITokenLogMiddleware-->>APITokenLogMiddleware: persist "[REDACTED]" response body
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 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 |
There was a problem hiding this comment.
Pull request overview
Adds first-class, API-provisionable “service accounts” to enable fully automated workspace provisioning: a bot user + workspace membership + workspace-scoped API token created atomically, with safeguards to prevent interactive login and to avoid persisting minted tokens in API activity logs.
Changes:
- Introduces shared service-account provisioning utility used by both a new management command and a new admin-scoped HTTP endpoint.
- Adds response-body redaction support to the API token logging middleware to prevent logging newly minted credentials.
- Adds contract/unit tests plus documentation covering service-account behavior and surfaces.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/service-accounts.md | Documents service accounts, roles, command usage, and the admin endpoint (including token handling/logging notes). |
| apps/api/plane/utils/service_account.py | Core transactional provisioning logic for bot user + membership + token. |
| apps/api/plane/tests/unit/middleware/test_logger.py | Adds tests proving response bodies are logged by default and redacted when flagged. |
| apps/api/plane/tests/contract/api/test_service_account.py | Contract tests for both the management command and the HTTP endpoint, including attribution and log redaction. |
| apps/api/plane/middleware/logger.py | Adds redact_response_body() + attribute flagging and middleware support to redact logged response bodies. |
| apps/api/plane/db/models/user.py | Extends BotTypeEnum with SERVICE bot type. |
| apps/api/plane/db/management/commands/create_service_account.py | New management command to create a service account and print the minted token once. |
| apps/api/plane/api/views/service_account.py | New admin-only endpoint to create service accounts and return the token once (with log redaction). |
| apps/api/plane/api/views/init.py | Exports the new service account API view. |
| apps/api/plane/api/urls/service_account.py | Adds route for POST /api/v1/workspaces/{slug}/service-accounts/. |
| apps/api/plane/api/urls/init.py | Includes service-account URL patterns in the API router. |
| apps/api/plane/api/serializers/service_account.py | Adds request/response serializers for service-account provisioning. |
| apps/api/plane/api/serializers/init.py | Exports the new service-account serializers. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/api/plane/db/management/commands/create_service_account.py`:
- Around line 42-57: Wrap the create_service_account call in handle with an
IntegrityError handler and re-raise a readable CommandError for email uniqueness
failures, covering both the user-supplied email race and synthetic uuid4 email
collisions. Preserve the existing validation and successful creation behavior.
In `@apps/api/plane/utils/service_account.py`:
- Around line 56-64: Update resolve_service_account_role so integer inputs are
validated against the allowed values in SERVICE_ACCOUNT_ROLES before returning;
preserve valid integers and raise the same ValueError style used for invalid
string roles when an integer is unsupported.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 6a2e8f2d-d3dc-4072-b115-11c1dbf1cd76
📒 Files selected for processing (13)
apps/api/plane/api/serializers/__init__.pyapps/api/plane/api/serializers/service_account.pyapps/api/plane/api/urls/__init__.pyapps/api/plane/api/urls/service_account.pyapps/api/plane/api/views/__init__.pyapps/api/plane/api/views/service_account.pyapps/api/plane/db/management/commands/create_service_account.pyapps/api/plane/db/models/user.pyapps/api/plane/middleware/logger.pyapps/api/plane/tests/contract/api/test_service_account.pyapps/api/plane/tests/unit/middleware/test_logger.pyapps/api/plane/utils/service_account.pydocs/service-accounts.md
There was a problem hiding this comment.
🧹 Nitpick comments (1)
docs/service-accounts.md (1)
67-67: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSpecify a language for fenced code blocks.
The code blocks at lines 67 and 89 lack a language specifier, triggering markdownlint MD040. Use
textfor the command output block andhttpfor the HTTP request example.📝 Proposed fix
-``` +```text Service account created successfully user_id : 1c2f...c7f3And at line 89:
-``` +```http POST /api/v1/workspaces/{slug}/service-accounts/🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/service-accounts.md` at line 67, Update the two fenced code blocks in the service-accounts documentation: add the text language specifier to the command output block and the http language specifier to the HTTP request example, without changing their contents.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@docs/service-accounts.md`:
- Line 67: Update the two fenced code blocks in the service-accounts
documentation: add the text language specifier to the command output block and
the http language specifier to the HTTP request example, without changing their
contents.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a0439c2a-aad6-4ff1-a43e-621418c93b39
📒 Files selected for processing (14)
apps/api/plane/api/serializers/__init__.pyapps/api/plane/api/serializers/service_account.pyapps/api/plane/api/urls/__init__.pyapps/api/plane/api/urls/service_account.pyapps/api/plane/api/views/__init__.pyapps/api/plane/api/views/service_account.pyapps/api/plane/db/management/commands/create_service_account.pyapps/api/plane/db/models/user.pyapps/api/plane/middleware/logger.pyapps/api/plane/tests/contract/api/test_service_account.pyapps/api/plane/tests/unit/middleware/test_logger.pyapps/api/plane/tests/unit/utils/test_service_account.pyapps/api/plane/utils/service_account.pydocs/service-accounts.md
🚧 Files skipped from review as they are similar to previous changes (11)
- apps/api/plane/api/serializers/init.py
- apps/api/plane/api/urls/init.py
- apps/api/plane/api/views/init.py
- apps/api/plane/api/urls/service_account.py
- apps/api/plane/db/management/commands/create_service_account.py
- apps/api/plane/api/serializers/service_account.py
- apps/api/plane/api/views/service_account.py
- apps/api/plane/tests/contract/api/test_service_account.py
- apps/api/plane/middleware/logger.py
- apps/api/plane/db/models/user.py
- apps/api/plane/utils/service_account.py
Add machine/service accounts so a self-hosted workspace can be provisioned
entirely over the API: a distinct, active actor with an API-mintable token and
no invite / email-verification / password flow.
What each account is (created in one transaction): an active, email-verified
User flagged as a bot (is_bot=True, bot_type=SERVICE) with an unusable password
and a synthetic unique username/email; a WorkspaceMember at the requested role;
and a workspace-scoped bot APIToken (user_type=Bot, is_service=True). is_bot
blocks interactive login (BOT_USER_LOGIN_FORBIDDEN); the account acts only via
its token, and its writes attribute to it via created_by.
- create_service_account management command (--workspace --name --role
[--email --description]) that prints the token.
- Optional admin-scoped POST /api/v1/workspaces/{slug}/service-accounts/
(WorkspaceOwnerPermission), mirroring the command over HTTP.
- Shared plane/utils/service_account.py helper so command and endpoint cannot
drift.
- Add SERVICE to BotTypeEnum. bot_type is a choice-less CharField, so no
migration is required.
- Security: redact secret-bearing response bodies from api_activity_logs so the
minted token is never persisted in plaintext (response-body analogue of the
existing SENSITIVE_HEADERS redaction).
- docs/service-accounts.md and contract + unit tests (token authenticates as a
distinct actor, writes attribute to it, non-admin gets 403, token not logged).
Signed-off-by: Seena Fallah <seenafallah@gmail.com>
Description
Add machine/service accounts so a self-hosted workspace can be provisioned entirely over the API: a distinct, active actor with an API-mintable token and no invite / email-verification / password flow.
What each account is (created in one transaction): an active, email-verified User flagged as a bot (is_bot=True, bot_type=SERVICE) with an unusable password and a synthetic unique username/email; a WorkspaceMember at the requested role; and a workspace-scoped bot APIToken (user_type=Bot, is_service=True). is_bot blocks interactive login (BOT_USER_LOGIN_FORBIDDEN); the account acts only via its token, and its writes attribute to it via created_by.
Type of Change
Summary by CodeRabbit