From e28cc6ba2d00b844bfa40abbd0bf0e9b1c557ddf Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 20 May 2026 03:39:52 +0000 Subject: [PATCH] docs: freeze cicd special-case boundaries --- AGENTS.md | 2 +- docs/reference/cicd-standardization.md | 28 +++++++++++++++ docs/reference/deploy.md | 2 +- docs/reference/deployment.md | 2 +- scripts/cli.ts | 7 ++-- scripts/src/docker.ts | 50 ++++++++++++++++++++++++++ scripts/src/help.ts | 8 ++++- 7 files changed, 93 insertions(+), 6 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 17fd4697..a525d86f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -32,7 +32,7 @@ UniDesk 是一个以主 server 为统一入口的分布式工作平台;本文 - `bun scripts/cli.ts server status`:查询固定端口、swap 摘要、容器状态、健康检查和访问 URL,包含生产 frontend、dev frontend proxy 和 provider ingress,判定标准见 `docs/reference/deployment.md` 与 `docs/reference/dev-environment.md`。 - `bun scripts/cli.ts server swap status|ensure [--path /swapfile] [--size 2GiB] [--dry-run]`:以 JSON 查看或幂等创建主 server swapfile,`ensure` 输出 before/after、动作、持久化状态和 degraded/failed 详情,规则见 `docs/reference/deployment.md`。 - `bun scripts/cli.ts server logs [--tail-bytes N]`:分页返回文件日志与 Docker 日志尾部并带截断元数据,日志规则见 `docs/reference/observability.md`。 -- `bun scripts/cli.ts server rebuild `:以 build-first、Compose lock、no-deps force-recreate 和 post-up validation 的异步 job 重建主 server Compose 内单个服务;`dev-frontend-proxy` 是 18083 dev 入口薄代理,Rust backend-core 迭代不得在 master server 用该命令编译,规则见 `docs/reference/deployment.md` 与 `docs/reference/dev-environment.md`。 +- `bun scripts/cli.ts server rebuild `:以 build-first、Compose lock、no-deps force-recreate 和 post-up validation 的异步 job 重建主 server Compose 内单个服务;对 database、File Browser、Code Queue 执行面、k3sctl-adapter 或未知对象返回结构化 `unsupported-server-rebuild`,规则见 `docs/reference/deployment.md` 与 `docs/reference/cicd-standardization.md`。 - `bun scripts/cli.ts provider attach [--master-server URL] [--up] [--force]`:在新增计算节点上生成两项配置的 provider-gateway 挂载包;默认只需要主 server URL(默认 `http://74.48.78.17/`)和唯一 Provider ID,生成的 Compose 固定 Docker socket、`pid: "host"`、`restart: always`、只读 `/workspace`、SSH 维护私钥挂载和 loopback egress proxy 端口,规则见 `docs/reference/provider-gateway.md`。 - `bun scripts/cli.ts ssh [ssh-like args...]`:通过 provider-gateway 的 Host SSH / WSL SSH 维护桥打开近似原生 ssh 的交互会话或远端命令,并在远端 PATH 注入 `apply_patch`、`glob` 与 `skill-discover`;`apply-patch`、`py`、`skills`、结构化 `find`、`glob` 和 `argv` 子命令用于避免远端补丁、Python stdin、skill 发现与常用只读命令的嵌套转义问题,使用规则见 `docs/reference/cli.md` 和 `docs/reference/provider-gateway.md`。 - `bun scripts/cli.ts microservice list/status/health/diagnostics/tunnel-self-test/proxy`:管理和验证挂载在主 server、计算节点 Docker 或 k3s 控制面上的用户服务,`proxy` 支持受控 JSON body,OA Event Flow/Todo Note/Baidu Netdisk/Code Queue Manager on main-server、k3s Control/Code Queue 执行面/MDTODO/Decision Center/FindJob/Pipeline/MET Nonlinear on D601 的规则见 `docs/reference/microservices.md`。 diff --git a/docs/reference/cicd-standardization.md b/docs/reference/cicd-standardization.md index 071bb609..632a6719 100644 --- a/docs/reference/cicd-standardization.md +++ b/docs/reference/cicd-standardization.md @@ -102,6 +102,32 @@ Pull-only CD validation must be expressed as concrete checks: | Service health | UniDesk private proxy health succeeds for `filebrowser` and `filebrowser-d601`; direct public exposure remains forbidden | | Build absence | no `docker build`, `docker compose up --build`, CI Dockerfile producer, or source checkout is used for these services | +## Frozen Special-Case Inventory + +This table freezes the boundary between standard artifact services, upstream image consumers, bootstrap or maintenance paths, unclear manual-risk paths, and legacy paths that may be removed only after replacement evidence exists. + +| Object | Classification | Current Path | Target Path | Cleanup Prerequisites | Risk If Misclassified | Next Stage / Remove Later | +| --- | --- | --- | --- | --- | --- | --- | +| `filebrowser` | `upstream-digest` | `config.json` registers D518 `unidesk-direct` with `repository.dockerfile=docker.io/filebrowser/filebrowser:v2.63.3`, `artifactSource.kind=upstream-image`, and provider-local `docker run --restart unless-stopped`. `CI.json` marks it blocked from source-build CI. | Pull-only upstream image consumer: resolve `docker.io/filebrowser/filebrowser:v2.63.3` to a manifest digest, optionally mirror that digest to D601 registry, run by digest, then verify image identity and private proxy health. | Implement upstream digest resolver/mirror worker, record mirror digest, add container image-id/digest validation, preserve File Browser state paths and rollback runbook. | Treating it as source-build would build the wrong artifact; deleting the docker-run repair path before pull-only CD exists can break D518 file access. | Do not delete in the next stage; implement digest/mirror CD first. | +| `filebrowser-d601` | `upstream-digest` | Same upstream image and blocked CI catalog as `filebrowser`, but provider-local container is `unidesk-filebrowser-d601` on D601. | Same pull-only digest or mirror digest model as `filebrowser`, scoped to D601. | Same digest/mirror worker and runtime verification, plus D601 path/volume audit. | Same source-build confusion; premature cleanup can remove D601 file access used by operations. | Do not delete in the next stage; implement with `filebrowser`. | +| `database` | `upstream-digest` | Main-server Compose service uses `postgres:16-alpine`, named volume `unidesk_pgdata_10gb`, init SQL, and pinned config files. It is lifecycle-managed by `server start`/`server stop`, not by `server rebuild`. | Upstream digest pin or mirror for PostgreSQL image; Compose remains volume-preserving and pull-only for the image. | Digest pin for `postgres:16-alpine`, database backup/restore drill, major-version upgrade policy, and no `down -v` or volume deletion. | Data loss or unplanned PostgreSQL upgrade; a source-build model is meaningless for this service. | Keep; never remove as legacy. | +| `provider-gateway` | `bootstrap-keep` | Main-server Compose `server rebuild provider-gateway` and provider `provider.upgrade mode=schedule` can repair the control bridge. Host SSH keys are mounted read-only for maintenance, while normal automation uses WebSocket/provider tasks. | Standard source artifact publication for normal releases plus retained protected self-upgrade/repair path; Host SSH remains explicit maintenance only. | Prove provider-gateway artifact consumer or protected upgrade can recover a broken provider without SSH session lifetime coupling; keep Docker socket scope and loopback egress checks. | Removing the bridge repair path can strand providers and block CD, diagnostics, or registry relay. | Keep; not removable next stage. | +| `dev-frontend-proxy` | `bootstrap-keep` | Main-server Compose service built from `src/components/dev-frontend-proxy/Dockerfile`, exposed on the dev frontend port, and rebuildable by `server rebuild dev-frontend-proxy`. | Small bootstrap proxy kept as a main-server support service; optional future source artifact only after dev frontend proxy health and D601 dev UI rollout are covered. | Decide whether the proxy should become a standard artifact, add CI image and pull-only consumer if yes, and preserve dev UI recovery. | Deleting it breaks the public dev UI path even when production is healthy. | Keep; not removable next stage. | +| `server rebuild backend-core` | `bootstrap-keep` | Local main-server Compose build/recreate, serialized by Compose lock and validated after up. Docs forbid using it for Rust iteration or standard prod CD. | Recovery-only path; standard production path is D601 CI artifact plus `deploy apply --env prod --service backend-core`. | Backend-core artifact CD rollback proven under outage conditions; recovery runbook can repair a broken core without local Rust build. | Removing too early can block recovery when core or registry relay is degraded. | Keep; not removable next stage. | +| `server rebuild frontend` | `bootstrap-keep` | Local main-server Compose build/recreate for production frontend; maintenance-only and not release evidence. | Standard frontend release is CI `unidesk/frontend:` plus dev/prod artifact consumer and health/image-label verification. | Equivalent pull-only repair command, registry rollback, and frontend health verification runbook. | Local dirty bundle can become accidental production truth; deleting too early removes emergency UI repair. | Keep for now; degrade only after pull-only repair is proven. | +| `server rebuild baidu-netdisk` | `bootstrap-keep` | Local main-server Compose build/recreate for Baidu Netdisk; maintenance-only. | D601 CI source-build artifact plus dev/prod pull-only consumer. | Pull-only repair and token/staging persistence validation. | Dirty rebuild can hide token/staging regressions; premature deletion can block storage service repair. | Keep for now; degrade after pull-only repair is proven. | +| `server rebuild todo-note`, `code-queue-mgr`, `project-manager`, `oa-event-flow` | `bootstrap-keep` | Local main-server Compose rebuild for internal or direct main-server services; some have artifact consumer validation, while live prod apply may remain gated. | Convert each to CI artifact plus pull-only consumer and live health commit verification where supported; keep recovery entry until equivalent repair exists. | Per-service artifact consumer, runtime deploy metadata, rollback, and persistence validation. | Dirty local rebuilds can bypass `deploy.json`; deleting before rollback can break main-server service recovery. | Keep; reassess service by service. | +| `server rebuild provider-gateway` | `bootstrap-keep` | Local Compose rebuild for the main-server provider gateway. | Keep as bridge repair; normal upgrades should use protected provider upgrade or artifact path when available. | Same provider-gateway recovery proof as above. | May strand host-level observability and maintenance dispatch. | Keep. | +| `server rebuild filebrowser*`, `database`, `code-queue`, `k3sctl-adapter`, unknown services | `allowed-remove-later` for silent fallback only | Historically the CLI threw a generic usage error; no valid main-server Compose rebuild exists for these objects. | Structured `unsupported-server-rebuild` result; no job creation, no source build, no Compose mutation. | Operators must use documented upstream digest, k3s artifact, bridge repair, or manual-risk path instead. | Generic errors can lead operators to invent hand-built fallback commands. | Silent/generic fallback is removed; do not delete the real upstream/bootstrap runtime paths. | +| `deploy apply --env prod` unsupported services | `needs-manual` | Environment-ref prod apply reads `origin/master:deploy.json`; services without reviewed prod artifact consumers return structured unsupported. | Add service-specific CI producer, D601 registry artifact, prod consumer, and live commit/digest verification before enabling. | Silent target-side builds would bypass registry, dirty-worktree, and live verification guardrails. | Not removable as a class; enable per service only after review. | +| Local-manifest `deploy apply --file ...` for reviewed prod artifact consumers | `allowed-remove-later` | CLI blocks reviewed prod artifact consumers before source materialization and points to `deploy apply --env prod --service `. | Environment-ref deploy and artifact consumer only for standard production. | Confirm no recovery runbook requires local-manifest prod apply; provide rollback via registry. | Dirty local `deploy.json` or target-side source build can become production truth. | Allow removing or further degrading after recovery runbooks move to env-ref artifacts. | +| D601 target-side build path for dev `backend-core` | `bootstrap-keep` | `deploy apply --env dev --service backend-core` builds on D601 and rolls out only `unidesk-dev`. | Keep as controlled dev/Rust boundary until backend-core dev artifact consumer replaces it. | D601 CI artifact publication, dev consumer, Rust check/build parity, and rollback evidence. | Removing it can block Rust validation on the resource-appropriate host. | Keep; not removable next stage. | +| D601 maintenance-channel direct deploy for non-bridge services | `allowed-remove-later` | Direct provider `host.ssh` build/apply is blocked for normal D601 services; `codex deploy` is disabled. | Only artifact consumers or reviewed native bootstrap may mutate D601 services. | Confirm no supported runbook still calls the disabled path; keep structured unsupported output. | A second deploy control plane can bypass registry artifacts and k3s verification. | Remove stale callers/docs after no references remain. | +| `artifact-registry deploy-backend-core` | `allowed-remove-later` | Compatibility name returns a structured deprecated result; replacement is `deploy apply --env prod --service backend-core`. | Use only deploy reconciler entry for backend-core prod CD. | All callers and docs stop using the compatibility action. | Bypasses common deploy guardrails if re-enabled casually. | Remove compatibility after callers are migrated. | +| `k3sctl-adapter` | `bootstrap-keep` | D601 direct Compose control bridge outside k3s; artifact consumer is plan/dry-run only and live prod apply needs supervisor confirmation. | Keep outside the k3s fault domain; optionally publish artifact for controlled upgrade, but retain bridge repair. | Supervisor-approved live upgrade path, adapter health/control-plane validation, and rollback without losing Kubernetes access. | Removing or moving it into k3s can remove the bridge needed to repair k3s. | Keep; not removable next stage. | +| Maintenance SSH / manual Docker / manual k3s commands | `needs-manual` | Available through provider-gateway Host SSH, WSL SSH, manual Docker, and native k3s commands for repair and investigation. | Explicit maintenance-only runbooks with bounded commands, no silent source builds, no dirty worktree release truth, and no default CD fallback. | For each manual entry, document owner, trigger, rollback, volume/scope safety, and replacement artifact path. | Manual state can become undocumented production truth or destroy bootstrap access if over-cleaned. | Do not delete globally; constrain and document per path. | +| Dirty worktree, mutable `latest` tag, hand-mutated container state | `allowed-remove-later` as release truth | These may exist as local operator state or Docker cache, but they are not valid deployment evidence. | Standard releases use `deploy.json` commit, commit-tagged or digest-pinned images, image labels, and live commit/digest verification. | Runtime label checks, digest pins, env-ref deploy, and runbooks that reject `latest` and dirty worktree inputs. | Reproducibility and rollback are lost; a healthy old or hand-built container may be accepted accidentally. | Remove as accepted release evidence; keep only as diagnostic observations. | + ## Legacy Path Classification | Path | Classification | Current guardrail | Cleanup condition | @@ -123,6 +149,7 @@ Pull-only CD validation must be expressed as concrete checks: - `ci publish-user-service` returns a structured blocked result for 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`. +- `server rebuild` returns `unsupported-server-rebuild` for upstream image consumers, database, D601 execution/control-plane objects and unknown services; it does not create a job or mutate Compose for those objects. ### Guardrail Evidence Matrix @@ -132,6 +159,7 @@ Pull-only CD validation must be expressed as concrete checks: | `prod-artifact-consumer-local-manifest-blocked` | `bun scripts/cli.ts deploy apply --file deploy.json --service frontend --dry-run` returns `ok=false`, this error key, and points to `deploy apply --env prod --service --commit ` | prod source-build fallback for reviewed artifact consumers | keep; local manifest mode may still be needed for non-prod/recovery until runbooks are replaced | | `artifact-registry deploy-backend-core` deprecated result | `bun scripts/cli.ts artifact-registry deploy-backend-core --commit ` returns `ok=false`, `deprecated=true`, and replacement `deploy apply --env prod --service backend-core --commit ` | backend-core prod CD bypassing deploy reconciler guardrails | keep name only as compatibility until all callers stop using it | | prod unsupported result for services without artifact consumers | `deploy apply --env prod --service --dry-run` must return unsupported instead of falling back to source build | target-side source build/maintenance-channel prod deploy | keep disabled until service-specific artifact consumers exist | +| `unsupported-server-rebuild` | `bun scripts/cli.ts server rebuild filebrowser` and `bun scripts/cli.ts server rebuild database` return `ok=false`, `error=unsupported-server-rebuild`, classification, replacement path and allowed services | accidental source-build/Compose fallback for upstream images, database, k3s/control bridges and unknown services | keep; it removes only silent/generic fallback, not bootstrap or maintenance runtime paths | | backend-core/code-queue prod boundary | docs and deploy support matrix allow backend-core and D601 Code Queue only in dev validation for this phase | accidental prod validation entrypoints for backend-core or Code Queue | do not add executable prod test/deploy validation in this precheck | The guarded-but-not-deletable paths are: `server rebuild backend-core`, `server rebuild frontend`, `server rebuild baidu-netdisk`, provider-gateway protected upgrade, native k3s bootstrap, k3sctl-adapter bridge repair, File Browser provider-local docker-run repair, and D601 dev/backend target-side rollout. They remain because they are bootstrap, recovery, diagnostic, or controlled dev paths; deleting them requires replacement runbooks or reviewed artifact consumers. diff --git a/docs/reference/deploy.md b/docs/reference/deploy.md index ebe510a3..64976a54 100644 --- a/docs/reference/deploy.md +++ b/docs/reference/deploy.md @@ -217,4 +217,4 @@ The deploy job is not complete until live verification proves the running servic ## Unsupported Services -Image-only services, such as a service declared directly as `docker.io/vendor/image:tag` without a Dockerfile source artifact, do not satisfy target-side build policy. They must be converted to a source repository with a Dockerfile wrapper before the reconciler can manage them. Until then, `deploy check` and `deploy plan` should report them as unsupported. +Image-only services, such as a service declared directly as `docker.io/vendor/image:tag` without a Dockerfile source artifact, do not satisfy target-side source-build policy. They must not be silently converted into Dockerfile source builds. If the object is an approved upstream image exception, it must follow the digest-pinned pull-only model documented in `docs/reference/cicd-standardization.md`; otherwise `deploy check`, `deploy plan` and CD entrypoints should report it as unsupported until a reviewed artifact producer or upstream digest consumer exists. diff --git a/docs/reference/deployment.md b/docs/reference/deployment.md index 65c4e090..dfcb5208 100644 --- a/docs/reference/deployment.md +++ b/docs/reference/deployment.md @@ -46,7 +46,7 @@ swap 管理不能被强塞进所有热路径。`server start/status` 可以暴 ## Single Service Rebuild -前端、本机 provider-gateway、dev-frontend-proxy 或主 server 承载的 Todo Note/Code Queue Manager/Project Manager/Baidu Netdisk/OA Event Flow 用户服务需要非版本化本地重建时,统一使用 `bun scripts/cli.ts server rebuild `,其中 `` 只能是 `backend-core`、`frontend`、`dev-frontend-proxy`、`provider-gateway`、`todo-note`、`code-queue-mgr`、`project-manager`、`baidu-netdisk` 或 `oa-event-flow`。需要按 commit 上线或恢复到 desired-state 时必须改用 `bun scripts/cli.ts deploy apply --service `、backend-core artifact CD、`deploy apply --env dev|prod --service frontend|baidu-netdisk|decision-center|mdtodo|claudeqq` artifact consumer,或 dev-only `deploy apply --env dev --service code-queue` artifact consumer;直管微服务也不能把脏工作树或手工重建作为部署真相。`server rebuild frontend`、`server rebuild baidu-netdisk`、`server rebuild project-manager`、`server rebuild oa-event-flow`、`server rebuild todo-note` 和 `server rebuild code-queue-mgr` 都只作为维护/非标准路径保留,不得作为标准发布完成证据。Rust backend-core 迭代不得在 master server 用 `server rebuild backend-core` 编译,生产 backend-core 也不得用该命令完成 Rust 构建,必须走 D601 dev deploy/CI 或 D601 artifact registry CD。D601 Code Queue 执行面、File Browser、FindJob、Pipeline、MET Nonlinear 和 ClaudeQQ 部署在计算节点,不属于主 server Compose 可重建服务;其中 D601 Code Queue 执行面不得再通过 `codex deploy` 或维护通道直连 D601 部署,且本阶段 prod artifact deploy/rollout/manifest mutation 仍 unsupported。 +前端、本机 provider-gateway、dev-frontend-proxy 或主 server 承载的 Todo Note/Code Queue Manager/Project Manager/Baidu Netdisk/OA Event Flow 用户服务需要非版本化本地重建时,统一使用 `bun scripts/cli.ts server rebuild `,其中 `` 只能是 `backend-core`、`frontend`、`dev-frontend-proxy`、`provider-gateway`、`todo-note`、`code-queue-mgr`、`project-manager`、`baidu-netdisk` 或 `oa-event-flow`。对 `database`、`filebrowser`、`filebrowser-d601`、`code-queue`、`k3sctl-adapter` 或未知对象,CLI 必须返回结构化 `unsupported-server-rebuild`,不得创建 job、不得执行 Compose mutation,也不得把对象强行转成源码构建服务。需要按 commit 上线或恢复到 desired-state 时必须改用 `bun scripts/cli.ts deploy apply --service `、backend-core artifact CD、`deploy apply --env dev|prod --service frontend|baidu-netdisk|decision-center|mdtodo|claudeqq` artifact consumer,或 dev-only `deploy apply --env dev --service code-queue` artifact consumer;直管微服务也不能把脏工作树或手工重建作为部署真相。`server rebuild frontend`、`server rebuild baidu-netdisk`、`server rebuild project-manager`、`server rebuild oa-event-flow`、`server rebuild todo-note` 和 `server rebuild code-queue-mgr` 都只作为维护/非标准路径保留,不得作为标准发布完成证据。Rust backend-core 迭代不得在 master server 用 `server rebuild backend-core` 编译,生产 backend-core 也不得用该命令完成 Rust 构建,必须走 D601 dev deploy/CI 或 D601 artifact registry CD。D601 Code Queue 执行面、File Browser、FindJob、Pipeline、MET Nonlinear 和 ClaudeQQ 部署在计算节点,不属于主 server Compose 可重建服务;其中 D601 Code Queue 执行面不得再通过 `codex deploy` 或维护通道直连 D601 部署,且本阶段 prod artifact deploy/rollout/manifest mutation 仍 unsupported。特例冻结清单和下一阶段删除判断见 `docs/reference/cicd-standardization.md`。 frontend 改动必须明确上线到公网:修改 `src/components/frontend/src/`、`src/components/frontend/public/style.css`、frontend 使用的共享 TSX/TS 模块或 WebUI 导航后,标准发布顺序是先把 pushed commit 交给 `bun scripts/cli.ts ci publish-user-service --service frontend --commit `,再用 `bun scripts/cli.ts deploy apply --env dev --service frontend` 和 `bun scripts/cli.ts deploy apply --env prod --service frontend` 消费同一个 commit-pinned artifact。公网 WebUI 的 `/app.js` 是 `unidesk-frontend` 镜像内运行时 bundle;只改工作区文件、只跑 `bun run check`、只跑 `Bun.build`、只刷新浏览器或只 `server rebuild frontend` 都不能作为标准版本发布证据。 diff --git a/scripts/cli.ts b/scripts/cli.ts index df005b27..c9d10f46 100644 --- a/scripts/cli.ts +++ b/scripts/cli.ts @@ -1,6 +1,6 @@ import { readConfig } from "./src/config"; import { debugDispatch, debugHealth, debugTask, isDebugDispatchCommand, type DebugDispatchCommand } from "./src/debug"; -import { isRebuildableService, rebuildService, stackLogs, stackStatus, startStack, stopStack } from "./src/docker"; +import { isRebuildableService, rebuildService, stackLogs, stackStatus, startStack, stopStack, unsupportedRebuildService } from "./src/docker"; import { parseE2ERunOptions, runE2E } from "./src/e2e"; import { emitError, emitJson } from "./src/output"; import { jobWithTail, listJobs, listJobsSummary, readJob, runJob } from "./src/jobs"; @@ -197,7 +197,10 @@ async function main(): Promise { } if (sub === "rebuild") { if (!isRebuildableService(third)) { - throw new Error("server rebuild requires one of: backend-core, frontend, dev-frontend-proxy, provider-gateway, todo-note, code-queue-mgr, project-manager, baidu-netdisk, oa-event-flow"); + const result = unsupportedRebuildService(third); + emitJson(commandName, result, false); + process.exitCode = 1; + return; } emitJson(commandName, rebuildService(config, third)); return; diff --git a/scripts/src/docker.ts b/scripts/src/docker.ts index d0e7c1b3..86260631 100644 --- a/scripts/src/docker.ts +++ b/scripts/src/docker.ts @@ -27,6 +27,56 @@ export function isRebuildableService(value: string | undefined): value is Rebuil return rebuildableServices.some((service) => service === value); } +export function unsupportedRebuildService(value: string | undefined): Record { + const service = value ?? null; + const classifications: Record> = { + database: { + classification: "upstream-digest", + reason: "database uses the upstream postgres:16-alpine image and a named PGDATA volume; it is not a source-built UniDesk service", + replacement: "use server start/stop for lifecycle only; database image pin/mirror policy belongs to the upstream image precheck", + deleteAllowedLater: false, + }, + filebrowser: { + classification: "upstream-digest", + reason: "filebrowser is an upstream image consumer pinned by digest/mirror policy, not a Dockerfile source-build service", + replacement: "future pull-only upstream digest CD; current provider-local docker-run repair remains maintenance-only", + deleteAllowedLater: false, + }, + "filebrowser-d601": { + classification: "upstream-digest", + reason: "filebrowser-d601 is an upstream image consumer pinned by digest/mirror policy, not a Dockerfile source-build service", + replacement: "future pull-only upstream digest CD; current provider-local docker-run repair remains maintenance-only", + deleteAllowedLater: false, + }, + "code-queue": { + classification: "standard-artifact", + reason: "code-queue execution plane is D601 k3s-managed and only supports the dev artifact consumer in this phase", + replacement: "deploy apply --env dev --service code-queue or artifact-registry deploy-service --env dev --service code-queue", + deleteAllowedLater: false, + }, + "k3sctl-adapter": { + classification: "bootstrap-keep", + reason: "k3sctl-adapter is a D601 control bridge outside the main-server Compose stack", + replacement: "keep direct bridge repair and artifact plan/dry-run; live prod apply requires supervisor confirmation", + deleteAllowedLater: false, + }, + }; + return { + ok: false, + supported: false, + error: "unsupported-server-rebuild", + service, + ...(typeof value === "string" && classifications[value] !== undefined ? classifications[value] : { + classification: "needs-manual", + reason: "server rebuild can mutate only reviewed main-server Docker Compose services", + replacement: "inspect config.json, deploy.json, and docs/reference/cicd-standardization.md before choosing a release or maintenance path", + deleteAllowedLater: false, + }), + allowedServices: [...rebuildableServices], + policy: "server rebuild is a bootstrap/maintenance entrypoint and must not silently fall back to source builds for upstream images, D601 services, database, or unknown objects", + }; +} + export function resolveComposeCommand(config: UniDeskConfig, envFile: string): string[] { const composeFile = rootPath(config.docker.composeFile); if (commandOk(["docker", "compose", "version"], repoRoot)) { diff --git a/scripts/src/help.ts b/scripts/src/help.ts index 519b700b..78b279bf 100644 --- a/scripts/src/help.ts +++ b/scripts/src/help.ts @@ -12,7 +12,7 @@ export function rootHelp(): unknown { { command: "server status", description: "Show fixed ports, containers, service health, and public URLs." }, { command: "server swap status|ensure [--path /swapfile] [--size 2GiB] [--dry-run]", description: "Inspect or idempotently create host swap for low-memory main-server operation." }, { command: "server logs [--tail-bytes N]", description: "Return bounded tails from file logs and docker logs." }, - { command: "server rebuild ", description: "Build first, then serialize, force-recreate, and validate one Compose service." }, + { command: "server rebuild ", description: "Maintenance-only local Compose rebuild for reviewed main-server services; unsupported objects return structured errors instead of falling back to source builds." }, { command: "provider attach [--master-server URL] [--up] [--force]", description: "Generate the minimal external provider-gateway env/compose bundle; only master server URL and provider id are required." }, { command: "ssh [ssh-like args...]", description: "Open a Host SSH / WSL SSH maintenance session through the provider-gateway bridge with built-in remote helper tools in PATH." }, { command: "ssh apply-patch [tool args...] < patch.diff", description: "Invoke the injected remote apply_patch helper directly over SSH passthrough and stream the patch from local stdin." }, @@ -87,6 +87,12 @@ export function serverHelp(action: string | undefined = undefined): unknown { masterServer: "do not use server rebuild backend-core for Rust iteration; it would build locally", d601: "use deploy apply --env dev --service backend-core and CI for Rust build/check", }, + nonRebuildableBoundary: { + upstreamImages: ["filebrowser", "filebrowser-d601"], + infrastructure: ["database", "k3sctl-adapter"], + d601ExecutionPlane: ["code-queue"], + policy: "unsupported objects return unsupported-server-rebuild and must not be coerced into main-server Compose source builds", + }, }; }