Uh oh!
There was an error while loading. Please reload this page.
security(ci): verify kubeconform against a pinned digest before installing - #538
Merged
Conversation
…lling The template job installed kubeconform with: curl -sSL .../releases/latest/download/kubeconform-linux-amd64.tar.gz \ | tar xz -C /usr/local/bin Two independent problems. `releases/latest` is a mutable pointer, so the binary this job executed changed whenever upstream cut a release — we were not pinned to anything. And piping curl into tar extracts the bytes as they arrive, so there was no moment at which a digest could have been checked even if we had one; the archive was unpacked onto PATH first and inspected never. What could previously execute unreviewed: whatever those bytes happened to be. A replaced release asset, a compromised upstream account, or a MITM on the download would land an executable in /usr/local/bin and the next step ran it. This job runs on the matrix for all four platforms, so it happened four times per CI run. What now cannot: the download is pinned to an explicit version, written to a temp file, verified against a digest pinned in the workflow, and only installed once it matches. Bytes that do not match the digest never become an executable on PATH. Follows the pattern already used in tracebloc/.github's actionlint.yml (version + SHA-256 + `sha256sum -c`). kubeconform 0.8.0, kubeconform-linux-amd64.tar.gz sha256 9bc2bffbf71f261128533edaf912153948b7ff238f9a531ae6d34466ec287883 source: the release's own CHECKSUMS asset (not computed from a download) Version pin is behaviour-preserving: `releases/latest` currently redirects to v0.8.0. The digest is asserted to be 64 hex characters before use. `sha256sum -c` treats a malformed line as "no properly formatted checksum lines found", and whether that exits non-zero depends on the coreutils build — so an empty or truncated variable could otherwise verify nothing while the step still went green. Every failure mode was tested on ubuntu:22.04 (GNU coreutils 8.32): digest mismatch, empty digest, truncated digest, uppercase digest, HTTP 404, and a real substitution (pinned v0.8.0 digest against the v0.7.0 asset). All exit non-zero and leave no binary on PATH. Refs tracebloc/backend#1426 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
saadqbal
approved these changes
Aug 3, 2026
Uh oh!
There was an error while loading. Please reload this page.
LukasWodka
commented
Aug 3, 2026
ContributorAuthor
/fr-pass |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
The
templatejob installed kubeconform like this:Two independent problems:
releases/latestis a mutable pointer. The binary this job executed changed whenever upstream cut a release. We were not pinned to anything.curl | tarmakes verification impossible, not just absent. Piping extracts bytes as they arrive, so there is no point at which a digest could be checked. The archive was unpacked ontoPATHfirst and inspected never.curlalso lacked-f, so an HTTP error body was fed totaras if it were an archive.The next step then executes that binary — four times per CI run, once per matrix platform.
Pin + digest
0.8.0(wasreleases/latest)kubeconform-linux-amd64.tar.gz9bc2bffbf71f261128533edaf912153948b7ff238f9a531ae6d34466ec287883CHECKSUMSasset —https://github.com/yannh/kubeconform/releases/download/v0.8.0/CHECKSUMSThe digest is taken from upstream's published
CHECKSUMSfile, not computed from a download (computing it from the bytes you just fetched authenticates nothing).Version pin is behaviour-preserving:
releases/latestcurrently 302-redirects tov0.8.0, confirmed.Pattern copied from
tracebloc/.github'sactionlint.yml(version + SHA-256 +sha256sum -c) rather than invented.The failure path that reports success — and why this one doesn't
sha256sum -ctreats a malformed line as "no properly formatted checksum lines found", and whether that exits non-zero depends on the coreutils build: GNU exits 1, the macOSsha256sumexits 0. An empty or truncated digest variable is therefore a plausible way to ship a step that verifies nothing and still goes green. So the digest is asserted to be 64 hex characters before it is relied on.Tested on
ubuntu:22.04(GNU coreutils 8.32) by executing the verbatimrun:block extracted from this YAML, checking both the exit code and whether a binary landed onPATH:v0.8.0Every bad case fails closed and installs nothing.
Required checks
This touches the
templatejob, which runs the 4-platform matrix (aks,bm,eks,oc), sohelm-ciexercises the new step 4×.actionlint1.7.7 clean on this file. No chart or values changes, so Prereqs / PATH persist / E2E are untouched.Refs tracebloc/backend#1426
🤖 Generated with Claude Code
Note
Low Risk
CI-only workflow change with no chart or runtime impact; slightly reduces risk of unverified third-party binaries on runners.
Overview
The template job in
helm-cino longer installs kubeconform fromreleases/latestviacurl | tar. It pins v0.8.0 with a SHA-256 from upstream’sCHECKSUMS, downloads the tarball to disk (curl -fsSLwith retries), validates the digest (including a regex guard so empty/truncated digests cannot pass silently), and only then extracts and installs the binary.This hardens CI supply-chain for the step that runs kubeconform on rendered Helm manifests across the four-platform matrix; manifest validation behavior is unchanged aside from using a fixed, verified binary.
Reviewed by Cursor Bugbot for commit 4dc2029. Bugbot is set up for automated code reviews on this repo. Configure here.