Skip to content

feat(plugin): 接入标准运维开放插件运行时与治理能力#698

Open
dengyh wants to merge 34 commits into
TencentBlueKing:masterfrom
dengyh:feat/sops-open-plugin-backend
Open

feat(plugin): 接入标准运维开放插件运行时与治理能力#698
dengyh wants to merge 34 commits into
TencentBlueKing:masterfrom
dengyh:feat/sops-open-plugin-backend

Conversation

@dengyh

@dengyh dengyh commented Apr 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • 接入 uniform_api v4.0.0,补齐标准运维开放插件目录索引、空间治理、回调鉴权与任务运行时接入
  • 新增开放插件快照、版本状态回填与 plugin_source 统计维度扩展
  • 同步更新 APIGW 资源定义、中文文档与测试脚本环境兜底

Test Plan

  • pytest -o addopts='' tests/plugins/uniform_api/test_uniform_api_client.py tests/plugins/components/collections/uniform_api_test tests/interface/plugin/services/test_plugin_schema_service.py tests/interface/space/test_space_views.py tests/interface/apigw/test_list_plugins.py tests/interface/apigw/test_get_plugin_schema.py tests/interface/apigw/test_operate_task.py tests/interface/apigw/test_operate_task_node.py -q
  • pytest -o addopts='' tests/interface/statistics tests/engine/statistics -q
  • git diff --check -- bkflow tests scripts

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review Summary

大体量 PR,整体架构合理——uniform_api v4.0.0 协议扩展、开放插件目录索引 + 空间治理、回调鉴权与快照体系都方向正确,文档与 APIGW 资源同步也已覆盖。以下几点值得关注:

需要修复

  1. create_taskcollect_plugin_references 被重复调用 3 次(validate → build_reference → build_schema),每次内部都有 N+1 查询。建议抽取为一次调用,传递结果给后续方法。
  2. collect_plugin_references 存在 N+1 查询——循环内逐条查 OpenPluginCatalogIndexSpaceOpenPluginAvailability,在任务创建/模板保存等 API 路径上会放大。建议批量预取。
  3. 📄 backfill_open_plugin_snapshots.py 缺少开源协议头,项目规范要求每个新增 Python 文件顶部包含 MIT 许可声明。

建议优化

  1. enable_all_visible_plugins 循环调用 update_or_create,可改为 bulk_create + update 提升批量开启效率。
  2. _refresh_catalog_index 的循环 update_or_create 在低频同步场景可接受,若后续插件量增长可考虑批量化。
  3. SpaceViewSet 新增 4 个 open_plugin action,当前继承的 AdminPermission | SpaceSuperuserPermission | SpaceExemptionPermission 足够(空间管理功能),确认符合预期。

username=request.user.username,
scope_type=template.scope_type,
scope_id=template.scope_value,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

validate_pipeline_treebuild_reference_snapshotbuild_schema_snapshot 各自内部都调用了 collect_plugin_references,等于同一棵 pipeline_tree 被扫描了 3 遍且每次都有 N+1 查询。建议改为调用一次 collect_plugin_references,将结果传给后续方法复用。

if not plugin_id:
continue

catalog = cls._get_catalog_entry(space_id=space_id, plugin_id=plugin_id, source_key=source_key)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚡ 循环内逐条调用 _get_catalog_entry(ORM query)和 SpaceOpenPluginAvailability.objects.filter().exists(),对于含多个开放插件节点的 pipeline 会产生 2N 次查询。建议在循环前批量 filter(plugin_id__in=...) 预取 catalog 和 availability map。

@@ -0,0 +1,89 @@
from django.core.management.base import BaseCommand

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📄 缺少项目要求的开源协议头(MIT License),其他新增 .py 文件如 open_plugin_callback.pyopen_plugin_catalog.py 等都已包含。请补齐。

catalog_qs = catalog_qs.filter(source_key=source_key)

updated = []
for item in catalog_qs.only("source_key", "plugin_id"):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚡ 循环内调用 toggle_plugin(即 update_or_create),若空间内可用插件较多(如 100+)会产生 200+ 次查询。建议改为先 filter().update(enabled=True) 批量更新存在的记录,再 bulk_create 缺失记录。

Comment thread bkflow/apigw/views/operate_task_node.py Outdated
@return_json_response
def operate_task_node(request, space_id, task_id, node_id, operation):
data = json.loads(request.body)
if _is_open_plugin_callback_request(operation, data):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 开放插件回调分支在 Serializer 校验之前拦截,绕过了 OperateTaskNodeSerializer 的参数校验。当前 _handle_open_plugin_callback 内部有完整的 token 验签 + 字段提取逻辑,但 data["open_plugin_run_id"] 在第 81 行直接作为查询条件使用而未做格式校验——建议至少校验其非空且为合法字符串。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ 同上,此问题已通过引入独立的 /open_plugin_callback/ 入口解决,回调不再经过 operate_task_node 路径,无需绕过 Serializer 校验。

@classmethod
def get_snapshot_node_statuses(cls, space_id, extra_info):
statuses = {}
for ref in cls.get_reference_snapshot(extra_info):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚡ 与 collect_plugin_references 类似,get_snapshot_node_statuses 也在循环内逐条查 catalog + availability。若此方法会在高频路径上被调用,同样建议批量预取。

@tencentblueking-adm

tencentblueking-adm commented Jun 16, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
2 out of 3 committers have signed the CLA.

✅ dengyh
✅ Mianhuatang8
❌ dannydeng


dannydeng seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

新增 5 个提交引入了「开放插件来源准入」(OpenPluginSpaceGrant)两层校验,覆盖了查询、目录、模板保存、建任务、启动任务等路径,测试覆盖充分。

先前问题状态

先前审查报告的 6 个行内问题(collect_plugin_references 3x 调用、N+1 查询、缺少协议头、enable_all_visible_plugins 循环 update_or_create、open_plugin_run_id 格式校验、get_snapshot_node_statuses N+1)均未在本次增量提交中修改,维持原状。

新发现

  1. ⚠️ 数据迁移 0005 直接 import Service 类操作模型,未使用 apps.get_model(),有潜在迁移稳定性风险
  2. 📄 grant_open_plugin_source.py 缺少开源协议头
  3. validate_pipeline_tree 中新增的 is_granted 逐条查询可优化为批量预取
  4. ⚠️ _raise_uniform_api_catalog_access_error 可能静默 fallthrough,调用点紧跟另一个 raise,两条路径错误信息粒度不一致



def forwards(apps, schema_editor):
from bkflow.plugin.services.open_plugin_grant import OpenPluginGrantService

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ 数据迁移中直接 import OpenPluginGrantService(及其内部依赖 OpenPluginCatalogService / SpaceConfig / UniformAPIConfigHandler),绕过了 Django migration state。如果后续迁移修改了 OpenPluginSpaceGrantSpaceConfig 的字段,这个迁移可能会在全新环境跑 migrate 时报错。建议改用 apps.get_model() 操作,或至少将 import 包在 try/except 中并跳过失败。

@@ -0,0 +1,30 @@
from django.core.management.base import BaseCommand

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📄 新增文件缺少项目要求的 MIT 开源协议头,与同目录 backfill_open_plugin_snapshots.py 存在相同问题。

):
if ref["catalog"] is None:
raise serializers.ValidationError("开放插件 [{}] 不存在或已下线".format(ref["plugin_id"]))
if not OpenPluginGrantService.is_granted(space_id, ref["catalog"].source_key):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

is_grantedcollect_plugin_references 返回的每个 ref 循环内逐条调用,产生 N 次 DB exists() 查询。因为一个 pipeline 中不同 source_key 数量通常很少,可以在循环前一次性 granted_source_keys = set(OpenPluginGrantService.granted_source_keys(space_id)),循环内用 in 判断。

api_item["_meta_url"] = self._build_uniform_api_meta_url(api_item, version)

if not api_item or not api_item.get("_meta_url"):
self._raise_uniform_api_catalog_access_error(code)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ _raise_uniform_api_catalog_access_error 仅在 catalog 记录存在且匹配特定状态时才 raise,否则静默返回 None,然后执行到下一行的 raise ValueError。两个 raise 路径给出不同粒度的错误信息,建议统一:要么让 helper 总是 raise(找不到 catalog 时也抛带上下文的异常),要么将其返回错误信息字符串由调用方 raise。

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

新增 2 个提交:080c649 引入开放插件业务版本强校验,3545dec 合并 master 解决冲突。

新增代码评估

版本校验实现质量良好:

  • OpenPluginCatalogIndex.is_plugin_version_available 逻辑清晰,空列表兜底合理
  • PluginSchemaService._validate_uniform_api_plugin_version 在两处入口(_get_uniform_api_schema_get_single_by_type)均正确调用,拦截时机在远程请求之前,避免无效网络开销
  • _get_uniform_api_schema 中条件从 if version 改为 if api_item and version,修复了 api_itemNone 时的潜在 AttributeError
  • 测试覆盖了 snapshot 层和 schema 层的拒绝路径,且验证了远程 client 未被调用(mock_client_cls.assert_not_called()

先前问题状态

前两轮审查报告的 10 个行内问题(collect_plugin_references 3x 调用、N+1 查询、缺少协议头、循环 update_or_createopen_plugin_run_id 格式校验、迁移直接 import Service、is_granted 逐条查询、_raise_uniform_api_catalog_access_error 双 raise 路径)均未在本次增量提交中修改,维持原状。

结论

本次增量无新问题,代码实现简洁、测试充分。

@codecov-commenter

codecov-commenter commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 77.96976% with 306 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.03%. Comparing base (9a63478) to head (295f7ee).
⚠️ Report is 9 commits behind head on master.

Files with missing lines Patch % Lines
...ugins/components/collections/uniform_api/v4_0_0.py 53.36% 111 Missing ⚠️
bkflow/task/operations.py 51.51% 64 Missing ⚠️
bkflow/plugin/services/open_plugin_snapshot.py 84.66% 25 Missing ⚠️
...agement/commands/backfill_open_plugin_snapshots.py 62.06% 22 Missing ⚠️
bkflow/api_plugin_demo/v4.py 80.55% 21 Missing ⚠️
bkflow/plugin/services/plugin_schema_service.py 80.51% 15 Missing ⚠️
.../pipeline_plugins/query/uniform_api/uniform_api.py 86.13% 14 Missing ⚠️
bkflow/plugin/services/open_plugin_catalog.py 93.44% 8 Missing ⚠️
bkflow/interface/views.py 72.00% 7 Missing ⚠️
bkflow/plugin/models.py 93.75% 4 Missing ⚠️
... and 9 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #698      +/-   ##
==========================================
- Coverage   83.10%   83.03%   -0.07%     
==========================================
  Files         307      316       +9     
  Lines       18167    19513    +1346     
==========================================
+ Hits        15098    16203    +1105     
- Misses       3069     3310     +241     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

最新提交 6874eac 仅修复 lint 格式问题(__init__.py 尾空行、migration 文件行宽、测试文件 import 排列),无逻辑变更,无新问题。

先前问题状态

前三轮审查报告的 10 个行内问题(collect_plugin_references 3x 调用、N+1 查询、缺少协议头、循环 update_or_createopen_plugin_run_id 格式校验、迁移直接 import Service、is_granted 逐条查询、_raise_uniform_api_catalog_access_error 双 raise 路径)均未在本次增量提交中修改,维持原状。

结论

本次增量无新问题。纯代码风格修正,符合项目 lint 规范。

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

最新提交 91e603cb 新增 open plugin v4 协议演示接口(api_plugin_demo),包含 list_meta / detail_meta / execute / status / cancel 五个 demo endpoint 及对应测试。代码整体结构清晰,demo 数据使用常量 + copy.deepcopy 防止污染,v4 协议字段覆盖完整。

先前问题状态

前四轮审查报告的行内问题(collect_plugin_references 3x 调用、N+1 查询、缺少协议头、循环 update_or_create、迁移 import 风险等)均未在本次提交中修复,仍处于待处理状态。

新增代码问题

本次新增 2 个 Minor 级别问题(见行内评论)。

@@ -0,0 +1,99 @@
"""

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📄 新增测试目录 tests/interface/api_plugin_demo/ 缺少 __init__.py(同目录其他包如 apigw/plugin/space/ 均有),可能导致 pytest 无法正确发现测试。同时本文件缺少项目要求的 MIT 开源协议头。

Comment thread bkflow/api_plugin_demo/views.py Outdated
"""
Open Plugin V4 List Meta API - 获取 stage 联调用开放插件目录。
"""
limit = int(request.query_params.get("limit", 50))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ int(request.query_params.get("limit", 50)) 对非数字字符串(如 ?limit=abc)会直接抛 ValueError 导致 500。虽然是 demo 接口,建议加 try/except 或使用 Serializer 做参数校验以保持一致的错误响应格式。

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

最新提交 28eb0958 将开放插件回调验证逻辑从 interface 层 (operate_task_node.py) 下沉到 engine 层 (TaskNodeOperation._handle_open_plugin_callback),同时将 OpenPluginRunCallbackRef 模型从 plugin app 迁移至 task app。重构方向正确——回调鉴权与状态判定移到引擎侧更贴近执行语义,interface 只做透传。

先前问题状态

  • 🔒 operate_task_node.py:136 绕过 Serializer 校验:✅ 此问题已通过将校验下沉至 engine 解决,engine 层有完整的 token 验签 + callback_ref 校验链路
  • 其余先前报告的问题(collect_plugin_references 3x 调用、N+1 查询等)不在本次增量范围内,状态未变

新增代码小结

  • 迁移策略合理:plugin.0006 删除旧表 + task.0016 创建新表,因模型是本 PR 新增、尚无生产数据,不需要 data migration
  • 测试覆盖良好:4 个新增测试用例覆盖了 valid/invalid token、幂等、terminal state 等核心路径
  • 回调 token 验签流程在 engine 侧实现完整且安全(token 解密 → 过期检查 → DB ref 匹配 → 消费幂等 → 状态判定 → bamboo callback)

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

最新 2 个提交:28eb0958OpenPluginRunCallbackRef 模型和回调验证逻辑从 interface 层 (plugin app) 下沉到 engine 层 (task app),同时将 cancel 逻辑集成到 revokeforced_fail 操作中;b9440b34 纯文档新增,无代码变更。

架构评估

模型下沉方向正确——OpenPluginRunCallbackRef 的生命周期完全在 engine 内(组件执行时创建、回调时消费、取消时清理),放在 task app 下消除了跨模块 ORM 操作问题。plugin/services/open_plugin_callback.py 保留 re-export 做向后兼容也是合理的。

先前问题状态

  • operate_task_node.py:136 回调绕过 Serializer:✅ 此问题已通过架构变更解决——回调数据现在直接透传到 engine,由 _handle_open_plugin_callback 做完整的 token 验签和字段提取。

新发现问题(见行内评论)

  1. ⚠️ 迁移缺数据迁移步骤(部署风险)
  2. cancel_open_plugin_runs_for_task 同步串行 HTTP 调用(潜在阻塞)

@@ -0,0 +1,59 @@
# Generated by Django 3.2.25 on 2026-07-03 08:31

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ 模型从 plugin app 迁移到 task app(不同 DB 表),但没有数据迁移步骤。部署时 plugin_openpluginruncallbackref 中仍在飞行的回调记录会丢失。建议增加 RunPython 迁移 consumed_at IS NULL 的记录,或在 release notes 中注明部署窗口需确保无进行中的开放插件回调。

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

最新 3 个提交(bfd6b27fb3b9cc0c28eb0958)完成了两项重构:

  1. 将 v4 demo 从 views.py/plugins.py 拆分到独立的 v4.py,URL 路径从 open_plugin_v4/ 简化为 v4/
  2. 将回调验证逻辑和 OpenPluginRunCallbackRef 模型下沉到 engine 层(task app),interface 层只做透传

整体方向正确:engine 层统一管理回调状态与鉴权,网关资源收敛为 GET/POST 两个 matchSubpath 入口减少维护成本。

先前问题状态

  • operate_task_node.py:136 回调绕过 Serializer:✅ 此问题已通过架构变更解决——验签逻辑完整下沉到 engine
  • task/migrations/0016 缺数据迁移:已在上轮说明新功能无生产数据,维持原状
  • cancel_open_plugin_runs_for_task 同步串行 HTTP:不在本次增量范围,维持原状
  • tests/interface/api_plugin_demo/__init__.py 缺失:仍未修复

新发现

见行内评论(2 条)。


def _build_open_plugin_callback_payload(data):
callback_payload = {
"open_plugin_run_id": data["open_plugin_run_id"],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ 回调请求跳过了 Serializer 校验,但 _build_open_plugin_callback_payload 直接访问 data["status"]。若请求体只包含 open_plugin_run_id 而缺少 status,会触发未处理的 KeyError 导致 500。建议加 data.get("status", "") 或提前检查必填字段。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ 此问题已通过架构调整解决。最新提交将回调 URL 从 APIGW operate_task_node 路径改为独立的 /open_plugin_callback/ 内部入口,该入口在转发前显式校验 open_plugin_run_idstatus 字段存在性,不再有 KeyError 风险。旧路径仅为存量兼容保留。


@staticmethod
def _resolve_open_plugin_source_key(space_id, plugin_id, explicit_source_key=""):
return explicit_source_key or ""

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

_resolve_open_plugin_source_key 现在移除了 DB fallback,若调用方未传 uniform_api_plugin_source_key,执行将直接失败(line 181-185)。确认上游(模板保存/建任务时)已保证 source_key 必填即可。

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

最新提交 d656b88 补充了 v4 协议验证的 category 分类接口,包含视图、URL 路由、APIGW 文档和测试用例。实现简洁清晰,DEMO_CATEGORIES 常量 + copy.deepcopy 防污染模式与同文件其他接口一致,网关利用 matchSubpath: true 无需额外资源定义。

新增代码评估

  • category_api 实现简洁,GET 只读无副作用
  • 测试覆盖了 URL 路由解析和响应数据断言
  • 文档 api_plugin_demo_v4_get.md 同步更新了子路径表格和请求示例

先前问题状态

前几轮审查报告的行内问题状态不变:

  • collect_plugin_references 3x 调用:未修复
  • ⚡ N+1 查询(_get_catalog_entry / is_granted):未修复
  • 📄 backfill_open_plugin_snapshots.py / grant_open_plugin_source.py 缺开源协议头:未修复
  • 📄 tests/interface/api_plugin_demo/__init__.py 缺失:未修复
  • cancel_open_plugin_runs_for_task 同步串行 HTTP:未修复
  • ⚠️ operate_task_node.py 回调分支 data["status"] 未校验:未修复

结论

本次增量无新问题。代码风格与同文件既有模式一致,测试和文档同步到位。

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

最新 2 个提交:

  • d656b889 补充 v4 协议验证 category 分类接口
  • 5951b88c 纯文档/前端原型补充(sops_open_plugin_frontend_contract.md、交互设计、HTML 原型)

新增代码评估

  • category_api 实现简洁,与同文件既有 demo 接口风格一致,测试和 APIGW 文档已同步
  • 前端契约文档补充了 v4 节点保存字段清单和版本选择器交互规则,对前后端协作有正面价值
  • 无新引入的逻辑问题

先前问题状态

前几轮审查报告的行内问题均未在本次增量中修复,状态不变:

问题 状态
create_taskcollect_plugin_references 3x 调用 未修复
collect_plugin_references 循环内 N+1(_get_catalog_entry + exists() 未修复
cancel_open_plugin_runs_for_task 同步串行 HTTP 未修复
📄 backfill_open_plugin_snapshots.py / grant_open_plugin_source.py 缺开源协议头 未修复
📄 tests/interface/api_plugin_demo/__init__.py 缺失 未修复
⚠️ operate_task_node.py 回调分支 data["status"] 未校验(KeyError 风险) 未修复

结论

本次增量(docs + category demo endpoint)无新问题,代码风格与既有模式一致。建议在合入前优先处理上表中 ⚡ 性能相关的 Important 级问题(尤其是 collect_plugin_references 重复调用和 N+1 查询),其余 Minor 问题可后续跟进。

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

最新 5 个提交(bfd6b27f ~ e0221f4ced)完成了 v4 demo 代码重构和前端原型文档补充:

  1. 重构 v4 demo 模块:将 v4 协议验证代码从 views.py/plugins.py 拆分到独立 v4.py,URL 路径从 open_plugin_v4/ 简化为 v4/
  2. 补充 category 接口:新增 v4/category/ 分类查询端点
  3. APIGW 资源收敛:使用 matchSubpath: true 将 6 个独立资源合并为 GET/POST 两个入口,文档与 zip 同步更新
  4. 前端原型补充:按 wiremd 规范新增 V4.0.0 节点 API 插件的正常配置、版本切换、失效版本三态线框图,同步更新交互设计文档与前端对接协议

代码质量

重构质量良好:

  • v4.py 包含完整 MIT 协议头,常量与工具函数组织清晰
  • 旧 URL 引用已全部清理,测试用例同步验证了新路由结构
  • APIGW docs 与 api-resources.yml 同步完整,zip 已重新生成
  • 文档变更遵循 docs-management.mdc 目录规范

先前问题状态

  • ⚠️ int(request.query_params.get("limit", 50)) 未做异常处理的问��已从 views.py:374 迁移到 v4.py:232,仍未修复(已在先前轮次报告)
  • 📄 tests/interface/api_plugin_demo/__init__.py 仍缺失(已在先前轮次报告)
  • 其余先前报告的 10 个行内问题未在本批次提交中涉及,状态不变

结论

本批次提交为纯重构+文档补充,无新引入问题,代码组织更清晰。先前报告的 2 个未解决问题(int() 异常处理、测试目录 __init__.py)建议后续修复。

@dengyh
dengyh force-pushed the feat/sops-open-plugin-backend branch from e0221f4 to 00e27e7 Compare July 7, 2026 09:22

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

最新提交 00e27e72 纯文档/原型补充——新增 v4 节点 wireframe 设计文档(docs/guide/docs/specs/docs/plans/)和 4 张 wireframe 截图(prototypes/output/sops-open-plugin-v4-node-api-plugin/),覆盖正常配置、版本切换、不可用版本三种交互状态。无代码逻辑变更。

新增文档评估

  • 文档目录归属正确:guide → 前端协议约定,specs → 交互设计,plans → 实现计划增量
  • wireframe markdown 结构清晰,包含 ASCII art + 注释说明,便于前端实现对照
  • PNG 截图与 markdown 描述一一对应

先前问题状态

前几轮审查共报告 16 个行内问题,本次提交为纯文档变更,未涉及代码修改,先前报告的问题(collect_plugin_references 3x 调用、N+1 查询、缺少协议头、循环 update_or_create、数据迁移风险等)均未在此提交中解决,仍然 open。

无新问题。

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

最新提交 c19afb52 对前端原型和设计文档做了大幅精简——将 3 态完整 wireframe(正常配置/版本切换/失效版本)收敛为单一"节点配置增加版本选择"最小原型,同步简化了交互设计文档、全能力设计文档、前端对接协议和实现计划。

变更评估

  • 文档范围收窄合理:从过度设计的版本差异对比、调度模式展示、失效版本治理等复杂 UI 回归到最小可行产品(只增加版本选择项),与"服务端负责校验,前端不做复杂治理 UI"的设计原则一致
  • 删除冗余原型02-version-switch.md03-unavailable-version.md 及对应 PNG 已清除,新增 01-node-config-version.md 表达极简
  • 文档目录正确:specs → 设计规范,plans → 实施计划增量,guide → 前端协议约定,prototypes → wireframe 源文件
  • 无代码逻辑变更

先前问题状态

前几轮审查共报告 16 个行内问题,本次提交为纯文档变更,未涉及代码修改。以下 2 个低优先级问题仍待处理:

  • ⚠️ v4.py:231 int(request.query_params.get("limit", 50)) 未做异常保护(已在先前轮次报告,Minor 级别)
  • 📄 tests/interface/api_plugin_demo/__init__.py 仍缺失(已在先前轮次报告,Minor 级别)

其余先前报告的问题未在本次提交中涉及,状态不变。无新问题发现。

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

最新提交 a5f39d3b 仅调整 v4 节点版本原型的 wireframe 文档,将 wireframe 从独立的"版本选择"卡片扩展为完整的"画布 + 800px 侧滑"节点配置模拟,更贴近现有界面布局。无 Python 代码变更,无新问题引入。

先前问题状态

前序审查报告的行内问题(collect_plugin_references 3x 调用、N+1 查询、缺少协议头、循环 update_or_create、回调跳过 Serializer 校验、迁移数据丢失风险等)在本次提交中未涉及修复,仍待处理。

总结

本次增量无代码逻辑变更,仅为文档/原型优化,无新增审查意见。

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

最新 4 个提交(f273afbb ~ a073f761)实现了开放插件目录周期同步和展示配置与执行来源解耦:

  1. 目录周期同步:新增 dispatch_open_plugin_catalog_sync + sync_open_plugin_catalog_source Celery 任务,按已配置 ∩ 已准入来源投递独立子任务,具备限速和超时保护
  2. 展示/执行分层source_key 配置项允许多个 api_key 共享同一执行来源,目录同步按有效 source_key 聚合后刷新
  3. 请求加固_fetch_api_list 增加响应校验与超时配置,缺凭证/请求失败时抛明确异常而非静默返回空列表
  4. 前端版本持久化NodeConfig.vuewrapper_versionplugin_sourceplugin_codesource_key 完整保存到 api_meta,隐藏字段 uniform_api_plugin_source_key 确保运行时可溯源

代码质量

  • 超时/周期全部通过环境变量注入,符合配置化要求 ✅
  • Celery 任务日志覆盖充分(dispatch/异常/完成),max_retries=0 + rate_limit 避免雪崩 ✅
  • _effective_source_key 兼容 dict 和 Pydantic model 两种入口类型,边界处理到位 ✅
  • 测试覆盖完整:同步聚合、来源过滤、去重、超时传递、异常路径均有对应用例 ✅
  • 文档同步:space_config.md 和设计文档已更新 source_key 说明 ✅

先前问题状态

问题 状态
collect_plugin_references 循环内 N+1(_get_catalog_entry + exists() 未修复(不在本轮变更范围)
enable_all_visible_plugins 循环内 update_or_create 未修复(不在本轮变更范围)
get_snapshot_node_statuses 循环内逐条查 未修复(不在本轮变更范围)

新增发现

见行内评论。

总结

增量质量良好,架构设计合理地将展示配置与执行来源解耦,周期同步实现稳健。仅有 1 个 Minor 级别建议。

@@ -0,0 +1,52 @@
from unittest.mock import call, patch

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📄 新增文件缺少项目要求的 MIT 开源协议头。同目录 __init__.py 等文件均包含标准协议声明,建议补齐。

@dengyh
dengyh force-pushed the feat/sops-open-plugin-backend branch from a073f76 to 7930e7c Compare July 17, 2026 10:08

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

最新 6 个提交(925600f ~ 7930e7c)完成了三项工作:

  1. 目录同步请求加固_fetch_api_list 增加响应校验、超时配置,缺凭证/请求失败时抛明确异常
  2. 周期同步任务dispatch_open_plugin_catalog_sync + sync_open_plugin_catalog_source Celery 任务,限速+超时保护
  3. 展示配置与执行来源解耦source_key 配置项允许多个 api_key 共享同一执行来源
  4. 延迟加载回调模型apps.get_model 解决多模块部署下 bkflow.task 不在 interface 模块 INSTALLED_APPS 的问题
  5. 前端版本切换:完整的业务版本选择、持久化、隐藏字段保存逻辑
  6. 协议 Schema 增强anyOf 约束确保 v4 detail meta 必须包含完整字段集

代码质量

  • apps.get_model 方案正确——bkflow.pipeline_plugins 在 engine 和 interface 模块均加载,但 bkflow.task 仅在 engine 模块加载,直接 import 会在 interface 模块触发 LookupError ✅
  • Celery 任务设计稳健:max_retries=0 + rate_limit="10/m" + soft_time_limit 避免雪崩 ✅
  • _effective_source_key 兼容 dict 和 Pydantic model 两种入口,边界处理到位 ✅
  • UNIFORM_API_META_RESPONSE_DATA_SCHEMAanyOf 约束精确表达"要么不出现 v4 字段,要么全部出现" ✅
  • 测试覆盖全面:聚合、去重、超时传递、异常路径、Beat 注册均有用例 ✅

先前问题状态

问题 状态
collect_plugin_references 循环内 N+1 未修复(不在本轮变更范围)
📄 tests/interface/plugin/test_tasks.py 缺开源协议头 未修复(已在上轮报告)

新发现

见行内评论(1 条)。

if not space_config.json_value:
continue

config = UniformAPIConfigHandler(space_config.json_value).handle()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ UniformAPIConfigHandler.handle() 会在配置格式非法时抛出 ValidationError,单个空间配置损坏会导致整个 iter_configured_sources 迭代中断,dispatch_open_plugin_catalog_sync 将无法为任何来源投递同步任务。建议加 try/except 跳过并记录日志,保证周期任务对脏数据的容错性。

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

最新提交 9c73d1ed 实现了 Uniform API 目录缓存模式(remote/cache_first/cache_only),包括缓存命中本地过滤、远程回退后异步同步投递、配置验证。代码结构清晰,三层模式分支逻辑合理,测试覆盖充分(含分页、过滤、去重锁、异常处理)。

先前问题状态

前序审查报告的行内问题(collect_plugin_references 3x 调用、N+1 查询、缺少协议头、循环 update_or_create 等)不在本次提交变更范围内,状态未变。

新增代码问题

见行内评论(2 条 Important + 1 条 Minor)。

from .utils import check_resource_token

logger = logging.getLogger(__name__)
CATALOG_SYNC_DEDUP_SECONDS = 60

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ CATALOG_SYNC_DEDUP_SECONDS = 60 硬编码阈值。项目内同类配置(如 OPEN_PLUGIN_CATALOG_SYNC_REQUEST_TIMEOUT)均通过 env.pysettings 注入。建议改为 settings.OPEN_PLUGIN_CATALOG_SYNC_DEDUP_SECONDS,便于运维按环境调整去重窗口。

@@ -0,0 +1,289 @@
from unittest.mock import MagicMock, patch

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📄 新增文件缺少项目要求的 MIT 开源协议头。参考同目录其他测试文件补齐即可。

try:
lock_acquired = cache.add(lock_key, True, timeout=CATALOG_SYNC_DEDUP_SECONDS)
except Exception:
logger.exception("开放插件目录同步去重锁获取失败: space_id=%s, source_key=%s", space_id, source_key)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

_dispatch_catalog_sync 中的 logger 消息使用了中文。项目规范要求批量/清理操作日志统一使用英文,如 "open plugin catalog sync dedup lock acquire failed: space_id=%s, source_key=%s"

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incremental Review

最新提交 295f7ee1 实现了三项改进:

  1. 调度逻辑重构:将 v4 开放插件的状态处理提取为 _handle_open_plugin_status 统一方法,同时新增 plugin_schedule 入口调度和 _dispatch_schedule_callback 回调分支,消除了 trigger/polling 中的重复逻辑
  2. 独立回调入口:新增 /open_plugin_callback/space/{space_id}/task/{task_id}/node/{node_id}/ 直连内部端点,解决了先前审查指出的 operate_task_node 绕过 Serializer 校验问题
  3. 前端滚动优化apiPlugin.vue 改用声明式 @scroll 绑定替代手动 addEventListener

先前问题状态

  • operate_task_node.py Serializer 绕过 + KeyError 风险 — 已通过独立端点解决
  • ✅ 魔法数字 10 — 已抽取为 OPEN_PLUGIN_POLLING_INTERVAL 类常量
  • collect_plugin_references 3x 调用 — 未在本次提交中修改(create_task.py 无变更)

新增代码评估

  • 回调端点校验完整(payload 结构 + token 存在性),token 签名验证合理下沉到 engine 层
  • _handle_open_plugin_status 分支覆盖全面:SUCCESS/FAILED/WAITING_CALLBACK/RUNNING/unknown 各有对应处理
  • 测试覆盖充分(回调 4 个场景 + 调度 4 个场景 + 前端 1 个断言)
  • 设计文档已同步更新调度模式说明

代码质量良好,无新增 Critical/Important 级别问题。

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.

4 participants