fix: 隔离 HWLAB production 交付身份

This commit is contained in:
Codex
2026-07-15 11:48:03 +02:00
parent 514da3cc01
commit 0a5ab9362d
6 changed files with 128 additions and 42 deletions
+1 -1
View File
@@ -299,7 +299,7 @@ lanes:
install:
stateDir: /tmp/hwlab-release-source-workspace-bootstrap
sourceAuthority:
giteaMirrorRepoKey: hwlab-nc01-v03
giteaMirrorRepoKey: hwlab-nc01-production
cicdRepo: /root/hwlab-release-cicd.git
cicdRepoLock: /tmp/hwlab-release-cicd-repo.lock
app: hwlab-node-production
+22
View File
@@ -375,6 +375,28 @@ sourceAuthority:
readUrl: http://git-mirror-http.devops-infra.svc.cluster.local:8080/pikasTech/HWLAB.git
configRef: config/hwlab-node-lanes.yaml#lanes.v03.targets.NC01.git.readUrl
disposition: replaced-by-gitea
- key: hwlab-nc01-production
targetId: NC01
upstream:
repository: pikasTech/HWLAB
cloneUrl: https://github.com/pikasTech/HWLAB.git
branch: release
gitea:
owner: mirrors
name: pikasTech-HWLAB
mirrorMode: controlled-push
publicRead: true
readUrl: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-HWLAB.git
gitops:
branch: release-gitops
flushDisposition: retained-for-gitops-flush
snapshot:
naming: gitea-actions-immutable-source
prefix: refs/unidesk/snapshots/gitea-actions/hwlab-node-runtime/release
legacyGitMirror:
readUrl: http://git-mirror-http.devops-infra.svc.cluster.local:8080/pikasTech/HWLAB.git
configRef: config/hwlab-node-lanes.yaml#lanes.production.targets.NC01.git.readUrl
disposition: replaced-by-gitea
- key: selfmedia-nc01
targetId: NC01
credentialOverride:
+33 -10
View File
@@ -214,6 +214,10 @@ repositories:
variables:
NODE: NC01
LANE: v03
- extends: templates.repositories.hwlabProduction
variables:
NODE: NC01
LANE: production
- id: selfmedia-nc01
name: selfmedia-nc01
namespace: selfmedia-ci
@@ -434,20 +438,11 @@ consumers:
NODE: NC01
LANE: production
id: hwlab-nc01-production
repositoryRef: hwlab-nc01-v03
repositoryRef: hwlab-nc01-production
lane: production
pipeline: hwlab-nc01-production-ci-image-publish
pipelineRunPrefix: hwlab-nc01-production-ci-poll
argoApplication: hwlab-node-production
params:
source_branch: release
gitops_branch: release-gitops
source_snapshot_prefix: refs/unidesk/snapshots/gitea-actions/hwlab-node-runtime/release
pipeline_name: hwlab-nc01-production-ci-image-publish
pipeline_run_prefix: hwlab-nc01-production-ci-poll
service_account: hwlab-nc01-production-tekton-runner
lane: production
runtime_namespace: hwlab-production
sourceArtifact:
mode: remote-pipeline-annotation
renderer: hwlab-runtime-lane
@@ -758,6 +753,34 @@ templates:
node: "${NODE}"
lane: v03
runtime_namespace: hwlab-v03
hwlabProduction:
id: "hwlab-${nodeLower}-production"
name: "hwlab-${nodeLower}-production"
namespace: hwlab-ci
providerType: gitea
url: https://gitea.pikapython.com/mirrors/pikasTech-HWLAB
cloneUrl: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-HWLAB.git
owner: mirrors
repo: pikasTech-HWLAB
secretName: "pac-gitea-hwlab-${nodeLower}-production"
tokenKey: token
webhookSecretKey: webhook.secret
concurrencyLimit: 1
params:
git_read_url: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-HWLAB.git
git_write_url: http://git-mirror-write.devops-infra.svc.cluster.local:8080/pikasTech/HWLAB.git
source_branch: release
gitops_branch: release-gitops
source_snapshot_prefix: refs/unidesk/snapshots/gitea-actions/hwlab-node-runtime/release
pipeline_name: "hwlab-${nodeLower}-production-ci-image-publish"
pipeline_run_prefix: "hwlab-${nodeLower}-production-ci-poll"
service_account: "hwlab-${nodeLower}-production-tekton-runner"
workspace_pvc_size: 8Gi
git_ssh_secret: hwlab-git-ssh
pipeline_timeout: 1h0m0s
node: "${NODE}"
lane: production
runtime_namespace: hwlab-production
consumers:
agentrunV02:
id: "agentrun-${nodeLower}-v02"
@@ -19,23 +19,48 @@
- `https://hwlab.pikapython.com` YAML publicExposure
- PostgreSQL database、role、Secret consumer 和 migration ledger
- Kafka client、direct publish、refresh replay、projector 和 live SSE consumer group。
- production 与 development 共享同一个 HWLAB Gitea PaC Repository CR;两个 lane 使用独立 consumer,并由 consumer params 覆盖 source branch、snapshot、Pipeline 和 runtime identity。
- 共享 Repository 避免同一镜像仓库重复声明 PaC Repository;独立 consumer 仍保持 production 自动交付路径与 development 完全隔离。
- `lanes.production.targets.NC01.sourceAuthority.giteaMirrorRepoKey` 已统一为共享 authority `hwlab-nc01-v03`,不再引用不存在的 production repo key。
- delivery authority parser 以 consumer params 解析 branch 与 snapshot
- 显式 consumer override 优先
- 未显式覆盖时继承 Repository 默认;
- 多分支镜像优先匹配同 branch authority
- 唯一共享镜像允许 production consumer 复用同一 Repository。
- production 与 development 复用同一个 Gitea 物理仓库
`mirrors/pikasTech-HWLAB`,但分别声明独立 YAML source identity
- development`hwlab-nc01-v03` / `v0.3` / `v0.3-gitops`
- production`hwlab-nc01-production` / `release` / `release-gitops`
- production PaC consumer 精确引用 `hwlab-nc01-production` repository identity
branch、snapshot 和 GitOps revision 由该 repository identity 声明,
不再由 consumer params 覆盖 development identity
- `lanes.production.targets.NC01.sourceAuthority.giteaMirrorRepoKey`
精确引用 `hwlab-nc01-production`
- delivery authority parser 已删除同 target/owner/repo 的跨 branch fallback
- 必须同时精确匹配 target、Gitea owner/name 和 source branch
- 缺少或冲突时 fail-closed
- 禁止把 `v0.3` identity 猜作 `release` authority。
- 通用 HWLAB lane parser 和 plan 已投影 migration ledger,并从 owning YAML 动态生成合法 lane 提示。
- `config/platform-infra/kafka.yaml` 已声明 production Cloud API Kafka ACL,未改变 topic、实时和回放架构。
## 方案依据
- OpenGitOps 原则要求 desired state 声明式、版本化且不可变,并由软件代理自动拉取和持续 reconcile;因此 branch identity 与 immutable snapshot 必须由 owning YAML 明确声明,不能依赖运行时猜测。
- Tekton Pipelines 将 Git revision 作为显式输入:
- source branch 只负责选择受控镜像入口;
- 实际构建继续使用受控 snapshot/commit revision
- mutable branch 名不直接充当构建 provenance。
- Argo CD 的 `targetRevision` 明确选择 Git branch、tag 或 commitproduction 使用独立 `release-gitops`,避免与 `v0.3-gitops` 共用可变 desired state。
- Kubernetes 建议以不可变 image digest 或等价内容寻址 revision
固定工作负载版本:
- Pipeline 继续产出 commit-pinned artifact
- GitOps/Argo 只消费已固定 revision
- 禁止从运行面或脏 workspace 构建。
- 官方参考:
- OpenGitOps principles<https://opengitops.dev/>
- Tekton Git resolver revision<https://tekton.dev/docs/pipelines/git-resolver/>
- Argo CD tracking strategies<https://argo-cd.readthedocs.io/en/stable/user-guide/tracking_strategies/>
- Kubernetes image digest<https://kubernetes.io/docs/concepts/containers/images/>。
## Target 原入口证据
以下命令均在 `NC01:/root/unidesk/.worktree/2010-hwlab-release-production-lane` 执行:
- `git diff --check`:通过。
- `bun --check`
- `scripts/src/cicd-delivery-authority.ts`:通过;
- `scripts/src/hwlab-fake-model-provider.ts`:通过;
- `scripts/src/hwlab-node-lanes.ts`:通过;
- `scripts/src/hwlab-node/entry.ts`:通过;
@@ -50,19 +75,22 @@
- namespace 为 `hwlab-v03`
- development 配置继续可解析。
- `bun scripts/cli.ts platform-infra pipelines-as-code plan --target NC01 --consumer hwlab-nc01-production`
- Repository 为共享的 `hwlab-nc01-v03`
- Repository 为独立 identity `hwlab-nc01-production`
- consumer 为独立的 `hwlab-nc01-production`
- Tekton Pipeline 为 `hwlab-nc01-production-ci-image-publish`
- Argo Application 为 `hwlab-node-production`
- `single-path``yaml-source-of-truth``public-repository-url``gitea-internal-source``runtime-zero-docker` 均为 `true`
- `bun scripts/cli.ts platform-infra pipelines-as-code plan --target NC01 --consumer hwlab-nc01-v03`:通过,development consumer 保持独立。
- delivery authority 与 renderer 定向断言通过:
- NC01 声明个 HWLAB Gitea repositorykey 为 `hwlab-nc01-v03`
- production 与 v03 的 `repositoryRef` 均为 `hwlab-nc01-v03`
- production consumer 保持 `hwlab-nc01-production`
- production branch 为 `release`snapshot prefix 为 release 独立前缀
- authority 解析结果为 `pac-pr-merge`
- feature config renderer 使用 production consumer。
- NC01 声明个 HWLAB source identity,分别为
`hwlab-nc01-v03` `hwlab-nc01-production`
- 两个 identity 指向同一 Gitea 物理仓库
- production `repositoryRef``hwlab-nc01-production`branch`release`
- development `repositoryRef``hwlab-nc01-v03`branch 为 `v0.3`
- 两个 lane 的 snapshot prefix 与 GitOps branch 独立;
- production consumer 携带 `v0.3` source branch 查询时返回
`authority-identity-mismatch`,证明跨 branch fail-closed
- parser 源码不再包含 `branchAuthorityRepositories` fallback。
- 纯 Kafka 定向断言通过:
- `directPublish``liveKafkaSse``kafkaRefreshReplay``true`
- `transactionalProjector``projectionOutboxRelay``projectionRealtime``false`
@@ -72,7 +100,18 @@
- GitOps branch、runtime namespace、Argo Application、public origin
- PostgreSQL database、role、Secret、migration ledger
- Kafka direct publish、refresh replay 和 live SSE group
- shared Repository、independent consumer 和各 lane branch 参数
- shared physical Gitea repository、independent source/repository/consumer identity
## 验证边界
- `platform-infra gitea validate --target NC01` 未能进入本任务新增 identity 的运行面校验:
- 命令先被既有 `agentrun-nc01-release`
`legacyGitMirror.configRef` 缺失阻断;
- 该缺失存在于 `origin/master`,不属于本任务改动;
- 本轮未扩大范围修复该独立问题。
- 因用户明确禁止人工 mirror、PipelineRun、Argo 和创建 `release` branch
本轮证据证明的是 YAML 声明、controlled-push 选择、PaC binding 与 fail-closed 隔离;
合并后的真实自动链仍由后续授权阶段通过正常 GitHub release 提交触发。
## Primary Workspace 边界
+10
View File
@@ -21,6 +21,16 @@
- patch 不得改变交付 authority 或冒充终态;
- 结论必须写回 owning YAML/源码并由正常 PR 自动交付;
- 临时 patch 随后撤销或由声明式交付覆盖。
- HWLAB production release delivery authority
- development 与 production 复用同一个
`mirrors/pikasTech-HWLAB` Gitea 物理仓库;
- owning YAML 必须分别声明 `hwlab-nc01-v03`
`hwlab-nc01-production` source identity
- production identity 固定选择 `release`、独立 immutable snapshot prefix
`release-gitops`
- production PaC consumer 必须精确引用 production repository identity
- delivery authority parser 必须精确匹配 target、owner/name 与 branch
缺少 production identity 时 fail-closed,禁止回退到 `v0.3`
- 进入任何 HWLAB 工作前,按 `NC01/v03` 解析 route/workspace/sourceBranch/kubeRoute/runtime namespace 做预检、快进和验证:工作面是 `NC01:/root/hwlab-v03`、source branch 是 `v0.3`、k3s route 是 `NC01:k3s`、runtime namespace 是 `hwlab-v03`、公网入口由 YAML 的 NC01 target 声明。
- NC01 的 node-local registry 是 k3s workload/PVC,不是 host Docker registry。`hwlab nodes control-plane infra status --node NC01 --lane v03` 应显示 registry workload ready、PVC bound 和 endpoint ready;必须通过受控 `runtime-image preload``infra tools-image build/status` 补齐 BuildKit、runtime/base 和 tools image,再把 HWLAB/AgentRun status 与 web-probe smoke 作为可用性证据。
- HWLAB 项目内长期规则入口仍以目标 repo 的 `AGENTS.md` 为准。进入已解析的目标 workspace 后,必须重新读取该 workspace 的规则文件;不能只凭主 server 的压缩上下文继续操作。
+7 -15
View File
@@ -149,20 +149,12 @@ export function readCicdDeliveryAuthorityCatalog(): CicdDeliveryAuthorityCatalog
pacRepositories.filter((candidate) => same(candidate.id, repositoryRef)),
`${path}.repositoryRef=${repositoryRef}`,
);
const params = item.params === undefined ? null : record(item.params, `${path}.params`);
const sourceBranch = params === null
? pacRepository.sourceBranch
: requiredString(params.source_branch ?? pacRepository.sourceBranch, `${path}.params.source_branch`);
const sourceSnapshotPrefix = params === null
? pacRepository.sourceSnapshotPrefix
: requiredString(params.source_snapshot_prefix ?? pacRepository.sourceSnapshotPrefix, `${path}.params.source_snapshot_prefix`);
const authorityRepositories = giteaRepositories.filter((candidate) => same(candidate.targetId, node)
&& same(candidate.owner, pacRepository.owner)
&& same(candidate.repo, pacRepository.repo));
const branchAuthorityRepositories = authorityRepositories.filter((candidate) => same(candidate.sourceBranch, sourceBranch));
const authorityRepository = exactlyOne(
branchAuthorityRepositories.length > 0 ? branchAuthorityRepositories : authorityRepositories,
`${path} source authority ${node}/${pacRepository.owner}/${pacRepository.repo}@${sourceBranch}`,
giteaRepositories.filter((candidate) => same(candidate.targetId, node)
&& same(candidate.owner, pacRepository.owner)
&& same(candidate.repo, pacRepository.repo)
&& same(candidate.sourceBranch, pacRepository.sourceBranch)),
`${path} source authority ${node}/${pacRepository.owner}/${pacRepository.repo}@${pacRepository.sourceBranch}`,
);
return {
consumerId,
@@ -172,8 +164,8 @@ export function readCicdDeliveryAuthorityCatalog(): CicdDeliveryAuthorityCatalog
pipelineRunPrefix,
repositoryRef,
sourceRepository: authorityRepository.sourceRepository,
sourceBranch,
sourceSnapshotPrefix,
sourceBranch: authorityRepository.sourceBranch,
sourceSnapshotPrefix: pacRepository.sourceSnapshotPrefix,
giteaOwner: pacRepository.owner,
giteaRepository: pacRepository.repo,
giteaRepositoryUrl: pacRepository.url,