feat(core,plugin-security): B2+B4 — posture 阶梯 + capability 派生 (ADR-0095 D2/D3, #2920)#2938
Merged
Merged
Conversation
…(ADR-0095 D2/D3, #2920) Resolve an explicit monotonic posture rung (PLATFORM_ADMIN > TENANT_ADMIN > MEMBER > EXTERNAL) once in resolveAuthzContext and carry it on ResolvedAuthzContext.posture. D2 — new @objectstack/core/security module posture-ladder.ts reuses the spec AuthzPosture enum, pins the rung -> injection-rule mapping (one rule per rung), and locks its two ADR-required invariants as unit tests: strict nesting (rung n's visible set superset of n-1) and EXTERNAL deny-by-default (explicit shares only; OWD never widens it). EXTERNAL is defined/test-locked but never resolved (no external principal type yet); the floor is MEMBER. D3 — the rung derives from held capability grants, never a better-auth role: PLATFORM_ADMIN from the unscoped admin_full_access grant (the same viewAllRecords/modifyAllRecords evidence the superuser bypass trusts), TENANT_ADMIN from the organization_admin grant. The better-auth role remains a provisioning source only (auto-org-admin-grant.ts, mapMembershipRole); no enforcement path adjudicates the raw role, closing the #2836 dual-track class. Behavior-preserving: enforcement is unchanged (per-object Layer 0 exemption + per-side superuser bypass still gate access); posture is an additive derived, explainable field. authz-matrix-gate + dogfood authz-conformance stay green. - spec: add ORGANIZATION_ADMIN constant; auto-org-admin-grant.ts reuses it. - resolve-authz-context.test.ts: principal x grants -> posture matrix + nesting. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019QRUvVfpvSycAHMMF2xTxs
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 3 package(s): 109 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This was referenced Jul 15, 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.
概述
授权内核链第二段(#2920 的 B2 + B4),落地已合并的 ADR-0095 D2(单调 posture 阶梯)+ D3(posture 从 capability 派生)。基于 B1(Layer 0,已并入 main)。
行为保持。 enforcement 未改动——每对象的 Layer 0 豁免 + 每侧 superuser bypass 仍按原样裁决;
posture是一个 附加的、派生的、可解释的字段。authz-matrix-gate单元快照与 dogfood authz-conformance 全绿。无迁移。设计
B2 — posture 阶梯(D2)
resolveAuthzContext现解析并携带显式posture,复用 spec 的AuthzPosture枚举(explain.zod.ts,PLATFORM_ADMIN>TENANT_ADMIN>MEMBER>EXTERNAL);ResolvedAuthzContext新增posture?字段。packages/core/src/security/posture-ladder.ts:钉住每档恰好一条行可见性注入规则的映射(POSTURE_INJECTION_RULE),并把 ADR 要求的两条不变量作为单测锁死:postureVisibleRows参考模型,union-with-previous 构造,按构造单调)。MEMBER。resolve-authz-context.test.ts升级为principal × grants → posture矩阵 + 嵌套断言。B4 — posture 从 capability 派生(D3)
PLATFORM_ADMIN← 非作用域admin_full_access授予(即 superuser bypass 信任的viewAllRecords/modifyAllRecords证据)。TENANT_ADMIN←organization_admin授予。role='admin'仅作为授予 org_admin 岗位/organization_admin capability 的 provisioning 来源(auto-org-admin-grant.ts+resolveAuthzContext的mapMembershipRole投影,已加注释标注为唯一 provisioning 边界)。ORGANIZATION_ADMIN(org-admin capability 授予名),与既有ADMIN_FULL_ACCESS并列;auto-org-admin-grant.ts复用之,消除本地字面量。行为 delta
无。 这是纯粹的 behavior-preserving 变更:只新增一个派生字段与其不变量测试,未触碰任何 enforcement filter 计算。
消除 better-auth role 双轨的证据(grep)
全仓 grep enforcement 相关包(
plugin-security/core/security/plugin-sharing/runtime/security/rest)确认:当前主体的 admin 层 / posture 裁决绝不读sys_member.role——permission-evaluator与computeRlsFilter的 bypass 只读 capability 位(viewAllRecords/modifyAllRecords)与已归一化的ctx.positions。唯一在 enforcement 时读
sys_member.role的点是plugin-sharing/team-graph.ts的expandRoleUsers(roleName)——这是共享规则收件人/受众的正向群展开(ADR-0057 D4 过渡来源),按任意传入的roleName反查成员 user_id,不裁决请求主体的 admin 层,也不产生 #2836 类 deny-vs-allow 合成冲突。属既有机制、正确且超出本任务范围,未改动。验证(实测)
pnpm --filter @objectstack/core test— 339 passed(含新posture-ladder.test.ts+ posture 矩阵)。pnpm --filter @objectstack/plugin-security test— 366 passed(authz-matrix-gate保持绿,未改一格)。pnpm --filter @objectstack/spec test— 6777 passed(含 api-surface check;新增ORGANIZATION_ADMIN)。authz-conformance账本 — passed。rls-multitenant/rls-fixture/showcase-private-owd/showcase-public-read-owd/showcase-permission-zoo/two-doors-permission/showcase-bu-hierarchy-sharing/showcase-permission-projection/showcase-permission-seeding— 全绿(44 tests)。Reviewer checklist
admin_full_access/organization_admincapability 授予),未引入对 better-auth role 的 enforcement 读。EXTERNAL已定义 + 注入规则 + 语义锁测,但解析器永不返回(占位指向 ADR-0093)。postureVisibleRows)。authz-matrix-gate与 dogfood 全绿。ORGANIZATION_ADMIN作为 spec 常量单一真源,auto-org-admin-grant.ts已复用。ExecutionContext/ explainprincipal.posture——β 引擎消费为 C-phase follow-up;本 PR 刻意止步于解析器层,保持 blast radius 最小(含 OAuth agent 天花板的边界处理留待后续)。🤖 Generated with Claude Code
https://claude.ai/code/session_019QRUvVfpvSycAHMMF2xTxs
Generated by Claude Code