diff --git a/.agents/skills/unidesk-cicd/SKILL.md b/.agents/skills/unidesk-cicd/SKILL.md index bdd723cf..d44c3561 100644 --- a/.agents/skills/unidesk-cicd/SKILL.md +++ b/.agents/skills/unidesk-cicd/SKILL.md @@ -19,14 +19,11 @@ bun scripts/cli.ts hwlab g14 git-mirror status --lane v02 bun scripts/cli.ts agentrun control-plane status bun scripts/cli.ts platform-infra gitea mirror status --target JD01 bun scripts/cli.ts platform-infra gitea mirror webhook status --target JD01 -bun scripts/cli.ts platform-infra gitea mirror webhook test --target JD01 --repo unidesk-master --confirm bun scripts/cli.ts platform-infra pipelines-as-code status --target JD01 bun scripts/cli.ts platform-infra pipelines-as-code status --target JD01 --consumer hwlab-jd01-v03 bun scripts/cli.ts platform-infra pipelines-as-code closeout --target JD01 --consumer --source-commit --wait bun scripts/cli.ts platform-infra pipelines-as-code history --target JD01 --limit 10 bun scripts/cli.ts platform-infra pipelines-as-code history --target JD01 --id -bun scripts/cli.ts cicd branch-follower status -bun scripts/cli.ts cicd branch-follower debug-step --follower web-probe-sentinel-master --step state-read ``` 节点级只读状态必须优先用 `cicd status --node `。它从 `config/platform-infra/pipelines-as-code.yaml` 找到该 node 的所有当前 PaC consumer,一次性汇总 PipelineRun、Argo/GitOps、runtime readiness 和诊断;不要再靠阅读源码或手动拼三条 consumer 命令来回答 “NC01 的 CI/CD 流水线情况”。`platform-infra pipelines-as-code status --target --consumer ` 只作为单 consumer drill-down。 @@ -47,6 +44,7 @@ bun scripts/cli.ts cicd branch-follower debug-step --follower web-probe-sentinel - CI/CD、GitOps、rollout、PipelineRun、Argo、git-mirror 和 AgentRun 部署必须走受控 CLI;不要用裸 `kubectl`、`argo`、`tkn`、`curl` 当正式控制入口。 - CI/CD source authority 只能来自 YAML 声明的 Kubernetes 托管 source authority:legacy lane 使用 k8s git-mirror snapshot,Gitea/PaC migrated lane 使用 GitHub PR merge -> GitHub webhook bridge -> Gitea controlled mirror + immutable snapshot ref -> Pipelines-as-Code。受控命令先在 k8s 内同步/创建不可变 `refs/unidesk/snapshots/.../` stage ref;build/status/publish 只消费该 snapshot,host worktree、本地 `git fetch/pull`、可变 branch ref 或 Pipeline 内直连 GitHub 都不能作为 authoritative source。 - JD01/NC01 `agentrun--v02`、`sentinel--v03`、`hwlab--v03` 的正式 CI/CD closeout 入口是 `cicd status --node ` 和 `platform-infra pipelines-as-code closeout|status|history --target --consumer `。`closeout` 是通用 consumer 引导入口,只读取/等待 PaC、Tekton、GitOps、Argo 和 runtime 对齐,不触发旧手动发布。`cicd branch-follower` 和 `cicd gitea-actions-poc` 对这些 consumer 只保留历史/迁移只读用途,不得作为当前交付判断入口。 +- PaC `.tekton` 文件必须用 Repository CR 的 target/node 参数隔离 JD01/NC01,避免同一个 Gitea push 在一个 target cluster 内额外创建另一个 target 的 PipelineRun;history/detail 必须按实际 PipelineRun prefix/pipeline 归属 consumer。 - GitHub/Git 相关 egress 必须走 YAML-first host proxy/sourceRef:branch-follower controller 读 `config/cicd-branch-followers.yaml#controller.source.githubSsh`,runtime legacy git-mirror 读 owning lane/control-plane YAML 的 host proxy 和 `githubTransport`,Gitea/PaC 迁移 lane 读 `config/platform-infra/gitea.yaml` 与 `config/platform-infra/pipelines-as-code.yaml`;禁止依赖未声明 host env、trans proxy、裸直连 GitHub 或 CLI 输出解析。 - Gitea/PaC lane 的 GitHub -> Gitea 自动同步必须用 `platform-infra gitea mirror webhook apply|status|test`。该路径是单向同步,只更新 Gitea branch 和 immutable snapshot ref;不得引入 Gitea -> GitHub 回写、轮询 fallback、Gitea Actions/act_runner fallback 或第二套状态存储。 - Gitea webhook/FRPC/Caddy 变更的 closeout 必须看受控 CLI 的 rollout/status/test 证据;Secret 或 ConfigMap apply 成功不等于 connector Pod 已加载新 proxy/path。 diff --git a/.agents/skills/unidesk-cicd/references/gitea-pac.md b/.agents/skills/unidesk-cicd/references/gitea-pac.md index cd14c095..f4893554 100644 --- a/.agents/skills/unidesk-cicd/references/gitea-pac.md +++ b/.agents/skills/unidesk-cicd/references/gitea-pac.md @@ -16,6 +16,7 @@ GitHub remains the upstream write authority. A delivery should be triggered by m - Node-level status for these consumers is `bun scripts/cli.ts cicd status --node `. Consumer drill-down is `platform-infra pipelines-as-code status|history|closeout --target --consumer `. - Multi-node PaC consumers that share a GitHub upstream must not share a webhook bridge URL. Each target node declares its own GitHub webhook public path and FRP remote port in `config/platform-infra/gitea.yaml#targets[].webhookSync`, then `platform-infra gitea apply --target --confirm` renders the node-local bridge, FRPC proxy and PK01 Caddy path. - PaC Repository CR `spec.url` matches the URL in Gitea webhook payloads. Keep `config/platform-infra/pipelines-as-code.yaml#repositories[].url` on the public Gitea repository URL, and keep k8s-internal service URLs only in `cloneUrl` or `params.git_read_url`; otherwise PaC logs `cannot find a repository match` and no PipelineRun is created. +- Repositories shared by JD01 and NC01 must pass a target-specific `node` Repository param, and each `.tekton` PipelineRun must filter on that param with `pipelinesascode.tekton.dev/on-cel-expression`. A push for one target must not create the other target's PipelineRun in the same target cluster. ## Coverage Matrix @@ -29,6 +30,7 @@ GitHub remains the upstream write authority. A delivery should be triggered by m | `hwlab-nc01-v03` | `pikasTech/HWLAB@v0.3` | `hwlab-ci` | `hwlab-nc01-v03-ci-image-publish` | `hwlab-node-v03` | `platform-infra pipelines-as-code closeout --target NC01 --consumer hwlab-nc01-v03 --source-commit --wait` | Use `bun scripts/cli.ts platform-infra pipelines-as-code history --target --limit 10` for all-consumer trigger, timing and reuse audit. It must read live Gitea Repository CR plus Tekton PipelineRun/TaskRun objects on the target node, aggregate on the target side, and print `READ_ERRORS`. +`history --id ` must still apply the consumer's actual PipelineRun prefix or Tekton pipeline match, so a PipelineRun in a shared namespace cannot be attributed to both JD01 and NC01 consumers. ## Closeout Order diff --git a/.tekton/web-probe-sentinel-jd01-pac.yaml b/.tekton/web-probe-sentinel-jd01-pac.yaml index 3d79ae30..35ff0169 100644 --- a/.tekton/web-probe-sentinel-jd01-pac.yaml +++ b/.tekton/web-probe-sentinel-jd01-pac.yaml @@ -5,6 +5,7 @@ metadata: annotations: pipelinesascode.tekton.dev/on-event: "[push]" pipelinesascode.tekton.dev/on-target-branch: "[master]" + pipelinesascode.tekton.dev/on-cel-expression: "event == 'push' && target_branch == 'master' && node == 'JD01'" labels: app.kubernetes.io/name: hwlab-web-probe-sentinel-jd01-pac app.kubernetes.io/part-of: hwlab-web-probe-sentinel diff --git a/.tekton/web-probe-sentinel-nc01-pac.yaml b/.tekton/web-probe-sentinel-nc01-pac.yaml index 360f75ac..c2ecee0e 100644 --- a/.tekton/web-probe-sentinel-nc01-pac.yaml +++ b/.tekton/web-probe-sentinel-nc01-pac.yaml @@ -5,6 +5,7 @@ metadata: annotations: pipelinesascode.tekton.dev/on-event: "[push]" pipelinesascode.tekton.dev/on-target-branch: "[master]" + pipelinesascode.tekton.dev/on-cel-expression: "event == 'push' && target_branch == 'master' && node == 'NC01'" labels: app.kubernetes.io/name: hwlab-web-probe-sentinel-nc01-pac app.kubernetes.io/part-of: hwlab-web-probe-sentinel diff --git a/config/platform-infra/pipelines-as-code.yaml b/config/platform-infra/pipelines-as-code.yaml index 491f2e30..b094402e 100644 --- a/config/platform-infra/pipelines-as-code.yaml +++ b/config/platform-infra/pipelines-as-code.yaml @@ -127,6 +127,7 @@ templates: git_read_url: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-agentrun.git git_write_url: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-agentrun.git source_branch: v0.2 + node: "${NODE}" gitops_branch: "${nodeLower}-v0.2-gitops" source_snapshot_prefix: refs/unidesk/snapshots/gitea-actions/agentrun-v0.2 pipeline_name: "agentrun-${nodeLower}-v02-ci-image-publish" diff --git a/docs/reference/platform-infra.md b/docs/reference/platform-infra.md index d69e2cd6..7bfcee5d 100644 --- a/docs/reference/platform-infra.md +++ b/docs/reference/platform-infra.md @@ -25,6 +25,7 @@ - PaC history is the trigger/timing audit surface for Gitea/PaC-managed lanes. It must query Gitea Repository CR and Tekton PipelineRun/TaskRun live objects on the target node, aggregate there, return Beijing-time display by YAML timezone, expose a detail id for drill-down, and report read errors explicitly; a large namespace or unreadable target object must never be rendered as a successful empty table. - Formal delivery for a PaC-migrated consumer starts with merging the GitHub PR into that consumer's YAML-declared upstream branch. The GitHub webhook bridge then syncs GitHub to the controlled Gitea mirror and immutable snapshot refs; the Gitea repository push webhook triggers Pipelines-as-Code, which creates the Tekton PipelineRun. Operators must not replace this with `trigger-current`, `webhook-test`, a direct Gitea push, raw PipelineRun creation, or a local Git mirror edit. `webhook-test` is only a connectivity diagnostic. - `config/platform-infra/pipelines-as-code.yaml` may declare multiple repositories and consumers. JD01 and NC01 both declare AgentRun, Web sentinel and HWLAB consumers; use `cicd status --node ` for node-level status, `history --target ` for all-consumer audit, and `status --target --consumer ` for consumer-scoped closeout. Consumer-scoped status must not mix PipelineRuns or env reuse evidence across repositories. +- Shared upstream repositories must isolate target-specific `.tekton` files with Repository CR params, currently `node`, and `pipelinesascode.tekton.dev/on-cel-expression`. A NC01 webhook delivery must not create JD01 PipelineRuns in the NC01 cluster, and history drill-down must not attribute the same PipelineRun to multiple consumers. - Public Gitea UI may use the YAML-declared HTTPS hostname, but k8s-internal consumers must use the ClusterIP service URL from YAML. Internal CI/Argo/runtime reads must not loop through public DNS/Caddy/FRP, and migrated lanes must not fall back to legacy git-mirror read URLs when the commit exists only in Gitea. - A PaC-migrated lane must keep a single trigger path: Gitea webhook -> Pipelines-as-Code -> Tekton -> GitOps/Argo -> k8s runtime. Do not add Gitea Actions, `act_runner`, branch-follower or custom script fallback unless a later issue explicitly changes the architecture. `config/cicd-gitea-actions-poc.yaml` is archived POC context only; snapshot refs that still contain `gitea-actions` are historical names retained for compatibility, not evidence that Gitea Actions is active. - k8s runtime remains Docker-free from the point it pulls already built images. CI build steps may use YAML-declared native build tooling, but Docker socket/daemon access must not become part of the runtime plane. diff --git a/scripts/src/help.ts b/scripts/src/help.ts index 183ea839..70816481 100644 --- a/scripts/src/help.ts +++ b/scripts/src/help.ts @@ -59,8 +59,8 @@ export function rootHelp(): unknown { { command: "decision show ", description: "Show one Decision Center record." }, { command: "deploy check|plan|apply [--file deploy.json|--env dev|prod] [--service id] [--commit full-sha] [--dry-run] [--force]", description: "Reconcile services from origin/master:deploy.json environments; --commit overrides one reviewed artifact consumer such as frontend for release/v1 validation or rollback. code-queue artifact consumption is dev-only." }, { command: "cicd status --node ", description: "Show one node's CI/CD closeout summary across current Pipelines-as-Code consumers, including PipelineRun, Argo and runtime readiness." }, - { command: "cicd gitea-actions-poc plan|status", description: "Historical CI/CD migration path for GH-1548/GH-1549; current node status should use cicd status --node ." }, - { command: "cicd branch-follower plan|apply|status|run-once|events|logs", description: "Deprecated migration-only Kubernetes branch follower controller; keep existing production status/debug during cutover, but do not add new self-maintained branch-following features." }, + { command: "cicd gitea-actions-poc plan|status", description: "Archived read-only CI/CD migration evidence for GH-1548/GH-1549; never use as a delivery or closeout path." }, + { command: "cicd branch-follower status|events|logs", description: "Archived migration diagnostics only; PaC-migrated JD01/NC01 lanes must use cicd status and platform-infra pipelines-as-code closeout/status/history." }, { command: "dev-env validate|prewarm-images", description: "Validate D601 unidesk-dev guardrails or prewarm dev foundation images into native k3s containerd through a bounded async job." }, { command: "artifact-registry plan|render|status|health|install|deploy-backend-core|deploy-service", description: "Manage the D601 host-managed CNCF Distribution registry and run pull-only artifact CD for supported services, including D601 direct, k3s-managed, and code-queue dev-only consumers." }, { command: "auth-broker contract|health --dry-run|credential-request --dry-run|pr-preflight --dry-run", description: "Inspect the P0 Rust auth broker and CLI adapter contract without reading token values, writing GitHub, or starting services." }, @@ -750,17 +750,13 @@ function webProbeHelpSummary(): unknown { function cicdHelpSummary(): unknown { return { - command: "cicd status --node | gitea-actions-poc ... | branch-follower ...", + command: "cicd status --node ", output: "text by default; use --json, --raw, or -o json|yaml for machine output", usage: [ "bun scripts/cli.ts cicd status --node NC01", "bun scripts/cli.ts cicd status --node NC01 --full", - "bun scripts/cli.ts cicd gitea-actions-poc plan", - "bun scripts/cli.ts cicd gitea-actions-poc status", - "bun scripts/cli.ts cicd branch-follower plan", - "bun scripts/cli.ts cicd branch-follower status", ], - description: "Node-level CI/CD status is the primary read path. Gitea Actions and branch-follower remain deprecated migration-only diagnostics.", + description: "Node-level CI/CD status is the primary read path for PaC-migrated consumers. Gitea Actions and branch-follower are archived diagnostics and are not delivery or closeout paths.", }; } diff --git a/scripts/src/platform-infra-pipelines-as-code-remote.sh b/scripts/src/platform-infra-pipelines-as-code-remote.sh index ee35c5df..cf53edfc 100644 --- a/scripts/src/platform-infra-pipelines-as-code-remote.sh +++ b/scripts/src/platform-infra-pipelines-as-code-remote.sh @@ -567,18 +567,23 @@ function rowFor(consumer, item, taskRuns) { }; } +function pipelineRunMatchesConsumer(consumer, item) { + const labels = item.metadata?.labels || {}; + const name = item.metadata?.name || ''; + return name.startsWith(consumer.pipelineRunPrefix) + || labels['tekton.dev/pipeline'] === consumer.pipeline + || labels['tekton.dev/pipelineName'] === consumer.pipeline; +} + const rows = []; const consumerSummaries = []; for (const consumer of consumers) { const pipelineRuns = kubectlJson(['-n', consumer.namespace, 'get', 'pipelinerun', '-o', 'json'], { items: [] }, `${consumer.id}:pipelinerun`); const taskRuns = kubectlJson(['-n', consumer.namespace, 'get', 'taskrun', '-o', 'json'], { items: [] }, `${consumer.id}:taskrun`); let matches = (pipelineRuns.items || []).filter((item) => { - const labels = item.metadata?.labels || {}; const name = item.metadata?.name || ''; - if (detailId) return name === detailId; - return name.startsWith(consumer.pipelineRunPrefix) - || labels['tekton.dev/pipeline'] === consumer.pipeline - || labels['tekton.dev/pipelineName'] === consumer.pipeline; + if (detailId) return name === detailId && pipelineRunMatchesConsumer(consumer, item); + return pipelineRunMatchesConsumer(consumer, item); }); matches = matches.sort((a, b) => Date.parse(b.metadata?.creationTimestamp || 0) - Date.parse(a.metadata?.creationTimestamp || 0)); if (!detailId) matches = matches.slice(0, limit); diff --git a/scripts/src/platform-infra-pipelines-as-code.ts b/scripts/src/platform-infra-pipelines-as-code.ts index 2164d5fc..7224a362 100644 --- a/scripts/src/platform-infra-pipelines-as-code.ts +++ b/scripts/src/platform-infra-pipelines-as-code.ts @@ -204,7 +204,7 @@ export async function runPlatformInfraPipelinesAsCodeCommand(config: UniDeskConf function help(): Record { return { - command: "platform-infra pipelines-as-code plan|apply|status|closeout|history|webhook-test", + command: "platform-infra pipelines-as-code plan|apply|status|closeout|history", configTruth: configLabel, usage: [ "bun scripts/cli.ts platform-infra pipelines-as-code plan --target JD01", @@ -214,9 +214,9 @@ function help(): Record { "bun scripts/cli.ts platform-infra pipelines-as-code closeout --target JD01 --consumer --source-commit --wait", "bun scripts/cli.ts platform-infra pipelines-as-code history --target JD01 [--consumer hwlab-jd01-v03] [--limit 10]", "bun scripts/cli.ts platform-infra pipelines-as-code history --target JD01 --id ", - "bun scripts/cli.ts platform-infra pipelines-as-code webhook-test --target JD01 --confirm", ], - boundary: "Sole CI trigger path for GH-1552: Gitea webhook -> Pipelines-as-Code -> Tekton -> Argo/k8s runtime.", + diagnostics: "webhook-test exists only for bounded connectivity diagnosis and must not be used as delivery evidence.", + boundary: "Sole CI trigger path for GH-1552/GH-1607: GitHub PR merge -> GitHub webhook bridge -> Gitea mirror/snapshot -> Pipelines-as-Code -> Tekton -> GitOps/Argo/k8s runtime.", }; } @@ -969,7 +969,6 @@ function nextCommands(targetId: string, consumerId: string, defaultConsumerId: s closeout: `bun scripts/cli.ts platform-infra pipelines-as-code closeout --target ${targetId}${suffix} --wait`, status: `bun scripts/cli.ts platform-infra pipelines-as-code status --target ${targetId}${suffix}`, history: `bun scripts/cli.ts platform-infra pipelines-as-code history --target ${targetId}${suffix}`, - webhookTest: `bun scripts/cli.ts platform-infra pipelines-as-code webhook-test --target ${targetId}${suffix} --confirm`, }; }