# Kestra V52 验证记录

- 代码分支：`codex/kestra-v50`
- 验证日期：2026-07-19
- 变更范围：独立 DataOps Runner、短时任务令牌、单次领取账本、受治理节点执行、
  数据源资源池复用和 Kestra 到 Runner 调用链

## 实现结果

- 新增独立 Runner 服务，监听容器内 `5600`，本机健康端口仅绑定
  `127.0.0.1:15600`；不与 Flask 请求进程共享连接池。
- Kestra 只调用内部网络别名 `dataops-runner`，不持有业务数据库账号、密码、
  密文、连接串或 Runner 签名密钥。
- Runner 使用显式配置构造平台 PostgreSQL、Neo4j 和业务数据源连接池，不再依赖
  Flask `current_app` 或请求上下文。
- 默认 2 个 Runner Worker、每数据源 `pool_size=1`、`max_overflow=1`、
  每 Worker 最多 4 个空闲池，理论业务库连接上限为 16，配置预算为 32。
- Runner 容器根文件系统只读，并实际生效 1 CPU、512 MiB、128 PID 限制；没有
  Docker Socket。
- 任务令牌使用 HS256，最长 300 秒，绑定 `task_uid`、DataFlow UID、流程版本、
  节点 ID/类型/摘要、用途、关联 ID 和一次性 `jti`，不携带数据源凭据。
- 新增 `runner_task_executions` 持久账本，`token_jti` 为主键、
  `task_uid` 唯一，跨 Worker 原子拒绝重复领取，并记录数据源 UID、幂等键、
  状态和 `commit_outcome`。
- SQL 查询只接受单条只读语句和绑定参数，使用原数据源池的只读事务；写节点必须
  同时具备受信任写授权和 WorkflowSpec 幂等策略。数据库连接在 COMMIT 时中断会
  记录为 `unknown`，不会被转换为普通可重试失败。
- Python 节点不接受任意源码，只允许镜像内注册处理器；子进程限制 CPU、内存、
  文件句柄、执行时间并禁用网络。默认白名单为空，未注册处理器失败关闭。
- HTTP 节点要求 HTTPS、部署白名单、无 URL 凭据和无内联授权头，禁止重定向并
  限制响应大小。

## TDD 与定向验证

测试均先确认缺失实现、安全约束或运行契约导致失败，再实现转绿。

### L1/L2

定向集合覆盖：

- `tests/runner`
- `tests/core/data_source`
- `tests/core/orchestration/test_kestra_compiler.py`
- `tests/test_datasource_api_security.py`
- `tests/test_datasource_pool_diagnostics.py`
- `tests/test_database_migrations.py`

覆盖令牌过期/篡改/节点绑定、重复领取、账本不可用失败关闭、SQL 只读边界、写授权、
未知提交结果、Python 时间/网络限制、HTTP 白名单、显式运行时、连接预算、Compose
隔离和数据库迁移。

最终 L1/L2 定向回归为 `89 passed, 1 skipped, 1 warning`。跳过项是需要临时
管理员数据库 URL 的通用空库迁移测试；V52 迁移已在当前隔离 PostgreSQL 中单独
完成升级、降级、再次升级和重复升级。警告来自本机 Python/LibreSSL 组合。

### L3

- Runner 镜像构建成功，PostgreSQL、Neo4j、两个外部数据源、Kestra 和 Runner
  均达到健康状态。
- `tests/integration/test_runner_datasource_pool.py` 对真实 PostgreSQL/MySQL 完成
  受治理查询；相同任务令牌第二次提交返回 409，账本只记录两次成功执行。
- `tests/integration/test_datasource_pool_failures.py` 停止 MySQL 后确认该数据源
  单独熔断，外部 PostgreSQL 和平台控制数据库仍可用，恢复后连接池正常重建。
- `tests/integration/test_kestra_runner_execution.py` 完成真实链路：
  Kestra 执行输入携带节点令牌，HTTP Task 调用 Runner，Runner 通过资源池读取
  PostgreSQL，Kestra 执行最终为 `SUCCESS`。
- 端到端首次执行暴露内部 DNS 名称缺失：编译器使用 `dataops-runner`，Compose
  只注册 `runner`。补充网络别名并增加自动化契约后，DNS 健康检查和完整执行转绿。
- V52 迁移在真实 PostgreSQL 完成升级、降回 V51、再次升级和重复升级，最终版本为
  `20260719_70 (head)`。
- 停止 Runner 时，平台健康接口与 n8n 健康接口均保持 HTTP 200，平台 PostgreSQL
  `SELECT 1` 成功；重新启动 Runner 后恢复健康。
- Runner/Kestra 日志扫描未发现测试业务库密码、业务连接串、凭据主密钥或密文字段；
  Kestra 当前测试流程数为 0。

最终 L3 定向回归为 `3 passed, 1 warning`。警告同样来自本机
Python/LibreSSL 组合。

## 未执行的验证

- 未运行全仓库测试、前端构建或全量容器验收；本版本只运行 V52 相关增量集合。
- 未开放任意 Python 代码执行，默认处理器白名单为空。
- 未由 AI/MCP 直接签发任务令牌或授予写权限；这些必须由 V53 策略、审批和审计
  Gateway 处理。
- 未执行正式影子写入或切换 n8n 主路径。

## 回滚

- 停止 Runner 和 Kestra 测试调用即可退出 V52 新执行路径。
- 保留现有 Flask 数据源资源池和 n8n 主路径，不需要回滚数据源定义或凭据治理。
- `runner_task_executions` 只保存受限执行元数据，不保存业务结果或凭据。

## 结论

V52 的独立 Runner、受治理执行、真实数据源池、重复提交防护、故障隔离和
Kestra 端到端调用已通过，当前允许进入 V53。V53 应实现 MCP Gateway、策略审批、
受信任令牌签发和全链路审计，保持“AI 可规划但不能自行扩大写权限”的边界。
