mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 01:06:59 +08:00
docs(agents): 完善自动化开发流程与验证证据规范
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# 领域文档待补充问题
|
||||
|
||||
这份文件只记录尚未确认的领域边界。问题确认后,把稳定术语移入根目录 `CONTEXT.md`,再从本文删除对应问题。
|
||||
这份文件是待查证目录,不是每项任务都要逐条询问的问卷。只处理影响当前任务的边界,先检查源码、测试和已有文档;仍无法确定且影响业务决策时再询问使用者。问题确认后,把稳定术语移入根目录 `CONTEXT.md`,行为规则放入对应按需文档,再从本文删除对应问题。
|
||||
|
||||
## 工作空间与用户
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
运行镜像由多个阶段组成:
|
||||
|
||||
1. 前端构建:`frontend/` 执行 `npm install` 和 `npm run build`,产物进入 `/opt/sqlbot/frontend/dist`。
|
||||
2. 后端构建:复制 `backend/`,使用 base 镜像中的 uv 安装依赖;存在 `backend/uv.lock` 时先按 lock 冻结安装,缺失时(如 CI 全新 checkout)回退按 `pyproject.toml` 解析。
|
||||
2. 后端构建:复制 `backend/`,使用 base 镜像中的 uv 安装依赖。以根 `Dockerfile` 为准:中间层包含 `uv sync --frozen` 尝试,最终层执行 `uv sync --extra cpu`,不是全程冻结安装。`uv.lock` 不入库,不能据此承诺全新 checkout 的依赖可复现;`|| echo` 的提示也不能证明失败只因缺少 lock,需检查实际构建日志。
|
||||
3. 图表服务构建:复制 `g2-ssr/app.js`、`package.json` 和 `charts/`,安装 Node 依赖和 canvas 相关库。
|
||||
4. 运行层:基于含 PostgreSQL / Python 的 base 镜像,复制前端、后端、g2-ssr、字体、向量模型和启动脚本。
|
||||
5. 启动脚本依次准备 PostgreSQL、supervisor/g2-ssr、MCP 服务和主 FastAPI 服务。
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
## 本地验证
|
||||
|
||||
普通代码任务不要默认构建镜像;Docker 构建需要外部镜像、模型资源和较长耗时。用户明确要求时才执行,并说明目标平台。
|
||||
普通代码任务不要默认构建镜像;Docker 构建需要外部镜像、模型资源和较长耗时。任务已要求镜像或部署验收时,构建属于验证范围,明确目标平台后执行;仅需接口或浏览器验证时优先启动必要的隔离服务,不自动扩大为镜像构建。
|
||||
|
||||
可以做的轻量检查:
|
||||
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
- `keyExpression` 能取到真实资源 ID;
|
||||
- 列表语义不会被单个资源绕过;
|
||||
- 管理员、工作空间管理员和普通用户路径都明确。
|
||||
- 权限表达式引用的参数缺失、解析失败或归属不匹配时必须拒绝,不能回退为直接执行处理函数。
|
||||
- 子资源归属从服务端记录推导并校验完整关系(如字段 → 表 → 数据源 → 工作空间);请求中的 `ds_id`、`oid` 仅为待校验输入。不能仅验证调用者有权访问所提供的数据源,再按任意表/字段 ID 执行操作。
|
||||
- 批量接口明确整批拒绝还是仅操作有权记录,并测试混合归属输入;单项、批量、同步、导出等入口应遵循相同授权边界。
|
||||
- 手写查询归属时,同时校验:
|
||||
- 资源存在;
|
||||
- 资源属于当前工作空间;
|
||||
@@ -25,7 +28,7 @@
|
||||
|
||||
## SQL 生成与执行
|
||||
|
||||
当前主流程的安全顺序不可弱化:
|
||||
修改主流程时应满足以下安全顺序;需在实际入口和调用链验证,不能把本清单当作现状已安全的证明:
|
||||
|
||||
1. 只把允许的表和字段元数据提供给模型;
|
||||
2. 解析模型返回 JSON 并提取 SQL;
|
||||
@@ -45,7 +48,7 @@
|
||||
|
||||
## 认证、Host 与嵌入
|
||||
|
||||
- 不要改变 `backend/main.py` 中中间件注册顺序;`HostValidationMiddleware` 必须在外层拒绝非法 Host。
|
||||
- 修改 `backend/main.py` 的中间件顺序时,验证实际请求执行顺序(不能只看注册顺序);`HostValidationMiddleware` 必须在认证/业务使用 Host 前拒绝非法值,并回归预检与正常请求。
|
||||
- Host 只允许合法域名 / IPv4 / IPv6 形态,不能包含 `/`、`@` 或空白。
|
||||
- 认证和助手 token 头由后端中间件与前端 request interceptor 处理;不要新增手工传递或复制 token 的路径。
|
||||
- 页面嵌入协议必须保持:
|
||||
@@ -60,8 +63,8 @@
|
||||
|
||||
- 不信任上传文件名、扩展名、MIME、sheet 名或用户提供的 `filePath`。
|
||||
- 上传必须限制类型和大小,落盘使用服务端生成的文件名或 opaque ID。
|
||||
- 读取用户可控路径前必须证明路径仍位于允许目录内;优先使用 `os.path.commonpath` 或仅通过内部 ID 映射真实路径。
|
||||
- 下载响应使用 `os.path.basename` 或 FileResponse,不回显绝对路径。
|
||||
- 读取用户可控路径前,解析真实路径后用 `os.path.commonpath` 等验证其仍位于允许目录内,或通过已授权的内部 ID 映射路径;不使用字符串前缀判断。校验到打开之间不得允许不可信方替换路径或符号链接。
|
||||
- 下载前先校验权限和服务端文件实际路径的目录归属,包括符号链接解析;`os.path.basename` 只适合清理下载展示名,`FileResponse` 只负责传输,两者都不能替代路径授权。响应不回显内部绝对路径。
|
||||
- Excel/CSV 解析错误不能变成可猜测的内部路径信息。
|
||||
|
||||
## 前端渲染
|
||||
@@ -80,7 +83,7 @@
|
||||
|
||||
## 必测场景
|
||||
|
||||
修改相关逻辑时至少覆盖:
|
||||
按本次涉及的入口选择相关场景;不要求每次安全改动执行下列全部类别,但必须说明未覆盖的相关风险:
|
||||
|
||||
- 未登录、无权限、资源不存在、跨工作空间访问;
|
||||
- 管理员、工作空间管理员、普通用户、助手用户;
|
||||
|
||||
+24
-7
@@ -2,9 +2,10 @@
|
||||
|
||||
## 测试布局
|
||||
|
||||
所有测试都在 `backend/tests/`,从 `backend/` 目录用同一条命令运行:
|
||||
当前入库的自动化测试集中在 `backend/tests/`。以下命令从仓库根进入 `backend/` 后运行;其余文档中的命令也应按注明的工作目录执行:
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
uv run pytest -q
|
||||
uv run pytest -q tests/<relevant-test.py>
|
||||
```
|
||||
@@ -18,18 +19,34 @@ uv run pytest -q tests/<relevant-test.py>
|
||||
|
||||
不要为了速度跳过与改动相关的层,也不要把所有历史失败当成当前变更造成的问题;先用目标测试定位边界。
|
||||
|
||||
## 环境与证据
|
||||
|
||||
- 记录测试提交、命令、工作目录和必要的依赖版本/配置;不记录凭据。独立 worktree 复用环境时确认模块实际从当前 worktree 导入,避免测试到旧代码。
|
||||
- `uv run` 可能解析、同步依赖;需要保留已准备环境或 editable 安装时使用 `uv run --no-sync`,并说明依赖来源。没有入库 lockfile 时,不能仅凭代码 SHA 宣称依赖可完全复现。
|
||||
- 分别报告源码/静态检查、单元或守卫测试、真实接口/数据库、浏览器、镜像部署的覆盖;没有执行的层不能标为通过。AST/源码文本测试不能替代真实导入、路由和授权调用链验证。
|
||||
- Bug 修复应有修复前失败、修复后通过的用例,或等价的前后行为证据,并覆盖相关边界。权限验证同时检查拒绝路径、合法操作对照、响应内容及持久化结果。
|
||||
- 未登录、请求格式错误、服务未启动、依赖不可用等不满足复现前提的结果标为无效验证;不能把 401/422 或连接失败当作修复成功。有效前提下预期的认证拒绝仍可作为对应认证测试证据。
|
||||
- 测试失败先区分环境问题、既有问题和本次回归。声称既有失败时,在相同配置的未修改基线上对照,或给出可核验的历史证据;无法确认时保留不确定性,不跳过失败后宣称全部通过。
|
||||
|
||||
## 集成与产品验收
|
||||
|
||||
- 默认单元/守卫测试离线、可重复;真实数据库、LLM、网络和浏览器测试单独显式运行。新增集成用例应使用独立目录或明确的选择机制,默认收集不能因配置了凭据就意外访问外部服务;暂不规定仓库尚未实现的 marker 或运行器。
|
||||
- 在授权的测试环境中使用独立数据库、schema、账号或有明确标识的测试记录;不覆盖业务数据。外部环境与凭据用途必须与任务一致,只传输必要数据,LLM 回归优先使用合成数据。
|
||||
- UI 验收检查真实产品 DOM、交互与保存后状态;静态演示页或截图不能代替完整操作链。LLM 功能同时检查选表/上下文、生成 SQL、执行结果;预置结果不能证明模型行为。
|
||||
- 记录本次启动的进程、端口和测试资源;结束时仅停止、清理本次拥有的临时资源。需要保留复现环境时说明入口和生命周期,不留下共享凭据或无主服务,不删除共享数据卷。
|
||||
|
||||
## 新增测试约定
|
||||
|
||||
- 测试可隔离的纯逻辑或服务函数;
|
||||
- 用 `Mock`、`SimpleNamespace`、SQLite 或 AST 加载方式隔离外部数据库和驱动;
|
||||
- 不访问真实 LLM、数据库或互联网;
|
||||
- 默认单元/守卫测试不访问真实 LLM、外部数据库或互联网;需要这些依赖时遵循上面的集成验收约定;
|
||||
- 命名和断言风格跟随相邻测试。
|
||||
|
||||
`LOG_FORMAT` 只是 `logging.Formatter` 的百分号格式串模板,代码中没有 JSON 日志实现;若本机环境把它设成了非默认格式串导致 formatter 初始化失败,测试前 `unset LOG_FORMAT` 恢复默认。
|
||||
`LOG_FORMAT` 只是 `logging.Formatter` 的百分号格式串模板,代码中没有 JSON 日志实现;若本机环境把它设成了非默认格式串导致 formatter 初始化失败,先检查进程环境与 dotenv 来源;`unset LOG_FORMAT` 后 dotenv 仍可能重新加载该值。可在单次测试命令中使用 `LOG_FORMAT='%(levelname)s %(message)s'`,不要为测试覆盖共享配置。
|
||||
|
||||
## 守卫维护
|
||||
|
||||
当 intentional 变更导致守卫失败时,更新守卫以表达新契约;不要删除断言、扩大白名单或降低安全约束来让测试通过。
|
||||
修改守卫前先说明原断言保护的行为、新需求的依据以及替代覆盖。提交历史只能证明行为曾被改动,不能单独证明新行为正确。确认旧契约不再适用后,更新守卫以表达新契约;不要仅为消除失败删除断言、扩大白名单或降低安全约束。删除集成测试时说明失去的覆盖及保留/替代方式,不把缺少凭据时跳过描述为永久不可用。
|
||||
|
||||
## 前端验证
|
||||
|
||||
@@ -54,7 +71,7 @@ npm run build
|
||||
```bash
|
||||
cd backend
|
||||
uv run ruff check <changed-file.py...>
|
||||
uv run ruff format <changed-file.py...>
|
||||
uv run ruff format --check <changed-file.py...>
|
||||
```
|
||||
|
||||
`pyproject.toml` 配置了 mypy strict,但历史代码尚未建立全仓库通过基线。新代码应避免引入新的类型问题;是否运行 mypy 由改动范围和相邻模块现状决定,不要自动对全仓库执行大规模修复。
|
||||
@@ -75,5 +92,5 @@ uv run ruff format <changed-file.py...>
|
||||
- 相关测试通过,或明确记录与本次改动无关的既有失败;
|
||||
- 新行为有回归测试或说明为什么不适用;
|
||||
- 没有为了通过测试削弱安全约束;
|
||||
- 没有引入网络、数据库、密钥或不可重复依赖;
|
||||
- 正确仓库的 status/diff 只包含任务相关变更。
|
||||
- 默认测试不隐式访问外部服务;集成验证的环境、选择方式和限制已说明,提交中不含密钥;
|
||||
- 本次暂存和提交的 diff 只包含任务相关变更;用户原有无关改动保留原样。
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## 主工程对 xpack 的运行时依赖
|
||||
|
||||
以下事实在"已发布 wheel"与"源码联调(editable)"两种模式下一致,修改依赖、初始化、许可证或前端集成前先掌握:
|
||||
以下描述以当前依赖实现为背景;包内路由、许可证和静态资源行为会随 xpack 版本变化。修改相关集成时记录实际安装版本,并核对对应 wheel 的 `core.py` / `init_fastapi_app`;源码联调核对目标 checkout,不把本文当作所有版本的固定契约。主仓库入口见 `backend/main.py`、`backend/pyproject.toml` 和 `frontend/src/router/watch.ts`:
|
||||
|
||||
- `sqlbot-xpack` 是 `backend/pyproject.toml` 的**必装依赖**(不是 optional extra),索引指向 TestPyPI,CE 镜像构建必然包含;构建环境需能访问 test.pypi.org。
|
||||
- 后端启动即无条件 import:`backend/main.py` 与多个业务模块(登录加解密、AES 落库、审计、行权限、参数管理、embedded 签名)顶层 import,没有降级路径——xpack 缺失则后端无法启动。8001 的 MCP 进程因 `uvicorn main:mcp_app` import 同一 `main` 模块,同样加载。
|
||||
@@ -25,16 +25,13 @@ SQLBOT_XPACK_REPO=/replace/with/your/sqlbot-xpack-checkout
|
||||
| --- | --- |
|
||||
| 未配置或值无效 | 仅当任务需要 xpack 时,询问一次是否开启本地关联;同意后验证并保存路径。 |
|
||||
| `false` | 继续使用已发布 wheel。不读取路径、不安装 editable 包、不修改 xpack、不重复询问。若任务无法绕开闭源实现,说明需要用户主动开启开关。 |
|
||||
| `true` | 验证路径后,把该 checkout 作为可修改的 xpack 工作区,读取 `sqlbot-xpack/AGENTS.md`,并协调两个仓库的变更。 |
|
||||
| `true` | 验证路径后读取目标仓库根目录的 `AGENTS.md`,在已授权的任务范围内联调;开关本身不授权无关修改、推送或发布。 |
|
||||
|
||||
路径目录名可以任意,但必须是指向 xpack Git 仓库根目录的绝对路径;用 `git -C "$SQLBOT_XPACK_REPO" rev-parse --show-toplevel` 验证。环境变量优先于 `AGENTS.local.env`。不要静默覆盖该文件,也不要在其中保存密钥。
|
||||
|
||||
本地联调时,先加载配置,把 xpack 以 editable 方式安装进后端环境,并使用 `--no-sync` 避免 uv 用锁定 wheel 替换它:
|
||||
本地联调前按上述优先级读取两个配置值:已设置的环境变量优先,只从本机可信配置文件补齐未设置项;不要直接 `source` 文件覆盖环境变量或执行其中任意 shell 内容。确认开关为 `true` 且路径验证通过后,导出解析得到的 `SQLBOT_XPACK_REPO`。下面命令从 SQLBot 根目录运行,作用于选定后端环境;优先使用隔离环境,使用共享环境时先确认受影响的运行服务,并记录恢复方式:
|
||||
|
||||
```bash
|
||||
set -a
|
||||
. ./AGENTS.local.env
|
||||
set +a
|
||||
cd backend
|
||||
uv pip install -e "$SQLBOT_XPACK_REPO"
|
||||
uv run --no-sync pytest -q
|
||||
|
||||
Reference in New Issue
Block a user