feat(plugins): 插件管理器接线 —— 面板接入点快照 + 动作分发(PLG-2)

- GET /api/v1/admin/panels:按调用者角色过滤后的接入点快照(PLG-1 的 catalog 挂进插件管理器)
- POST /api/v1/admin/plugins/{id}/actions/{action}:**只接受该插件声明过的动作名**
  (未声明 ⇒ 404);写动作 writeAuth + 落审计;插件只给动作名不给 URL ⇒ 不给插件开任意请求面
- 生命周期:install/uninstall/enable/disable 变化后**重算面板集合**并经进程内 bus 推 panels_changed
  (前端可热更新;不新开端口)

契约 v0.78 登记由主会话随后统一落(本片报告给了可直接粘贴的契约段)。
This commit is contained in:
AskaEth committed 2026-10-06 09:03:57 +08:00
1 parent c907a34510
commit 2d21aa553e
9 files changed
+1990 -6

No files matched your search

+10
View File
@@ -162,6 +162,16 @@ func (s *Server) registerAdminRoutes(
// 任何新的持久化模型。
mux.Handle("GET /api/v1/admin/notifications", viewerAuth(http.HandlerFunc(s.adminListNotifications)))
// 插件管理面板的**唯一契约面**(design/09 §5.2.1;切片 PLG-2):
// - GET /admin/panels 是**按调用者角色过滤后**的接入点快照,走 viewerAuth ——
// viewer 拿到的是已被裁掉写面的只读投影(§5.4.1),因此这条读门不越权;
// - 动作端点走 viewerAuth,是因为 table/log 的 **source 读来源**动作对 viewer
// 可见;**写**动作(form 的 submit、table 的 rowActions)由 handler 内再按
// owner|admin 收紧(callerHasWrite,见 admin_panels.go),与「写动作一律
// writeAuth」逐字对齐 —— 路由中间件只能有一道门,写面的门因此落在 handler 里。
mux.Handle("GET /api/v1/admin/panels", viewerAuth(http.HandlerFunc(s.adminListPanels)))
mux.Handle("POST /api/v1/admin/plugins/{id}/actions/{action}", viewerAuth(http.HandlerFunc(s.adminPluginAction)))
// 保留给 owner/admin 的管理读:私有内容、其他账号的
// 数据与审计链。不对 viewer 开放。
mux.Handle("GET /api/v1/admin/memories", writeAuth(http.HandlerFunc(s.adminListMemories)))