Skip to content

fix(lint): ADR-0105 D6 ② 的收件人词表扩至 ADR 原文范围 —— unit_and_subordinates 也判红 (#4991) - #5004

Merged
xuyushun441-sys merged 1 commit into
mainfrom
claude/issue-4991-d6-unit-and-subordinates
Aug 3, 2026
Merged

fix(lint): ADR-0105 D6 ② 的收件人词表扩至 ADR 原文范围 —— unit_and_subordinates 也判红 (#4991)#5004
xuyushun441-sys merged 1 commit into
mainfrom
claude/issue-4991-d6-unit-and-subordinates

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

Fixes#4991

问题

org-axis-cross-org-bu-grant(ADR-0105 D6 ②)此前只对一种收件人判红:

if(recipientType!=='business_unit')return;

ShareRecipientType 里有两个业务单元收件人,漏掉的那个授权面更大:

sharedWith.type展开改前改后
business_unit正好一个 BU 的成员判红 ✅判红 ✅
unit_and_subordinates该 BU 加上其全部后代单元(ADR-0057 D5)放行判红 ✅

两者的缺陷完全相同 —— 平台级对象(tenancy.enabled: false / systemFields.tenant: false)没有 organization 列可供 Layer 0 收口,BU 子树没有任何 organization 可供解析,授权因而跨到库里每一个 organization。而漏掉的恰恰是 ADR-0105 D6 ② 自己点名的那一个:

Every BU mechanism — unit_and_subordinates sharing, adminScope delegation, depth scopes — operates within one organization. There is no cross-org tree.

词表核对(本单的核心要求)

以 spec 的 ShareRecipientType(packages/spec/src/security/sharing.zod.ts,sharedWith.type 的唯一可写词表,.strict() 逐名拒绝其余)为准逐词交叉核对。五个成员,拦二放三,差集在规则注释里以表格逐条写明:

ShareRecipientType理由
business_unitBusinessUnitGraphService,org-predicated
unit_and_subordinates同一解析器,严格更宽的授权
user字面 user id,完全不展开,没有树可解析
teamsys_team 是扁平协作分组(ADR-0090 D3),走 TeamGraphService
position扁平 holder 展开(ADR-0090 D3 已终结职位层级),走 PositionGraphService;D6 ② 同时点名的 BU depth scope 是 scope 机制,不是 sharing-rule 收件人

差集是故意的,不是遗漏:放行的三个正是共享平台级目录的既定方式(ADR-0066)。② 禁止的不是"共享全局对象",而是"在没有 organization 可供解析的地方解析 BU 子树"。逐一按 plugin-sharingexpandRecipient 复核过运行时展开路径 —— 恰好只有两个走 BusinessUnitGraphService

运行时契约 SharingRuleRecipientType 另有 queue,刻意不可授权(没有 sys_queue),expandRecipient 对其返回 [],注释里一并记账。

结构性防复发

新增断言:拦截半 ∪ 放行半 == ShareRecipientType.options#4991 正是这条断言缺席的产物 —— ② 照着一个收件人写完就没回头看枚举。将来枚举加第六个成员会在词表处失败,而不是无声地落进没人选过的那一桶。

双向证明

全部 fixture 走 #4992 引入的 sharingRule() meta-guard(先经真 SharingRuleSchema 解析,spec 合法才算数):

  • 判红且点名:unit_and_subordinates + tenancy.enabled: false / systemFields.tenant: false 两种拼法均判红,message 含 `unit_and_subordinates` 与 "AND every descendant unit"
  • 不回归:business_unit 既有拦截保持,message 不含 "descendant"
  • 判绿:user / team / position 在平台级对象上放行;unit_and_subordinates 在 org-scoped 对象上放行(showcase 的真实形状)

真实元数据复核(未沿用 #4984 的预核,独立重跑)

把改后的规则真跑在仓库的真实元数据上,而非只 grep:

=== app-showcase ===
objects scanned: 21
tenancy-disabled objects: (NONE)
sharing rules: 8
- share_new_inquiries_with_field_ops: sharedWith.type=unit_and_subordinates object=showcase_inquiry
- (其余 7 条均为 position)
org-axis findings: 0
=== app-crm ===
objects scanned: 6
tenancy-disabled objects: (NONE)
sharing rules: 3 (均为 position)
org-axis findings: 0
TOTAL org-axis reds on real metadata (widened rule): 0

并复核了 examples 之外:全仓 sharedWith 的非测试出现点只有这两个 examples;default-permission-sets.ts / app-default-permission-set.ts 不含任何 sharing rule;tenancy.enabled: false 的非测试声明为零。扩张后零新红,结论与 #4984 的预核一致但为独立重跑所得。

验证

  • pnpm --filter @objectstack/lint testTest Files 55 passed (55) / Tests 1017 passed | 4 skipped (1021)
  • 目标文件 25 passed(改前 20)
  • pnpm --filter @objectstack/lint typecheck → 干净
  • npx eslint 两个改动文件 → 干净
  • changeset:@objectstack/lint patch

改动限于 packages/lint(2 个文件)+ 1 个 changeset。未触碰 content/docs/releases/


Generated by Claude Code

… 也判红 (#4991)
`org-axis-cross-org-bu-grant` 此前只拦 `sharedWith.type === 'business_unit'`,
放行了授权面更大的另一个业务单元收件人 `unit_and_subordinates`(一个 BU 加上其
全部后代单元,ADR-0057 D5 子树扩张)—— 恰恰是 ADR-0105 D6 ② 原文点名的那一个。
两者缺陷完全相同:平台级对象没有 organization 列,BU 子树无从解析,授权跨到库里
每一个 organization。判定改为收件人类型 ∈ { business_unit, unit_and_subordinates },
诊断点名实际写下的类型与其触及范围。
词表与 spec 枚举 `ShareRecipientType` 的差集不再隐式:注释逐条写明放行
`user` / `team` / `position` 的理由(运行时展开均不经 `BusinessUnitGraphService`),
并加断言两半恰好划分该枚举 —— 将来加枚举成员会在词表处失败。
复核真实元数据:全仓 11 条已声明 sharing rule、零个对象关掉 tenancy,
扩张后 org-axis 红线数为 0。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018iARDqtrhQgz6fVHDeDkbQ
@vercel

vercelBot commented Aug 3, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 3, 2026 8:03pm

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling labels Aug 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/lint.

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

  • content/docs/automation/hook-bodies.mdx(via @objectstack/lint)
  • content/docs/permissions/authorization.mdx(via @objectstack/lint)
  • content/docs/releases/v17.mdx(via @objectstack/lint)

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.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ADR-0105 D6 ② 只拦 business_unit 收件人,漏了 unit_and_subordinates —— 同一个跨 org BU 授权,更宽的那个反而放行

2 participants

@xuyushun441-sys@claude