feat(authz): ADR-0099 two-axis model — Layer 1 tier stays the per-object scope bit; amendment + P2′ pins (#3211 M3/M3′)#3245
Merged
Conversation
…bject scope bit; P2 superseded by P2' (#3211) The pre-P2 verification found D2's Layer 1 row was not behavior-preserving as written: Layer 1's tier input is the per-object super-bit, a per-principal-x-per-object delegation primitive (custom set granting viewAllRecords on one object to a non-admin position — the auditor pattern, the industry-standard shape). Posture is per-principal and structurally cannot carry per-object scope; enforcing the MEMBER cell literally would inert a declared grantable bit (the ADR-0049 declared-but-unenforced class) and delete a mainstream delegation capability. Amendment (maintainer, 2026-07-18): two orthogonal axes, each with a single authority — posture is the boundary axis (Layer 0 exemption at PLATFORM_ADMIN, EXTERNAL replacement; both ladder ends), the per-object super-bits are the scope axis (the only Layer 1 tier input, unchanged). D1's single-input principle refines to single-authority-per-axis; new invariant I7 (scope never crosses a boundary posture has not opened — enforced by P1); I2 clarified as a per-rung floor. Original P2 rejected; P2' = documentation cells only (seeded-face agreement, the delegation cell, I7), zero behavior change. Inline markers added at the D1 bullet, D2 table, and Sequencing P2 entry; full rationale in the Amendment section. Docs-only; no changeset. check:role-word OK - check:doc-authoring 200 files clean. Refs #3211 - ADR-0099 / #3109 / #3218 / #3226 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DAHp4K7FvyMPBY1DPNkmRu
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
12 tasks
…yer 1 scope axis (#3211 M3′) The two-axis Amendment's documentation cells (zero behavior change). The original P2 (collapse Layer 1 tier onto posture) was rejected; these cells pin the corrected model in CI: - seeded-face agreement: every seeded super-bit holder is already >= TENANT_ADMIN, so the two axes coincide on the seeded surface (why the collapse looked safe until the delegation case); - the delegation cell (LOAD-BEARING): a MEMBER holding a delegated per-object viewAllRecords/modifyAllRecords on a private object short-circuits Layer 1 (sees all rows in-org) AND stays walled by Layer 0 (org-1 only) — the auditor pattern; a future posture-convergence cleanup must keep this green or it silently deletes the capability; - I7: the holder cannot read/write/insert cross-tenant (the scope axis never crosses a boundary posture has not opened); - contrast: a plain member without the bit is denied on the private object, so the bit is a real grantable capability, not conditionally inert (the ADR-0049 class the collapse would have introduced). New fixture invoice_auditor (delegated per-object super-bit). G2 audit: single authority per axis holds — boundary fact derived once (core resolver) + consumed at the Layer 0 gate (fallback probe narrows only); scope fact evaluated only via hasSuperuser*Bypass. plugin-security 510 passed; tsc + check:role-word + check:doc-authoring clean; plugin-security build green. Refs #3211 - ADR-0099 two-axis Amendment (#3245) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DAHp4K7FvyMPBY1DPNkmRu
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 11 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DAHp4K7FvyMPBY1DPNkmRu
os-zhuang
marked this pull request as ready for review
July 19, 2026 02:57
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.
目的
#3211 的收尾 PR:记录 M3 裁决(maintainer,2026-07-18)——原 P2「Layer 1 tier 收敛读 posture」否决,ADR-0099 修正为两轴模型——并落 P2′ 钉住格把修正后的模型钉进 CI。docs + test,零行为变更。
背景:P2 前核实推翻了「行为保持」声明
D2 表 Layer 1 行写着 tier 读 posture、「per today's semantics」——核实证明不是今天的语义:Layer 1 的 tier 输入是每对象超级位,一个可委派给非管理员的原语(自定义集给审计员岗授「某对象全部可见」= Salesforce 对象级 View All 同款)。posture 是每主体一个 rung,结构上装不下每对象范围。照原文强制会 (a) 让一个已声明、可授予的位条件性失效(ADR-0049 禁止的 declared-but-unenforced 类),(b) 砍掉主流委派能力、逼出过度授权。
内容
1. ADR-0099 两轴 Amendment(docs)
2. P2′ 钉住格(test,
authz-matrix-gate.test.ts)invoice_auditor(某 private 对象委派 view/modify all)→ Layer 1 短路(组织内全行)且被 Layer 0 墙住(org-1)。审计员模式,未来任何「posture 收敛清理」必须保持它绿、否则静默删掉该能力。3. changeset
@objectstack/plugin-securitypatch(test-only,循 #3218 先例)。裁决依据(四视角)
① 主流平台(Salesforce 对象级 View All / Dynamics org 级实体访问 / Frappe)委派原语不绑管理员人格;② posture(每主体) 与位(每主体×对象) 粒度不可互换,压轴=类型错误;③ 审计员/风控式 view-all 委派是低代码日常;④ 条件性死位是 AI 作者最踩的静默 miss 类(#3003/#3005 同族)。两轴给 AI 的规则一句话:位定对象内行范围,posture 定租户边界。
验证(全绿)
pnpm --filter @objectstack/plugin-security test— 510 passed / 20 files(含 P2′ 全部钉住格)tsc --noEmit(plugin-security)通过;check:role-word/check:doc-authoringclean;plugin-security build 绿hasSuperuser*Bypass求值,无第三处派生 ✓收口
合并后 #3211 走 G2 关闭(P3/EXTERNAL 留 #2776 item 6;advisory lint 另立后续 issue 追踪)。
Refs #3211 · ADR-0099 / #3109 · #3218(P0)· #3226(P1)· ADR-0049 · #2946 Finding 2
🤖 Generated with Claude Code
https://claude.ai/code/session_01DAHp4K7FvyMPBY1DPNkmRu