From 240ff7bdb1048756f6672d5348edbcc93e11a97b Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 20 May 2026 00:27:51 +0000 Subject: [PATCH] chore: add cicd legacy cleanup precheck --- AGENTS.md | 3 +- CI.json | 60 +++++++++++++++++++++++ config.json | 16 ++++++ docs/reference/artifact-registry.md | 5 +- docs/reference/ci.md | 2 +- docs/reference/cicd-standardization.md | 52 ++++++++++++++++++++ docs/reference/cli.md | 2 +- docs/reference/deploy.md | 15 ++++++ docs/reference/devops-hygiene.md | 3 ++ docs/reference/user-service-delivery.md | 10 ++++ scripts/src/artifact-registry.ts | 24 ++++++++- scripts/src/ci.ts | 7 ++- scripts/src/config.ts | 25 ++++++++++ scripts/src/deploy.ts | 21 ++++++++ scripts/src/help.ts | 12 +++-- src/components/backend-core/src/config.ts | 17 +++++++ src/components/backend-core/src/types.rs | 13 +++++ src/components/backend-core/src/types.ts | 8 +++ 18 files changed, 283 insertions(+), 12 deletions(-) create mode 100644 docs/reference/cicd-standardization.md diff --git a/AGENTS.md b/AGENTS.md index d0fc1c65..38c5d7a9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -40,7 +40,7 @@ UniDesk 是一个以主 server 为统一入口的分布式工作平台;本文 - `bun scripts/cli.ts decision diary import/list/months/show`:把带日期标题的工作日志 Markdown 拆成 `YYYY-MM/YYYY-MM-DD.md` 日记条目并写入 PostgreSQL,规则见 `docs/reference/microservices.md`。 - `bun scripts/cli.ts deploy check/plan/apply [--file deploy.json|--env dev|prod] [--service ]`:按根目录 `deploy.json` 或 `origin/master:deploy.json#environments.` 的服务 repo 和 commit 期望状态校验或更新用户服务;`--env dev` 当前开放 D601 `backend-core`/`frontend` persistent dev rollout 和 `baidu-netdisk` artifact-consumer validation,规则见 `docs/reference/deploy.md` 与 `docs/reference/dev-environment.md`。 - `bun scripts/cli.ts dev-env validate [--manifest path] [--kubectl-dry-run]` / `dev-env prewarm-images`:离线校验 D601 `unidesk-dev` 生产隔离护栏,或把开发底座基础镜像预热到 D601 原生 k3s containerd,规则见 `docs/reference/deploy.md` 与 `docs/reference/microservices.md`。 -- `bun scripts/cli.ts artifact-registry plan|render|status|health|install|deploy-backend-core|deploy-service`:管理 D601 host-managed CNCF Distribution registry,并通过短生命周期 relay 或 D601 pull/import 做 commit-pinned pull-only artifact CD,规则见 `docs/reference/artifact-registry.md`。 +- `bun scripts/cli.ts artifact-registry plan|render|status|health|install|deploy-backend-core|deploy-service`:管理 D601 host-managed CNCF Distribution registry,并通过短生命周期 relay 或 D601 pull/import 做 commit-pinned pull-only artifact CD;`deploy-backend-core` 是 deprecated 兼容名,backend-core prod CD 标准入口是 `deploy apply --env prod --service backend-core`,规则见 `docs/reference/artifact-registry.md`。 - `bun scripts/cli.ts ci install/status/run/publish-backend-core/publish-user-service/run-dev-e2e/logs`:在 D601 原生 k3s 上安装和运行 Tekton CI,支持每 commit 检查、Code Queue 只读性能门禁、backend-core 与 user-service commit-pinned 镜像发布和手动触发的 `origin/master:deploy.json#environments.dev` 临时 namespace e2e;`run-dev-e2e` 的 Git 控制 runner、短 launcher 和 no-CD 边界见 `docs/reference/dev-ci-runner.md`,Tekton 规则见 `docs/reference/ci.md`。 - `bun scripts/cli.ts codex deploy `:旧 Code Queue 兼容部署入口已禁用,原因是它会绕过受控部署边界直连 D601 部署 Code Queue;规则见 `docs/reference/codex-deploy.md`。 - `bun scripts/cli.ts codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue ]`:通过 backend-core 私有代理提交 Code Queue 任务;控制面默认走主 server `code-queue-mgr` 写入 PostgreSQL,`--dry-run` 可只检查请求体不入队,规则见 `docs/reference/cli.md`。 @@ -78,6 +78,7 @@ UniDesk 是一个以主 server 为统一入口的分布式工作平台;本文 - `docs/reference/pipeline-model-proxy.md`:Pipeline v2 model proxy 链路架构、D601 宿主 proxy 服务部署、harness token 注入规则和 smoke test 验证流程。 - `docs/reference/deploy.md`:`deploy.json` desired-state、target-side build、一次性构建 proxy、直管/代管服务部署 executor 和 live commit 验证规则。 - `docs/reference/devops-hygiene.md`:Git-backed deployment truth、dirty worktree/manual repair 边界、受限手动操作和 CI 私有仓库 source-auth 规则。 +- `docs/reference/cicd-standardization.md`:镜像 artifact 标准化目标、File Browser 上游镜像例外、legacy CI/CD 路径分类和本轮 guardrail。 - `docs/reference/release-governance.md`:`release/v1` 稳定维护线、`master` 集成线、CI/CD server 版本固定、master CLI 兼容和 feature flag 治理规则;决策记录见 GitHub issue #6。 - `docs/reference/artifact-registry.md`:D601 host-managed CNCF Distribution registry、loopback-only 边界和 backend-core artifact CD 目标流程。 - `docs/reference/user-service-delivery.md`:用户服务默认交付流程、CI 镜像构建与 registry、Baidu Netdisk 主 server 直管微服务样板、dev 自动测试、prod 拉镜像部署和 Decision Center 产品化需求管理规则。 diff --git a/CI.json b/CI.json index a2b87c40..64460183 100644 --- a/CI.json +++ b/CI.json @@ -41,6 +41,66 @@ "volumes" ] }, + "upstreamImageConsumers": [ + { + "serviceId": "filebrowser", + "source": "upstream-image", + "upstreamImageRef": "docker.io/filebrowser/filebrowser:v2.63.3", + "upstreamSourceRepo": "https://github.com/filebrowser/filebrowser", + "upstreamSourceRevision": "ca5e249e3c0c94159c2136a0cd431a424eb18472", + "digestPin": { + "required": true, + "status": "pending-network-verification", + "expectedRefShape": "docker.io/filebrowser/filebrowser@sha256:" + }, + "mirrorStrategy": { + "mode": "mirror-after-digest-verification", + "targetRepository": "127.0.0.1:5000/upstream/filebrowser/filebrowser", + "targetDigestRefShape": "127.0.0.1:5000/upstream/filebrowser/filebrowser@sha256:" + }, + "ciBuild": { + "dockerfileBuild": false, + "publishCommand": null, + "reason": "third-party upstream image; CD may only pull a verified digest or mirror digest" + }, + "pullOnlyCdValidation": [ + "resolve tag to upstream manifest digest before mirroring or rollout", + "pull by digest or from the digest-verified local mirror", + "verify container image id/digest and OCI labels report filebrowser 2.63.3 / ca5e249e3c0c94159c2136a0cd431a424eb18472", + "verify provider-private File Browser health through the UniDesk microservice proxy", + "do not run docker build, docker compose up --build, or a CI Dockerfile producer" + ] + }, + { + "serviceId": "filebrowser-d601", + "source": "upstream-image", + "upstreamImageRef": "docker.io/filebrowser/filebrowser:v2.63.3", + "upstreamSourceRepo": "https://github.com/filebrowser/filebrowser", + "upstreamSourceRevision": "ca5e249e3c0c94159c2136a0cd431a424eb18472", + "digestPin": { + "required": true, + "status": "pending-network-verification", + "expectedRefShape": "docker.io/filebrowser/filebrowser@sha256:" + }, + "mirrorStrategy": { + "mode": "mirror-after-digest-verification", + "targetRepository": "127.0.0.1:5000/upstream/filebrowser/filebrowser", + "targetDigestRefShape": "127.0.0.1:5000/upstream/filebrowser/filebrowser@sha256:" + }, + "ciBuild": { + "dockerfileBuild": false, + "publishCommand": null, + "reason": "third-party upstream image; CD may only pull a verified digest or mirror digest" + }, + "pullOnlyCdValidation": [ + "resolve tag to upstream manifest digest before mirroring or rollout", + "pull by digest or from the digest-verified local mirror", + "verify container image id/digest and OCI labels report filebrowser 2.63.3 / ca5e249e3c0c94159c2136a0cd431a424eb18472", + "verify provider-private File Browser health through the UniDesk microservice proxy", + "do not run docker build, docker compose up --build, or a CI Dockerfile producer" + ] + } + ], "artifacts": [ { "serviceId": "baidu-netdisk", diff --git a/config.json b/config.json index 7d8a385a..f9b8ae4c 100644 --- a/config.json +++ b/config.json @@ -413,6 +413,14 @@ "url": "https://github.com/filebrowser/filebrowser", "commitId": "ca5e249e3c0c94159c2136a0cd431a424eb18472", "dockerfile": "docker.io/filebrowser/filebrowser:v2.63.3", + "artifactSource": { + "kind": "upstream-image", + "imageRef": "docker.io/filebrowser/filebrowser:v2.63.3", + "digestPinRequired": true, + "mirrorRepository": "127.0.0.1:5000/upstream/filebrowser/filebrowser", + "ciDockerfileBuild": false, + "pullOnlyCd": true + }, "composeFile": "docker run --restart unless-stopped", "composeService": "unidesk-filebrowser-d518", "containerName": "unidesk-filebrowser-d518" @@ -460,6 +468,14 @@ "url": "https://github.com/filebrowser/filebrowser", "commitId": "ca5e249e3c0c94159c2136a0cd431a424eb18472", "dockerfile": "docker.io/filebrowser/filebrowser:v2.63.3", + "artifactSource": { + "kind": "upstream-image", + "imageRef": "docker.io/filebrowser/filebrowser:v2.63.3", + "digestPinRequired": true, + "mirrorRepository": "127.0.0.1:5000/upstream/filebrowser/filebrowser", + "ciDockerfileBuild": false, + "pullOnlyCd": true + }, "composeFile": "docker run --restart unless-stopped", "composeService": "unidesk-filebrowser-d601", "containerName": "unidesk-filebrowser-d601" diff --git a/docs/reference/artifact-registry.md b/docs/reference/artifact-registry.md index f6e3e96b..ed1e774d 100644 --- a/docs/reference/artifact-registry.md +++ b/docs/reference/artifact-registry.md @@ -57,7 +57,6 @@ bun scripts/cli.ts artifact-registry render bun scripts/cli.ts artifact-registry install bun scripts/cli.ts artifact-registry status bun scripts/cli.ts artifact-registry health -bun scripts/cli.ts artifact-registry deploy-backend-core --commit bun scripts/cli.ts artifact-registry deploy-service --service baidu-netdisk --commit bun scripts/cli.ts artifact-registry deploy-service --service frontend --env prod --commit bun scripts/cli.ts artifact-registry deploy-service --service frontend --env dev --commit @@ -68,7 +67,7 @@ bun scripts/cli.ts artifact-registry deploy-service --service decision-center -- 真实 `install` 必须是幂等动作:创建远端目录,写入 CLI 渲染出的 config/compose/unit,执行 `systemctl daemon-reload`,启用并启动 `unidesk-artifact-registry.service`,然后运行与 `health` 相同的验收检查。若远端文件 hash 与期望不一致,install 可以覆盖由本 CLI 管理的 unit/config/compose,但不得删除 registry storage。 -`deploy-backend-core` 是 production backend-core 的 CD 入口。它必须先通过 CNCF Distribution HTTP API 确认 D601 registry 中已经存在 `unidesk/backend-core:`,随后通过 provider-gateway Host SSH 流式执行 `docker save | gzip`,在 master server 侧 `docker load`、retag、Compose `--no-build` recreate 和 live commit 验证;如果镜像不存在,应失败并要求先运行 CI artifact publication。 +`deploy-backend-core` 是旧兼容入口,当前作为标准路径已禁用。Production backend-core CD 必须使用 `bun scripts/cli.ts deploy apply --env prod --service backend-core --commit `,由 deploy reconciler 先执行共同的 artifact-consumer guardrail,再调用通用 `deploy-service` consumer。旧入口只能返回 structured deprecated 结果,不得绕过 `deploy apply --env prod`。 `deploy-service` 是标准化后的最小通用 artifact consumer。它目前只支持 `backend-core`、`baidu-netdisk`、prod/dev `frontend` 和 `decision-center`,并且必须先通过 D601 registry 的 commit-pinned manifest 校验,再执行拉取、导入/retag、部署和健康验证: @@ -133,4 +132,4 @@ Baidu Netdisk is the first main-server direct user-service sample in this flow. - provider-gateway SSH image stream 是临时控制动作,不开放长期公网 registry。 - CI 可以有较多依赖;CD 只做拉取、retag、recreate 和 live commit 验证。 - CD 不执行 `cargo build`、`docker build`、`docker compose build ` 或任何等价构建动作。 -- `server rebuild backend-core` 和 `server rebuild baidu-netdisk` 仍是维护/非标准路径,不得作为 artifact CD 完成证据。 +- `artifact-registry deploy-backend-core`、`server rebuild backend-core` 和 `server rebuild baidu-netdisk` 仍是维护/兼容/非标准路径,不得作为 artifact CD 完成证据。 diff --git a/docs/reference/ci.md b/docs/reference/ci.md index 0338bc87..8c972184 100644 --- a/docs/reference/ci.md +++ b/docs/reference/ci.md @@ -175,7 +175,7 @@ Publish a backend-core artifact for production CD: bun scripts/cli.ts ci publish-backend-core --commit --wait-ms 1200000 ``` -This command creates the `unidesk-backend-core-artifact-publish` Tekton PipelineRun. It is a CI producer action only: it may build and push `127.0.0.1:5000/unidesk/backend-core:`, but it must not recreate the master server container. Production deployment is triggered separately with `artifact-registry deploy-backend-core`. +This command creates the `unidesk-backend-core-artifact-publish` Tekton PipelineRun. It is a CI producer action only: it may build and push `127.0.0.1:5000/unidesk/backend-core:`, but it must not recreate the master server container. Production deployment is triggered separately with `deploy apply --env prod --service backend-core --commit `. Publish a user-service artifact: diff --git a/docs/reference/cicd-standardization.md b/docs/reference/cicd-standardization.md new file mode 100644 index 00000000..08c26f27 --- /dev/null +++ b/docs/reference/cicd-standardization.md @@ -0,0 +1,52 @@ +# CI/CD Standardization Precheck + +This document classifies CI/CD paths while UniDesk converges on image-artifact delivery. It is a precheck and guardrail document, not a mass-deletion plan. + +## Target Shape + +The standard release shape is: + +1. CI builds or locks the artifact from a pushed commit or verified upstream digest. +2. The artifact is published to the D601 artifact registry or a controlled mirror. +3. Dev validation consumes that same artifact. +4. Production CD is pull-only and verifies live commit or upstream digest. +5. Runtime metadata can be traced back to a live Git commit or upstream image digest. + +`backend-core` and D601 `code-queue` may be validated only in dev in this phase. This document must not be used to introduce production deploy validation for either service. + +## Upstream Image Consumers + +`filebrowser` and `filebrowser-d601` are upstream-image consumers, not source-built UniDesk services. + +| Service | Upstream image | Source revision | Catalog home | CI Dockerfile build | Digest / mirror strategy | CD validation | +| --- | --- | --- | --- | --- | --- | --- | +| `filebrowser` | `docker.io/filebrowser/filebrowser:v2.63.3` | `ca5e249e3c0c94159c2136a0cd431a424eb18472` | `CI.json.upstreamImageConsumers[]` and `config.json.microservices[].repository.artifactSource` | forbidden | resolve tag to `docker.io/filebrowser/filebrowser@sha256:`, then optionally mirror to `127.0.0.1:5000/upstream/filebrowser/filebrowser@sha256:` | pull by digest or mirror digest, verify OCI labels, container image id/digest, and private proxy health | +| `filebrowser-d601` | `docker.io/filebrowser/filebrowser:v2.63.3` | `ca5e249e3c0c94159c2136a0cd431a424eb18472` | `CI.json.upstreamImageConsumers[]` and `config.json.microservices[].repository.artifactSource` | forbidden | same as `filebrowser` | same as `filebrowser` | + +The current precheck could inspect the locally cached image labels and image id, but Docker Hub and registry HTTP requests timed out from this container. Therefore the catalog records `digestPin.status=pending-network-verification`; rollout must remain blocked until a reachable registry path resolves the manifest digest and records the mirror digest. The locally cached image shows `org.opencontainers.image.version=2.63.3`, `org.opencontainers.image.revision=ca5e249e3c0c94159c2136a0cd431a424eb18472`, `linux/amd64`, and image id `sha256:6a4d051140ef9313ad87b443f55ccb1cd6331e7463b4becbec2174b494ea533c`, but a local image id is not a registry digest pin. + +## Legacy Path Classification + +| Path | Classification | Current guardrail | Cleanup condition | +| --- | --- | --- | --- | +| `deploy apply --env prod` for services without a reviewed artifact consumer | Must stay disabled/degraded | returns structured unsupported and refuses maintenance-channel fallback | enable only after each service has a documented artifact producer, dev consumer, prod consumer and live verification | +| Local-manifest `deploy apply` for prod artifact consumers (`backend-core`, `frontend`, `baidu-netdisk`, `decision-center`) | Must stay disabled/degraded as a standard prod path | blocked before source build; operator is pointed to `deploy apply --env prod` | remove only after all production deploys use env-ref artifact consumers and no recovery runbook depends on local manifests | +| `artifact-registry deploy-backend-core` | Legacy compatibility entry | returns structured deprecated result; replacement is `deploy apply --env prod --service backend-core` | remove after callers and docs use only `deploy apply --env prod` | +| `server rebuild frontend` and `server rebuild baidu-netdisk` | Maintenance / non-standard | docs classify as maintenance-only; standard release requires CI artifact plus dev/prod artifact consumer | keep until recovery runbooks have equivalent pull-only repair commands | +| `server rebuild backend-core` | Diagnostic/recovery only; not Rust iteration or prod CD | docs forbid Rust iteration and prod backend-core artifact CD through this command | keep for bootstrap/recovery until backend-core artifact CD and rollback are proven under outage conditions | +| `server rebuild dev-frontend-proxy`, `code-queue-mgr`, `project-manager`, `oa-event-flow`, `todo-note`, `provider-gateway` on main-server Compose | Bootstrap / recovery / diagnostic | still serialized through Compose lock and post-up validation | reassess service by service after artifact consumers exist | +| `provider.upgrade mode=schedule` for provider-gateway | Must be retained | protected upgrade path with validation; Host SSH self-rebuild remains forbidden | do not delete; it is the provider-gateway recovery path | +| D601 direct `docker build`, `kubectl apply`, `docker compose up --build` used by deploy executor for allowed dev/backend bootstrap and native k3s setup | Bootstrap / recovery / controlled dev | limited to allowed target-side executor, native k3s initialization, and dev backend-core; Code Queue prod is not enabled | convert only after artifact consumers or native bootstrap replacements exist | +| D601 direct Code Queue / old `codex deploy` | Must stay disabled/degraded | compatibility command throws; docs classify direct deployment as forbidden | wait for controlled Code Queue dev/prod CD worker | +| File Browser `docker run` image-only path | Needs later worker | now cataloged as upstream-image consumer; no CI Dockerfile build allowed | implement digest-resolved pull-only/mirror CD before treating it as standard deployment | + +## Guardrails Added + +- Upstream-image services are represented in `CI.json.upstreamImageConsumers[]` and in `config.json.microservices[].repository.artifactSource`; they are explicitly outside `CI.json.artifacts[]`. +- `ci publish-user-service` rejects registered `upstream-image` services instead of trying to interpret `repository.dockerfile` as a source Dockerfile. +- Local-manifest production deploy for reviewed artifact consumers is blocked before source materialization/build, so prod cannot silently fall back to target-side source build or a dirty worktree. +- `artifact-registry deploy-backend-core` is demoted to a structured deprecated result; backend-core production CD must enter through `deploy apply --env prod`. + +## Not Removed Yet + +Bootstrap and repair paths remain because they still protect recovery: native k3s initialization, provider-gateway protected upgrade, k3sctl-adapter control bridge repair, main-server Compose maintenance rebuilds, and File Browser docker-run operations. These paths must be replaced by reviewed artifact consumers or explicit recovery runbooks before deletion. diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 3927a923..7bff6f01 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -28,7 +28,7 @@ CLI 可以从 `master` 快速演进,但必须兼容 `deploy.json` 固定的 CI - `deploy check/plan/apply` 默认从根目录 `deploy.json` 读取服务 repo 与 commit 期望状态,join `config.json` 和现有 manifest 后使用 target-side build 单一路径校验或更新已支持目标;`deploy plan --env dev|prod` 只从 `origin/master:deploy.json#environments.` 读取 manifest 并输出 dry-run 环境计划,不使用本地 dirty worktree;当前 `deploy apply --env dev` 支持 D601 `backend-core` target-side rollout,以及 `frontend`/`baidu-netdisk`/`decision-center` artifact consumers,dev desired-state smoke 使用 `ci run-dev-e2e`;规则见 `docs/reference/deploy.md`、`docs/reference/dev-environment.md` 和 `docs/reference/dev-ci-runner.md`。 - `dev-env validate [--manifest path] [--kubectl-dry-run]` 离线校验 D601 `unidesk-dev` namespace、dev PostgreSQL 底座和 dev workload manifest。默认检查 `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-foundation.k8s.yaml`;也可显式校验 `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml` 或 `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-code-queue.k8s.yaml`。所有 namespaced 对象必须只落到 `unidesk-dev`,foundation manifest 必须包含 `postgres-dev` StatefulSet/Service、dev secret/config、迁移 Job 和 DB URL guard,core manifest 必须包含 `backend-core-dev`/`frontend-dev` Deployment/Service,Code Queue dev manifest 必须包含 `code-queue-scheduler-dev`、`code-queue-read-dev`、`code-queue-write-dev` 和 dev provider egress proxy。加 `--kubectl-dry-run` 时额外执行 `kubectl apply --dry-run=client --validate=false -f `,仍不 apply 资源。 - `dev-env prewarm-images [--image image] [--provider-id D601] [--no-pull] [--proxy-url URL] [--pull-timeout-ms N] [--dry-run]` 创建异步 job,通过 UniDesk SSH 维护桥在 D601 上把开发底座依赖镜像从 Docker 缓存导入原生 k3s containerd。默认镜像是 `postgres:16-alpine` 和 `rancher/mirrored-library-busybox:1.36.1`,用于避免 `postgres-dev` 与 local-path helper pod 卡在外部 registry 拉取。该命令固定验证 `/etc/rancher/k3s/k3s.yaml` 指向的 native k3s 上下文,并输出 `dev_env_containerd_image_ready=...` 作为成功判据;它不 apply manifest、不修改生产 `unidesk` namespace。 -- `artifact-registry plan|render|status|health|install|deploy-backend-core|deploy-service` 管理 D601 host-managed CNCF Distribution registry 的声明、安装、只读检查和 pull-only artifact CD。该 registry 固定为 D601 loopback `127.0.0.1:5000`,由 systemd + Docker Compose 管理,位于 native k3s 故障域外;`deploy-backend-core` 和 `deploy-service` 只拉取 CI 已发布的 commit-pinned 镜像、retag/recreate 或导入 native k3s,并做 live commit 验证,不构建 runtime source。长期规则见 `docs/reference/artifact-registry.md`。 +- `artifact-registry plan|render|status|health|install|deploy-backend-core|deploy-service` 管理 D601 host-managed CNCF Distribution registry 的声明、安装、只读检查和 pull-only artifact CD。该 registry 固定为 D601 loopback `127.0.0.1:5000`,由 systemd + Docker Compose 管理,位于 native k3s 故障域外;`deploy-service` 只拉取 CI 已发布的 commit-pinned 镜像、retag/recreate 或导入 native k3s,并做 live commit 验证,不构建 runtime source。`deploy-backend-core` 是 deprecated 兼容名,标准 backend-core prod CD 入口是 `deploy apply --env prod --service backend-core`。长期规则见 `docs/reference/artifact-registry.md`。 - `ci install|status|run|publish-backend-core|publish-user-service|run-dev-e2e|logs` 管理 D601 原生 k3s 上的 Tekton CI。`run` 手动创建每 commit 检查和 Code Queue 只读性能门禁;`publish-backend-core` 与 `publish-user-service` 从 pushed Git commit 构建并发布 `127.0.0.1:5000/unidesk/:` commit-pinned artifacts,输出 `artifactSummary`(含 `serviceId`、`sourceCommit`、`sourceRepo`、`dockerfile`、`imageRef`、`tag`、`digest`、`digestRef`),但不部署生产;`run-dev-e2e` 的 Git 控制 runner、短 launcher、host fetch 边界、临时 smoke namespace 和 no-CD 规则只在 `docs/reference/dev-ci-runner.md` 定义;Tekton CI 通用规则见 `docs/reference/ci.md`。 - `codex deploy ` 是旧 Code Queue 兼容部署入口,已禁用以防止维护通道直连 D601 部署 Code Queue;当前 dev 自动化只做 `ci run-dev-e2e` smoke,不提供 Code Queue CD,详细规则见 `docs/reference/codex-deploy.md`。 - `codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue queueId] [--provider-id id] [--cwd path] [--model model] [--reasoning-effort effort] [--execution-mode mode] [--max-attempts N] [--reference-task-id id] [--dry-run]` 通过 backend-core 私有代理向稳定 `code-queue` 用户服务路径提交任务;prompt 必须且只能来自位置参数、文件或 stdin 之一,`--dry-run` 只返回结构化请求且不实际入队。提交确认和 dry-run 必须返回完整 prompt、字符数和 `truncated=false`,不能套用任务详情的预览截断策略,否则长任务 prompt 无法被人工验收。真实提交会经过本机本地串行化保护和短节流,避免同一指挥端并发 submit 把低内存主机或 `code-queue-mgr` 控制面打抖;返回值会附带 `submitConcurrencyGuard` 说明本次提交的锁与等待信息。backend-core 默认把提交、队列 CRUD、已读状态、历史摘要和轻量 Trace 读取分流到主 server `code-queue-mgr`,由它写入主 PostgreSQL;D601 scheduler 只轮询并执行已入库任务。 diff --git a/docs/reference/deploy.md b/docs/reference/deploy.md index 7d92ab13..84bb41cc 100644 --- a/docs/reference/deploy.md +++ b/docs/reference/deploy.md @@ -42,6 +42,8 @@ The optional non-service execution declaration under `environments.dev` is inten Environment mode never reads the local dirty working tree manifest. `deploy check --env ...`, `deploy plan --env ...` and `deploy apply --env ...` fetch `origin/master`, read `origin/master:deploy.json`, select `environments.`, and report the manifest commit/blob, service commit IDs, target namespace, database fingerprint and Provider identity. `deploy apply --env dev` is currently enabled for persistent D601 dev `backend-core` target-side rollout and for `frontend`/`baidu-netdisk`/`decision-center` artifact consumers; all other D601 services remain rejected before runtime mutation. `deploy apply --env prod` exposes only reviewed D601 registry artifact consumers (`backend-core`, `frontend`, `baidu-netdisk`, `decision-center`). Production backend-core artifact CD is a separate executor because its build target is D601 CI while its runtime target is the master server. The default user-service delivery policy, including CI build, registry publication, dev validation, production CD and manual acceptance, is documented in `docs/reference/user-service-delivery.md`. +For services with reviewed production artifact consumers, local-manifest `deploy apply --file ...` is not a production fallback. The CLI blocks `backend-core`, `frontend`, `baidu-netdisk` and `decision-center` before source materialization or Docker build and directs operators to `deploy apply --env prod --service --commit `. This prevents a dirty worktree, local manifest or target-side source build from bypassing the pull-only artifact CD guardrails. The broader precheck and legacy-path classification live in `docs/reference/cicd-standardization.md`. + The current implementation has not yet enabled separate stable and integration dev lanes. Future lane names such as `dev-v1` and `dev-master`, or an equivalent nested schema, must be added as explicit `deploy.json` and CLI semantics before use. A deploy command must print the manifest ref it used and must not infer `release/v1` from a local branch, a dirty file, or an undocumented environment alias. CI/CD server and control-plane services are normal deployable services for versioning purposes: production runtime must be pinned by `deploy.json` to a known commit. A CLI built from `master` may orchestrate the pinned server only through backward-compatible APIs and server-reported capabilities; it must not bypass server-side deploy policy when the pinned server does not support a requested operation. @@ -132,6 +134,7 @@ The exception is narrow: - CI on D601 builds `src/components/backend-core/Dockerfile` from a pushed commit, stamps image labels and publishes `127.0.0.1:5000/unidesk/backend-core:` to the D601 artifact registry. - CD on the master server pulls that existing image through the controlled artifact-registry relay, retags it for the Compose service, recreates only `backend-core` with `--no-build --no-deps --force-recreate`, and verifies the running commit. - CD must not run Rust compilation, Docker build, Compose build or `server rebuild backend-core`. +- The legacy `artifact-registry deploy-backend-core` compatibility entry is deprecated and disabled as a standard entrypoint; use `deploy apply --env prod --service backend-core --commit ` so the common artifact-consumer guardrails execute first. - The pushed Git commit remains the version source of truth. The image registry is a content cache and transfer boundary, not a replacement for `deploy.json` or Git. - `baidu-netdisk` is the first main-server direct user-service sample for the same split: CI publishes `127.0.0.1:5000/unidesk/baidu-netdisk:` from `src/components/microservices/baidu-netdisk/Dockerfile`; dev validation and prod CD both pull that artifact, retag `baidu-netdisk`, recreate only `baidu-netdisk` with `--no-build --no-deps --force-recreate`, and verify image labels plus `/health.deploy.commit`. - `frontend` is the UniDesk UI artifact sample: CI publishes `127.0.0.1:5000/unidesk/frontend:` from `src/components/frontend/Dockerfile`; dev CD imports that artifact into native k3s `frontend-dev`, prod CD retags it as `unidesk-frontend` for the master-server Compose service, and both paths verify image labels plus `/health.deploy.commit`. @@ -139,6 +142,18 @@ The exception is narrow: The registry contract is defined in `docs/reference/artifact-registry.md`; the CI producer rules are defined in `docs/reference/ci.md`. +## Upstream Image Exception + +`filebrowser` and `filebrowser-d601` are not source-built UniDesk services and must not be moved into `CI.json.artifacts[]`. Their minimal catalog expression is `CI.json.upstreamImageConsumers[]` plus `config.json.microservices[].repository.artifactSource`: + +- upstream image: `docker.io/filebrowser/filebrowser:v2.63.3`; +- upstream source revision: `ca5e249e3c0c94159c2136a0cd431a424eb18472`; +- digest pin: required before rollout; +- mirror strategy: mirror only after digest verification to `127.0.0.1:5000/upstream/filebrowser/filebrowser`; +- CD: pull-only by digest or mirror digest, then verify image identity, OCI labels and private proxy health. + +If the upstream registry is unavailable during precheck, the service remains `pending-network-verification`; a locally cached image id is supporting evidence only and not a manifest digest pin. + ## One-Shot Build Proxy Target-side source fetches and Docker builds that need external network access use a one-shot proxy scope through provider-gateway WS egress. Provider targets connect only to their node-local provider-gateway egress endpoint, normally `http://127.0.0.1:18789`; provider-gateway carries the TCP stream over the already-authenticated provider WebSocket to the main server, and the main server opens the final outbound TCP connection. This is the only allowed proxy channel for provider-side deploy source fetches and builds. The deploy path must not mutate host-global proxy settings: diff --git a/docs/reference/devops-hygiene.md b/docs/reference/devops-hygiene.md index bdaee04e..76565e3d 100644 --- a/docs/reference/devops-hygiene.md +++ b/docs/reference/devops-hygiene.md @@ -23,6 +23,8 @@ The following practices are not acceptable as the long-term or hidden source of - Copying large local shell scripts, generated manifests, Docker images or application source to D601 as the main deployment mechanism. - Fixing dev or production reachability by adding direct D601 public ports, NodePorts or backend-core hardcoded service entries instead of updating the proper catalog/control bridge. - Treating `server rebuild backend-core` as a Rust backend-core iteration path; Rust build/check belongs to D601 dev deploy or D601 CI only. +- Using local-manifest production deploy for services that already have artifact consumers. `backend-core`, `frontend`, `baidu-netdisk` and `decision-center` production deploys must enter through `deploy apply --env prod` so CD consumes a commit-pinned registry artifact instead of silently falling back to target-side source build. +- Treating upstream images as UniDesk source-build services. `filebrowser` and `filebrowser-d601` are upstream-image consumers; they require digest pin or digest-verified mirror governance and must not be added to Dockerfile CI artifacts. - Considering manual curl, kubectl or Docker checks sufficient when live commit metadata, deploy plan, health checks and CI/e2e disagree. ## Bounded Manual Operations @@ -33,6 +35,7 @@ Manual operations are allowed only when they are narrow, visible and followed by - `deploy apply --service k3sctl-adapter` may update the k3s control bridge catalog through the documented local manifest exception in `docs/reference/deploy.md`. - Host SSH/provider-gateway dispatch may start the `ci run-dev-e2e` short launcher described in `docs/reference/dev-ci-runner.md`; it must not carry large shell bodies or become a general deployment path. - Read-only smoke checks such as `curl http://74.48.78.17:18083/health`, `server status`, `microservice proxy .../health` and `kubectl get` may validate state, but they do not replace desired-state and live-commit verification. +- File Browser recovery may use the existing provider-local image-only/docker-run path only as a bounded repair path. Standardization requires first resolving `docker.io/filebrowser/filebrowser:v2.63.3` to an upstream manifest digest or a digest-verified local mirror, then validating the running container through the UniDesk private proxy. If a manual repair is needed to unblock the platform, the durable fix must be committed and pushed, then redeployed or revalidated through the normal path. Do not preserve the repair only as hidden runtime state. diff --git a/docs/reference/user-service-delivery.md b/docs/reference/user-service-delivery.md index 3718e666..a1e96329 100644 --- a/docs/reference/user-service-delivery.md +++ b/docs/reference/user-service-delivery.md @@ -38,6 +38,16 @@ The default release flow for a user-service change is: - Every production release must finish with a manual acceptance step after the automated checks pass. - Multi-service delivery programs may use Code Queue parallelization, but the supervisor must follow `docs/reference/code-queue-supervision.md`: tasks need self-contained prompts, isolated worktrees, bounded queue concurrency, explicit acceptance evidence, and infrastructure defects split into separate follow-up tasks when they block several lanes. +## Upstream Image Services + +Some registered user services are intentionally upstream-image consumers instead of source-built services. `filebrowser` and `filebrowser-d601` are in this class. + +- They must be cataloged as upstream images, not as `CI.json.artifacts[]` Dockerfile producers. +- `ci publish-user-service` must reject them; there is no UniDesk Dockerfile build for these services. +- The release input is an upstream manifest digest or a digest-verified mirror in the D601 registry, not a Git commit tag built by Tekton. +- CD must be pull-only and must verify the image identity, OCI labels and service health through the UniDesk private proxy. +- Until the upstream digest has been resolved and mirrored or pinned, File Browser remains a recovery/diagnostic image-only path rather than a standard release path. + ## Frontend Pairing Many user services are surfaced through the UniDesk frontend rather than through their own browser-exposed product. When a user-service backend has a paired UniDesk frontend page, the frontend change must be validated in the same dev/prod release window as the backend artifact. The frontend itself is also a reviewed artifact producer/consumer sample: its release unit is `127.0.0.1:5000/unidesk/frontend:`, and the live UI must expose the same requested commit through image labels and `/health.deploy.commit`. diff --git a/scripts/src/artifact-registry.ts b/scripts/src/artifact-registry.ts index 1bcf1d54..cb53d1d2 100644 --- a/scripts/src/artifact-registry.ts +++ b/scripts/src/artifact-registry.ts @@ -71,6 +71,7 @@ const defaultOptions: ArtifactRegistryOptions = { }; const supportedArtifactConsumerServices = ["backend-core", "baidu-netdisk", "decision-center", "frontend"] as const; type SupportedArtifactConsumerService = typeof supportedArtifactConsumerServices[number]; +const legacyDeployBackendCoreDisabled = true; interface ArtifactConsumerSpec { serviceId: SupportedArtifactConsumerService; @@ -1108,6 +1109,20 @@ function deployBackendCoreJob(args: string[], options: ArtifactRegistryOptions): }; } +function legacyDeployBackendCoreResult(options: ArtifactRegistryOptions): Record { + return { + ok: false, + supported: false, + deprecated: true, + action: "deploy-backend-core", + replacement: "bun scripts/cli.ts deploy apply --env prod --service backend-core --commit ", + serviceId: "backend-core", + environment: options.environment ?? "prod", + commit: options.commit, + policy: "backend-core production CD must enter through deploy apply --env prod so the standard artifact-consumer guardrails run before any mutation; the legacy artifact-registry deploy-backend-core entry is retained only as a documented compatibility name.", + }; +} + function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: ArtifactConsumerSpec, target: ArtifactConsumerTarget, commit: string): Record { const environment = options.environment ?? "prod"; const sourceImage = artifactImageRef(options, spec, commit); @@ -1458,7 +1473,6 @@ function localHelp(): Record { "bun scripts/cli.ts artifact-registry status [--provider-id D601]", "bun scripts/cli.ts artifact-registry health [--provider-id D601]", "bun scripts/cli.ts artifact-registry install [--provider-id D601]", - "bun scripts/cli.ts artifact-registry deploy-backend-core --commit [--run-now] [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --service baidu-netdisk --commit [--dry-run] [--run-now] [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --service frontend --env prod --commit [--dry-run] [--run-now] [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --service frontend --env dev --commit [--dry-run] [--run-now] [--provider-id D601]", @@ -1482,6 +1496,13 @@ function localHelp(): Record { ], rollbackShape: "rerun the same artifact consumer with a previous commit-pinned image", }, + legacyEntrypoints: { + "deploy-backend-core": { + deprecated: true, + enabled: !legacyDeployBackendCoreDisabled, + replacement: "bun scripts/cli.ts deploy apply --env prod --service backend-core --commit ", + }, + }, defaults: defaultOptions, }; } @@ -1503,6 +1524,7 @@ export async function runArtifactRegistryCommand(args: string[]): Promise"); + if (legacyDeployBackendCoreDisabled) return legacyDeployBackendCoreResult(options); return options.runNow ? await deployBackendCoreNow(options) : deployBackendCoreJob(args, options); } if (action === "deploy-service") { diff --git a/scripts/src/ci.ts b/scripts/src/ci.ts index d56b3f28..7dcea0ea 100644 --- a/scripts/src/ci.ts +++ b/scripts/src/ci.ts @@ -204,6 +204,9 @@ function requireSupportedUserService(config: UniDeskConfig, serviceId: string): } const service = config.microservices.find((item) => item.id === serviceId); if (service === undefined) throw new Error(`unknown user service: ${serviceId}`); + if (service.repository.artifactSource?.kind === "upstream-image") { + throw new Error(`ci publish-user-service does not build ${serviceId}: it is an upstream image consumer (${service.repository.artifactSource.imageRef}). Use the upstream-image digest/mirror governance path; do not add it to Dockerfile CI artifacts.`); + } const isD601K3sService = service.providerId === d601ProviderId && service.development.providerId === d601ProviderId && service.deployment.mode === "k3sctl-managed"; @@ -1123,7 +1126,7 @@ async function publishBackendCoreArtifact(config: UniDeskConfig, options: CiPubl condition, next: [ `bun scripts/cli.ts ci logs ${name}`, - `bun scripts/cli.ts artifact-registry deploy-backend-core --commit ${options.commit}`, + `bun scripts/cli.ts deploy apply --env prod --service backend-core --commit ${options.commit}`, ], }; } @@ -1473,7 +1476,7 @@ export function ciHelp(): Record { backendCoreArtifact: { producer: "D601 CI", registry: "127.0.0.1:5000/unidesk/backend-core:", - cdCommand: "bun scripts/cli.ts artifact-registry deploy-backend-core --commit ", + cdCommand: "bun scripts/cli.ts deploy apply --env prod --service backend-core --commit ", }, userServiceArtifact: { producer: "D601 CI", diff --git a/scripts/src/config.ts b/scripts/src/config.ts index cba66a55..5baf4aca 100644 --- a/scripts/src/config.ts +++ b/scripts/src/config.ts @@ -51,6 +51,14 @@ export interface UniDeskMicroserviceConfig { url: string; commitId: string; dockerfile: string; + artifactSource?: { + kind: "upstream-image"; + imageRef: string; + digestPinRequired: boolean; + mirrorRepository: string; + ciDockerfileBuild: boolean; + pullOnlyCd: boolean; + }; composeFile: string; composeService: string; containerName: string; @@ -150,6 +158,22 @@ function stringArrayField(obj: Record, key: string, path: strin return value as string[]; } +function optionalArtifactSource(repository: Record, path: string): UniDeskMicroserviceConfig["repository"]["artifactSource"] { + const value = repository.artifactSource; + if (value === undefined) return undefined; + const source = asRecord(value, `${path}.artifactSource`); + const kind = stringField(source, "kind", `${path}.artifactSource`); + if (kind !== "upstream-image") throw new Error(`${path}.artifactSource.kind must be upstream-image`); + return { + kind, + imageRef: stringField(source, "imageRef", `${path}.artifactSource`), + digestPinRequired: booleanField(source, "digestPinRequired", `${path}.artifactSource`), + mirrorRepository: stringField(source, "mirrorRepository", `${path}.artifactSource`), + ciDockerfileBuild: booleanField(source, "ciDockerfileBuild", `${path}.artifactSource`), + pullOnlyCd: booleanField(source, "pullOnlyCd", `${path}.artifactSource`), + }; +} + function optionalRestrictedHostAccess(network: Record): UniDeskConfig["network"]["restrictedHostAccess"] { const value = network.restrictedHostAccess; if (value === undefined) return undefined; @@ -182,6 +206,7 @@ function microserviceConfig(item: Record, index: number): UniDe url: stringField(repository, "url", `${path}.repository`), commitId: stringField(repository, "commitId", `${path}.repository`), dockerfile: stringField(repository, "dockerfile", `${path}.repository`), + artifactSource: optionalArtifactSource(repository, `${path}.repository`), composeFile: stringField(repository, "composeFile", `${path}.repository`), composeService: stringField(repository, "composeService", `${path}.repository`), containerName: stringField(repository, "containerName", `${path}.repository`), diff --git a/scripts/src/deploy.ts b/scripts/src/deploy.ts index bee7a783..77d15313 100644 --- a/scripts/src/deploy.ts +++ b/scripts/src/deploy.ts @@ -138,6 +138,7 @@ const d601MaintenanceDeployAllowedServiceIds = new Set(["backend-core", const devApplySupportedServiceIds = new Set(["backend-core"]); const devArtifactConsumerServiceIds = new Set(["baidu-netdisk", "decision-center", "frontend"]); const prodArtifactConsumerServiceIds = new Set(["backend-core", "baidu-netdisk", "decision-center", "frontend"]); +const prodForbiddenTargetSideBuildServiceIds = prodArtifactConsumerServiceIds; const deployEnvironmentTargets: Record = { dev: { environment: "dev", @@ -2671,6 +2672,23 @@ function prodArtifactUnsupportedResult(services: DeployManifestService[]): Recor }; } +function prodArtifactConsumerLocalManifestResult(services: DeployManifestService[]): Record { + return { + ok: false, + supported: false, + error: "prod-artifact-consumer-local-manifest-blocked", + services: services.map((service) => ({ + id: service.id, + repo: service.repo, + commitId: service.commitId, + supported: true, + reason: "This service has a reviewed artifact consumer; production source-build deploy from a local manifest is blocked.", + })), + policy: "prod artifact consumers must enter through deploy apply --env prod so CD consumes an existing commit-pinned registry image and never falls back to source build or a dirty worktree", + commandShape: "bun scripts/cli.ts deploy apply --env prod --service --commit ", + }; +} + async function runArtifactConsumerApplyNow( manifest: DeployManifest, options: DeployOptions, @@ -2830,6 +2848,9 @@ export async function runDeployCommand(config: UniDeskConfig | null, args: strin if (config === null) throw new Error("deploy local manifest mode requires config.json"); const manifest = resolveManifestCommits(await readDeployManifest(options.file), options.serviceId); if (action === "check" || action === "plan") return await checkOrPlan(config, manifest, options, action); + const prodArtifactConsumers = selectedEnvironmentServices(manifest, options.serviceId) + .filter((service) => manifest.environment !== "dev" && prodForbiddenTargetSideBuildServiceIds.has(service.id)); + if (prodArtifactConsumers.length > 0) return prodArtifactConsumerLocalManifestResult(prodArtifactConsumers); if (!options.dryRun) { const blocked = blockedD601MaintenanceDeployServices(config, manifest, options.serviceId); if (blocked.length > 0) throw new Error(d601MaintenanceDeployBlockMessage(blocked)); diff --git a/scripts/src/help.ts b/scripts/src/help.ts index a5db6199..e23d64af 100644 --- a/scripts/src/help.ts +++ b/scripts/src/help.ts @@ -38,7 +38,7 @@ 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 a repo+commit manifest; --env reads origin/master:deploy.json environments and can apply supported dev target-side builds plus decision-center's dev artifact consumer, or supported prod artifact consumers." }, { 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 decision-center dev/prod artifact consumers." }, + { 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; deploy-backend-core is a deprecated compatibility name." }, { command: "schedule list|get|runs|run|delete", description: "Manage backend-core scheduled tasks and run history; schedule run supports --wait-ms N." }, { command: "schedule upsert-pgdata-backup [--time HH:MM] [--remote-base /SERVER_DATA/UNIDESK_PG_DATA]", description: "Create or update the daily PGDATA physical backup task that uploads monthly rotated archives to Baidu Netdisk." }, { command: "codex deploy [--provider-id D601] [--timeout-ms N]", description: "Compatibility wrapper for deploy apply --service code-queue with a temporary repo+commit manifest." }, @@ -260,7 +260,6 @@ function artifactRegistryHelp(): unknown { "bun scripts/cli.ts artifact-registry status [--provider-id D601]", "bun scripts/cli.ts artifact-registry health [--provider-id D601]", "bun scripts/cli.ts artifact-registry install [--provider-id D601]", - "bun scripts/cli.ts artifact-registry deploy-backend-core --commit [--run-now] [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --service baidu-netdisk --commit [--dry-run] [--run-now] [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --service frontend --env prod --commit [--dry-run] [--run-now] [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --service frontend --env dev --commit [--dry-run] [--run-now] [--provider-id D601]", @@ -271,10 +270,17 @@ function artifactRegistryHelp(): unknown { "registry endpoint is D601 loopback 127.0.0.1:5000 only", "service is host-managed by systemd + Docker Compose, not k3s-managed", "install writes the rendered host unit/config and starts the registry", - "deploy-backend-core only pulls commit-pinned backend-core artifacts and does not build backend-core on the master server", + "deploy-backend-core is a deprecated compatibility name; use deploy apply --env prod --service backend-core so standard artifact-consumer guardrails run first", "deploy-service currently supports backend-core, baidu-netdisk, prod/dev frontend, and decision-center as standardized consumers", "status and health use provider-gateway Host SSH readonly checks", ], + legacyEntrypoints: { + "deploy-backend-core": { + deprecated: true, + enabled: false, + replacement: "bun scripts/cli.ts deploy apply --env prod --service backend-core --commit ", + }, + }, }; } diff --git a/src/components/backend-core/src/config.ts b/src/components/backend-core/src/config.ts index b9d67d92..3e6a60ee 100644 --- a/src/components/backend-core/src/config.ts +++ b/src/components/backend-core/src/config.ts @@ -71,6 +71,22 @@ function optionalStringArrayFromRecord(value: Record, key: stri return stringArrayFromRecord(value, key, path); } +function optionalArtifactSourceFromRecord(repository: Record, path: string): MicroserviceConfig["repository"]["artifactSource"] { + const field = repository.artifactSource; + if (field === undefined) return undefined; + const source = asRecord(field, `${path}.artifactSource`); + const kind = stringFromRecord(source, "kind", `${path}.artifactSource`); + if (kind !== "upstream-image") throw new Error(`${path}.artifactSource.kind must be upstream-image`); + return { + kind, + imageRef: stringFromRecord(source, "imageRef", `${path}.artifactSource`), + digestPinRequired: booleanFromRecord(source, "digestPinRequired", `${path}.artifactSource`), + mirrorRepository: stringFromRecord(source, "mirrorRepository", `${path}.artifactSource`), + ciDockerfileBuild: booleanFromRecord(source, "ciDockerfileBuild", `${path}.artifactSource`), + pullOnlyCd: booleanFromRecord(source, "pullOnlyCd", `${path}.artifactSource`), + }; +} + function parseMicroserviceConfig(value: unknown, index: number): MicroserviceConfig { const path = `MICROSERVICES_JSON[${index}]`; const item = asRecord(value, path); @@ -92,6 +108,7 @@ function parseMicroserviceConfig(value: unknown, index: number): MicroserviceCon url: stringFromRecord(repository, "url", `${path}.repository`), commitId: stringFromRecord(repository, "commitId", `${path}.repository`), dockerfile: stringFromRecord(repository, "dockerfile", `${path}.repository`), + artifactSource: optionalArtifactSourceFromRecord(repository, `${path}.repository`), composeFile: stringFromRecord(repository, "composeFile", `${path}.repository`), composeService: stringFromRecord(repository, "composeService", `${path}.repository`), containerName: stringFromRecord(repository, "containerName", `${path}.repository`), diff --git a/src/components/backend-core/src/types.rs b/src/components/backend-core/src/types.rs index 2efc32c1..aac62a1a 100644 --- a/src/components/backend-core/src/types.rs +++ b/src/components/backend-core/src/types.rs @@ -57,11 +57,24 @@ pub struct MicroserviceRepositoryConfig { pub url: String, pub commit_id: String, pub dockerfile: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub artifact_source: Option, pub compose_file: String, pub compose_service: String, pub container_name: String, } +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ArtifactSourceConfig { + pub kind: String, + pub image_ref: String, + pub digest_pin_required: bool, + pub mirror_repository: String, + pub ci_dockerfile_build: bool, + pub pull_only_cd: bool, +} + #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct MicroserviceBackendConfig { diff --git a/src/components/backend-core/src/types.ts b/src/components/backend-core/src/types.ts index c94ba233..72ed0c27 100644 --- a/src/components/backend-core/src/types.ts +++ b/src/components/backend-core/src/types.ts @@ -40,6 +40,14 @@ export interface MicroserviceConfig { url: string; commitId: string; dockerfile: string; + artifactSource?: { + kind: "upstream-image"; + imageRef: string; + digestPinRequired: boolean; + mirrorRepository: string; + ciDockerfileBuild: boolean; + pullOnlyCd: boolean; + }; composeFile: string; composeService: string; containerName: string;