Skip to content

Dev/michaelhu#364

Merged
Matrix-X merged 6 commits intodevelopfrom
dev/michaelhu
Mar 9, 2026
Merged

Dev/michaelhu#364
Matrix-X merged 6 commits intodevelopfrom
dev/michaelhu

Conversation

@Matrix-X
Copy link
Contributor

@Matrix-X Matrix-X commented Mar 9, 2026

Summary

  • 简述本次改动目标与范围

Changes

  • 列出核心改动点(代码/文档/配置)

Verification

  • 本地验证步骤已执行(请附关键命令/结果)

WS/TaskBus Contract Checklist(必填)

  • 本次是否涉及 WS/TaskBus(topic、publish/register、envelope、鉴权、tenant/trace)?
  • 若涉及,是否同步更新主契约:specs/004-eventbus-message-fabric/spec.md
  • 若涉及 WS 传输,是否同步更新:specs/023-websocket-notify/spec.mdspecs/023-websocket-notify/contracts/http-openapi.yaml
  • 是否运行一致性检查:bash scripts/specs/check_ws_taskbus_contracts.sh

Risks

  • 已评估兼容性/回滚影响

Matrix-X added 6 commits March 4, 2026 19:31
  1. plugin.enabled=false 时,插件菜单直接不返回

  - 文件:menus_agg.go
  - 行为:BuildPluginMenusPublic 开头读取全局配置,若 cfg.Plugin.Enabled == false,直接返回空菜单。

  2. 补了最小测试锁行为

  - 文件:menus_agg_test.go
  - 新增用例:
      - TestBuildPluginMenusPublicReturnsEmptyWhenPluginDisabled
      - TestBuildPluginMenusPublicReadsConfigFromEtcWhenGlobalNil
  - 后者确保在 GlobalConfig=nil 且从 etc/config.yaml 读取到 plugin.enabled: false 时,同样返回空菜单。

  验证

  - go test ./internal/transport/http/admin/plugin -count=1 通过。
  1. 关闭 PXAdmin 页面日志

  - 删除了这两处 console.log:
  - web-admin/app/pages/_p/[pluginId]/admin/[...rest].vue
  - web-admin/app/pages/_p/[pluginId]/admin/index.vue

  2. 过滤 iframe 内插件桥接日志(默认)

  - 在 PluginWebView 的 onLoad 注入了 console 前缀过滤,屏蔽:
  - [Bridge][Plugin] ...
  - [embedded] ...
  - 文件:
  - web-admin/app/components/PluginWebView.vue

  3. 保留“开发时打开”开关

  - URL 上加 ?px_debug=1 可临时开启日志。
  - 或运行时配置 public.pluginConsoleDebug=true 也可开启。

  说明

  - 这个过滤依赖 iframe 同源(你现在是 /_p/... 同源,生效)。
  - web-admin 没有 lint 脚本(已确认),所以没法跑 lint;脚本列表里只有 build/dev/test:unit/test:e2e。
  - 磁盘残留插件(未进入 registry、manager 不可用时兜底读到)标记为 state = "broken"。
  - 市场 v2 的 systemStatus 映射增加 broken。
  - 文件:
      - registry_fallback.go
      - market_handler.go

  2. 前端显示

  - 插件卡片新增红色 异常 Badge(当 systemStatus === "broken")。
  - 市场筛选新增 异常 选项。
  - 文件:
      - PluginCard.vue
      - market.vue

  3. 验证

  - go test ./internal/transport/http/admin/plugin -count=1 通过
  - cd web-admin && npm run build 通过
  - 保持严格策略:migrations.entry 缺失仍失败,不做静默跳过。
  - 修了插件迁移 DSN 时区编码问题(Asia%2FShanghai -> Asia/Shanghai)。
  - 文件:host_config.go、migrations.go、migrations_test.go

  2. 网页本地安装与接口行为不一致

  - 根因:目录上传走 multipart 时,后端只拿到 basename,目录层级被压平,backend/bin/migrate 变成根目录 migrate。
  - 修复:前端上传 file_paths;后端按 file_paths 还原相对目录。
  - 文件:InstallDialog.vue、install_handler.go

  3. 插件菜单显示规则

  - 后端菜单聚合改为仅 enabled 状态进入侧栏(installed/disabled 不显示)。
  - 文件:menus_agg.go

  4. 安装/卸载/启停后侧栏不自动刷新

  - 加了全局菜单刷新信号 px-menu-refresh-token。
  - 安装成功、插件详情页卸载/启停、已安装页启停都会触发;侧栏监听后调用 refreshMenus()。
  - 文件:InstallDialog.vue、Sidebar.vue、[id].vue、installed.vue

  5. 安装弹层无法下滑

  - 给弹层内容区加内部滚动:max-h-[80vh] overflow-y-auto。
  - 文件:InstallDialog.vue

  已跑过的测试

  - go test ./internal/infra/plugin/manager -count=1
  - go test ./internal/transport/http/admin/plugin -count=1
  1. standard_mapping.md
     内容:SKILL.md -> SkillManifest 字段映射、兼容策略、校验规则、版本策略、错误码建议。
  2. runtime_architecture.md
     内容:双路径运行时(Agent+Skill / Gateway+Skill)、三层决策(Intent/Planner/Executor)、Skill Resolver 融入现有 Intent 层、流程图、观测要求。
  3. api_contracts.md
     内容:Admin/Tenant/Plugin 接口契约、请求响应示例、统一返回结构、鉴权与错误码。
  4. data_model_and_registry.md
     内容:核心实体、状态机、版本与回滚、索引建议、与 Capability Registry 关系。
  5. security_and_governance.md
     内容:来源可信、权限边界、ToolGrant/safe mode、多租户隔离、审计字段、风险分级。
  6. plugin_third_party_integration.md
     内容:插件与第三方导入、绑定 capability、独立调用与 Agent+Skill 混合模式。
  7. testing_and_rollout.md
     内容:测试矩阵、验收标准、灰度与回滚、里程碑。
  8. skill_standard_definition.md
     内容:Skill 标准定义、使用原理、Agent 调度原理与流程图、开源 Skill 安装流程图、安装后三种使用模式(含不依赖 flow 的方式)、官方网络出处。
  9. examples/skill_manifest_example.md
     内容:标准与 PowerX 扩展示例、调用 payload 示例。
  10. test_use_cases/README.md
     内容:独立用例索引与执行顺序。
  11. 独立测试用例(每个用例一个文件,含步骤/预期/通过标准)

  - 01_manifest_parse.md
  - 02_publish_and_rollback.md
  - 03_agent_minimal_skill_execution.md
  - 04_intent_to_planner_decision.md
  - 05_gateway_protocol_skill.md
  - 06_authz_and_tenant_isolation.md
  - 07_open_source_skill_installation.md
  - 08_stability_regression.md

  更新文档

  1. management.md
     已改为总索引,并对齐新增文档导航(含 skill_standard_definition.md 与 test_use_cases)。
  1. 认证路由统一

  - 把底座与前端调用统一到 admin/{identity}/auth 策略。当前主路径:/admin/user/auth/*。
  - 清理了旧的 admin/auth 路径残留(路由、调用、文档同步)。

  2. 403/404 根因修复(之前)

  - /_p/.../admin/user/auth/* 原来会被网关当插件 API 处理,先鉴权再改写 token,导致 403/404/401 混杂。
  - 现在身份路由不再走插件语义链路。

  3. 401 根因修复(关键)

  - 网关 /_p/:id/api/* 原本会 mintPluginToken 并覆盖 Authorization,这对插件业务 API 合理,但对用户身份接口不成立。
  - 已改为:命中 admin/{identity}/auth/* 时,从 /_p 自动重定向到宿主 /api/v1/admin/{identity}/auth/*,避免插件 token 混入用户会话。
  - 位置:
    router.go

  4. 文档对齐

  - 明确写入规则:
      - /_p/:id/api/* 只用于插件业务 API
      - /api/v1/admin/{identity}/auth/* 必须走宿主主路由
  - 已更新:RBAC/SSO/插件运行手册等文档。

  5. 菜单版本显示(你刚确认“终于对了”)

  - 后端菜单 DTO 增加 pluginVersion 并在插件菜单聚合时透传。
  - 菜单合并阶段把版本带到插件分组 header(POWERX BASE PLUGIN 这一行)。
  - 前端改为只在该分组标题显示版本,不在子菜单(如 Templates)显示。
  - 关键位置:
    menu.go
    menus_agg.go
    merge_handler.go
    Sidebar.vue
    SidebarMenuItem.vue

  6. 插件版本卸载策略

  - 调整为:卸载当前版本时清理该插件历史版本,避免“删新留旧”造成歧义与脏数据。

  7. 当前结论

  - 你现在这条插件链路已可正常使用:
      - 身份认证走宿主
      - 插件业务走 /_p
      - 左侧插件分组版本显示位置正确。
@Matrix-X Matrix-X merged commit a83f1f4 into develop Mar 9, 2026
1 check passed
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 408ac2e623

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +104 to +106
catalogPath := filepath.Join(root, filepath.Clean(relPath))
if !strings.HasPrefix(filepath.Clean(catalogPath), filepath.Clean(root)) {
return plugin_mgr.NewError(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 用可靠的子路径校验阻止 catalog 路径逃逸

这里的逃逸校验使用了 strings.HasPrefix 比较清理后的绝对路径,无法区分兄弟目录前缀(例如 root=/tmp/plugin 时,/tmp/plugin-secret/... 也会通过),因此 catalogs.* 可以通过 ../ 读取插件根目录外的文件。该问题会在安装/加载带 catalog 的插件时触发,属于明确的路径穿越风险,建议改为 filepath.Rel/isSubPath 这类基于路径段的判断。

Useful? React with 👍 / 👎.

Comment on lines +116 to +118
root := strings.TrimSpace(p.Paths.Root)
if root != "" {
_ = os.RemoveAll(root)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 在 fallback 卸载中限制 purge 删除路径范围

当插件管理器不可用时,卸载回退逻辑会直接对 registry 中的 p.Paths.Root 执行 os.RemoveAll,没有像主卸载流程那样校验是否仍位于 installed root 下。只要 registry 文件被手工修改、损坏或写入异常路径,purge=true 就可能删除任意目录,属于高风险数据破坏问题。

Useful? React with 👍 / 👎.

Comment on lines +673 to +676
traceID := strings.TrimSpace(c.GetHeader("X-Trace-Id"))
if traceID == "" {
traceID = strings.TrimSpace(c.GetHeader("X-Trace-ID"))
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 从 Gin 上下文转发生成的 trace/request ID

TraceInjectionMiddleware 会在缺少请求头时生成 trace_id/request_id 并写入 Gin context,但这里转发到插件上游时只读取原始请求头;对未携带 X-Trace-* 的常见浏览器请求,上游将收不到这些 ID,导致新增的链路追踪在插件调用链上断裂。建议优先读取 c.Get("trace_id")/c.Get("request_id") 再回退到 header。

Useful? React with 👍 / 👎.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant