fix(security): revoke package permission rows on uninstall — no ghost grants (#2747) - #2760
Merged
Conversation
… 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
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 3 package(s): 14 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
…l-defined (#2747) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP13MuGwFWLcVxVtuA7rgq
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.
摘要
修复 #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/delete的context在第二个参数里;此前尾随的{ 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 个任务全绿。DELETE /api/v1/packages/com.example.showcase→cleanups: [{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