Skip to content

fix(security): revoke package permission rows on uninstall — no ghost grants (#2747) - #2760

Merged
os-zhuang merged 2 commits into
mainfrom
claude/loving-knuth-y1g4d3
Jul 10, 2026
Merged

fix(security): revoke package permission rows on uninstall — no ghost grants (#2747)#2760
os-zhuang merged 2 commits into
mainfrom
claude/loving-knuth-y1g4d3

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

摘要

修复 #2747:此前卸载包只删 sys_metadata 行和 sys_packages 持久化记录,包属数据面权限行原样保留——卸载后授权继续生效(ghost grants),违反 ADR-0090 D5 的 "uninstalling the package revokes it everywhere at once"。而且排查发现线上(hono/rest)栈的 DELETE /api/v1/packages/:id 只执行裸 DELETE FROM sys_packages,连元数据清理都没走。

metadata-protocol

  • deletePackage 新增卸载清理接缝(与发布物化器完全对镜):领域插件通过 registerUninstallCleanup(name, fn) 注册具名清理,每个清理拿到被卸载的 packageId 执行,结果上报在响应新增的 cleanups 数组——撤销失败(安全事件)对调用方可见,绝不静默。
  • deletePackage 顺带把包从内存 SchemaRegistry 卸载(best-effort),运行中的内核立即停止服务该包,不必等重启(dispatcher 原本单独做这步,rest 路由完全没做)。

plugin-security

  • 注册 security.package-permissions 清理:删除该包自有的 sys_permission_set 行(仅 managed_by:'package'package_id 匹配——环境自建与他包的行绝不触碰,ADR-0086 D4)、指向它们的 sys_position_permission_set / sys_user_permission_set 绑定(先删绑定,不留悬挂授权),以及该包的 sys_audience_binding_suggestion 行(重装后重新提示,D5)。
  • 顺带修复建议模块的引擎调用签名:find/deletecontext第二个参数里;此前尾随的 { context } 参数被忽略,删除以无主体上下文执行(D12 门禁对受治理表正确地 fail closed——这正是首次 e2e 里只删掉 1 行的根因)。

rest

  • DELETE /api/v1/packages/:id(不带 version)改走 protocol.deletePackage——一个卸载语义,不再是三种方言;响应携带 deletedCount + cleanups。带 ?version= 的删除保留原有窄语义(仅持久化注册表)。

测试与验证

  • 新增单测:cleanup-package-permissions.test.ts(4 用例:全量回收、provenance 保护、幂等、空参兜底)、durable-package.test.ts 新增 3 用例(清理钩子调用/失败上报/幂等替换)。
  • pnpm turbo test(metadata-protocol、plugin-security、rest 及全部下游)75 个任务全绿。
  • 真实环境端到端(fresh showcase):确认建议产生绑定 → DELETE /api/v1/packages/com.example.showcasecleanups: [{name: 'security.package-permissions', removed: 10}](8 权限集 + 1 绑定 + 1 建议),库中包属行清零,平台/环境自有权限集(4 个)原样保留。

Closes#2747

🤖 Generated with Claude Code

https://claude.ai/code/session_01DP13MuGwFWLcVxVtuA7rgq


Generated by Claude Code

… grants (#2747)
Uninstall previously removed only sys_metadata rows and the durable
sys_packages record; the package's data-plane permission rows survived,
so grants kept working after uninstall (ghost grants), violating
ADR-0090 D5's "uninstalling the package revokes it everywhere at once".
metadata-protocol:
- deletePackage gains an uninstall-cleanup seam (mirror of the publish
materializer): registerUninstallCleanup(name, fn); outcomes reported
on the response's new `cleanups` array — a failed revocation is
visible, never silent
- deletePackage also unregisters the package from the in-memory
SchemaRegistry (best-effort), so the running kernel stops serving it
without waiting for a restart
plugin-security:
- registers the security.package-permissions cleanup: deletes the
package's own sys_permission_set rows (managed_by 'package' +
matching package_id only — env-authored/foreign rows never touched,
ADR-0086 D4), their position/user bindings (bindings first), and the
package's sys_audience_binding_suggestion rows
- fixes the engine-call signature in the suggestion module: find/delete
read `context` from their second argument; the previous trailing
{ context } arg was ignored, so deletes ran principal-less (the D12
gate correctly failed them closed on governed tables)
rest:
- DELETE /api/v1/packages/:id (no version pin) now goes through
protocol.deletePackage — one uninstall semantic, not three dialects;
response carries deletedCount + cleanups. Version-scoped deletes keep
the narrow durable-registry semantics
Verified end-to-end on a fresh showcase: confirm a suggestion (binding
created) → DELETE the package → cleanups removed 10 rows (8 sets +
1 binding + 1 suggestion), zero package rows left, platform/env sets
untouched. 75 turbo test tasks green across affected packages.
Closes#2747
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DP13MuGwFWLcVxVtuA7rgq
@vercel

vercelBot commented Jul 10, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
specCanceledCanceledJul 10, 2026 9:00am

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling size/m labels Jul 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/metadata-protocol, @objectstack/plugin-security, @objectstack/rest.

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

  • content/docs/api/error-catalog.mdx(via @objectstack/rest)
  • content/docs/api/error-handling-server.mdx(via @objectstack/rest)
  • content/docs/api/index.mdx(via @objectstack/rest)
  • content/docs/concepts/metadata-lifecycle.mdx(via @objectstack/metadata-protocol)
  • 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 packages/plugins/plugin-security, packages/rest)
  • 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, @objectstack/rest)
  • content/docs/plugins/packages.mdx(via @objectstack/plugin-security, @objectstack/rest)
  • content/docs/releases/implementation-status.mdx(via @objectstack/plugin-security, @objectstack/rest)
  • content/docs/ui/dashboards.mdx(via @objectstack/plugin-security)
  • content/docs/ui/role-based-interfaces.mdx(via packages/plugins/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 10, 2026 09:24
@os-zhuang
os-zhuang merged commit 1056c5f into mainJul 10, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/loving-knuth-y1g4d3 branch July 10, 2026 09:24
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.

Package uninstall does not clean up data-plane permission rows by package_id (ADR-0086 D3 wiring gap)

2 participants

@os-zhuang@claude