251 lines
9.7 KiB
Markdown
251 lines
9.7 KiB
Markdown
# PostgreSQL / MySQL Runtime Smoke 环境建议
|
||
|
||
## 结论
|
||
|
||
当前阶段的目标推荐方案是:**让 QA agent 直接在升级后的 `local-db-codex` 容器内执行 smoke,并通过挂载宿主机 Docker daemon、Docker 配置、Cargo 与 Rustup 目录来复用宿主能力**。
|
||
|
||
- 继续复用现有 `docker-compose.demo.yml`、bootstrap 脚本和 SQL fixtures
|
||
- 不依赖长期运行的宿主机 PostgreSQL / MySQL
|
||
- 不再要求 QA 手动切回宿主机执行
|
||
- 将 Docker、Rust、Cargo mirror、Docker registry mirror 的能力统一沉淀到容器运行时
|
||
|
||
在该部署升级完成前,宿主机执行仍然是可用 fallback;但后续默认路径应转向容器内 agent 自行完成 smoke。
|
||
|
||
2026-03-26 的 [CMP-17](/CMP/issues/CMP-17#comment-0cd53e93-25a5-456b-8dba-31ea098c2aa8) 已证明该路径可以成立:宿主机 PostgreSQL / MySQL smoke 已执行完成,因此“当前 QA runner 无 Docker”只代表本 agent 本地限制,不再代表方案无效。
|
||
|
||
## 三种方案对比
|
||
|
||
### 方案 A:宿主机长期运行 PostgreSQL / MySQL
|
||
|
||
优点:
|
||
|
||
- 首次接入快
|
||
- QA 不需要每次拉起容器
|
||
|
||
缺点:
|
||
|
||
- 状态容易漂移,重复执行时很难保证数据库干净
|
||
- 需要长期维护端口、用户、权限和版本
|
||
- 一旦多人共用宿主机,测试数据会互相污染
|
||
- 更适合共享开发环境,不适合作为 release smoke 证据来源
|
||
|
||
结论:**可作为临时兜底,不作为推荐主路径。**
|
||
|
||
### 方案 B:为 `local-db-codex` 部署增加 Docker runtime 能力
|
||
|
||
优点:
|
||
|
||
- 从 agent 视角最方便,理论上可以把 smoke 也放回当前容器体系
|
||
- 后续若多个项目都依赖容器型集成测试,长期上限更高
|
||
|
||
缺点:
|
||
|
||
- 这是平台/安全/运维改造,不是当前仓库内的小改动
|
||
- 会引入容器嵌套、权限边界、镜像缓存、资源隔离等额外复杂度
|
||
- 当前项目的真实瓶颈是缺可执行宿主,不是缺应用层代码
|
||
|
||
结论:**不适合作为本阶段 unblock 手段,只在未来多个项目都提出同类需求时再立项。**
|
||
|
||
### 方案 C:QA runner 在宿主机执行,数据库通过 Docker Compose 临时拉起
|
||
|
||
优点:
|
||
|
||
- 直接复用现有仓库资产,落地最快
|
||
- 每次 `up` / `down -v` 都是干净环境,可重复性最好
|
||
- 不要求改 `local-db-codex` 平台
|
||
- 后续可平滑迁移到自托管 runner 或专用 QA 主机
|
||
|
||
缺点:
|
||
|
||
- 需要一台具备 Docker / `docker compose` 的宿主机
|
||
- 宿主机上仍需准备 Rust toolchain 或 release binary
|
||
|
||
结论:**作为 fallback 可用,但不再是长期目标路径。**
|
||
|
||
### 方案 D:升级 `local-db-codex`,让 agent 在容器内复用宿主机 Docker 和 Rust
|
||
|
||
优点:
|
||
|
||
- agent 可直接在容器内执行 PostgreSQL / MySQL Docker-backed smoke
|
||
- 后续每个功能实现后的测试路径一致,不需要在人和 agent 之间切换执行环境
|
||
- 继续复用宿主机 Docker daemon 的镜像缓存、registry mirror 和权限体系
|
||
- 继续复用宿主机 Rust toolchain、Cargo 配置和 crates mirror 配置
|
||
|
||
缺点:
|
||
|
||
- 需要维护容器与宿主机之间的挂载关系
|
||
- Docker socket 暴露会提升容器能力边界,需明确接受该风险
|
||
- 宿主机 Docker / Rust 环境本身出问题时,容器内 agent 会继承同样问题
|
||
|
||
结论:**这是后续迭代的目标方案。**
|
||
|
||
## 推荐执行方式
|
||
|
||
### 容器化 QA runner 要求
|
||
|
||
- `deploy/local-db-codex` 已升级,挂载:
|
||
- 宿主机 Docker socket
|
||
- 宿主机 Docker config
|
||
- 宿主机 Cargo home
|
||
- 宿主机 Rustup home
|
||
- 容器内可直接运行:
|
||
- `docker`
|
||
- `cargo`
|
||
- `rustc`
|
||
- 宿主机 Docker daemon 已配置好 registry mirror(如有)
|
||
- 宿主机 Cargo / Rustup mirror 配置已就绪(如有)
|
||
|
||
### 使用步骤
|
||
|
||
1. 启动升级后的 `local-db-codex` 部署
|
||
2. 进入 agent 所在容器运行环境,确认 `docker`、`cargo`、`rustc` 可用
|
||
3. 在工作区准备 CLI:
|
||
- 开发验证:`cargo build`
|
||
- 或使用已生成的 `target/debug/dbtool` / `target/release/dbtool`
|
||
4. 导出密码环境变量:
|
||
|
||
```bash
|
||
export DBTOOL_PASSWORD=dbtool
|
||
export DBTOOL_POSTGRES_ADMIN_PASSWORD=dbtoolroot
|
||
```
|
||
|
||
5. 拉起 PostgreSQL / MySQL:
|
||
|
||
```bash
|
||
docker compose -f docker-compose.demo.yml up -d postgres mysql
|
||
```
|
||
|
||
6. 导入 demo 数据:
|
||
|
||
```bash
|
||
./examples/scripts/bootstrap-postgres.sh
|
||
./examples/scripts/bootstrap-mysql.sh
|
||
```
|
||
|
||
如果本机 PostgreSQL demo 容器早于本轮权限修正创建,先清旧卷再重建:
|
||
|
||
```bash
|
||
docker compose -f docker-compose.demo.yml down -v
|
||
docker compose -f docker-compose.demo.yml up -d postgres mysql
|
||
./examples/scripts/bootstrap-postgres.sh
|
||
./examples/scripts/bootstrap-mysql.sh
|
||
```
|
||
|
||
PostgreSQL demo 当前权限边界:
|
||
|
||
- `postgres` / `dbtoolroot`:只用于 seed、restricted probe 建立与清理
|
||
- `dbtool` / `dbtool`:QA 与 TUI/CLI live 路径使用的非超级用户
|
||
|
||
可先验证 `dbtool` 不再是超级用户:
|
||
|
||
```bash
|
||
PGPASSWORD="$DBTOOL_POSTGRES_ADMIN_PASSWORD" \
|
||
psql -h 127.0.0.1 -p 55432 -U postgres -d dbtool_demo \
|
||
-c "select rolname, rolsuper, rolcreaterole, rolcreatedb from pg_roles where rolname='dbtool';"
|
||
```
|
||
|
||
PostgreSQL restricted-schema 最小复验步骤:
|
||
|
||
```bash
|
||
PGPASSWORD="$DBTOOL_POSTGRES_ADMIN_PASSWORD" \
|
||
psql -h 127.0.0.1 -p 55432 -U postgres -d dbtool_demo <<'SQL'
|
||
drop schema if exists restricted_probe cascade;
|
||
create schema restricted_probe;
|
||
create table restricted_probe.audit_log (
|
||
id bigint primary key,
|
||
note text not null
|
||
);
|
||
insert into restricted_probe.audit_log values (1, 'hidden from dbtool');
|
||
revoke all on schema restricted_probe from public;
|
||
revoke all on all tables in schema restricted_probe from public;
|
||
revoke all on schema restricted_probe from dbtool;
|
||
revoke all on all tables in schema restricted_probe from dbtool;
|
||
SQL
|
||
|
||
export DBTOOL_PASSWORD=dbtool
|
||
cargo run -p dbtool-cli -- inspect --driver postgres --host 127.0.0.1 --port 55432 --database dbtool_demo --username dbtool --password-env DBTOOL_PASSWORD
|
||
cargo run -p dbtool-cli -- inspect --driver postgres --host 127.0.0.1 --port 55432 --database dbtool_demo --username dbtool --password-env DBTOOL_PASSWORD --schema restricted_probe
|
||
```
|
||
|
||
预期:
|
||
|
||
- root inspect 出现 `restricted_probe [restricted]`
|
||
- 显式 `--schema restricted_probe` 返回 restricted inspect error,而不是 empty tables
|
||
|
||
清理:
|
||
|
||
```bash
|
||
PGPASSWORD="$DBTOOL_POSTGRES_ADMIN_PASSWORD" \
|
||
psql -h 127.0.0.1 -p 55432 -U postgres -d dbtool_demo \
|
||
-c "drop schema if exists restricted_probe cascade;"
|
||
```
|
||
|
||
7. 按 `SMOKE_RUNBOOK.md` 执行 PostgreSQL / MySQL 的 happy-path;按 `HOST_FAILURE_PATH_CHECKLIST.md` 执行 failure-path
|
||
8. 将结果回填到 `ACCEPTANCE_CHECKLIST.md`、`TEST_STRATEGY.md`、`PRE_RELEASE_CHECKLIST.md`
|
||
9. 清理环境:
|
||
|
||
```bash
|
||
docker compose -f docker-compose.demo.yml down -v
|
||
```
|
||
|
||
## Failure-path 执行入口
|
||
|
||
- PostgreSQL / MySQL happy-path 继续使用 `SMOKE_RUNBOOK.md`
|
||
- PostgreSQL / MySQL failure-path 统一使用 `HOST_FAILURE_PATH_CHECKLIST.md`
|
||
- 证据记录格式继续以 `FAILURE_PATH_EVIDENCE_TEMPLATE.md` 为准
|
||
- 在发起宿主机或 sidecar live 执行前,先跑离线夹具收敛 helper / wrapper 契约:
|
||
|
||
```bash
|
||
scripts/qa/test-failure-path-fixtures.sh
|
||
```
|
||
|
||
- 若只想检查单一路径,可改跑:
|
||
|
||
```bash
|
||
scripts/qa/test-failure-path-fixtures.sh format
|
||
scripts/qa/test-failure-path-fixtures.sh sidecar
|
||
```
|
||
|
||
## 2026-03-28 当前容器化 runner 观察
|
||
|
||
- QA runner 已可访问 Docker daemon,但当前仍缺 `docker compose` 子命令。
|
||
- QA runner 不能直接访问 `127.0.0.1:55432/53306`,也不能直接访问 demo 数据库容器 IP。
|
||
- 当前有效补充路径是:
|
||
1. 复用已运行的 `dbtool-cli-v1-postgres-1` / `dbtool-cli-v1-mysql-1`
|
||
2. 用 `docker exec` 直接导入 PostgreSQL / MySQL demo 数据
|
||
3. 创建 sidecar container 并加入 `dbtool-cli-v1_default` 网络
|
||
4. 在 sidecar container 内执行 `dbtool`,默认主机名跟随 `QA_POSTGRES_CONTAINER` / `QA_MYSQL_CONTAINER`(当前默认是 `dbtool-cli-v1-postgres-1` / `dbtool-cli-v1-mysql-1`)
|
||
|
||
这条 sidecar network execution 路径在 2026-03-28 当前 heartbeat 已被直接验证,可用于继续补 PostgreSQL / MySQL failure-path 证据。
|
||
|
||
为减少重复手工步骤,当前仓库已提供:
|
||
|
||
```bash
|
||
scripts/qa/run-failure-path-evidence-sidecar.sh ./target/release/dbtool ./tmp/failure-path-evidence
|
||
```
|
||
|
||
这条脚本化路径会自动完成:
|
||
|
||
- PostgreSQL / MySQL demo 数据重导入
|
||
- sidecar container 创建与清理
|
||
- sidecar 内 failure-path helper 执行
|
||
- 证据文件回传到本地输出目录
|
||
- 当前 PostgreSQL sidecar 重导入默认使用 `postgres` / `dbtoolroot`;若宿主机 demo 管理员身份被改写,可改传 `QA_POSTGRES_ADMIN_USER` / `QA_POSTGRES_ADMIN_PASSWORD`
|
||
|
||
## 团队职责
|
||
|
||
- 后端:维护 `docker-compose.demo.yml`、bootstrap 脚本、fixtures、命令契约和容器内 smoke 兼容性
|
||
- QA:优先在容器内 agent 运行环境执行 smoke,沉淀证据和失败复现记录
|
||
- 前端:当前继续 gated,不参与此轮 runtime smoke
|
||
- CTO:维持方案边界,并确保 `local-db-codex` 能长期承载容器内 smoke
|
||
|
||
## 风险与维护成本
|
||
|
||
- Docker socket 暴露:容器获得了较强的宿主机控制能力,必须明确接受这一安全边界。
|
||
- 宿主机 Docker / Rust 环境漂移:容器会继承宿主机配置,出现问题时必须同时排查宿主机。
|
||
- 二进制与文档漂移:QA 执行时必须绑定具体 commit 或 release artifact。
|
||
- 端口冲突:必要时继续参数化 compose 端口。
|
||
- 当前已知结论:宿主机 patched-run 已确认 MySQL 中文与 emoji 输出正常,问题根因收敛到 bootstrap/import 字符集路径;后续需要把这类验证稳定迁入容器内 smoke 路径。
|
||
|
||
总体维护成本可控,因为主路径继续复用仓库现有 smoke 资产,只是把执行宿主从人工宿主机切换成可复用宿主能力的 Paperclip 容器。
|