14. Checksum-verify third-party binaries downloaded in CI
Date: 2026-06-29
Status
Accepted
Context
The static CI job fetches the kubeconform release tarball with curl and
extracts it straight into /usr/local/bin:
curl -fsSL -o /tmp/kc.tgz ".../kubeconform-linux-amd64.tar.gz"
tar -C /usr/local/bin -xzf /tmp/kc.tgz kubeconform
The version was pinned (KUBECONFORM_VERSION), but the content was not verified.
A pinned tag still trusts whatever bytes the release URL serves: a hijacked release,
a replaced asset, or a compromised upstream account would put an attacker-controlled
binary on PATH and run it in CI. This is the same supply-chain class as ADR-0013
(actions pinned to SHAs) — pinning the reference is not enough if the fetched
artifact itself can change underneath the pin.
Decision
Pin the content hash alongside the version and verify it before use. The
expected SHA256 (from the release CHECKSUMS file) lives next to the version in the
workflow env, with a comment requiring the two to move together:
KUBECONFORM_VERSION: v0.8.0
KUBECONFORM_SHA256: "9bc2bffbf71f261128533edaf912153948b7ff238f9a531ae6d34466ec287883"
curl -fsSL -o /tmp/kc.tgz ".../kubeconform-linux-amd64.tar.gz"
echo "${KUBECONFORM_SHA256} /tmp/kc.tgz" | sha256sum -c -
tar -C /usr/local/bin -xzf /tmp/kc.tgz kubeconform
sha256sum -c exits non-zero on mismatch, failing the job before the binary is
extracted or run. The check executes on every CI run, so it is self-testing — no
separate guard is needed; a tampered or wrong-version download simply breaks the
build.
The principle generalises: any third-party binary fetched during a gating CI run is verified against a pinned checksum before it is executed.
Consequences
- A tampered or substituted
kubeconformdownload fails CI instead of running. - Upgrading
kubeconformnow requires updatingKUBECONFORM_SHA256as well asKUBECONFORM_VERSION; the env comment makes that explicit. This is deliberate friction — the cost of an upgrade is one checksum lookup. tests/bootstrap.shalso downloadskubeconform(andhelm) without verification, but it is a best-effort, multi-platform local developer installer, not a gating path. Hardening it would need a per-OS/arch checksum map and is left as a separate follow-up rather than folded into this CI-scoped change.helmitself is installed in CI via the SHA-pinnedazure/setup-helmaction (ADR-0013), which verifies its own download, so it is already covered.