[codex] 重构 prototypes 原型工具并补齐 bkflow engine admin 深度原型#699
Conversation
There was a problem hiding this comment.
Code Review Summary
本 PR 是前端原型工具的整体重构,将扁平的 prototypes/ 目录重组为 masters/、features/、examples/ 三层结构,并基于真实审计结果重建了 bkflow_engine_admin 的完整原型链路。
变更范围:纯前端原型(HTML/CSS/JS)+ 文档 + 截图 + Python 结构合同测试。不涉及 Django 视图、API 端点、权限配置或后端逻辑,因此权限体系、API 网关同步等项目规范不适用。
正面评价:
- 目录结构清晰,masters/features/examples 的职责划分合理
- 合同测试覆盖全面,确保目录结构、README 内容、页面链接一致性等不会悄悄退化
serve.py是零依赖的标准库实现,带热重载,轻量实用- 共享 JS 交互层使用声明式
data-*属性驱动,保持了原型页面的可维护性
需关注的问题:见行内评论(共 4 条)。
| - `prototypes/features/<slug>/` holds demand-specific prototype pages. | ||
| - `prototypes/examples/` is reference-only, mainly `component-showcase.html`. | ||
| - `prototypes/features/_legacy/` is history only and should not be treated as an active destination. | ||
| - `prototypes/base.html` is not part of the current flow. |
There was a problem hiding this comment.
✨ SKILL.md 第 29-30 行提到 prototypes/base.html 和 prototypes/output/ 已不再使用,但措辞是"不是当前流程的一部分"。由于本 PR 已明确移除这些路径,建议将描述更新为"已废弃并移除"以避免歧义。
|
|
||
| var selector = trigger.getAttribute("data-toggle-target"); | ||
| var className = trigger.getAttribute("data-toggle-class"); | ||
| document.querySelectorAll(selector).forEach(function (target) { |
There was a problem hiding this comment.
🔒 data-toggle-target、data-right-panel-open、data-right-panel-close 等属性的值被直接作为 CSS 选择器传入 querySelectorAll。当前所有调用点都是静态 HTML 中的硬编码 ID 选择器,实际风险很低。但如果未来有动态生成 HTML 的场景,建议对选择器做简单白名单校验(如 /^[#.\w-]+$/),避免选择器注入。
| full = os.path.normpath(os.path.join(PROTOTYPES_ROOT, rel)) | ||
| if os.path.isdir(full): | ||
| index_html = os.path.join(full, "index.html") | ||
| if os.path.isfile(index_html): |
There was a problem hiding this comment.
🔒 目录 index.html 分支(L148-152)在调用 _send_html_with_reload 前跳过了 _under_root 检查。虽然 _is_safe_relpath 已拒绝 .. 路径片段,但如果 PROTOTYPES_ROOT 下存在指向外部的符号链接,此路径仍可逃逸。建议在 L150 前加上 if not _under_root(index_html, PROTOTYPES_ROOT): ... 保持与 L153 一致的防御层级。
There was a problem hiding this comment.
index.html 分支仍然跳过了 _under_root 检查直接调用 _send_html_with_reload。
|
|
||
| 日期:2026-04-20 | ||
|
|
||
| 环境:`https://stag-dot-bkflow-eng-svc.bkapps-sz.woa.com/bkflow_engine_admin/?space_id=171` |
There was a problem hiding this comment.
stag-dot-bkflow-eng-svc.bkapps-sz.woa.com)。如果仓库是公开的或未来会公开,建议将具体域名替换为占位符或移到私有文档中。
976300b to
8a1d583
Compare
There was a problem hiding this comment.
Incremental Code Review (synchronize)
第二次提交 8a1d583 新增了 bkflow engine admin 深度原型页面、测试、设计文档和计划文档。以下是本轮增量审查结果。
之前的评论状态
第一次提交中报告的 4 个问题(serve.py _under_root 缺失、SKILL.md 措辞、审计文档内部 URL、bkflow-prototype.js 选择器注入)在本次提交中均未修改对应文件,问题仍然存在。不再重复报告。
新发现
| 文件 | 级别 | 问题 |
|---|---|---|
docs/plans/...prototype-overhaul.md:24 |
硬编码开发者本地路径 /Users/dengyh/Projects/bk-flow |
|
tests/.../test_bkflow_engine_admin_feature.py:1 |
✨ Minor | 缺少开源协议头(项目规范要求新 Python 文件包含版权注释) |
总体评价
新增的原型 HTML 页面质量不错:资产引用路径一致、敏感数据已脱敏(如 credential 页用 ******)、无废弃 base.html 引用。测试文件覆盖了结构合同验证(页面存在性、导航链接、master 数量一致性),结构清晰。设计文档无内部 URL 泄漏。
There was a problem hiding this comment.
Incremental Code Review (synchronize)
第三次提交 69db637 主要是代码风格修复:将 Python 3.10+ 类型提示语法(X | Y、dict[str, str])降级为兼容写法(Union、Dict),统一引号风格,以及将 .direnv/.venv/.worktrees 加入 .flake8 排除列表。
之前的评论状态
| # | 文件 | 状态 |
|---|---|---|
| 1 | prototypes/serve.py L149-153 _under_root 缺失 |
|
| 2 | .ai/skills/prototype-generator/SKILL.md L29 措辞 |
未变更,仍 open |
| 3 | .ai/docs/specs/...audit...md 内部 URL |
未变更,仍 open |
| 4 | docs/plans/...overhaul.md 硬编码本地路径 |
未变更,仍 open |
| 5 | prototypes/assets/bkflow-prototype.js 选择器注入 |
未变更,仍 open |
| 6 | test_bkflow_engine_admin_feature.py 缺开源协议头 |
未变更,仍 open |
新发现
-
⚠️ test_bkflow_engine_admin_feature.py:83—extract_sections的返回类型仍使用dict[str, str](内建泛型语法),而同文件中extract_top_nav_links已被本次提交改为Dict[str, ...]。如果本次提交的目的是兼容 Python 3.8,需要将dict[str, str]也改为Dict[str, str];或者如果项目最低支持 3.9+,则extract_top_nav_links的改动就不必要。风格应保持一致。 -
✨
prototypes/serve.py:117—_json_mtime_value的返回类型从int | float改为Union[int, float],但该文件首行已有from __future__ import annotations,使所有注解延迟求值,int | float在任何 Python 3.7+ 下都有效。改动无害但多余。
总结
本次提交为代码风格和兼容性的小修复,无 Critical/Important 级别的新问题。之前报告的 serve.py _under_root 检查缺失(Important 级别)仍未修复,建议在后续提交中处理。
There was a problem hiding this comment.
Incremental Code Review (synchronize)
第四批提交(ead51ff ~ bef38ca,共 8 个提交)新增了原型展厅首页(showcase homepage)功能:showcase_catalog.py 数据聚合、serve.py 首页 HTML 渲染、bkflow-showcase.css/js 前端交互、以及完整的测试覆盖和文档同步。
之前的评论状态
| # | 文件 | 状态 |
|---|---|---|
| 1 | prototypes/serve.py L515-518 _under_root 缺失 |
🔒 仍未修复(已再次标注) |
| 2 | .ai/skills/prototype-generator/SKILL.md 措辞 |
✅ 已在本批提交中全面重写解决 |
| 3 | .ai/docs/specs/...audit...md 内部 URL |
未变更,仍 open |
| 4 | docs/plans/...overhaul.md 硬编码本地路径 |
未变更,仍 open |
| 5 | prototypes/assets/bkflow-prototype.js 选择器注入 |
未变更,仍 open |
| 6 | test_bkflow_engine_admin_feature.py 缺开源协议头 |
未变更,仍 open |
| 7 | test_bkflow_engine_admin_feature.py:83 dict[str, str] 风格不一致 |
未变更,仍 open |
新发现摘要
| 级别 | 文件 | 问题 |
|---|---|---|
| 🔒 Important | prototypes/serve.py:518 |
目录 index.html 分支仍缺 _under_root 检查(同 #1,再次标注) |
prototypes/showcase_catalog.py:18,60 |
使用 dict[str, Any]、Path | None 等 3.10+ 语法,与上一提交的降级方向矛盾 |
|
prototypes/serve.py:151 |
同上,list[dict]、tuple[list[str], list[str]] 等内建泛型语法需要 3.9+ |
|
| ✨ Minor | prototypes/showcase_catalog.py:1 |
新增 Python 文件缺少开源协议声明 |
| ✨ Minor | tests/.../test_showcase_catalog.py:1 |
同上 |
| ✨ Minor | tests/.../test_showcase_homepage.py:1 |
同上 |
总体评价
展厅首页功能实现完整:catalog 聚合逻辑清晰(默认值回退、无效页过滤、排序策略合理);前端 JS 用 IIFE + data-* 声明式驱动搜索和筛选,轻量无依赖;CSS 变量体系完整,响应式适配到位;测试覆盖从 catalog 数据层、serve.py 渲染层到 JS 交互行为(通过 Node vm 模拟)都有覆盖,结构合同测试也同步更新了展厅首页的契约。SKILL.md 的重写内容丰富且实用。主要待处理项是 _under_root 安全加固和类型提示风格统一。
| index_html = os.path.join(full, "index.html") | ||
| if os.path.isfile(index_html): | ||
| self._send_html_with_reload(index_html) | ||
| return |
There was a problem hiding this comment.
🔒 目录 index.html 分支仍然跳过了 _under_root(index_html, PROTOTYPES_ROOT) 检查。虽然 _is_safe_relpath 已拒绝 .. 片段,但 symlink 仍可能逃逸。建议在此行前加 if not _under_root(index_html, PROTOTYPES_ROOT): ...。(此问题自第一轮 review 起仍未修复)
|
|
||
|
|
||
| def _safe_read_json(path: Path) -> dict[str, Any]: | ||
| try: |
There was a problem hiding this comment.
dict[str, Any](此行)和 Path | None(L60)等 Python 3.10+ 类型提示语法,但上一个提交 69db637 刚将同类语法降级为 Dict/Union 以兼容低版本。风格应保持一致。
|
|
||
|
|
||
| def _collect_filter_options(features: list[dict]) -> tuple[list[str], list[str]]: | ||
| statuses: list[str] = [] |
There was a problem hiding this comment.
showcase_catalog.py 同样的问题:list[dict]、list[str]、tuple[list[str], list[str]] 等内建泛型语法需要 Python 3.9+。上一个提交已在其他文件做了降级处理,这里应保持风格一致。
| @@ -0,0 +1,167 @@ | |||
| """Catalog helpers for the BKFlow prototypes showcase homepage.""" | |||
|
|
|||
There was a problem hiding this comment.
✨ 新增 Python 文件缺少开源协议声明(# -*- coding: utf-8 -*- 及版权注释),项目规范要求每个新增 Python 文件顶部包含。
| @@ -0,0 +1,176 @@ | |||
| import importlib.util | |||
| import json | |||
| @@ -0,0 +1,446 @@ | |||
| from __future__ import annotations | |||
|
|
|||
bef38ca to
7e7fd23
Compare
There was a problem hiding this comment.
Incremental Code Review (synchronize — squash rebase)
本次 synchronize 事件是将之前的多个提交压缩为单个 squash commit 7e7fd23。以下是针对压缩后最终状态的增量审查。
之前评论状态更新
| # | 文件 | 状态 |
|---|---|---|
| 1 | serve.py L515-519 目录 index.html 缺少 _under_root 检查 |
|
| 2 | SKILL.md 废弃路径引用 |
✅ 已在 squash 中解决 |
| 3 | 审计文档内部 staging URL | ✅ 已在 squash 中解决 |
| 4 | bkflow-prototype.js 选择器注入 |
低风险,不再重复 |
| 5 | 计划文档硬编码开发者路径 | /Users/dengyh/Projects/bk-flow) |
| 6 | 新增测试文件缺少开源协议头 | ✨ 仍缺失(所有 tests/interface/prototypes/test_*.py) |
| 7 | showcase_catalog.py Python 3.10+ 类型提示 |
✅ 误报 — 文件有 from __future__ import annotations,运行时不会报错 |
| 8 | serve.py Python 3.10+ 类型提示 |
✅ 误报 — 同上,from __future__ import annotations 已导入 |
| 9 | showcase_catalog.py 缺少开源协议头 |
✨ 仍缺失 |
本轮新发现
无新增问题。Squash 后的代码整体质量良好:
- HTML 渲染全面使用
html.escape(),无 XSS 风险 bkflow-showcase.js使用.textContent赋值,安全- 测试覆盖完整,包括结构合同、功能合同和展厅首页测试
唯一仍需关注的安全项是 serve.py L515-519 的 _under_root 缺失(已留行内评论)。其余为文档/规范类小项。
| if os.path.isdir(full): | ||
| index_html = os.path.join(full, "index.html") | ||
| if os.path.isfile(index_html): | ||
| self._send_html_with_reload(index_html) |
There was a problem hiding this comment.
🔒 目录 index.html 分支在 _send_html_with_reload(index_html) 前仍未检查 _under_root(index_html, PROTOTYPES_ROOT)。_is_safe_relpath 仅拒绝 .. 片段,但如果 PROTOTYPES_ROOT 下存在指向外部的符号链接目录,os.path.normpath + isdir + join("index.html") 可以构造出逃逸路径。建议在 L517 之前加上 if not _under_root(full, PROTOTYPES_ROOT): self.send_error(HTTPStatus.FORBIDDEN); return。(此问题自首轮 review 以来持续存在)
7e7fd23 to
65f214b
Compare
There was a problem hiding this comment.
Incremental Code Review (synchronize — re-squash)
本次 synchronize 事件是将 7e7fd23 重新压缩为 65f214b。以下是针对当前最终状态的增量审查。
之前评论状态更新
| # | 问题 | 状态 |
|---|---|---|
| 1 | serve.py L515-519 目录 index.html 缺少 _under_root 检查 |
🔒 仍未修复(见行内评论) |
| 2 | SKILL.md 废弃路径引用 |
✅ 已解决 |
| 3 | 审计文档内部 staging URL | ✅ 已解决(已标注为"已脱敏") |
| 4 | bkflow-prototype.js 选择器注入 |
低风险,不再重复 |
| 5 | 计划文档硬编码开发者路径 /Users/dengyh/... |
docs/plans/2026-04-21-bkflow-engine-admin-prototype-overhaul.md:24) |
| 6 | 新增 Python 文件缺少开源协议头 | ✨ 仍缺失(serve.py、showcase_catalog.py 及 8 个测试文件) |
| 7 | showcase_catalog.py / serve.py Python 3.10+ 类型提示 |
✅ 非问题——两个文件均使用了 from __future__ import annotations,语法在 Python 3.7+ 有效 |
本轮结论
代码与上次审查 7e7fd23 无实质变更,仅为 re-squash rebase。未发现新问题。
仍需关注的 2 项:
- 🔒
serve.pyL515-519 的_under_root检查缺失是跨多轮审查一直标记的安全问题 - ✨ 10 个新增 Python 文件缺少项目规范要求的开源协议头
Summary
prototypes/目录为masters/、features/、examples/三层结构,并补齐共享壳子、页面类型母版、feature 交付页和结构合同测试bkflow_engine_admin的space / system / plugin原型链路,覆盖流程编辑、任务详情、调试链路、配置页、决策表等关键页面prototypes/features/_legacy/,同步更新prototype-generatorskill、审计/spec/plan 文档、截图证据和预览服务器行为Why
prototypes/目录扁平且不可追踪,output/无法表达页面类型和需求归属base.html与真实 BKFlow 页面交互差异很大,尤其是流程编辑页、任务详情页、多容器浮层和跨模块跳转docs/specs/docs/plans对齐Validation
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 ./.venv/bin/pytest -c /dev/null -p no:django tests/interface/prototypes -vpython -m py_compile prototypes/serve.py/,/features/bkflow-engine-admin-prototype-overhaul/index.html,/features/_legacy/sops-open-plugin/main-flow.html,/assets/icons/bkflow-logo.svgNotes
133683187master基线的整套原型工具重构成果,而不只是最后一轮 Task 8 收尾