Digest-pin all base images: ci/images/{ansible,k8s,tofu}/Containerfile (alpine:3.21) and ci/images/claude/Containerfile (node:22-alpine) now pin FROM to the current manifest-list digest, resolved via the Docker Hub registry API at fix time.
Checksum-verify tool downloads in ci/images/k8s/Containerfile: talosctl, kubectl, and velero downloads are now verified against their published sha256 checksums before use.
Replace curl | bash flux install: swapped for a pinned-version (FLUX_VERSION=2.9.2) tarball download, checksum-verified the same way as the other tools - removes the unpinned fetch-and-execute pattern.
Pin kubectl version: previously resolved dynamically from dl.k8s.io/release/stable.txt at build time (floating); added KUBECTL_VERSION=v1.36.2 ARG, matching the existing TALOS_VERSION/VELERO_VERSION pattern. Its checksum is still fetched per-build from dl.k8s.io (immutable per version) and verified.
Checksum-verify tofu download in ci/images/tofu/Containerfile.
Pin CLAUDE_CODE_VERSION in ci/images/claude/Containerfile from latest to 2.1.209 (current npm latest dist-tag at fix time) - this is the image holding repo/issue-write tokens for the AI agents, so this was the highest-priority item.
All digests/checksums were independently verified against the upstream registries/release APIs (Docker Hub registry v2 API + docker manifest inspect cross-check for image digests; GitHub release asset checksum files for talosctl/velero/tofu/flux; dl.k8s.io's per-version .sha256 file for kubectl; npm registry dist-tags.latest for claude-code).
Note: velero's upstream repo moved from vmware-tanzu/velero to velero-io/velero (GitHub redirects, but I pointed the download URL at the canonical new location since that's also where the checksum file was sourced from).
.woodpecker/build-ci-images.yml needed no changes - it builds with Containerfile ARG defaults and doesn't pass --build-arg overrides, so pinning the defaults directly closes the gap.
Fixes #209.
## Changes
- Digest-pin all base images: ci/images/{ansible,k8s,tofu}/Containerfile (alpine:3.21) and ci/images/claude/Containerfile (node:22-alpine) now pin FROM to the current manifest-list digest, resolved via the Docker Hub registry API at fix time.
- Checksum-verify tool downloads in ci/images/k8s/Containerfile: talosctl, kubectl, and velero downloads are now verified against their published sha256 checksums before use.
- Replace `curl | bash` flux install: swapped for a pinned-version (FLUX_VERSION=2.9.2) tarball download, checksum-verified the same way as the other tools - removes the unpinned fetch-and-execute pattern.
- Pin kubectl version: previously resolved dynamically from dl.k8s.io/release/stable.txt at build time (floating); added KUBECTL_VERSION=v1.36.2 ARG, matching the existing TALOS_VERSION/VELERO_VERSION pattern. Its checksum is still fetched per-build from dl.k8s.io (immutable per version) and verified.
- Checksum-verify tofu download in ci/images/tofu/Containerfile.
- Pin CLAUDE_CODE_VERSION in ci/images/claude/Containerfile from `latest` to 2.1.209 (current npm latest dist-tag at fix time) - this is the image holding repo/issue-write tokens for the AI agents, so this was the highest-priority item.
All digests/checksums were independently verified against the upstream registries/release APIs (Docker Hub registry v2 API + `docker manifest inspect` cross-check for image digests; GitHub release asset checksum files for talosctl/velero/tofu/flux; dl.k8s.io's per-version .sha256 file for kubectl; npm registry dist-tags.latest for claude-code).
Note: velero's upstream repo moved from vmware-tanzu/velero to velero-io/velero (GitHub redirects, but I pointed the download URL at the canonical new location since that's also where the checksum file was sourced from).
`.woodpecker/build-ci-images.yml` needed no changes - it builds with Containerfile ARG defaults and doesn't pass --build-arg overrides, so pinning the defaults directly closes the gap.
Addresses #209. All four ci/images/*/Containerfile FROM lines were
tag-pinned only (alpine:3.21, node:22-alpine), letting the base silently
change between builds. Pin each to its current manifest-list digest.
ci/images/k8s/Containerfile downloaded talosctl, kubectl, and velero via
curl with no integrity check, and installed flux via `curl | bash`
(itself an unpinned, unverified fetch-and-execute). Replace the flux
install with a pinned-version tarball download verified against its
published sha256 checksum, same as talosctl/kubectl/velero now are.
kubectl's version was also resolved dynamically from dl.k8s.io's
stable.txt at build time instead of being pinned; add KUBECTL_VERSION.
ci/images/tofu/Containerfile's tofu.zip download gets the same
sha256 verification.
ci/images/claude/Containerfile's CLAUDE_CODE_VERSION defaulted to
`latest` and was never overridden by build-ci-images.yml, so the image
holding repo/issue-write tokens floated to whatever npm resolved at
build time. Pin it to the current release (2.1.209).
Checksums and digests verified against the respective registries/release
APIs at fix time (2026-07-14).
Co-Authored-By: Claude Bot <claude-bot@renner.uno>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes #209.
Changes
curl | bashflux install: swapped for a pinned-version (FLUX_VERSION=2.9.2) tarball download, checksum-verified the same way as the other tools - removes the unpinned fetch-and-execute pattern.latestto 2.1.209 (current npm latest dist-tag at fix time) - this is the image holding repo/issue-write tokens for the AI agents, so this was the highest-priority item.All digests/checksums were independently verified against the upstream registries/release APIs (Docker Hub registry v2 API +
docker manifest inspectcross-check for image digests; GitHub release asset checksum files for talosctl/velero/tofu/flux; dl.k8s.io's per-version .sha256 file for kubectl; npm registry dist-tags.latest for claude-code).Note: velero's upstream repo moved from vmware-tanzu/velero to velero-io/velero (GitHub redirects, but I pointed the download URL at the canonical new location since that's also where the checksum file was sourced from).
.woodpecker/build-ci-images.ymlneeded no changes - it builds with Containerfile ARG defaults and doesn't pass --build-arg overrides, so pinning the defaults directly closes the gap.