# PJ2026-01060308 CI/CD YAML目标治理

## 修改历史

| 版本 | 对应 commit id | 更新日期 | 变更说明 |
| --- | --- | --- | --- |

当前正文仍在规格治理草稿中；未定稿前不新增版本号，不为单次编辑追加 `待提交` 版本。

## 正文

## PJ2026-01060308 CI/CD YAML目标治理需求规格

## 1. 文档控制

| 字段 | 内容 |
| --- | --- |
| 编号 | PJ2026-01060308 |
| 短名 | YAML目标治理 |
| 层级 | L3 子课题 |
| 状态 | 已生效 |
| 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) |
| 上级规格 | [PJ2026-010603 YAML运维](PJ2026-010603-yaml-first-ops.md) |
| 关联规格 | [PJ2026-010601 发布流水](PJ2026-010601-controlled-release.md)、[PJ2026-010602 源码同步](PJ2026-010602-source-sync.md)、[PJ2026-01060307 控制面模块化](PJ2026-01060307-control-plane-modularity.md)、[PJ2026-010604 公开入口](PJ2026-010604-public-entry.md)、[PJ2026-010605 运维监控](PJ2026-010605-observability-monitoring.md) |
| 实现引用版本 | draft-2026-06-25-cicd-yaml-targets |
| 规格治理索引 | [规格治理](spec-governance.md) |

本文采用 ISO/IEC/IEEE 29148 需求规格模板的项目裁剪版：正文只保留 CI/CD、YAML-first 和平台运维控制面中 target、lane、Secret、public exposure、PipelineRun/Argo/git-mirror 与公共 ops primitive 的稳定治理口径。

## 2. 目的和范围

### 2.1 目的

YAML目标治理负责把 CI、deploy、artifact-registry、HWLAB node/lane、AgentRun、platform-infra、Secret 分发和 public exposure 中的运行目标事实收敛到 owning YAML 或显式参数，使新增 node/lane/target 时不需要发布 TypeScript 代码来改变默认目标、namespace、route、registry endpoint 或 SecretRef。

本规格建立在控制面模块化完成后的领域目录边界上。代码可以保留 legacy adapter、测试夹具、错误消息和帮助示例中的历史目标名，但主路径不得继续通过隐藏默认值把 `G14`、`D601`、`v02`、`v03`、namespace、route、registry endpoint 或工作目录写死在解析逻辑中。

### 2.2 范围内

- `config/hwlab-node-lanes.yaml`、`config/agentrun.yaml`、`config/platform-infra/*.yaml`、`config/secrets-distribution.yaml`、`config/cicd/targets.yaml` 和 `config/artifact-registry.yaml` 的 target/lane/configRef/sourceRef 职责。
- `scripts/src/ops/` 中的 configRef、target resolver、Secret redaction、public exposure、K8s/CI-CD 和 bounded output 公共原语。
- `ci`、`deploy`、`artifact-registry`、`hwlab g14`、`hwlab nodes`、`agentrun`、`platform-infra observability` 和 `secrets` CLI 对目标来源、配置引用图和脱敏状态的解释输出。
- hardcode inventory 的分类：`remove-code-default`、`keep-domain-special`、`legacy-adapter`、`test-fixture` 和 `help-example`。

### 2.3 范围外

- 不把所有配置合并成单一超级 YAML。
- 不删除必要的 legacy 安全阻断；legacy 入口必须隔离并在输出中标注。
- 不把运行面 Secret、pod env、日志或数据库状态反向写成本地配置真相。
- 不绕过 UniDesk 受控 CLI 使用原生 `kubectl`、`argo`、`tkn`、`curl` 或临时 shell 作为正式控制入口。
- 不为业务策略数值新增合同测试、硬编码范围或 schema 数值限制。

## 3. 术语表

| 术语 | 定义 |
| --- | --- |
| target | YAML 中描述部署目标、运行节点、route、kubeRoute、namespace、workspace、registry、public URL 或 CI/CD 参数的对象。 |
| lane | YAML 中描述一条 runtime 或 control-plane 运行线的对象，通常包含 node、source truth、runtime namespace、gitops、CI、Secret 和 publicExposure。 |
| configRef | `path/to/file.yaml#object.path` 形式的跨 YAML 引用，解析器只校验引用存在性、类型和摘要，不把合并结果写成第二真相。 |
| sourceRef | Secret 来源声明。输出只能显示来源标识、key 名、presence、fingerprint、字节数和 `valuesPrinted=false`。 |
| hidden default | 代码在未显式参数或未读取 YAML 时自动选择固定目标、namespace、route、registry、lane 或工作目录。 |
| legacy adapter | 为历史入口保留的隔离兼容路径。它可以拒绝 mutation 或提示替代命令，但不得污染主 runtime lane 解析。 |
| ops primitive | 跨领域复用的配置引用、目标解析、Secret redaction、K8s apply/status、public exposure 和 bounded output helper。 |

## 4. 系统边界和接口

| 边界项 | 内容 |
| --- | --- |
| 外部使用者 | 平台维护者、发布操作人员、AgentRun/HWLAB lane 运维者、自动化任务和后续代码维护者。 |
| 外部输入 | CLI 参数、YAML 配置、configRef/sourceRef、node/lane/target、desired-state manifest、Git commit 和运行面只读状态。 |
| 受控资源 | target resolver、配置引用图、CI/CD manifest 渲染、Secret 同步摘要、public exposure 渲染、PipelineRun/Argo/git-mirror 状态和 CLI 输出。 |
| 外部输出 | 有界 plan/status/dry-run、配置来源路径、resolved target、redacted Secret evidence、drill-down 命令和 legacy adapter 提示。 |
| 用户接口 | `bun scripts/cli.ts ci ...`、`artifact-registry ...`、`deploy ...`、`hwlab ...`、`agentrun ...`、`platform-infra observability ...` 和 `secrets ...`。 |
| 系统边界 | 本规格定义配置如何成为运行目标真相；不定义业务能力语义、不替代发布/源码/公开入口/监控规格，也不让运行面状态成为配置来源。 |

## 5. 内部分工与架构

### 5.1 配置引用图

```mermaid
flowchart LR
  CICD[config/cicd/targets.yaml] --> OpsTarget[ops/targets.ts]
  Artifact[config/artifact-registry.yaml] --> OpsTarget
  Hwlab[config/hwlab-node-lanes.yaml] --> OpsTarget
  AgentRun[config/agentrun.yaml] --> OpsTarget
  Observability[config/platform-infra/observability.yaml] --> ConfigRef[ops/config-refs.ts]
  Secrets[config/secrets-distribution.yaml] --> OpsSecret[ops/secrets.ts]
  ConfigRef --> Hwlab
  ConfigRef --> AgentRun
  OpsTarget --> DomainCLI[domain CLI plan/status/dry-run]
  OpsSecret --> DomainCLI
  DomainCLI --> Runtime[controlled runtime or bounded output]
```

### 5.2 target/lane 解析数据流

```mermaid
flowchart TD
  Args[explicit --target/--node/--lane] --> Select[selection]
  Defaults[YAML defaults] --> Select
  Select --> Resolver[ops target resolver]
  Resolver --> Validate[shape and reference validation]
  Validate --> Plan[resolved target summary]
  Plan --> Domain[CI/deploy/artifact/HWLAB/AgentRun/platform-infra]
  Domain --> Output[bounded summary + drill-down]
```

命令行或 issue 已明确 node/lane/target 时，resolver 只校验和解释该目标，不得用全局 default 覆盖。未显式传入目标时，resolver 可以读取 domain YAML default，并在输出中说明默认来源路径。

### 5.3 Secret sourceRef 同步链路

```mermaid
sequenceDiagram
  participant YAML as owning YAML
  participant CLI as controlled CLI
  participant Source as local sourceRef
  participant Runtime as runtime Secret
  YAML->>CLI: sourceRef + sourceKey + targetKey
  CLI->>Source: inspect presence and fingerprint
  Source-->>CLI: presence/fingerprint only
  CLI-->>CLI: valuesPrinted=false
  CLI->>Runtime: sync only when --confirm
  Runtime-->>CLI: object/key presence
  CLI-->>YAML: no reverse write-back
```

缺少 sourceRef、targetKey、providerCredential 或 tool credential 时，CLI 必须暴露 YAML/AipodSpec binding 缺口，不得通过复制其他 lane Secret、手工创建 legacy Secret 或 patch runtime namespace 规避。

### 5.4 publicExposure/Caddy/FRPC 链路

```mermaid
flowchart LR
  PublicYaml[publicExposure YAML] --> PublicHelper[ops/public-exposure.ts]
  PublicHelper --> Frpc[FRPC Secret/render]
  PublicHelper --> Caddy[PK01 Caddy managed block]
  PublicHelper --> Probe[HTTPS public health probe]
  Probe --> Summary[public URL + diagnostic endpoint summary]
```

正式用户入口来自 YAML 中的 public URL 和 publicExposure；FRP remote port、Caddy backend、本地 service DNS、direct port 或历史 nip.io 域名只能作为实现细节、诊断入口或 legacy 对照。

### 5.5 CI PipelineRun/Argo/git-mirror 状态链路

```mermaid
sequenceDiagram
  participant CLI
  participant Target as YAML target
  participant Mirror as git-mirror
  participant Tekton
  participant Argo
  participant Runtime
  CLI->>Target: resolve CI/CD target
  CLI->>Mirror: read/sync/flush via controlled entry
  Mirror-->>CLI: refs and pendingFlush summary
  CLI->>Tekton: PipelineRun status or dry-run manifest
  Tekton-->>CLI: PipelineRun/TaskRun bounded summary
  CLI->>Argo: Application sync/health status
  Argo-->>Runtime: desired runtime state
  Runtime-->>CLI: readiness/public probe summary
```

状态输出必须区分 PR merge commit、current source head、PipelineRun、Argo revision、git-mirror pendingFlush 和 runtime readiness；不得只用一个当前 head 推断所有阶段完成。

## 6. 原子需求

### 6.1 OPS-TARGET-REQ-001 YAML target 真相

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-TARGET-REQ-001 | 目标真相 | PJ2026-01060308 YAML目标治理 | [YAML运维](PJ2026-010603-yaml-first-ops.md) |

CI/CD、deploy、artifact-registry、HWLAB node/lane、AgentRun 和 platform-infra 的 target、lane、namespace、route、workspace、registry endpoint、public URL、SecretRef、gitops path 和 CI/CD 参数必须来自 owning YAML 或显式参数。

代码不得在主路径中新增隐藏默认 `G14`、`D601`、`v02`、`v03`、namespace、route、registry endpoint 或工作目录。缺少配置时应报出 YAML 路径、字段名和下一步配置入口。

### 6.2 OPS-TARGET-REQ-002 configRef 解析

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-TARGET-REQ-002 | 配置引用 | PJ2026-01060308 YAML目标治理 | [公共原语](PJ2026-010603-yaml-first-ops.md#66-ops-yaml-req-006-公共-ops-primitive) |

跨 YAML 目标事实必须通过 `path/to/file.yaml#object.path` configRef 表达。configRef parser 只负责读取、校验存在性、生成摘要 hash、展示引用链和暴露缺失字段；不得把解析后的大对象写回另一个 YAML 成为第二真相。

`platform-infra observability` 的 serviceConnection 不得复制 HWLAB/AgentRun 的 node/lane/namespace 事实，必须通过 configRef 指向对应 lane 配置，并在 `plan/status --full` 中展示解析链。

### 6.3 OPS-TARGET-REQ-003 公共 resolver 和 domain 注入默认

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-TARGET-REQ-003 | resolver | PJ2026-01060308 YAML目标治理 | [控制面模块化](PJ2026-01060307-control-plane-modularity.md) |

公共 option parser 不允许内置 domain target 默认。公共 parser 可以返回 `targetId: null`，由调用 domain 把 YAML default 注入并输出 default 来源路径。`ciTarget()`、deploy provider resolver、artifact-registry options 和 platform-infra common options 都必须遵循该规则。

### 6.4 OPS-TARGET-REQ-004 Secret 与 credential 脱敏一致性

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-TARGET-REQ-004 | Secret脱敏 | PJ2026-01060308 YAML目标治理 | [用户管理](PJ2026-0105-user-management.md)、[Agent编排](PJ2026-0102-agent-orchestration.md) |

Secret plan/status 只允许输出对象名、key 名、sourceRef、targetKey、presence、fingerprint、字节数、缺失项和 `valuesPrinted=false`。AgentRun provider credential、tool credential、HWLAB bootstrap Secret、platform-infra Secret 和通用 `secrets` 命令必须使用同一类 redacted sourceRef/fingerprint 语义。

### 6.5 OPS-TARGET-REQ-005 legacy adapter 隔离

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-TARGET-REQ-005 | legacy隔离 | PJ2026-01060308 YAML目标治理 | [发布流水](PJ2026-010601-controlled-release.md) |

D601 maintenance deploy、G14 DEV/PROD retirement、v02-only runtime migration、Code Queue compat path 等历史入口可以保留为 legacy adapter，但必须在代码和输出中标注原因、替代命令和是否允许 mutation。legacy adapter 不得成为主 runtime lane 的 fallback，也不得补齐缺失 YAML/Secret。

### 6.6 OPS-TARGET-REQ-006 hardcode inventory 与验收

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-TARGET-REQ-006 | inventory | PJ2026-01060308 YAML目标治理 | [平台运维](PJ2026-0106-platform-ops.md) |

每轮治理必须维护 hardcode inventory，并把命中分类为 `remove-code-default`、`keep-domain-special`、`legacy-adapter`、`test-fixture` 或 `help-example`。代码中保留的目标名必须属于后四类之一；`remove-code-default` 必须迁移到 YAML 或公共 helper。

验收至少覆盖 `ci plan/status --target <id>`、`artifact-registry plan/status --target <id>`、`deploy apply --dry-run` 目标来源说明、`hwlab nodes control-plane status --node <node> --lane <lane>` 的 YAML-declared lane、`platform-infra observability plan/status --full` 的 configRef 解析链和 `secrets status --config ... --full` 的脱敏输出。

## 7. 过程控制

本规格的执行 issue 为 [#911](https://github.com/pikasTech/unidesk/issues/911)。源码文件头部应标注 `SPEC: PJ2026-01060308 cicd-yaml-targets draft-2026-06-25-cicd-yaml-targets`；自动生成文件、纯配置、锁文件和无法承载注释头的二进制产物可例外。

首轮 hardcode inventory：

| 命中 | 分类 | 治理动作 |
| --- | --- | --- |
| `ciTarget()`、`d601ProviderId`、CI pipeline manifest、node label、host/root/workspace | remove-code-default | 迁入 `config/cicd/targets.yaml`，CI resolver 读取 YAML。 |
| `artifact-registry` 默认 D601、`127.0.0.1:5000`、runtime image、storageDir | remove-code-default | 迁入 `config/artifact-registry.yaml`。 |
| `deploy` artifact consumer provider 默认 D601 | remove-code-default | 从 artifact-registry YAML default 解析；compat path 显式 legacy。 |
| `HwlabRuntimeLane = "v02" | "v03"` 和 `isSupportedLaneId()` | remove-code-default | lane id 改为 YAML 声明 string，新增 lane 不要求改 TypeScript union。 |
| `platform-infra observability` 复制 `targetNode/lane/namespace` | remove-code-default | 改为 serviceConnection configRef 并输出解析链。 |
| D601 maintenance deploy、Code Queue compat path、v02 runtime migration | legacy-adapter | 保留安全阻断和替代命令，不作为主路径默认。 |
| 帮助示例、错误消息、历史说明中的 G14/D601/v02/v03 | help-example | 允许保留，必要时补 `configTruth` 或 legacy 标注。 |
