Skip to content

feat: add container image version bumper (make container-bump-image-versions)#5811

Open
jonpspri wants to merge 4 commits into
mainfrom
jps-containerfile-version-bumper
Open

feat: add container image version bumper (make container-bump-image-versions)#5811
jonpspri wants to merge 4 commits into
mainfrom
jps-containerfile-version-bumper

Conversation

@jonpspri

@jonpspri jonpspri commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

What

Adds scripts/container-bump-image-versions.sh, exposed as make container-bump-image-versions, which bumps the pinned Red Hat UBI image tags in the repo's Containerfiles to the latest build tag within their current minor line.

Why

The base-image pins (UBI_BASE, NODEJS_IMAGE, UBI_MINIMAL) are full build tags (<minor>-<epoch-buildid>) chosen for reproducibility, but nothing keeps them current — they drift until someone checks by hand. No Dependabot/Renovate config exists in the repo today, and Renovate would treat the two UBI_MINIMAL pin sites as independent updates, whereas they must change atomically.

How it works

  • Discovers tags anonymously via the Red Hat Catalog (Pyxis) API (catalog.redhat.com/api/containers/v1/...); registry.access.redhat.com allows anonymous access, unlike registry.redhat.io.
  • Tag semantics are <minor>-<epoch-buildid>, so "latest" is the numeric max of the epoch component, restricted to each pin's current minor line. Bumping minors (e.g. 10.2 → 10.3) stays a deliberate, reviewed change.
  • All lookups and validation complete before any file is written: a failed or malformed API response means zero files modified.
  • UBI_MINIMAL is pinned in both Containerfile and infra/wheels/Containerfile; both are always updated together.
  • The ENABLE_FIPS=true build path overrides these ARGs with UBI 9 images at build time and is intentionally not managed.

Testing

  • New bats suite tests/scripts/container-bump-image-versions.bats (11 tests: tag filtering, atomic two-file update, no-op idempotence, minor-line policy, zero-write failure paths, non-pinned-tag refusal), run via the new make bats target, which discovers all tests/**/*.bats.
  • Verified end-to-end against the live Pyxis API: a run correctly identified and applied the pending 10.2-line updates, and a second run was a clean no-op. This surfaced (and fixed, with a stub regression lock) a real curl URL-globbing failure on the sort_by=last_update_date[desc] query parameter.
  • The actual pin bump is intentionally not included here; it is being handled independently.

Notes for reviewers

  • bats-core is a new dev-only prerequisite (brew install bats-core); make bats fails gracefully with an install hint when absent.
  • bats is currently not wired into make test or CI — worth deciding in review whether it should be.
  • .secrets.baseline line-number drift in the Makefile commit is the detect-secrets hook's own regeneration.

@prakhar-singh1928

Copy link
Copy Markdown
Collaborator

@jonpspri with respect to this PR there are Two Blocking Issues

Issue 1 : repo_for_arg maintains a parallel hard-coded map that can drift from the actual image path already available in the Containerfile. The Pyxis repo path should be derived from ${value%:*} (which the script already extracts as image_of[$arg]) rather than a separate static case statement. If a deliberate minor-bump changes the path, the map would silently query the wrong endpoint.

Issue 2: sed -i '' in the bats test is macOS-only. GNU sed (Ubuntu — the likely CI runner) has no empty-suffix form; it will fail with "No such file or directory". The main script uses the portable sed -i.bak pattern already; the test should match it.

local f
for f in "${files[@]}"; do
if sed -i.bak "s|^ARG ${arg}=.*|ARG ${arg}=${image_of[$arg]}:${new_tag[$arg]}|" "$f"; then
rm -f "${f}.bak"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential .bak leak: sed -i.bak renames the original to ${f}.bak before writing. For UBI_MINIMAL, files has two entries. If sed succeeds on the first file (its .bak is deleted by line 128), then sed fails on the second file (disk full, permissions changed mid-run, etc.), the second .bak is left on disk. die calls exit 1 immediately with no cleanup.

Low probability, but easy to close with a trap:

declare -a _baks=()
trap 'rm -f "${_baks[@]}"' EXIT
# then in the loop:
sed -i.bak "..." "$f" && _baks+=("${f}.bak") && rm -f "${f}.bak"

local files=("$CONTAINERFILE_PATH")
# UBI_MINIMAL is pinned in both Containerfiles; keep them identical.
if [ "$arg" = "UBI_MINIMAL" ]; then
files+=("$WHEELS_CONTAINERFILE_PATH")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional Style/Consistency note: ${!new_tag[@]} iterates associative array keys in undefined order in bash. The sed calls for each ARG are independent today so the result is correct regardless of order, but this diverges from the plan and report loops which both iterate "${MANAGED_ARGS[@]}" in declaration order. If the apply logic ever gains an ordering dependency (e.g. a second ARG's sed pattern could match the first ARG's line), this becomes a latent bug.

Consistent, order-safe alternative:

for arg in "${MANAGED_ARGS[@]}"; do
    [[ -v new_tag[$arg] ]] || continue
    ...

jonpspri added 3 commits July 24, 2026 14:07
Signed-off-by: Jonathan Springer <jps@s390x.com>
Signed-off-by: Jonathan Springer <jps@s390x.com>
Remove the hard-coded ARG-to-repository map (repo_for_arg) that could
drift from the actual image path in the Containerfile; the Pyxis
repository is now derived from each pin's image reference, with a
fail-fast guard for pins outside registry.access.redhat.com.

Replace the macOS-only 'sed -i ""' in the bats test with the portable
sed -i.bak pattern so the suite runs on GNU sed (Ubuntu CI).

Add regression tests for the derived-repository lookup and the
foreign-registry refusal.

Signed-off-by: Jonathan Springer <jps@s390x.com>
@jonpspri
jonpspri force-pushed the jps-containerfile-version-bumper branch from 3d44aa2 to 07983eb Compare July 24, 2026 13:07

@prakhar-singh1928 prakhar-singh1928 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Install an EXIT trap removing Containerfile .bak files so a sed failure
mid-apply (die path) cannot strand backup files on disk; the redundant
per-file rm in the loop is folded into the trap.

Iterate the apply phase over MANAGED_ARGS in declaration order instead
of undefined associative-array key order, matching the plan and report
loops and removing a latent ordering hazard.

Add a regression test asserting no .bak files remain after an update.

Signed-off-by: Jonathan Springer <jps@s390x.com>
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.

2 participants