feat(pikaoa): 补齐测试 Secret 初始化闭环

This commit is contained in:
Codex
2026-07-15 04:08:33 +02:00
parent 712fc66cbf
commit d5f4a4c13b
8 changed files with 264 additions and 108 deletions
@@ -0,0 +1,52 @@
# R1.5.9.5 任务报告
## 结论
已在 PR #2084 完成 NC01 固定 `pikaoa-test` 测试运行面的 YAML-first Secret 初始化闭环和单步 CLI 收口。测试运行面使用 PK01 host PostgreSQL 独立 `pikaoa_test` role/database、固定 NodePort `32080`,不创建专用测试集群、动态 namespace 或 namespace-local PostgreSQL,也未恢复 dedicated 门禁。
## 实现
- `config/secrets-distribution.yaml`
- 声明 `platform-infra/pikaoa-test.env`,必需 key 为 `DATABASE_URL``PIKAOA_SESSION_SECRET`
- `createIfMissing` 只生成 `PIKAOA_SESSION_SECRET`,保留 platform-db export 写入的 `DATABASE_URL`
- 增加 `pikaoa-test-nc01` target,固定 `NC01:k3s``pikaoa-test` namespace 和 `pikaoa-test` scope
- 增加 `pikaoa-test-runtime` Secret 映射,继续消费既有管理员和员工 external raw sources。
- `config/pikaoa.yaml`
- `testRuntime.runtime.sessionSecret` 改读 `platform-infra/pikaoa-test.env#PIKAOA_SESSION_SECRET`
- 保留 PK01 `pikaoa_test` 数据库、固定 namespace、附件 PVC、NodePort、OTel/Prometheus 和单步工作负载声明。
- `pikaoa test-target`
- 新增 `--step foundation`
- foundation 不要求 `--commit` 或业务 Secret,只提交带所有权标签的固定 Namespace/PVC
- migration、api、worker、web 和 all 继续要求 commit 与 Secret source
- plan 只投影当前 step 所需对象,并保持 Secret 脱敏。
- `docs/reference/pikaoa.md`
- 删除专用测试集群、动态 namespace 和临时 PostgreSQL 旧设计;
- 写明 foundation、Secret sync、migration、api、worker、web 顺序;
- 写明先稳定 CLI,再建设独立 test CI/CD,且不得成为业务阻塞门禁。
## 验证
- `bun --check scripts/src/pikaoa-test-target.ts`:通过。
- `bun test scripts/src/pikaoa-test-target-async.test.ts`2 pass0 fail。
- `bun scripts/cli.ts check --syntax-only`11 pass0 fail。
- `pikaoa test-target plan --step foundation`
- `readyForMutation=true`
- `missingFields=[]`
- `blockers=[]`
- 仅投影 Namespace 与 PersistentVolumeClaim
- `secretRequired=false`
- `valuesPrinted=false`
- `secrets plan --scope pikaoa-test`
- target 为 `pikaoa-test-nc01`
- Secret 为 `pikaoa-test-runtime`
- 投影四个声明 key
- `mutation=false`
- `valuesPrinted=false`
- `git diff --check`:通过。
## 边界
- 本任务只修改代码、YAML、测试和文档。
- 未执行 foundation、Secret sync、migration、API、Worker、Web 或任何部署。
- 未读取、打印或从 Kubernetes 反解 Secret 值。
- 原入口真实部署与 NodePort 验收由主代理在合并后按文档顺序执行。
+1 -1
View File
@@ -105,7 +105,7 @@
##### R1.5.9.4 [completed]
在 PK01 host PostgreSQL 声明独立 pikaoa_test database/role、Secret export 与 NC01 HBA,执行记录见 [pikasTech/unidesk#2078](https://github.com/pikasTech/unidesk/issues/2078),完成任务后将详细报告写入[任务报告](./details/pikaoa-enterprise-platform/R1.5.9.4_Task_Report.md)。
##### R1.5.9.5 [in_progress]
##### R1.5.9.5 [completed]
在 NC01 pikaoa-test namespace 实现外部 PK01 测试 DSN、API/Worker/Web/迁移/附件 PVC、OTel/Prometheus、YAML hostIP 端口和受控单步 CLI,执行记录见 [pikasTech/unidesk#2079](https://github.com/pikasTech/unidesk/issues/2079),完成任务后将详细报告写入[任务报告](./details/pikaoa-enterprise-platform/R1.5.9.5_Task_Report.md)。
##### R1.5.9.6 [completed]
+99 -81
View File
@@ -1,99 +1,117 @@
# PikaOA 开发与测试运行面
# PikaOA
## 配置真相
- PikaOA 平台配置唯一真相是 `config/pikaoa.yaml`
- 正式交付与临时测试运行面职责分离
- `delivery.targets` 只描述正式 CI/CD、GitOps、运行 namespace、数据库和公网暴露
- `testRuntime.targets` 只描述专用测试集群上的临时后端运行面。
- 禁止把现有节点推断成 PikaOA 专用测试集群。
- `testRuntime.targets` 为空时表示当前没有获准的测试运行面:
- `plan``status` 返回 `configured=false``mutation=false`
- `start` `stop` 在任何远端调用前失败
- 测试运行面固定使用
- Target`NC01`
- route`NC01:k3s`
- namespace`pikaoa-test`
- NodePort`32080`
- 测试 namespace 不根据 commit、instance 或任务动态生成。
- `pikaoa` `pikaoa-ci` 是正式交付保护 namespace
- 测试入口不得渲染、覆盖或删除保护 namespace 中的对象。
## 受控入口
## 数据库边界
```bash
bun scripts/cli.ts pikaoa test-target plan
bun scripts/cli.ts pikaoa test-target status
bun scripts/cli.ts pikaoa test-target start --target <id> --instance <run-id> --commit <sha> --confirm
bun scripts/cli.ts pikaoa test-target stop --target <id> --instance <run-id> --confirm
```
- 测试数据库固定使用 PK01 host PostgreSQL。
- `config/platform-db/postgres-pk01.yaml` 声明独立的:
- role`pikaoa_test`
- database`pikaoa_test`
- schema`pikaoa`
- `DATABASE_URL` export`platform-infra/pikaoa-test.env`
- `pikaoa-test` namespace 不创建 PostgreSQL StatefulSet、Service 或临时数据库。
- 数据库生命周期独立于 namespace 和业务 workload。
- 测试数据清理由 PK01 PostgreSQL 受控入口负责,不依赖删除 namespace。
- `plan` 是本地只读渲染入口,不接受 `--dry-run`
- `start``stop` 只在显式 `--confirm` 后执行。
- `--config <path>` 可用于 fixture 或本地 override`validationOnly=true` 的 target 永远不连接 route。
- 默认输出是紧凑文本;`--output json``--json` 输出单一 JSON 文档。
- 长启动使用提交与短轮询分离的远程任务:
- `start --confirm` 只提交由 `target/instance` 唯一定位的启动任务,返回 `start-submitted``jobId`、namespace 和 `mutation=true`
- 相同 `target/instance/commit` 重复提交只返回已有任务状态,不再启动并行任务;
- 相同 `target/instance` 改用其他 commit 时返回 `start-instance-conflict`,操作者应使用新 instance
- `status` 返回 `running/succeeded/failed/canceled`、当前阶段、时间、终态 code、exit code 和有界事件尾部;
- `status` 的运行面查询只使用 YAML 声明的短 request timeout,不进入启动等待循环。
- 远程任务事实只保存在 target YAML `taskState.rootPath` 对应的单一状态目录:
- `taskState.statusRequestTimeoutSeconds` 控制短查询预算;
- `taskState.logTailLines` 控制事件尾部上限;
- 不建立第二数据库、控制器、租约或独立锁服务。
## Secret 初始化
## 临时运行面
- `config/secrets-distribution.yaml` 声明:
- source`platform-infra/pikaoa-test.env`
- target`pikaoa-test-nc01`
- scope`pikaoa-test`
- Kubernetes Secret`pikaoa-test-runtime`
- `platform-infra/pikaoa-test.env` 必须包含:
- `DATABASE_URL`
- `PIKAOA_SESSION_SECRET`
- `DATABASE_URL``platform-db postgres export-secrets` 写入并保留。
- `createIfMissing` 只为 `PIKAOA_SESSION_SECRET` 生成值,不覆盖已有 `DATABASE_URL`
- 管理员和员工密码继续使用既有 external raw sources
- `~/.unidesk/.env/pikaoa-admin-password.txt`
- `~/.unidesk/.env/pikaoa-employee-password.txt`
- Secret 输出只披露对象、key、presence、fingerprint 和摘要,不读取或打印值。
- namespace 固定由 YAML `namespacePrefix` 和 CLI `--instance` 组成。
- namespace、API、Worker、临时 PostgreSQL、Service 和 Secret 都带以下可审计标签:
## Test Target CLI
- 受控入口是 `bun scripts/cli.ts pikaoa test-target`
- `config/pikaoa.yaml#testRuntime` 声明固定 namespace、镜像、PVC、Secret 引用、迁移、工作负载、探针和暴露端口。
- 所有创建对象都带以下所有权标签:
- `app.kubernetes.io/managed-by=unidesk-pikaoa-test-target`
- `pikaoa.unidesk.io/test-runtime=true`
- `pikaoa.unidesk.io/target=<target-id>`
- `pikaoa.unidesk.io/instance=<run-id>`
- `stop` 删除前重新校验 target、instance 和 managed-by 标签,只删除精确实例 namespace
- `stop` 发现同一实例的启动任务仍在运行时,先写入精确任务的取消请求,再删除 namespace;返回 `startTaskDisposition` 说明是 `cancel-requested``cancel-already-requested``already-terminal``not-found`
- 正式 namespace 保护集合来自以下 YAML 字段:
- `delivery.targets.*.namespace`
- `delivery.targets.*.ci.namespace`
- 测试入口不得渲染或删除保护集合中的任何对象。
- PostgreSQL 使用 namespace 内的临时存储,namespace 删除后测试数据随之清理。
- 临时数据库连接只由 target YAML 渲染:
- `database.name``database.username``database.schema` 都是必填 PostgreSQL identifier
- renderer 使用结构化 URL 参数写入 `sslmode``search_path`,不提供隐藏 schema 默认值;
- 缺少 schema 或形状不合法时,在任何 route 调用前返回具名配置错误。
- 附件运行参数与 namespace 内的临时 PVC 来自 target YAML
- `runtime.attachment.storageRoot``runtime.attachment.maxBytes` 直接写入严格 runtime YAML
- PVC 名称、容量、StorageClass 和 access mode 只从同一 target 声明读取;
- API 挂载该 PVC,删除临时 namespace 时一并删除 PVC。
- 空数据库启动固定分为三个受控阶段:
- 先渲染基础对象并等待 namespace 内 PostgreSQL 就绪;
- 再使用 `source.images.migration``migration.command` 运行产品内置 `pikaoa migrate up` Job
- 迁移 Job 完成后才创建 API 和 Worker Deployment 并等待 rollout。
- PostgreSQL、迁移 Job 或业务 Deployment 失败会返回具名失败码,不会静默进入下一阶段。
- TTL 和清理策略来自 target YAML
- TTL 写入 namespace annotation
- 当前 `cleanup.mode=delete-namespace`,由显式 `stop` 执行;
- `cleanup.requireOwnershipLabels=true` 时,删除前必须校验归属标签;
- 不建立额外控制器或长期状态库。
- `pikaoa.unidesk.io/instance=<instance-id>`
- `stop` 只允许删除同时匹配固定 namespace 和全部所有权标签的运行面
- CLI 使用异步任务状态目录记录有界状态和事件,不建立第二数据库、控制器、租约或锁服务
## Secret 与可观测性
## 初始化顺序
- Secret 值只从 YAML `sourceRef` 读取并写入目标 Secret
- CLI 输出只显示 `sourceRef``targetKey`、presence 和 fingerprint,始终保持 `valuesPrinted=false`
- `plan` 的数据库投影只显示 schema 和 DSN 参数 presence,不显示完整 DSN、用户名、密码或参数值。
- 含 Secret 的 runner 文件使用 owner-only 权限,运行后立即删除;manifest 只在 runner 的临时目录存活,终态前由 trap 清理。
- 状态和事件只记录公开 ID、阶段、typed code 和时间,不保存命令 stderr、DSN、manifest 正文或 Secret 值。
- Secret 缺失会在连接测试集群前阻塞 `start`
- 迁移 Job、API 和 Worker 从同一 Secret key 挂载严格的 PikaOA runtime YAML,数据库 schema 与 `search_path` 因此保持一致。
- OTel endpoint、Prometheus scrape、指标路径和探针全部由 target YAML 声明。
- 配置一致性、镜像/commit 漂移和 OTel exporter 失败只产生 `blocking=false` warning,不作为 MVP 门禁。
1. 使用 `platform-db postgres` 受控入口准备 PK01 `pikaoa_test` role/database,并 export `DATABASE_URL`
2. 执行 foundation
## 本地验收
```bash
bun scripts/cli.ts pikaoa test-target start \
--target NC01 \
--instance default \
--step foundation \
--confirm
```
`config/fixtures/pikaoa-test-target.yaml` 只用于本地验证:
3. foundation 只创建带所有权标签的固定 `pikaoa-test` Namespace 和附件 PVC,不要求业务 Secret 已存在。
4. 执行 Secret 下发:
- 证明 namespace、选择器、附件 PVC、迁移 Job、工作负载和 Secret 引用的渲染结果;
- 证明 TTL、OTel、Prometheus 和正式 namespace 保护;
- fixture target 固定为 `validationOnly=true`,不得用于真实集群操作。
```bash
bun scripts/cli.ts secrets sync \
--config config/secrets-distribution.yaml \
--scope pikaoa-test \
--confirm
```
```bash
bun scripts/cli.ts pikaoa test-target plan \
--config config/fixtures/pikaoa-test-target.yaml \
--target TEST01 \
--instance issue-2046 \
--commit 0123456789abcdef \
--output json
```
5. `secrets sync` 按 YAML 声明补齐允许生成的本地来源,并下发 `pikaoa-test-runtime`。
6. 使用同一 commit 依次执行:
- `--step migration`
- `--step api`
- `--step worker`
- `--step web`。
7. Web 固定通过 `152.53.229.148:32080` 的 NodePort 入口验收。
## 单步运行
- foundation 不需要 `--commit`,也不检查业务 Secret。
- migration、api、worker、web 和 all 必须显式提供 `--commit`。
- 每个 `start` 立即返回任务 ID;使用同一 target、instance 和 step 的 `status` 查询终态。
- 相同任务重复提交只返回已有任务状态,不并行创建第二任务。
- 迁移、rollout 或运行面查询失败返回具名失败码,不静默进入下一阶段。
- OTel exporter、配置版本和 commit 对齐漂移只产生 `blocking=false` warning,不恢复 dedicated 门禁。
## 交付阶段
- 当前阶段先稳定 YAML-first CLI 原入口和固定 NC01 测试运行面。
- CLI 闭环通过后,再建设独立 test CI/CD:
- 复用同一 owning YAML
- 按 foundation、Secret sync、migration、api、worker、web 顺序编排;
- 不创建专用测试集群;
- 不生成动态 namespace
- 不创建 namespace-local PostgreSQL
- 不把测试 CI/CD 变成生产交付或用户业务的阻塞门禁。
- PR、构建或单测不能替代固定 NodePort 原入口验收。
## 本地验证
- `config/fixtures/pikaoa-test-target.yaml` 只用于 renderer 和 CLI 测试。
- fixture target 固定为 `validationOnly=true`,不得连接真实 route。
- 最小验证包括:
- `bun --check scripts/src/pikaoa-test-target.ts`
- `bun test scripts/src/pikaoa-test-target-async.test.ts`
- `bun scripts/cli.ts check --syntax-only`
- `pikaoa test-target plan --step foundation`
- `git diff --check`。