Skip to content

chore(ci): unify check-image-pins.py — add the canonical copy (JDWLABS-451) - #48

Merged
jdwillmsen merged 1 commit into
mainfrom
chore/JDWLABS-451-unify-check-image-pins
Aug 29, 2026
Merged

chore(ci): unify check-image-pins.py — add the canonical copy (JDWLABS-451)#48
jdwillmsen merged 1 commit into
mainfrom
chore/JDWLABS-451-unify-check-image-pins

Conversation

@jdwillmsen

Copy link
Copy Markdown
Member

Summary

deployments/tools/check-image-pins.py and platform/tools/check-image-pins.py were forks of the same digest-pinning gate that had diverged into two different programs. This PR adds the canonical, merged copy under tools/ here, with the union of both test suites, a tools-tests.yml gate, and a docs/ci-standards.md section recording the vendoring convention. The delivery-repo PRs (deployments, platform) vendor this file byte-for-byte and add a CI drift guard pinned to a commit SHA in this repo — this PR must merge first, and those two must then be re-pinned from the branch SHA to the merged SHA.

Divergence classification

Divergence Classification Resolution
Discovery: deployments Helm-merges charts/<chart>/values-<env>.yaml onto values.yaml and fails a chart with no overlay; platform globs every YAML under tenants/ + helm-charts/ repo-specific by design Both kept as config-selectable source kinds (helm-overlays, tree) in tools/image-pin-check.yaml
Allowlist key: (path, repository, tag) vs (path, ref) accidental drift (same intent, two schemas) One schema, ref = full composed reference; deployments allowlist migrated (7 entries)
Unquoted numeric tag: deployments coerces + reports malformed (lossy 1.101.1 in the message); platform preserves literal text but treats it as an ordinary, allowlistable violation accidental drift Union: literal text preserved and reported malformed / not allowlistable (Helm's own parser makes the same lossy conversion, so it is a defect in both repos)
Digest-only tag: "@sha256:…" rejected in deployments only; platform composed repo:@sha256:… which matched the digest regex and read as pinned accidental drift (false negative in platform) Rejected as malformed in structured blocks; raw repo@sha256:… strings stay valid (deployments wrongly flagged those)
Truncated digest / invalid OCI tag grammar checks deployments only Applied everywhere
registry:/digest: fields, registry-only blocks, <name>Image/<name>Tag sibling keys, embedded ConfigMap manifests, non-reference filtering (URLs, paths, templates), multi-document files platform only Applied everywhere
Template scan: deployments trims trailing # comments and scans .tpl; platform's regex missed any line with a trailing comment and never scanned .tpl accidental drift (false negative in platform) Union
Dedup of a reference repeated in one file platform only Applied everywhere
Full report (Digest-pinned: inventory, 0 issues line, MALFORMED/UNCHECKED CHARTS sections) deployments only Applied everywhere
check-remote-chart-image-pins.py (platform) reuses the checker's loader/walker repo-specific Given a stable entry point, refs_in_tree()

Mechanism

Shared script + per-repo config file (not flags): the repo-specific part is the whole discovery model, which is too large to express as flags. Drift guard = cmp against raw.githubusercontent.com/jdwlabs/.github/<sha>/tools/… in each consumer's image-pin job, following the SHA-pin decision for reusable workflows recorded in docs/ci-standards.md.

Test plan

  • python3 -m unittest discover -s tools/tests -t tools/tests — 107 tests, OK (1 skip: the real-repo integrity test needs a per-repo config)
  • Same file vendored into deployments (143 tests OK) and platform (228 tests OK, incl. remote-chart checker)
  • Checker run against both repos' real manifests: deployments 6 pinned / 7 allowlisted / 0 unexplained, platform 18 / 26 / 0 — identical counts to the pre-unification scripts
  • actionlint .github/workflows/tools-tests.yml

Refs JDWLABS-451.

🤖 Generated with Claude Code

https://claude.ai/code/session_016XRddumw4ZNvFqHSd9KSf6

… repos

deployments and platform each carried their own fork of the image-pin
checker. They had diverged far enough that each repo caught defects the
other missed: one preserved the literal text of an unquoted numeric tag but
let a digest-only `tag:` read as pinned, the other rejected digest-only
tags but crashed on numeric ones and skipped trailing-comment template
lines. This is the union of both rule sets, parameterised per repo by a
tools/image-pin-check.yaml (scan sources + allowlist path) so the script
itself is byte-identical everywhere.

Consumers vendor this file and its test file and compare them against this
repo at a pinned commit in CI, the same SHA-pin convention already used for
reusable workflows. tools-tests.yml gates changes here, which is the only
PR signal a shared script gets before it propagates.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016XRddumw4ZNvFqHSd9KSf6
@jdwillmsen
jdwillmsen merged commit 402a119 into main Aug 29, 2026
6 checks passed
@jdwillmsen
jdwillmsen deleted the chore/JDWLABS-451-unify-check-image-pins branch August 29, 2026 21:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant