Repository navigation
Legal and finance can edit a counterparty they do not own - #193
Merged
Merged
Conversation
Legal could not edit a counterparty or a playbook clause it did not create: both objects were public_read, so every write was owner-scoped and no sharing rule covered legal (or finance on the banking pair). Under ruling D both become public_read_write. The platform opens the row scope for update only; deletes stay owner-only, and the object permissions and field locks in src/profiles (unchanged) still decide who writes which field. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn
Contributor
Author
席位核对 — ACCEPT · head
|
| check | reading |
|---|---|
| shape | draft → main, Fixes #152; mergeable clean |
| CI on the head | both Validate check-runs success on 8ab6300 = PR head.sha |
| scope | ruling D (6607872904): clm_party sharingModel public_read → public_read_write, and the rider clm_clause gets the same change (same shape measured on main: counsel1's edit of a seeded clause was refused at row level). Nothing in src/profiles changes grants. The seat added one comment-only commit (8ab6300) correcting two comments the change made false (contract-intake.flow.ts, requester.profile.ts). Nothing governed; lint 0 warnings |
| measured (zh-CN demo staff, API and browser) | counsel1 sets risk_flag on a party it did not create: 403 → 200. finance writes bank_name: 403 → 200. finance writes name: 403 (now the field lock, not row level). requester1 PATCHes its own party: 403 (object permission). records: 403. Non-owner DELETE: 403, row kept. Clause: counsel1 edits a seeded clause 403 → 200; finance, requester1 and records still 403; DELETE 403. In the browser, finance's party form opens only bank_name / bank_account |
| governed text | §03 object map and row labels, and the §04 OWD sentence, go to the seat's design PR #120 |
Landing: under the maintainer's merge authorization (project thread: 「你可以自己审核的就自己合并」).
Generated by Claude Code
zhuangjianguo
marked this pull request as ready for review
November 3, 2026 16:05
This was referenced Nov 3, 2026
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.
Fixes #152
Ruling D (comment 6607872904, maintainer 2026-11-03):
clm_partybecomespublic_read_write; the permission sets stay as they are. The rider,clm_clause, measured the same shape on main, so it gets the same one-line change under the same ruling.What changed
src/objects/party.object.ts:sharingModel: 'public_read'to'public_read_write', with a short comment on why.src/objects/clause.object.ts: the same change (rider, ruling item 4).src/profileschanges. Platform 18.2.0 (plugin-securityplatform-ownership-policies.ts,owdOpenWritesCoversOperation) opens the row scope forupdateonly. Deletes stay owner-only, and object permissions plus field locks still decide who may write which field.Measured: zh-CN demo staff, 18.2.0, port 3162, a fresh
.objectstackDB per sideBefore = origin/main
7e7c2dc. After = this branchcf33339. Each persona signed in with its own session (requester1,counsel1,finance,records@example.com). Every write was read back with a GET as the same persona. Seeded rows were owned by the dev admin at reading time.API
risk_flagon the party requester1 created您无权访问这条记录…(server log: row-level security)watchrisk_flagon seeded 峰顶翻译watchbank_name(same two parties)name[Security] Field write denied: not permitted to edit [name] on 'clm_party'(field lock)contact_nameon the party it created您没有执行此操作的权限…(object permission)contact_nameposition_noteon a seeded clause (rider)Browser (Chromium, zh-CN console, signed in as each persona)
编辑button and no双击编辑cell. The more-actions menu offers only添加到收藏/分享. counsel1 and finance see the same on a clause.编辑, sets 风险标记 to关注and fills 风险说明, then clicks更新. Result:PATCH /api/v1/data/clm_party/… → 200, toast相对方“北风物流”已更新. After a reload the header reads 风险标记关注.编辑. The form leaves onlybank_nameandbank_accountopen; the other 13 controls (name included) are locked. Finance edits 开户行 and saves:PATCH → 200, toast相对方“北风物流”已更新, and the read-back holds it.编辑, changesposition_noteand saves:PATCH /api/v1/data/clm_clause/… → 200, toast条款“服务质量保证”已更新.编辑on the party, and finance sees none on the clause.401on the sign-in page (the pre-session probe), plus one404on counsel1's first page load.Gates (tree of
cf33339, no edit after the run; each exit captured before any pipe)Acceptance notes
allowDeleteonclm_partyorclm_clause; onlyclm_admindoes, and it hasmodifyAllRecords. So every non-owner DELETE measured here is refused at the object-permission layer. The platform's owner-only delete floor on apublic_read_writeobject is confirmed from source, but no persona can reach it.src/profilesdoes not change, so this PR does not edit them:src/flows/contract-intake.flow.ts, theclm_partynote, says "(on a party legal does not own, writes are owner-scoped today, see [Decision] Legal and finance cannot edit a counterparty they do not own — §04 gives them update on clm_party, but its writes are owner-scoped #152)". After this PR that is no longer true.src/profiles/requester.profile.tssays "Configuration objects are public_read: everyone reads every row".clm_clauseis nowpublic_read_write. The claim that everyone reads every row still holds.🤖 Generated with Claude Code
https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn