148 lines
14 KiB
Markdown
148 lines
14 KiB
Markdown
# CI/CD Standardization
|
|
|
|
This document defines the stable split between CI artifact producers, artifact catalog data, legacy guardrails and CD consumers. Detailed Tekton rules remain in `docs/reference/ci.md`; registry runtime and consumers remain in `docs/reference/artifact-registry.md`; user-service delivery order remains in `docs/reference/user-service-delivery.md`.
|
|
|
|
## 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.
|
|
|
|
## Artifact Catalog
|
|
|
|
Root `CI.json` is the CI producer catalog. It is not a deployment manifest.
|
|
|
|
Allowed catalog data:
|
|
|
|
- stable `serviceId`;
|
|
- artifact `kind`: `source-build` or `upstream-image`;
|
|
- producer command: `ci publish-backend-core` or `ci publish-user-service`;
|
|
- source repository URL, optional repo root and repo-relative Dockerfile path;
|
|
- image repository naming and commit tag policy;
|
|
- upstream image digest, upstream source revision and D601 mirror intent for image-only services;
|
|
- the required success summary contract.
|
|
|
|
Forbidden catalog data:
|
|
|
|
- provider IDs;
|
|
- runtime namespace, Compose service, Kubernetes Service or health path;
|
|
- ports, environment variables, replicas or volumes;
|
|
- desired deployment commits or rollout targets.
|
|
|
|
Runtime topology belongs to `config.json`, `deploy.json`, existing Kubernetes manifests and the artifact-registry executor.
|
|
|
|
## Producer Contract
|
|
|
|
`bun scripts/cli.ts ci publish-user-service --service <id> --commit <full-sha>` reads `source.repo`, `source.dockerfile` and image repository naming from `CI.json`. It rejects command-line repo overrides. Successful source-build producers must label the image with:
|
|
|
|
- `unidesk.ai/service-id`;
|
|
- `unidesk.ai/source-commit`;
|
|
- `unidesk.ai/source-repo`;
|
|
- `unidesk.ai/dockerfile`.
|
|
|
|
The successful `artifactSummary` must contain `serviceId`, `sourceCommit`, `sourceRepo`, `dockerfile`, `imageRef`, `tag`, `digest` and `digestRef`.
|
|
|
|
`blocked` catalog entries must return a structured blocked result. They must not silently skip, build from a dirty worktree, fall back to target-side maintenance deployment, or mutate production.
|
|
|
|
## Current Coverage
|
|
|
|
Supported source-build artifact producers:
|
|
|
|
- `backend-core` through `ci publish-backend-core`;
|
|
- `frontend`, `baidu-netdisk`, `decision-center`, `project-manager`, `oa-event-flow`, `todo-note`, `code-queue-mgr`, `findjob`, `pipeline`, `met-nonlinear`, `k3sctl-adapter`, `mdtodo`, `claudeqq` through `ci publish-user-service`.
|
|
|
|
Cataloged but blocked:
|
|
|
|
- `code-queue`: source input is known, but this phase allows only dev image validation and not prod-oriented artifact publication.
|
|
- `filebrowser` and `filebrowser-d601`: upstream image-only services pinned to `docker.io/filebrowser/filebrowser@sha256:289c5dd677c56662440f26eeb44266ed9746fe563d2e9100f546bff558534d70`; they need a future upstream mirror producer before CI can publish them.
|
|
|
|
`code-queue-mgr` is a supported CI producer because the source-build input is known and the remote consumer commit already added a reviewed artifact consumer shape. Its production live apply remains supervisor-gated by deploy/artifact-registry and is not authorized by `CI.json`.
|
|
|
|
## 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.artifacts[]` with `kind=upstream-image` plus `config.json.microservices[].repository.artifactSource` | forbidden | resolve tag to `docker.io/filebrowser/filebrowser@sha256:<manifest-digest>`, then optionally mirror to `127.0.0.1:5000/upstream/filebrowser/filebrowser@sha256:<manifest-digest>` | 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.artifacts[]` with `kind=upstream-image` plus `config.json.microservices[].repository.artifactSource` | forbidden | same as `filebrowser` | same as `filebrowser` |
|
|
|
|
The catalog records the resolved upstream digest for the current image. If a future tag refresh cannot resolve the registry manifest digest, rollout must remain blocked until a reachable registry path resolves the manifest digest and records the mirror digest. A local Docker image id is supporting evidence only and not a registry digest pin.
|
|
|
|
### Upstream Image Evidence
|
|
|
|
The catalog expression is intentionally minimal and parseable:
|
|
|
|
| Evidence command | Required result shape |
|
|
| --- | --- |
|
|
| `jq '.artifacts[] | select(.kind=="upstream-image") | {serviceId, upstream, status}' CI.json` | both File Browser services show `upstream.imageRef=docker.io/filebrowser/filebrowser:v2.63.3`, a sha256 `upstream.digestRef`, `sourceRevision=ca5e249e3c0c94159c2136a0cd431a424eb18472`, mirror intent under `upstream/filebrowser/filebrowser`, and `status=blocked` |
|
|
| `bun scripts/cli.ts config show` with the File Browser `artifactSource` projection | both services parse as `kind=upstream-image`, `digestPinRequired=true`, `mirrorRepository=127.0.0.1:5000/upstream/filebrowser/filebrowser`, `ciDockerfileBuild=false`, and `pullOnlyCd=true` |
|
|
| `docker manifest inspect --verbose docker.io/filebrowser/filebrowser:v2.63.3` | must resolve the upstream manifest digest before rollout; if the registry request times out, rollout remains blocked |
|
|
| `bun scripts/cli.ts ci publish-user-service --service filebrowser --commit <full-sha> --dry-run` | returns `ok=false` with `status=blocked`, upstream digest/mirror metadata, and no Dockerfile source build |
|
|
|
|
The digest/mirror dry-run contract is:
|
|
|
|
1. Resolve `docker.io/filebrowser/filebrowser:v2.63.3` to `docker.io/filebrowser/filebrowser@sha256:<manifest-digest>`.
|
|
2. Mirror only that resolved digest to `127.0.0.1:5000/upstream/filebrowser/filebrowser@sha256:<manifest-digest>`.
|
|
3. Record the digest ref used by CD; do not promote a mutable tag as release truth.
|
|
4. Refuse pull-only CD while the digest is unknown or the mirror digest differs from the upstream digest.
|
|
|
|
Pull-only CD validation must be expressed as concrete checks:
|
|
|
|
| Check | Form |
|
|
| --- | --- |
|
|
| Pull source | `docker pull docker.io/filebrowser/filebrowser@sha256:<manifest-digest>` or `docker pull 127.0.0.1:5000/upstream/filebrowser/filebrowser@sha256:<manifest-digest>` |
|
|
| Runtime identity | `docker inspect` reports the expected image id/digest and OCI labels `org.opencontainers.image.version=2.63.3` and `org.opencontainers.image.revision=ca5e249e3c0c94159c2136a0cd431a424eb18472` |
|
|
| 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 |
|
|
|
|
## 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.artifacts[]` with `kind=upstream-image` and in `config.json.microservices[].repository.artifactSource`; they are explicitly outside source-build producers.
|
|
- `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`.
|
|
|
|
### Guardrail Evidence Matrix
|
|
|
|
| Guardrail name / result key | Command evidence | Legacy path covered | Deletion status |
|
|
| --- | --- | --- | --- |
|
|
| `upstream-image` CI publish rejection | `bun scripts/cli.ts ci publish-user-service --service filebrowser --commit <full-sha> --dry-run` returns `ok=false`, `status=blocked`, and upstream metadata | File Browser accidentally entering Dockerfile CI | keep; deletion of docker-run repair waits for digest/mirror CD |
|
|
| `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 <service-id> --commit <full-sha>` | 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 <full-sha>` returns `ok=false`, `deprecated=true`, and replacement `deploy apply --env prod --service backend-core --commit <full-sha>` | 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 <unsupported-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 |
|
|
| 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.
|
|
|
|
## Safety Boundary
|
|
|
|
CI may build images, push to the D601 loopback registry and report immutable digests. CI must not run production CD, call `deploy apply` for production, mutate production namespaces, recreate production Compose services or update `deploy.json`.
|
|
|
|
backend-core and D601 `code-queue` remain restricted to dev image validation in this phase. Any future production rollout for them must be implemented as an explicit CD consumer change, not as a CI producer side effect.
|
|
|
|
## Validation Boundary
|
|
|
|
This precheck uses lightweight parsing and dry-run evidence only. It intentionally does not run full `check`, e2e, Playwright, or other broad browser/runtime test suites on the master server because those are outside the precheck scope and may exceed master-server resource limits. `backend-core` and D601 `code-queue` production validation are also out of scope; backend-core dev rollout can be attempted only through the existing D601 dev path, and a provider-offline result is an infrastructure blocker rather than permission to validate production.
|