Operator rule 2026-10-29: image creation, hosting and lifecycle belong to CI/CD, never to a workstation build/push. Nothing had ever been pushed to the Gitea registry. - .gitea/workflows/images.yaml + scripts/images.sh: PRs build+verify (no credential); main builds, verifies and pushes toolbox, agent-runner (FROM toolbox) and conformance-runner as sha-<commit> + main, reading the digest back from the registry. Only changed images build. - Each image's own build-image.sh does the build and in-image verification, now engine-neutral (DinD: no podman-only calls, probe over stdin not a bind mount). New toolbox build-image.sh. - Digest references carry `# renovate-digest:` markers; renovate.json5 gains a custom.regex manager for them. The worker Job template is deliberately untracked (it would loop). - renovate.yaml pins renovate-version 44.167.0: the action's default (39.264.0) rejects the current config's managerFilePatterns, so every run would have died at CONFIG_VALIDATION. - Push credential: REGISTRY_PUSH_TOKEN secret; the Actions token has no package scope in Gitea 1.24.3 (container.go Authenticate). Retention: infra/gitea/registry-retention.sh. Co-Authored-By: Claude Opus 5.5 <[email protected]>
71 lines
4.6 KiB
Bash
71 lines
4.6 KiB
Bash
# Pinned tool versions for the conformance harness (R-TEST-02: deterministic).
|
|
# The harness is only reproducible if the toolchain is pinned. Bumps flow through the
|
|
# normal update path (ADR-0011) with the suite re-green as the gate — never bumped
|
|
# silently. `run.sh` sources this file; the in-cluster Chainsaw Job image (see
|
|
# incluster/chainsaw-job.yaml) MUST use the same CHAINSAW_VERSION.
|
|
|
|
# Chainsaw — L1 rendering / L2 behavioral / L3 fault-injection runner (ADR-0011).
|
|
CHAINSAW_VERSION="v0.2.12"
|
|
# The UPSTREAM chainsaw image. It is NOT what the in-cluster Job runs — see
|
|
# CONFORMANCE_RUNNER_IMAGE below. It carries the chainsaw binary and essentially nothing
|
|
# else (no bash, no python3, no kubectl, no git), so `command: ["./run.sh"]` on this image
|
|
# fails at exec. Kept only as the provenance of the chainsaw binary we rebuild from.
|
|
CHAINSAW_IMAGE="ghcr.io/kyverno/chainsaw:v0.2.12"
|
|
|
|
# kubectl — used by run.sh for cluster reachability preflight and by probe scripts.
|
|
KUBECTL_VERSION="v1.36.4"
|
|
|
|
# Kyverno CLI — L0 static/policy gate (owned by T-0.5, referenced here for a single
|
|
# pinned toolchain view). Not invoked by run.sh yet.
|
|
KYVERNO_VERSION="v1.19.0"
|
|
|
|
# Python 3 — coverage generator + JUnit emitter use stdlib only (no pip deps), so the
|
|
# only constraint is a modern interpreter.
|
|
PYTHON_MIN="3.9"
|
|
|
|
# --- In-cluster conformance runner image -------------------------------------
|
|
# Built from conformance/incluster/Containerfile by conformance/incluster/build-image.sh.
|
|
# This — not CHAINSAW_IMAGE — is what the L2/L3 Job runs (bash + python3 + chainsaw +
|
|
# kubectl + git). Closes docs/plans/l2-l3-conformance-ci-wiring.md §3 item 1.
|
|
#
|
|
# It ALSO carries /usr/local/bin/conformance-clone (0755 root:root, no argument surface) as the
|
|
# init container's only entrypoint. That is a security fixture, not a convenience: the
|
|
# admission policy never reads `initContainers`, so an init container with an inline shell
|
|
# script is currently admitted with the privileged runner SA. The policy rule that makes the
|
|
# fixed path REQUIRED is not in this branch — see conformance/incluster/README.md.
|
|
#
|
|
# THE REPOSITORY PATH IS NOT A PREFERENCE. platform/kyverno/admission/
|
|
# conformance-trigger-job-shape.yaml is a fail-closed Enforce ClusterPolicy (R-SEC-02) that
|
|
# ADMITS a conformance-trigger Job only when its image matches
|
|
# gitea.home.keithjackson.dev/home-network/conformance-runner@sha256:*
|
|
# Any other path, and any TAG reference, is DENIED at admission. Do not "tidy" these values.
|
|
CONFORMANCE_RUNNER_IMAGE_REPO="gitea.home.keithjackson.dev/home-network/conformance-runner"
|
|
# Local build handle only. Admission never sees the tag; a Job must reference the digest.
|
|
# CI publishes under `sha-<commit>` and `main` instead (.gitea/workflows/images.yaml).
|
|
CONFORMANCE_RUNNER_IMAGE_TAG="chainsaw0.2.12-kubectl1.36.4-fc44"
|
|
#
|
|
# ############################################################################
|
|
# # THE DIGEST IS WRITTEN BY RENOVATE, NOT BY HAND. #
|
|
# ############################################################################
|
|
# CI builds and verifies the image (non-root uid 65532, read-only rootfs, the
|
|
# conformance-clone refusals) and, on a push to main, publishes it and prints the digest the
|
|
# REGISTRY returned (.gitea/workflows/images.yaml). Renovate follows the image's `main` tag
|
|
# through the marker below and opens the pull request that moves this value. Nobody pushes
|
|
# this image from a workstation, and nobody pastes a digest here.
|
|
#
|
|
# ALL-ZERO UNTIL THE FIRST PUBLISH. Before 2026-10-29 this was EMPTY, so that a consumer
|
|
# rendering the Job would fail visibly. It is now the same impossible all-zero digest
|
|
# platform/pm-agent/ uses, because Renovate can only replace a digest that is there to match.
|
|
# A consumer MUST treat the all-zero value as "not published" (no consumer exists yet: the
|
|
# L2/L3 trigger is unwired, docs/plans/l2-l3-conformance-ci-wiring.md). Note also that
|
|
# chainsaw-job.yaml's @@CONFORMANCE_RUNNER_IMAGE_DIGEST@@ takes the 64 hex digits WITHOUT the
|
|
# `sha256:` prefix this value carries — the trigger must strip it.
|
|
# renovate-digest: image=gitea.home.keithjackson.dev/home-network/conformance-runner tag=main
|
|
CONFORMANCE_RUNNER_IMAGE_DIGEST="sha256:0000000000000000000000000000000000000000000000000000000000000000"
|
|
CONFORMANCE_RUNNER_IMAGE="${CONFORMANCE_RUNNER_IMAGE_REPO}@${CONFORMANCE_RUNNER_IMAGE_DIGEST}"
|
|
#
|
|
# AFTERWARDS, TIGHTEN THE BOUNDARY: the header of conformance-trigger-job-shape.yaml asks for
|
|
# its `@sha256:*` wildcard to be replaced with the LITERAL digest once the image exists —
|
|
# that closes the residual "anyone who can push to this path" gap. Separate PR, human
|
|
# reviewed, because it edits the security boundary itself.
|