docs(release): document GHCR tag immutability contract
This commit is contained in:
parent
b1327ec3f1
commit
84e3e02e0a
10
.github/workflows/main-branch-flow.md
vendored
10
.github/workflows/main-branch-flow.md
vendored
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
53
docs/operations/ghcr-tag-policy.md
Normal file
53
docs/operations/ghcr-tag-policy.md
Normal 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.
|
||||
@ -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
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user