Repository navigation
fix(plugin-security): an organization administrator's update by id is refused before the row is looked up, whatever the id names - #30200
Conversation
… refused before the row is looked up, whatever the id names Claude-Session: https://claude.ai/code/session_01QSeKYn5CmmdShCJifm6WYj Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 17 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 934e0bacd4e918a9c6b3bc11a05dbac3d013b0c0 && git checkout 934e0bacd4e918a9c6b3bc11a05dbac3d013b0c0
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin dfafae81324e508cc666171d3385a15b89f31050 a88b52d7d9072269f8eea2965aa1bd2b3d6d8226 && git checkout -B drift-repro dfafae81324e508cc666171d3385a15b89f31050 && git merge --no-ff a88b52d7d9072269f8eea2965aa1bd2b3d6d8226
node scripts/docs-audit/affected-docs.mjs --json dfafae81324e508cc666171d3385a15b89f31050
|
|
security#1 · os-justin · session_01QSeKYn5CmmdShCJifm6WYj 席位核对ACCEPT · head
|
Refs #30198
Clause-②: no
Metadata-protocol: none
维护者速读
adminScope)按 id 修改授权行时,恢复“先拒绝、不查行”的顺序:无论这个 id 指向能读到的行、读不到的行还是不存在的行,都回答同一个403 PERMISSION_DENIED(“never edited in place”)。按 id 删除不变:读不到的行和不存在的 id 仍回答读取门的404。adminScope的组织管理员都不变;放行与拒绝的集合不变,只有这一类拒绝的状态码从 404 回到 403。回滚即撤销本 PR。packages/plugins/plugin-security/src/delegated-admin-gate.ts的organizationAdminFailure(删去 update 分支的hiddenFromCaller调用,以及随之不再使用的这个方法);org-admin-assignment-boundary.posture.test.ts里改指向的两处 update 断言。pnpm --filter @objectstack/dogfood exec vitest run test/update-by-id-refusal-order.dogfood.test.ts,预期全部通过,组织管理员那条对照用例对行和不存在的 id 都是 403。What changes
DelegatedAdminGate.organizationAdminFailure(ADR-0090 D12), the update branch no longer reads the row first. An edit in place is never part of the organization administrator's right, so that refusal does not depend on the row, and the update-by-id refusal order puts it before any lookup. A row, a row the administrator cannot read, and an id naming no row all get one403 PERMISSION_DENIEDwith the same sentence and details. The private helper that only that read used is removed.adminScopeis still judged by the delegated walk, so its update of a row it cannot read still answers the not-found.Tests
packages/qa/dogfood/test/update-by-id-refusal-order.dogfood.test.tsis unchanged. Its control "an organization administrator, who reads the platform grant object, keeps the administration gate's sentence for a row and for no row" is the case this restores.org-admin-assignment-boundary.posture.test.ts:groupandisolated, the update of a row the caller cannot read and of an id naming no row is one403 PERMISSION_DENIED, compared whole, while the delete stays the read door's not-found, compared whole;singlecontrol, the update of a row it reads and of an id naming no row is the same whole refusal.org-admin-assignment-removal-unreadable-row.dogfood.test.ts:PATCHof the row behind the wall and of a missing id answers one403, whileDELETEstays equal to theGETof that id.delegated-admin-assignment-write-unreadable-row.dogfood.test.tsis unchanged. Its organization administrator holds a scope, so it is judged by the delegated walk.Acceptance notes
.changeset/assignment-write-unaddressable-row-not-found.mdsays that an organization administrator's edit in place "is asked the same question first". After this PR that sentence is no longer accurate: the edit is refused before any lookup. The new changeset states the rule. The old bullet is left as it stands, so that this fix carries no second changeset correction (which would need confirmation). It wants a one-line correction before the release that ships both.Verification
Local readings (the plugin-security typecheck and suite, the posture rig, the three dogfood files, the derived gate families) are taken at this PR's head under the shared verify lock and reported to the seat. CI's families are this PR's own check-runs.
Generated by Claude Code