docs(release): document GHCR tag immutability contract

This commit is contained in:
Chummy 2026-02-25 12:59:49 +00:00 committed by Chum Yin
parent b1327ec3f1
commit 84e3e02e0a
4 changed files with 68 additions and 6 deletions

View File

@ -163,10 +163,12 @@ Workflow: `.github/workflows/pub-docker-img.yml`
1. `publish` job runs on tag pushes `v*` only.
2. Workflow trigger includes semantic version tag pushes (`v*`) only.
3. Login to `ghcr.io` uses `${{ github.actor }}` and `${{ secrets.GITHUB_TOKEN }}`.
4. Tag computation includes semantic tag from pushed git tag (`vX.Y.Z`) + SHA tag.
4. Tag computation includes semantic tag from pushed git tag (`vX.Y.Z`) + SHA tag (`sha-<12>`) + `latest`.
5. Multi-platform publish is used for tag pushes (`linux/amd64,linux/arm64`).
6. Typical runtime in recent sample: ~139.9s.
7. Result: pushed image tags under `ghcr.io/<owner>/<repo>`.
6. `scripts/ci/ghcr_publish_contract_guard.py` validates anonymous pullability and digest parity across `vX.Y.Z`, `sha-<12>`, and `latest`, then emits rollback candidate mapping evidence.
7. Trivy scans are emitted for version, SHA, and latest references.
8. Typical runtime in recent sample: ~139.9s.
9. Result: pushed image tags under `ghcr.io/<owner>/<repo>` with publish-contract + scan artifacts.
Important: Docker publish now requires a `v*` tag push; regular `dev`/`main` branch pushes do not publish images.
@ -262,7 +264,7 @@ flowchart TD
T --> P["pub-docker-img.yml publish job"]
R --> R1["Artifacts + SBOM + checksums + signatures + GitHub Release"]
W --> R2["Verification build only (no GitHub Release publish)"]
P --> P1["Push ghcr image tags (version + sha)"]
P --> P1["Push ghcr image tags (version + sha + latest)"]
```
## Quick Troubleshooting

View File

@ -31,6 +31,7 @@ Merge-blocking checks should stay small and deterministic. Optional checks are u
- `.github/workflows/pub-docker-img.yml` (`Docker`)
- Purpose: PR Docker smoke check on `dev`/`main` PRs and publish images on tag pushes (`v*`) only
- Additional behavior: `ghcr_publish_contract_guard.py` enforces GHCR publish contract from `.github/release/ghcr-tag-policy.json` (`vX.Y.Z`, `sha-<12>`, `latest` digest parity + rollback mapping evidence)
- `.github/workflows/feature-matrix.yml` (`Feature Matrix`)
- Purpose: compile-time matrix validation for `default`, `whatsapp-web`, `browser-native`, and `nightly-all-features` lanes
- Additional behavior: each lane emits machine-readable result artifacts; summary lane aggregates owner routing from `.github/release/nightly-owner-routing.json`
@ -136,6 +137,7 @@ Merge-blocking checks should stay small and deterministic. Optional checks are u
1. `CI Required Gate` failing: start with `.github/workflows/ci-run.yml`.
2. Docker failures on PRs: inspect `.github/workflows/pub-docker-img.yml` `pr-smoke` job.
- For tag-publish failures, inspect `ghcr-publish-contract.json` / `audit-event-ghcr-publish-contract.json` and Trivy artifacts from `pub-docker-img.yml`.
3. Release failures (tag/manual/scheduled): inspect `.github/workflows/pub-release.yml` and the `prepare` job outputs.
- Start with `release-trigger-guard.json` / `audit-event-release-trigger-guard.json` artifacts for authorization and provenance failures.
- Then inspect `release-artifact-guard.verify.json` / `release-artifact-guard.publish.json` and corresponding audit-event envelopes for contract completeness failures.
@ -170,6 +172,7 @@ Merge-blocking checks should stay small and deterministic. Optional checks are u
- Keep audit event schema + retention metadata aligned with `docs/audit-event-schema.md` (`emit_audit_event.py` envelope + workflow artifact policy).
- Keep rollback operations guarded and reversible (`ci-rollback.yml` defaults to `dry-run`; `execute` is manual and policy-gated).
- Keep canary policy thresholds and sample-size rules current in `.github/release/canary-policy.json`.
- Keep GHCR tag taxonomy and immutability policy current in `.github/release/ghcr-tag-policy.json` and `docs/operations/ghcr-tag-policy.md`.
- Keep pre-release stage transition policy + matrix coverage + transition audit semantics current in `.github/release/prerelease-stage-gates.json`.
- Keep required check naming stable and documented in `docs/operations/required-check-mapping.md` before changing branch protection settings.
- Follow `docs/release-process.md` for verify-before-publish release cadence and tag discipline.

View File

@ -0,0 +1,53 @@
# GHCR Tag Policy
This document defines the production container tag contract for `.github/workflows/pub-docker-img.yml`.
## Policy Source
- Machine policy: `.github/release/ghcr-tag-policy.json`
- Enforcement script: `scripts/ci/ghcr_publish_contract_guard.py`
- Workflow integration: `.github/workflows/pub-docker-img.yml` (`publish` job)
## Tag Taxonomy
Release publishes are restricted to stable git tags matching `vX.Y.Z`.
For each publish run, the workflow must produce three GHCR tags:
1. `vX.Y.Z` (release tag, immutable)
2. `sha-<12>` (commit SHA tag, immutable)
3. `latest` (mutable pointer for the newest stable release)
## Immutability Contract
The guard enforces digest parity:
1. `digest(vX.Y.Z) == digest(sha-<12>)`
2. `digest(latest) == digest(vX.Y.Z)` (while `require_latest_on_release=true`)
If any required tag is missing, not pullable, or violates digest parity, publish contract validation fails.
## Rollback Mapping
Rollback candidates are emitted deterministically from policy class order (`rollback_priority`):
1. `sha-<12>`
2. `vX.Y.Z`
The guard outputs this mapping to `ghcr-publish-contract.json` for auditability.
## Artifacts and Retention
Publish run emits:
- `ghcr-publish-contract.json`
- `ghcr-publish-contract.md`
- `audit-event-ghcr-publish-contract.json`
- Trivy reports (`trivy-<tag>.sarif`, `trivy-<tag>.txt`, `trivy-sha-<12>.txt`, `trivy-latest.txt`)
Retention defaults:
- Contract artifacts: `21` days
- Trivy scan artifacts: `14` days
Retention values are defined in `.github/release/ghcr-tag-policy.json` and reflected in workflow artifact uploads.

View File

@ -104,12 +104,16 @@ Expected publish outputs:
- `audit-event-release-artifact-guard-publish.json` proving publish-stage artifact contract completeness
- `zeroclaw.sha256sums.intoto.json` + `audit-event-release-sha256sums-provenance.json` for checksum provenance linkage
- `release-notes-supply-chain.md` / `release-notes-supply-chain.json` with release-asset references (manifest, SBOM, provenance, guard audit artifacts)
- Docker publish evidence from `Pub Docker Img`: `ghcr-publish-contract.json` + `audit-event-ghcr-publish-contract.json` + Trivy reports
### 5) Post-release validation
1. Verify GitHub Release assets are downloadable.
2. Verify GHCR tags for the released version (`vX.Y.Z`) and release commit SHA tag (`sha-<12>`).
3. Verify install paths that rely on release assets (for example bootstrap binary download).
2. Verify GHCR tags for the released version (`vX.Y.Z`), release commit SHA tag (`sha-<12>`), and `latest`.
3. Verify GHCR digest parity evidence confirms:
- `digest(vX.Y.Z) == digest(sha-<12>)`
- `digest(latest) == digest(vX.Y.Z)`
4. Verify install paths that rely on release assets (for example bootstrap binary download).
### 5.1) Canary gate before broad rollout