UN-3853 [FIX] Attribute platform-key-created resources to the API key's creator - #2274
Open
kirtimanmishrazipstack wants to merge 4 commits into
Open
UN-3853 [FIX] Attribute platform-key-created resources to the API key's creator#2274kirtimanmishrazipstack wants to merge 4 commits into
kirtimanmishrazipstack wants to merge 4 commits into
Conversation
Contributor
|
Contributor
Author
Merge this before the cloud PRZipstack/unstract-cloud#1753 imports |
…reator A platform API key authenticates as a service account, and every resource create path granted the OWNER membership row to that machine identity. Service accounts are filtered out of every owner surface (HasMembersMixin), so such a resource ended up with no human owner: invisible to its creator in list views, manageable only through the org-admin fallback, and rendered in "Owned By" as a synthetic @platform.internal address dressed up as a colleague. Record the key's creator as owner instead — the same successor delete_api_user_for_key already hands ownership to when a key is deleted, now applied at creation rather than only at deletion. The service account loses nothing: permission classes and for_user() short-circuit on is_service_account. Where no human can be named (the key's creator has since been deleted), the resource stays deliberately ownerless and the table labels it "Platform key" rather than naming a machine. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JHnDZZWGhsevUdwgMyR2ai
…s too The ticket asks for Owned By to be correct on every resource type. The API deployment and ETL pipeline card views were still wrong: OwnerFieldRow read created_by_email only, and their serializers never exposed owner_emails — so those cards named the audit creator, which on a platform-key create is the service account. The backend fix alone could not reach them. Expose owner_emails on both serializers (their querysets already prefetch memberships__user, so it costs no extra query), and move the owner-label rule into one resolveOwnerDisplay helper shared by the table and the cards. The two had already drifted on both the source field and the "Me" rule — the card said "Me" to any owner, which is the co-owner bug the table's comment warns about. Cards now match the table: "Me" tracks the displayed owner. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JHnDZZWGhsevUdwgMyR2ai
kirtimanmishrazipstack
force-pushed
the
UN-3853-co-ownership-resources-with-platform-key
branch
from
September 3, 2026 06:10
90013a8 to
b818d85
Compare
…platform-key Both conflicts were adjacency-only in backend/api_v2 — each side kept: - api_deployment_views.py: main's PlatformKeyAutoSchema import landed on the line owner_user_for occupies. - serializers.py: main's get_run_count comment abuts get_owner_emails. Regenerated specs/docstudio-oss.json: #2278 publishes the deployment listing, so owner_emails now belongs in APIDeploymentSummary and the committed spec must byte-match a fresh render (test_docstudio_spec). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BAfubrF8kR2rKewMSjXagg
`owner_user_for` had no coverage. Adds the resolver's own branches (normal user early-returns with no query, service account resolves to the key's creator, a deleted creator or a missing key leaves the resource ownerless) and one case per OSS resource that grants an OWNER row on create: workflow, prompt studio, ETL pipeline, API deployment, connector, adapter. The resource cases drive the real URLconf and middleware chain with a key minted in the test, so the service-account swap that caused the bug is exercised rather than simulated. Verified by mutation: reverting each call site to the raw request user fails the matching case. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BAfubrF8kR2rKewMSjXagg
Contributor
Frontend Lint Report (Biome)✅ All checks passed! No linting or formatting issues found. |
|
Contributor
Unstract test resultsPer-group results
Critical paths
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What
Why
Unknown, and since UN-3770 [MISC] Make list pagination consistent across shared resource endpoints #2208 prints the robot's synthetic@platform.internaladdress with an avatar, which reads as a colleague who does not exist.UN / Unknownin Owned By.How
owner_user_for(user)inbackend/platform_api/services.py: if the acting user is a platform key's service account, return the key'screated_by; otherwise return the user unchanged. It short-circuits before any query for a normal session, so the UI path is unaffected.delete_api_user_for_keyin the same module already hands everything a key created over toplatform_api_key.created_bywhen the key is deleted. The change applies that same successor at creation time instead of only at deletion time.for_user()manager already short-circuits onis_service_account.created_byis untouched everywhere. It is an audit field, and "the robot did it" is the truthful answer.renderOwnerinResourceTable.jsxrecognises the reservedplatform.internaldomain and rendersPlatform keyinstead of dressing a machine identity up as a person. This is what makes a data migration unnecessary — rows created before this change still read correctly.Can this PR break any existing features. If yes, please list possible items. If no, please explain why.
owner_user_for()returns the user unchanged before touching the database, so every UI-driven create behaves exactly as before — bit for bit.IsOwner,IsOwnerOrSharedUser,IsParentWorkflowOwnerand friends all returnTruefor a service account before ownership is consulted, andfor_user()returns the unfiltered queryset for one.delete_api_user_for_keystill works. Its membership transfer simply finds nothing left to move, and itscreated_by/modified_byre-pointing is unchanged and still required.Database Migrations
Platform keylabel, and they are exactly as reachable as they are today (org admins). If we later decide to repair them, the shipped_transfer_membership_rows(key.api_user, key.created_by)does it from a shell — no new code, and no irreversible migration running against production for a handful of rows.Env Config
Relevant Docs
Related Issues or PRs
created_by_emailfallback added in UN-3770 [MISC] Make list pagination consistent across shared resource endpoints #2208 is what changed the symptom fromUnknownto a synthetic address; this PR removes the need for it on the platform-key path.Dependencies Versions
Notes on Testing
Unknownin Owned ByPOST /api/v1/unstract/{org}/prompt-studio/using a Bearer platform key, then open the Prompt Studio listcreated_by, then reload the listPlatform keyPlatform key, same access as beforeNo automated tests added, per the repo convention of not adding tests unless asked. Happy to add coverage for
owner_user_forif reviewers want it.Screenshots
Checklist
I have read and understood the Contribution Guidelines.
🤖 Generated with Claude Code
https://claude.ai/code/session_01JHnDZZWGhsevUdwgMyR2ai