190 lines
9.7 KiB
Markdown
190 lines
9.7 KiB
Markdown
# HWLAB Artifact Catalog Contract
|
|
|
|
The artifact catalog is the DEV-only MVP contract for interpreting generated
|
|
deployment artifacts. It pins which HWLAB service image, commit, profile,
|
|
namespace, and health path GitOps render must inject into runtime manifests.
|
|
`deploy/deploy.json` stays the human-authored runtime config truth source.
|
|
|
|
This file is not automatically a CI publish record. It proves only the state it
|
|
declares:
|
|
|
|
- `artifactState: "contract-skeleton"` means the source/artifact commit and image
|
|
tags are aligned, but `ciPublished=false`, `registryVerified=false`, and every
|
|
digest must stay `not_published`.
|
|
- `artifactState: "published"` is allowed only after a DEV publish report proves
|
|
every required enabled service was published for the same source commit with a
|
|
real `sha256:<64 hex>` registry digest. Services explicitly disabled in the
|
|
service inventory must stay `not_published` and carry a disabled reason.
|
|
|
|
Do not infer registry existence, digest values, or deployment from commit tags.
|
|
Real publish evidence must come from the publishing workflow and registry
|
|
metadata, then be copied into the catalog by the refresh command below.
|
|
|
|
## Scope
|
|
|
|
- Environment: DEV only.
|
|
- Namespace: `hwlab-dev`.
|
|
- Public DEV endpoint: `http://74.48.78.17:16667`.
|
|
- Profile: `dev`.
|
|
- Health path: `/health/live`.
|
|
- Artifact state: contract skeleton only.
|
|
- PROD deployment, PROD smoke, secret reads, force push, real image publish, and
|
|
UniDesk runtime substitution are forbidden.
|
|
|
|
## Files
|
|
|
|
| File | Role |
|
|
| --- | --- |
|
|
| `deploy/artifact-catalog.dev.json` | Machine-readable DEV artifact identity truth for generated image, digest, commit, and publish provenance fields. |
|
|
| `deploy/deploy.json` | Human-authored DEV runtime config such as service topology, env, health, profile, replicas, and endpoints. |
|
|
| `scripts/g14-gitops-render.mjs` | Declares the Tekton primitive CI tasks and minimal guardrails that generate the G14 CI/CD control plane. |
|
|
| `scripts/deploy-desired-state-plan.mjs` | Read-only planner/checker for catalog artifact identity, generated identity leakage into deploy config, and deploy/runtime config contracts. |
|
|
| `scripts/refresh-artifact-catalog.mjs` | Previews artifact catalog identity by default; only G14 Tekton promotion uses `--write` to update `deploy/artifact-catalog.dev.json` before committing generated state to `G14-gitops`. |
|
|
| `scripts/validate-artifact-catalog.mjs` | Local static validator for the catalog and deploy manifest skeleton. |
|
|
| `scripts/preflight-dev-base-image.mjs` | Local DEV builder base-image preflight for future artifact publish. |
|
|
| `docs/dev-base-image-preflight.md` | Operator contract for interpreting preflight readiness and blockers. |
|
|
|
|
## Pin Rules
|
|
|
|
Every service entry in `deploy/artifact-catalog.dev.json` must satisfy these
|
|
rules:
|
|
|
|
| Field | Rule |
|
|
| --- | --- |
|
|
| `serviceId` | Must be one of the frozen HWLAB service IDs and must appear exactly once. |
|
|
| `commitId` | Must match the top-level catalog commit ID. Short or full lowercase Git SHA is allowed. |
|
|
| `image` | Must match the DEV registry target `<registry>/<namespace>/<serviceId>:<imageTag>`. The matching field must not be copied into `deploy/deploy.json`. |
|
|
| `imageTag` | Must be the first seven characters of `commitId`. Mutable tags such as `latest`, `dev`, or `main` are forbidden. |
|
|
| `profile` | Must be `dev`. |
|
|
| `namespace` | Must be `hwlab-dev`. |
|
|
| `healthPath` | Must be `/health/live` and match the DEV health contract. |
|
|
| `publishState` | Must be `skeleton-only` in a blocked skeleton catalog, or `published` only when the catalog was refreshed from a successful publish report. |
|
|
| `sourceState` | Must be `source-present` for MVP services with repository source, or `intentionally-disabled` for zero-replica services excluded from MVP publication. |
|
|
| `artifactRequired` | Must match `serviceInventory.requiredServiceIds`; only required services need publish digests. |
|
|
| `artifactScope` | `required` for services that must be published, or `disabled` with a `notPublishedReason`. |
|
|
| `digest` | Must be `not_published` in the skeleton catalog; it may be a registry `sha256:<64 hex>` digest only after publish evidence exists. |
|
|
|
|
The catalog `commitId` is the artifact source commit, not proof that a registry
|
|
artifact exists. It must match every service `commitId` and the image tag. If a
|
|
later target ref changes artifact build inputs after the
|
|
publish source, the DEV gate preflight may reopen `artifact-source-commit` even
|
|
when the base-image blocker is already closed.
|
|
|
|
## Desired-State Plan
|
|
|
|
Use the read-only planner before refreshing or reviewing deploy desired-state:
|
|
|
|
```sh
|
|
node scripts/deploy-desired-state-plan.mjs --plan --pretty
|
|
node scripts/deploy-desired-state-plan.mjs --check
|
|
node scripts/deploy-desired-state-plan.mjs --target-ref origin/G14 --pretty
|
|
node scripts/deploy-desired-state-plan.mjs --target-tag <tag> --pretty
|
|
node scripts/deploy-desired-state-plan.mjs --promotion-commit <sha> --check
|
|
```
|
|
|
|
The planner treats `deploy/deploy.json` as human-authored runtime config,
|
|
`deploy/artifact-catalog.dev.json` as artifact identity truth, and
|
|
`deploy/k8s/base/workloads.yaml` as a runtime template. It reports catalog
|
|
service `commitId`/`image`/`imageTag`, blocks generated artifact identity that
|
|
leaks into `deploy.json`, and leaves workload image/env mirror values to GitOps
|
|
render because render overwrites them from the catalog.
|
|
|
|
`--check` exits non-zero when the source files are missing or invalid, generated
|
|
artifact identity leaks into `deploy.json`, an explicit target tag is invalid or
|
|
mutable, or catalog artifact identity does not match the requested target. The
|
|
source branch catalog is only a seed contract; published artifact identity is
|
|
stored on `G14-gitops`. The optional report snapshot is contextual evidence only
|
|
and is not an authoritative desired-state source.
|
|
|
|
For PR review or CI/CD promotion handoff, use `--promotion-commit <sha>
|
|
--check`. That mode is stricter than a `--target-ref` plan: the catalog
|
|
top-level commit and each catalog service commit/image tag must align with the
|
|
promotion commit/tag. A stale but internally consistent catalog is a blocker in
|
|
promotion mode because applying it would roll DEV back.
|
|
|
|
The planner does not prove registry existence, publish success, DEV apply, or
|
|
M3 DEV-LIVE. Only real DEV observation of
|
|
`res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1` with operation,
|
|
trace, audit, and evidence records can be called M3 DEV-LIVE.
|
|
|
|
## Refresh Boundary
|
|
|
|
Human source work must not refresh artifact identity into the source branch. To
|
|
preview what a blocked catalog would look like, use read-only mode:
|
|
|
|
```sh
|
|
node scripts/refresh-artifact-catalog.mjs --target-ref HEAD --blocked --no-write
|
|
node scripts/deploy-desired-state-plan.mjs --check
|
|
```
|
|
|
|
This prints the planned catalog state and does not modify any repository file.
|
|
Blocked skeleton refresh is intentionally preview-only.
|
|
|
|
After a successful DEV artifact publish, only the G14 Tekton promotion path may
|
|
record digests from the publish report:
|
|
|
|
```sh
|
|
node scripts/refresh-artifact-catalog.mjs --target-ref <source-sha> --publish-report /workspace/source/dev-artifacts.json --write
|
|
```
|
|
|
|
The publish-report mode refuses to update the catalog unless the report says
|
|
`artifactPublish.status="published"`, covers every frozen service in the v2
|
|
publish plan, matches the target source commit, and contains a valid `sha256`
|
|
digest for each required service. Disabled services remain `skeleton-only` with
|
|
`digest: "not_published"`. The written catalog is committed only to
|
|
`G14-gitops`; `deploy/deploy.json` remains human-authored source truth.
|
|
|
|
## Relationship To `deploy/deploy.json`
|
|
|
|
`deploy/deploy.json` remains the human-authored deploy manifest. The artifact
|
|
catalog does not replace it and must not be consumed as proof that a release was
|
|
built. GitOps render combines human config from `deploy.json` with generated
|
|
artifact identity from the catalog; artifact identity must not be copied back
|
|
into `deploy.json`.
|
|
|
|
If a future CI workflow publishes real images, it should update or generate a
|
|
publish result that includes registry digests and provenance. That publish
|
|
result may be compared with this contract, but it must not be inferred from this
|
|
contract.
|
|
|
|
## DEV Builder Preflight
|
|
|
|
Before a future DEV artifact publish attempts to build or publish service
|
|
images, run:
|
|
|
|
```sh
|
|
npm run --silent dev-base-image:preflight
|
|
```
|
|
|
|
The preflight is local-only and checks for an approved builder base image through
|
|
`HWLAB_DEV_BASE_IMAGE`, a local `node:20-*` Docker image, or an explicit local
|
|
HWLAB dev base tag such as `hwlab-dev-base:<tag>`. It prints the image source,
|
|
local tag, image ID, publish usability, blockers, next steps, and
|
|
machine-readable preload/provision commands. The recommended source is
|
|
`node:20-bookworm-slim`; the recommended HWLAB-local tag is
|
|
`127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim`. A blocked result
|
|
means artifact publish must stop and must not be reported as a successful
|
|
publish.
|
|
|
|
## Validation
|
|
|
|
Run the local static validator:
|
|
|
|
```sh
|
|
node --check scripts/deploy-desired-state-plan.mjs
|
|
node --check scripts/src/deploy-desired-state-plan.mjs
|
|
node --test scripts/deploy-desired-state-plan.test.mjs
|
|
node scripts/deploy-desired-state-plan.mjs --check
|
|
node --check scripts/validate-artifact-catalog.mjs
|
|
node --check scripts/refresh-artifact-catalog.mjs
|
|
node --check scripts/preflight-dev-base-image.mjs
|
|
node --check scripts/src/dev-base-image-preflight.mjs
|
|
node scripts/validate-artifact-catalog.mjs
|
|
```
|
|
|
|
The validator and refresh command read local repository files and optional
|
|
publish reports; refresh is read-only unless `--write` is explicitly supplied.
|
|
The desired-state planner has the same read-only boundary.
|
|
These commands do not contact a registry, read secrets, build images, push
|
|
images, deploy to DEV, or deploy to PROD.
|