UN-3586 [FEAT] Allow platform API key rotation via API#2133
UN-3586 [FEAT] Allow platform API key rotation via API#2133Deepak-Kesavan wants to merge 4 commits into
Conversation
Operational automation (RLDatix) needs credential rotation through the API, but the rotate endpoint was gated by IsOrganizationAdmin, which rejects service accounts — so a platform API key could not rotate itself. Add CanRotatePlatformApiKey for the rotate action: session callers still must be org admins (may rotate any key in the org), while a platform API key (bearer) may rotate ONLY its own key (pk == request.platform_api_key.id). Cross-org access remains impossible (auth middleware + org-scoped queryset); this only relaxes the intra-org gate to self-rotation. read keys still can't POST (middleware), so only read_write/full_access keys reach rotate. rotate returns the new key once via PlatformApiKeyDetailSerializer. No model or migration change.
WalkthroughThis PR adds dedicated authorization for platform API key rotation and applies it only to the ChangesPlatform API key rotation access control
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 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 |
…iew) Relocate the 'key may rotate only its own key' constraint from has_permission (view-level, via view.kwargs[pk]) to has_object_permission, the idiomatic DRF location for per-object access control — it receives the already-fetched obj. has_permission stays as the coarse session-vs-key gate. Behavior is unchanged (self-rotate 200, cross-key 403): this permission is only used by the rotate detail action, which calls get_object() and so always triggers the object-level check. (Greptile)
Empirically confirmed on staging that rotating a platform API key via the API (bearer token) is blocked (403 'Only organization admins...') — the automation path UN-3586 asks for. Enable it: a platform API key caller may rotate, same as a session org admin. Drop the earlier self-only restriction (not a ticket requirement) and the now-unneeded has_object_permission. Org scoping (auth middleware + org-scoped queryset) still confines a key to its own org; read keys still can't POST (middleware). rotate already returns the new key.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
backend/platform_api/permissions.py (1)
26-40: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDocstring conflates "own organization" with "own key."
The docstring says platform API key callers are confined to their own org via middleware/queryset, but the PR objectives claim callers may rotate only their "own key." Given the missing object-level check flagged above, the actual enforced behavior (org-wide, not key-specific) doesn't match the PR's documented intent. Once the object-permission gap is fixed, update this docstring to accurately describe the enforced scope.
🤖 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 `@backend/platform_api/permissions.py` around lines 26 - 40, Update the CanRotatePlatformApiKey docstring to match the actual permission scope enforced by the rotate flow. The current wording in the class docstring suggests platform API key callers are limited to their “own key,” but the behavior in this permission and the org-scoped queryset/middleware is organization-wide unless an object-level check is added elsewhere. Adjust the text in CanRotatePlatformApiKey to describe the exact enforced scope and remove the “own key”/“own organization” mismatch.
🤖 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 `@backend/platform_api/permissions.py`:
- Around line 26-40: Update the CanRotatePlatformApiKey docstring to match the
actual permission scope enforced by the rotate flow. The current wording in the
class docstring suggests platform API key callers are limited to their “own
key,” but the behavior in this permission and the org-scoped queryset/middleware
is organization-wide unless an object-level check is added elsewhere. Adjust the
text in CanRotatePlatformApiKey to describe the exact enforced scope and remove
the “own key”/“own organization” mismatch.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 715dc80c-dd6b-453d-a5ad-d2c3c9cb2e78
📒 Files selected for processing (1)
backend/platform_api/permissions.py
…lation) Greptile caught a real privilege escalation: after dropping self-only, a read_write bearer key could rotate a full_access key and read its new secret from the rotate response (rotate returns the new key), escalating read_write -> full_access. Fix: key-based callers must present a full_access key to rotate. read_write keys can no longer rotate; a full_access caller rotating any key gains no privilege (already top tier) and matches what a session admin can do. Session-admin rotate and org scoping unchanged.
|
Unstract test resultsPer-group results
Critical paths
|



What
Allow a platform API key (bearer token) to call the
rotateendpoint, so credentials can be rotated via the API for automation. Session org-admins keep rotate (unchanged).Why
UN-3586 (RLDatix on-prem blocker) asks for "rotate credentials through the API" for operational automation. Confirmed empirically on staging (
globe.unstract.com, main):Rotation via a logged-in admin session already works (the UI's rotate button), but rotation with a platform API key was blocked — the
rotateendpoint'sIsOrganizationAdmingate rejects service accounts, and a platform API key authenticates as a service account. So the token/automation path did not exist. This PR opens it.How
CanRotatePlatformApiKeypermission on therotateaction:full_accesskey (the admin-equivalent tier, which already permits DELETE).read/read_writekeys cannot rotate.full_access(not any bearer key):rotatereturns the new key value, so letting a lower-tierread_writekey rotate afull_accesskey would let it read that key's new secret and escalateread_write → full_access. Requiringfull_accesscloses that path — afull_accesscaller rotating any key gains no privilege (it's already the top tier), matching what a session admin can do.org_idagainst the key's immutable org (403 on mismatch), and the viewset queryset is org-scoped — a key can only rotate keys in its own organization. Cross-org is impossible.rotatealready returns the new key once viaPlatformApiKeyDetailSerializer— no serializer change.Note: an earlier revision restricted key callers to self-only rotation; that wasn't a ticket requirement and was dropped in favor of the
full_access-tier gate above (afull_accesskey may rotate any key in its org, matching a session admin) — which also closes a privilege-escalation path flagged in review.Can this PR break any existing features? If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)
No.
Database Migrations
None.
Env Config
None.
Notes on Testing
globe.unstract.com, main) baseline: bearerrotate→ 403 (blocked); same key reads deployments → 200. Confirms the gap.deepak-unstract-dev,snapshot.1782909801): verified live against the new pod — afull_accesskey rotating a different key via bearer → 200 + new key; aread_writekey attempting rotate → 403 (tested 3×, all denied — the privilege-escalation path is closed); session admin rotate → 200. Cross-org remains blocked (auth middleware + org-scoped queryset).Related Issues or PRs
full_accesstier).Checklist
I have read and understood the Contribution Guidelines.