Repository navigation
Conversation
ritwik-g
left a comment
There was a problem hiding this comment.
Self-review round 1 — unstract:review-deep (INITIAL) at tip f0790242d
Review: review-deep. The diff touches permissions/, which trips the auth trigger, so review-shallow's gate refuses it. Findings are triaged by Ritwik's must-haves bar: only billing, data, security or a wrong operator action blocks; everything else is an accepted note.
Verdict — REQUEST CHANGES
Summary — Critical: 0 · High: 0 · Medium: 3 · Low: 1 · Lenses run: 19/19 (N/A: 12, 14, 18, 19).
Scope change — NO
Security deep-dive: done. No candidates, so filtering was not needed; not degraded. It found no change to any authorization decision.
Boundary sweep: 2 sinks traced (audit rows, and the best-effort failure logs), clean. Share recipients' e-mails go only into admin-only audit rows, as member events already do. Logs carry no message.
Base fetch: ok. The count is verified (12 files).
Accepted notes (recorded, not fixed, per the must-haves bar)
resource_refis called outsidebest_effortbefore each delete. Nothing in the current registry can make it raise; this is hardening only.- Two concurrent share requests can leave a
shared_to_orgtoggle unrecorded. The same accepted window exists for users and groups. - Adapter create: an
IntegrityErrorfrom the later default save can leave the adapter row (pre-existing) with no event. resource.createdandresource.deletedcarry emptychanges; the rows don't say so.TargetTypeenum members for the kinds are not added (target_type is free text).- Share recipients are not searchable; they live in
changes, not the summary. - The co_owner_removed row omits "e-mail in summary".
- The README doesn't say outright that cloud kinds get sharing and co-owner events only.
- The org-scoping test can't tell the resource's org from the request's org (they are always equal in views).
- The sharing test can't tell e-mail from username (fixture sets both alike).
resources.pydocstring: "the share endpoints" don't usekind; "any other model" overstates create/delete.- The README summary rule conflicts with the co-owner summary (e-mail).
- "
ETL,TASK" reads as the full list of pipeline types.
Lens checklist
- Spec & intent — See findings #1
- Architectural fit & precedent — Clean (code-reviewer)
- Correctness & edge cases — See findings #2 (silent-failure-hunter and code-reviewer, otherwise notes only)
- Security — Clean (orchestrator, security deep-dive done with 0 findings, boundary sweep of 2 sinks)
- Data integrity & migrations — Clean (infra agent, no migrations, events recorded after commit)
- Concurrency — Clean (infra agent, one accepted note)
- API & contract compatibility — See findings #1, #3 (type-design-analyzer, no consumers yet)
- Reliability & resilience — Clean (infra agent, recording is best-effort)
- Performance & cost — Clean (code-reviewer)
- Observability — Clean (code-reviewer)
- Operational safety — Clean (infra agent, revertable, no schema)
- LLM/agent-specific — N/A — no LLM code
- Testing — See findings #4 (pr-test-analyzer, 15 emit sites mutation-covered)
- Dependencies & build — N/A — none
- Code quality — Clean (orchestrator ran the pinned pre-commit, all hooks pass)
- Doc & comment accuracy — See findings #2
- Cross-document rule consistency — See findings #3
- On-prem deployment experience — N/A — no chart, schema or settings
- Scaling & workload lifecycle — N/A — no workload config
cost: agents=8 wall=12:02 lenses-examined=15 of 19 files=12 lines=514
ritwik-g
left a comment
There was a problem hiding this comment.
Self-review round 2 — unstract:review-deep (FOLLOWUP) at tip bedbcccab
Review: review-deep, delta only (f0790242d..bedbcccab, 100 lines, 3 files); there is no cold read under 200 lines. The must-haves bar applies.
Verdict — REQUEST CHANGES
Summary — Critical: 0 · High: 0 · Medium: 2 · Low: 0 · Lenses run: 19/19 (N/A: 12, 14, 18, 19). There are 2 must-haves; 3 notes are accepted.
Prior context fetched — followup-fetch.sh fetched 6 of 6. "Since" boundary: f0790242d.
Scope change — NO
Security deep-dive: done. No candidates, so filtering was not needed; not degraded.
Boundary sweep: 1 new sink (the import event row: tool id and name only), clean.
Prior findings status
#1→RESOLVEDinbedbcccab(its failure-path test is #5).#2,#3,#4→RESOLVEDinbedbcccab.
Accepted notes
- The in-use connector test asserts
>= 400, not409. create_connectorhardcodes its name.- The cascade sentence reads as the only example (API deployment keys are covered elsewhere in the README).
Lens checklist
- Spec & intent — See findings #6
- Architectural fit & precedent — Clean (code-reviewer)
- Correctness & edge cases — See findings #6
- Security — Clean (orchestrator, security deep-dive done with 0 findings)
- Data integrity & migrations — Clean (orchestrator, no model change)
- Concurrency — Clean (orchestrator, no shared state)
- API & contract compatibility — Clean (orchestrator, the Target types line now matches the registry)
- Reliability & resilience — Clean (orchestrator, the emit is best-effort)
- Performance & cost — Clean (code-reviewer)
- Observability — Clean (code-reviewer)
- Operational safety — Clean (orchestrator, no config)
- LLM/agent-specific — N/A — no LLM code
- Testing — See findings #5
- Dependencies & build — N/A — none
- Code quality — Clean (orchestrator ran the pinned pre-commit, all hooks pass)
- Doc & comment accuracy — Clean (comment-analyzer, one note)
- Cross-document rule consistency — Clean (orchestrator, README cascade and target types agree with the code)
- On-prem deployment experience — N/A — no chart, schema or settings
- Scaling & workload lifecycle — N/A — no workload config
cost: agents=4 wall=04:35 lenses-examined=15 of 19 files=3 lines=100
ritwik-g
left a comment
There was a problem hiding this comment.
Self-review round 3 — unstract:review-deep (FOLLOWUP) at tip f43427d41
Review: review-deep, delta only (bedbcccab..f43427d41, 64 lines, 2 files). The must-haves bar applies.
Verdict — APPROVE
Summary — Critical: 0 · High: 0 · Medium: 0 · Low: 0 · Lenses run: 19/19 (N/A: 12, 14, 18, 19). There are no must-haves; 1 note is accepted.
Prior context fetched — followup-fetch.sh fetched 6 of 6. "Since" boundary: bedbcccab.
Scope change — NO
Security deep-dive: done. No candidates, so filtering was not needed; not degraded.
Boundary sweep: 1 new sink (the backup event row: id, name, and a summary with the source project name, same org), clean.
Prior findings status
#5→RESOLVEDinf43427d41.#6→RESOLVEDinf43427d41.
Accepted notes
- The sync-prompts test stubs the sync step, so moving the backup emit after the sync would survive. The current order is correct, and the general lens confirmed that no other user-reachable
CustomToolcreate path remains.
Lens checklist
- Spec & intent — Clean (code-reviewer)
- Architectural fit & precedent — Clean (code-reviewer)
- Correctness & edge cases — Clean (code-reviewer, every create_tool_from_import_data caller now records)
- Security — Clean (orchestrator, security deep-dive done with 0 findings)
- Data integrity & migrations — Clean (orchestrator, no model change)
- Concurrency — Clean (orchestrator, no shared state)
- API & contract compatibility — Clean (orchestrator, no contract change)
- Reliability & resilience — Clean (orchestrator, the emit is best-effort)
- Performance & cost — Clean (code-reviewer)
- Observability — Clean (code-reviewer)
- Operational safety — Clean (orchestrator, no config)
- LLM/agent-specific — N/A — no LLM code
- Testing — Clean (pr-test-analyzer, 5 of 6 mutants killed, the survivor is an accepted note)
- Dependencies & build — N/A — none
- Code quality — Clean (orchestrator ran the pinned pre-commit, all hooks pass)
- Doc & comment accuracy — Clean (orchestrator, the two new comments match the code)
- Cross-document rule consistency — Clean (orchestrator, no rule changed)
- On-prem deployment experience — N/A — no chart, schema or settings
- Scaling & workload lifecycle — N/A — no workload config
cost: agents=3 wall=04:22 lenses-examined=15 of 19 files=2 lines=64
[Medium impact] Adds audit logging for resource lifecycle and sharing events. Fix the membership retry path before merging; overlapping share changes can make adding a co-owner fail.
|
Two requests can both pass validation for the same add or remove; the second save changes nothing. The owner serializers now return whether they changed ownership, and the view records only then. Addresses Greptile review on #2350. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Record create and delete of adapters, connectors, workflows, API deployments, pipelines and Prompt Studio projects, and every change made through the shared share and co-owner endpoints, in the platform audit log. - platform_audit/resources.py names a resource by its SHAREABLE_RESOURCES kind and reads it before a delete; recording is best-effort. - Five resource.* actions in a new 'resources' category. - Sharing records only the axes that changed; no-op shares record nothing. - Field-level edits are out of scope. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Record resource.created when a Prompt Studio project is imported. - README: a workflow delete also removes its pipelines and API deployments without events; the Target types line lists the resource kinds. - Test that a delete refused because the connector is in use records nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Record resource.created for the backup copy sync-prompts makes. - Test that a failed import still records the project row it leaves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two requests can both pass validation for the same add or remove; the second save changes nothing. The owner serializers now return whether they changed ownership, and the view records only then. Addresses Greptile review on #2350. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8cebbc3 to
def12cd
Compare
8cebbc3 split update_or_create into an update then get_or_create; a share landing between them left the user a viewer while the add reported success. get_or_create first, then promote whatever row exists; 'changed' comes from the writes. Addresses Greptile review on #2350. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A concurrent unshare could remove the viewer row between the read and the promotion, leaving a successful add with no owner row. Promote under select_for_update inside a transaction (the guarantee update_or_create gave), and create the owner row if it was removed. Addresses Greptile review on #2350. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| if row is None: # a concurrent unshare removed it | ||
| resource.memberships.create(user_id=user_id, role=ResourceRole.OWNER) | ||
| return True |
There was a problem hiding this comment.
After get_or_create() returns a viewer row, an overlapping unshare can delete it and another share can create a replacement. The lookup by the old primary key then returns None. This plain create() violates uniq_resource_membership, so the ownership request fails instead of promoting the replacement viewer.
Retry by the user/resource key and lock the returned row before deciding whether ownership changed.
Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/permissions/membership_serializers.py
Line: 58-60
Comment:
**Adding a co-owner can fail**
After `get_or_create()` returns a viewer row, an overlapping unshare can delete it and another share can create a replacement. The lookup by the old primary key then returns `None`. This plain `create()` violates `uniq_resource_membership`, so the ownership request fails instead of promoting the replacement viewer.
Retry by the user/resource key and lock the returned row before deciding whether ownership changed.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Unstract test resultsPer-group results
Critical paths
|



What
Records resource actions in the platform audit log (UN-4398, PB-T01), stacked on #2342. Hari confirmed the scope in the v1 channel; see UN-4398 comment 47129.
resource.createdresource.deletedresource.sharing_changedshare/on any shareable resource; only the axes that changed (user e-mails, group names,shared_to_org)resource.co_owner_added/resource.co_owner_removedowners/add and remove; co-owner e-mail in the summarykindfromSHAREABLE_RESOURCES, so it matches the share endpoints. On cloud, Agentic Studio projects and Look-Ups use the same share and co-owner endpoints, so their sharing is recorded too.LLM, ...) or pipeline type (ETL,TASK) where there is one.How
platform_audit/resources.py:resource_refreads type, id and name before a delete, since a deleted row has no pk.record_resource_eventandrecord_sharing_changearebest_effortwrappers overrecord_platform_event.perform_destroyoverride.Tests
platform_audit/tests/test_resource_events.pyhas 12 tests, all through the real viewsets:shareoverride;Every emit site was mutation-checked: removing any one of the 12 create/delete calls, or the share and co-owner logic, fails a test. The touched apps' suites pass, except
test_pdf_marker_inside_other_content_does_not_smuggle_a_file_through, which also fails on main.Merge order
The base is
feat/UN-4398-platform-audit(#2342). Merge after #2342.🤖 Generated with Claude Code