Skip to content

feat(api): add API-provisionable service accounts#9399

Open
clwluvw wants to merge 1 commit into
makeplane:previewfrom
clwluvw:svc-account
Open

feat(api): add API-provisionable service accounts#9399
clwluvw wants to merge 1 commit into
makeplane:previewfrom
clwluvw:svc-account

Conversation

@clwluvw

@clwluvw clwluvw commented Jul 11, 2026

Copy link
Copy Markdown

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

  • Bug fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Improvement (change that would cause existing functionality to not work as expected)
  • Code refactoring
  • Performance improvements
  • Documentation update

Summary by CodeRabbit

  • New Features
    • Added workspace service accounts provisioning via an admin-only HTTP endpoint and a management command.
    • Provisioned accounts receive a workspace-scoped API token and can authenticate as a distinct actor.
    • Role support includes admin, member, and guest.
  • Security
    • One-time token display; plaintext tokens are redacted from persisted API activity logs.
    • Access restricted to workspace administrators (non-admins are blocked).
  • Documentation
    • Added service-account setup and operational guidance, including token handling and revocation behavior.
  • Tests
    • Added contract and unit tests covering successful provisioning, authorization, redaction, and error handling.

Copilot AI review requested due to automatic review settings July 11, 2026 22:51
@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4c852bf2-011f-406a-8035-258d3b84d590

📥 Commits

Reviewing files that changed from the base of the PR and between 6137f99 and 3fed241.

📒 Files selected for processing (14)
  • apps/api/plane/api/serializers/__init__.py
  • apps/api/plane/api/serializers/service_account.py
  • apps/api/plane/api/urls/__init__.py
  • apps/api/plane/api/urls/service_account.py
  • apps/api/plane/api/views/__init__.py
  • apps/api/plane/api/views/service_account.py
  • apps/api/plane/db/management/commands/create_service_account.py
  • apps/api/plane/db/models/user.py
  • apps/api/plane/middleware/logger.py
  • apps/api/plane/tests/contract/api/test_service_account.py
  • apps/api/plane/tests/unit/middleware/test_logger.py
  • apps/api/plane/tests/unit/utils/test_service_account.py
  • apps/api/plane/utils/service_account.py
  • docs/service-accounts.md
✅ Files skipped from review due to trivial changes (2)
  • apps/api/plane/api/serializers/service_account.py
  • apps/api/plane/api/urls/service_account.py
🚧 Files skipped from review as they are similar to previous changes (10)
  • apps/api/plane/api/serializers/init.py
  • apps/api/plane/api/urls/init.py
  • apps/api/plane/api/views/init.py
  • apps/api/plane/tests/unit/utils/test_service_account.py
  • apps/api/plane/db/models/user.py
  • apps/api/plane/middleware/logger.py
  • apps/api/plane/utils/service_account.py
  • apps/api/plane/db/management/commands/create_service_account.py
  • apps/api/plane/tests/contract/api/test_service_account.py
  • apps/api/plane/api/views/service_account.py

📝 Walkthrough

Walkthrough

Service-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.

Changes

Service Account Provisioning

Layer / File(s) Summary
Provisioning core
apps/api/plane/db/models/user.py, apps/api/plane/utils/service_account.py, apps/api/plane/tests/unit/utils/test_service_account.py
Defines service-account roles, transactional bot-user, workspace-membership, and scoped-token creation, with role-resolution tests.
Admin HTTP creation flow
apps/api/plane/api/serializers/..., apps/api/plane/api/views/..., apps/api/plane/api/urls/..., apps/api/plane/tests/contract/api/test_service_account.py
Adds the workspace-owner POST endpoint, serializers, routing, token response, and endpoint contract coverage.
Management command flow
apps/api/plane/db/management/commands/create_service_account.py, apps/api/plane/tests/contract/api/test_service_account.py
Adds CLI provisioning with role, workspace, email, and description validation, error handling, and one-time token output.
Response logging redaction
apps/api/plane/middleware/logger.py, apps/api/plane/tests/unit/middleware/test_logger.py
Adds opt-in response-body redaction and tests that secret response content is replaced in API logs.
Service-account documentation
docs/service-accounts.md
Documents provisioning flows, roles, token handling, attribution, and operational behavior.

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
Loading

Possibly related PRs

  • makeplane/plane#9148: Updates APITokenLogMiddleware behavior around token and response logging used by the redaction flow.

Suggested reviewers: dheeru0198, pablohashescobar, Prashant-Surya, pushya22

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.68% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: API-provisionable service accounts.
Description check ✅ Passed The description covers the feature and type of change, though it omits screenshots, test scenarios, and references.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread apps/api/plane/utils/service_account.py
Comment thread docs/service-accounts.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between dc9d80b and 3227e94.

📒 Files selected for processing (13)
  • apps/api/plane/api/serializers/__init__.py
  • apps/api/plane/api/serializers/service_account.py
  • apps/api/plane/api/urls/__init__.py
  • apps/api/plane/api/urls/service_account.py
  • apps/api/plane/api/views/__init__.py
  • apps/api/plane/api/views/service_account.py
  • apps/api/plane/db/management/commands/create_service_account.py
  • apps/api/plane/db/models/user.py
  • apps/api/plane/middleware/logger.py
  • apps/api/plane/tests/contract/api/test_service_account.py
  • apps/api/plane/tests/unit/middleware/test_logger.py
  • apps/api/plane/utils/service_account.py
  • docs/service-accounts.md

Comment thread apps/api/plane/db/management/commands/create_service_account.py Outdated
Comment thread apps/api/plane/utils/service_account.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
docs/service-accounts.md (1)

67-67: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Specify a language for fenced code blocks.

The code blocks at lines 67 and 89 lack a language specifier, triggering markdownlint MD040. Use text for the command output block and http for the HTTP request example.

📝 Proposed fix
-```
+```text
 Service account created successfully
   user_id  : 1c2f...c7f3

And 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

📥 Commits

Reviewing files that changed from the base of the PR and between 3227e94 and 6137f99.

📒 Files selected for processing (14)
  • apps/api/plane/api/serializers/__init__.py
  • apps/api/plane/api/serializers/service_account.py
  • apps/api/plane/api/urls/__init__.py
  • apps/api/plane/api/urls/service_account.py
  • apps/api/plane/api/views/__init__.py
  • apps/api/plane/api/views/service_account.py
  • apps/api/plane/db/management/commands/create_service_account.py
  • apps/api/plane/db/models/user.py
  • apps/api/plane/middleware/logger.py
  • apps/api/plane/tests/contract/api/test_service_account.py
  • apps/api/plane/tests/unit/middleware/test_logger.py
  • apps/api/plane/tests/unit/utils/test_service_account.py
  • apps/api/plane/utils/service_account.py
  • docs/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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants