Skip to content

test(security): ADR-0099 P0 — probe vs carried-rung equivalence gate; accept ADR-0099 (#3211 M1)#3218

Merged
os-zhuang merged 1 commit into
mainfrom
claude/authz-improvement-tasks-1f5u82
Jul 18, 2026
Merged

test(security): ADR-0099 P0 — probe vs carried-rung equivalence gate; accept ADR-0099 (#3211 M1)#3218
os-zhuang merged 1 commit into
mainfrom
claude/authz-improvement-tasks-1f5u82

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

目的

ADR-0099 的 P0 等价门#3211 M1)+ Accepted 转态(maintainer 决定,2026-07-18)。这是 ADR-0099 §Phasing 里写明「随 ADR 落地」但实际缺失的那一步——P1(Layer 0 豁免门翻转读携带 rung)落在这道门后面。Test-only + docs:零行为变更。

内容

1. hasPlatformAdminCapability 纯函数提取(机械,行为逐字节不变)

security-plugin.ts 的私有探针 hasPlatformAdminPosture 的谓词体提为导出纯函数,私有方法变薄壳。仅为让等价门直接断言 enforcement 实际运行的谓词,不经 (plugin as any)

2. authz-matrix-gate.test.ts — ADR-0099 P0 格(+9 cells)

  • [D1 equivalence] 种子形态等价(4 格):unscoped admin_full_access 持有者 / organization_admin / baseline member / W1 permissive-policy fixture——探针与 derivePosture rung 逐一一致。全绿:D1 的行为保持声明在种子面上成立。
  • [KNOWN DIVERGENCE] 对抗形态(2 格,本 PR 的核心侦察产出):
  • [I3] 收窄方向证明:rung=PLATFORM_ADMIN ⇒ 探针 true 对全部形态成立(rung ⊆ 探针)→ P1 翻转只可能收窄豁免,不可能放宽
  • [I2] 嵌套不变量落到裁决现场:对锁定矩阵逐对象列断言可见性沿阶梯单调不放宽(all-rows > org-scoped > owner/self > deny)。
  • [I4 staging] posture-blind 钉住格(2 格,P1 的翻转靶):携带 posture:'MEMBER' 的作用域 grant 持有者今天在 private 对象上仍豁免(read null——P1 后此格翻为 {organization_id:'org-1'});携带 PLATFORM_ADMIN rung 的真平台管理员豁免(P1 后不得变化)。
  • [D3 dead branch]:任何 capability-grant 证据组合都不派生 EXTERNAL

I1(TENANT_ADMIN 永不越 Layer 0)已由既有 Finding 2 格覆盖;I5/I6 在 posture 未进裁决前无断言对象,随 P1/P2 落格;EXTERNAL × layer 共享 fixture 格已在 posture-ladder.test.ts 语义锁,P3 扩展。

3. ADR-0099 转 Accepted(maintainer 决定,2026-07-18)

4. changeset

@objectstack/plugin-security patch(test-only,循 #3208 先例)。

验证

G1 裁决输入(分歧名单)

# 主体形态 今天(探针) P1 后(rung) 恢复路径
(a) 作用域 admin_full_access grant 在 private/platform-global/better-auth 对象上跨租户豁免 墙到自己 org 补授 unscoped admin_full_access
(b) 自定义集零散授平台专属能力(且另有超级位时) 同上 同上 同上

种子主体(platform_admin / org_admin / member / no-org)零变化

后续

Refs #3211 · ADR-0099 / #3109 · #2946 · #2949 · #2956

🤖 Generated with Claude Code

https://claude.ai/code/session_01DAHp4K7FvyMPBY1DPNkmRu


Generated by Claude Code

… accept ADR-0099

Land the P0 equivalence cells the ADR's phasing prescribed (#3211 M1) in
authz-matrix-gate.test.ts: seeded-shape probe/rung equivalence, two
adversarial KNOWN DIVERGENCE pins (scoped admin_full_access grant;
piecemeal platform-exclusive capability), the I2 nesting and I3
narrowing invariants, posture-blindness staging pins for the P1 flip,
and the EXTERNAL dead-branch cell. Extract the platform-admin capability
probe as the exported pure hasPlatformAdminCapability (mechanical).

Flip ADR-0099 to Accepted (2026-07-18) with an acceptance addendum
recording the divergence class and its P1 disposition (rung authority,
fail-safe narrowing, adjudicated at #3211 G1).

Test-only + docs; zero behavior change. plugin-security: 498 passed.

Refs #3211

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DAHp4K7FvyMPBY1DPNkmRu
@vercel

vercel Bot commented Jul 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 18, 2026 2:26pm

Request Review

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling and removed size/m labels Jul 18, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/plugin-security.

11 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/getting-started/cli.mdx (via @objectstack/plugin-security)
  • content/docs/permissions/access-recipes.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/authorization.mdx (via @objectstack/plugin-security)
  • content/docs/permissions/explain.mdx (via @objectstack/plugin-security)
  • content/docs/permissions/permissions-matrix.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/plugin-security)
  • content/docs/plugins/index.mdx (via @objectstack/plugin-security)
  • content/docs/plugins/packages.mdx (via @objectstack/plugin-security)
  • content/docs/releases/implementation-status.mdx (via @objectstack/plugin-security)
  • content/docs/ui/audience-based-interfaces.mdx (via packages/plugins/plugin-security)
  • content/docs/ui/dashboards.mdx (via @objectstack/plugin-security)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang marked this pull request as ready for review July 18, 2026 14:49
@os-zhuang
os-zhuang merged commit 2f3c641 into main Jul 18, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/authz-improvement-tasks-1f5u82 branch July 18, 2026 14:50
os-zhuang added a commit that referenced this pull request Jul 19, 2026
…ect scope bit; amendment + P2′ pins (#3211 M3/M3′) (#3245)

* docs(adr): ADR-0099 two-axis amendment — Layer 1 tier stays the per-object 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

* test(security): ADR-0099 P2′ — pin the per-object super-bit as the Layer 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

* chore: changeset for ADR-0099 P2′ two-axis matrix cells (#3211)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DAHp4K7FvyMPBY1DPNkmRu

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants