Red Hat Developer logo

Skill

base-images-and-rpms

update base images and lockfiles

Covers Containers Configuration Automation Deployment

Description

Updates base images with updateBaseImages.sh and regenerates rpms.lock.yaml with rpm-lockfile-prototype in redhat-developer/rhdh, rhdh-must-gather, and rhdh-operator. Use --analyze for read-only Containerfile/Dockerfile scan (current vs latest tags, UBI skew). Use for weekly upstream maintenance, UBI/RHEL base image bumps, RPM lockfile refresh, base-images-and-rpms, main, release-*, or analyzing base images before updating.

SKILL.md

Base images and RPMs

Goal

Refresh base images and RPM lockfiles in the three upstream GitHub repos:

RepoNode / Go sourceRPM containerfile
rhdhbuild/containerfiles/Containerfile or docker/Dockerfile (release-1.9)build/containerfiles/Containerfile or .rhdh/docker/Dockerfile
rhdh-operatorgo.mod aligned with ubi9/go-toolset on main only.rhdh/docker/Dockerfile
rhdh-must-gatherContainerfile

Upstream helper scripts live in GitLab midstream rhidp/rhdh on branch rhdh-1-rhel-9 (see updateBaseImages.sh).

Prerequisites

  • jq, skopeo, curl, git
  • podman for rhdh node header version detection (see .nvm/releases/README.adoc)
  • gh when updateBaseImages.sh opens PRs (--pr, the default)
  • python3 and pip when rpm-lockfile-prototype is not already installed
  • Registry auth for base image queries: docker login registry.redhat.io (or skopeo login)

Install rpm-lockfile-prototype manually when needed:

python3 -m pip install --user https://github.com/konflux-ci/rpm-lockfile-prototype/archive/refs/heads/main.zip 2>/dev/null

On Fedora/RHEL hosts, dnf install podman skopeo python3-dnf may also be required for lockfile generation.

Branch mapping

Accepted -b values: main or any release-* branch (e.g. release-1.9, release-1.10, release-2.1).

GitHub branch (-b)GitLab scripts branch (-sb for updateBaseImages.sh)
mainrhdh-1-rhel-9
release-X.Yrhdh-X.Y-rhel-9

Verify the target branch exists in each repo before running.

Run the bundled script

Execute scripts/base-images-and-rpms.sh; do not reimplement the workflow inline.

SKILL=skills/base-images-and-rpms   # under 1-rhdh-skill checkout
chmod +x "${SKILL}/scripts/base-images-and-rpms.sh"

# All three repos under a parent directory
"${SKILL}/scripts/base-images-and-rpms.sh" -b release-1.10 --parent-dir ~/RHDH

# Explicit paths and on-disk tools
"${SKILL}/scripts/base-images-and-rpms.sh" -b main \
  --update-base-images-script ~/RHDH/rhdh/build/scripts/updateBaseImages.sh \
  --rpm-lockfile-prototype ~/.local/bin/rpm-lockfile-prototype \
  ~/RHDH/rhdh \
  ~/RHDH/rhdh-operator \
  ~/RHDH/rhdh-must-gather

Flags

FlagPurpose
-b, --branchRequired. main or release-*
--update-base-images-script PATHUse local updateBaseImages.sh (expects createPR.sh alongside; fetches if missing)
--rpm-lockfile-prototype PATHUse local binary; otherwise ~/.local/bin/rpm-lockfile-prototype or pip install
--parent-dir PATHAuto-discover 1-rhdh, 1-rhdh-operator, 1-must-gather (and common aliases)
REPO_DIR ...Explicit repo checkouts
--skip-base / --skip-rpmRun only one half of the workflow
--dirtyAllow dirty trees for updateBaseImages.sh
--pushLet updateBaseImages.sh push when branch policy allows (still uses --pr fallback)
--no-prCommit locally with --no-push only
--dry-runPrint commands without executing
--analyzeRead-only scan via analyze-base-images.sh (no -b required; defaults scripts to main)

Default: base image updates use --pr --no-push (local commits + PR creation, no push). RPM lockfile and node header changes are committed and pushed to the same open chore/automated-update-base-images-* PR branch when one exists; otherwise a chore/automated-update-rpm-lockfile/<branch> PR is opened.

Analyze without updating

Use --analyze to scan Containerfiles and Dockerfiles without checkout, commits, or registry writes:

"${SKILL}/scripts/base-images-and-rpms.sh" --analyze --parent-dir ~/RHDH

# Optional: match GitLab scripts branch to a release line
"${SKILL}/scripts/base-images-and-rpms.sh" --analyze -b release-1.10 --parent-dir ~/RHDH

Or run the analyzer directly:

"${SKILL}/scripts/analyze-base-images.sh" \
  -s /path/to/rhidp/rhdh/build/scripts \
  -w ~/RHDH/rhdh \
  -w ~/RHDH/rhdh-operator

The analyzer reports current vs latest per FROM line, flags malformed tags, and warns on UBI minor skew within a file. Tags must be major.minor-buildid or x.y.z-buildid; bare numeric registry tags are ignored (same rules as updateBaseImages.sh). Requires skopeo login registry.redhat.io.

Each registry FROM needs a comment URL on the line above:

# https://registry.access.redhat.com/ubi9/nodejs-24
FROM registry.access.redhat.com/ubi9/nodejs-24:9.8-...@sha256:... AS skeleton

For rhdh, paths under e2e-tests/ and .ci/ are excluded from scans.

Workflow

  1. Pick branch (-b).
  2. Ensure local clones are fetched and clean enough for updateBaseImages.sh (or pass --dirty).
  3. Run the script on all three repos.
  4. Review open PRs — each should include base image, rpms.lock.yaml, and (for rhdh) node header updates when applicable.
  5. Human merges PRs; do not push directly to protected branches without review.

What each step does

Base images (updateBaseImages.sh)

Mirrors weekly-maintenance.sh upstream section:

updateBaseImages.sh -w REPO_ROOT -b BRANCH -sb SCRIPTS_BRANCH -maxdepth 5 --pr

-maxdepth 5 reaches .rhdh/docker/Dockerfile in the operator repo as well as top-level containerfiles.

updateBaseImages.sh calls createPr() once per image bump; upstream createPR.sh runs gh pr view --web on every call, which re-opens the same PR URL. This skill sets GITLAB_PIPELINE=true during updateBaseImages.sh to suppress that, then opens each repo's PR once in the browser when --pr is in effect.

RPM lockfiles (rpm-lockfile-prototype)

Matches each repo's GitHub Action, then commits and pushes to the automation PR:

rpm-lockfile-prototype -f CONTAINERFILE rpms.in.yaml
git add rpms.lock.yaml
git commit -s -m "chore: update rpms.lock.yaml [skip-build]"
git push origin <chore/automated-update-base-images-*>   # same PR as base images

When no base-images PR exists (e.g. --skip-base), the script uses chore/automated-update-rpm-lockfile/<branch> and opens a PR.

Node headers (rhdh only)

When the ubi9/nodejs-* builder image in build/containerfiles/Containerfile ships a different Node version than .nvmrc / .nvm/releases/, the script:

  1. Reads node --version from the updated builder image (podman/docker)
  2. Downloads https://nodejs.org/dist/<version>/node-<version>-headers.tar.gz into .nvm/releases/
  3. Updates .nvmrc (version without v prefix) and .nvm/releases/README.adoc (date + version)
  4. Removes stale node-v*-headers.tar.gz files and pushes to the same automation PR

See rhdh .nvm/releases/README.adoc. On release-1.9, headers come from docker/Dockerfile (ubi9/nodejs-22), not Node 24.

Go toolchain (rhdh-operator, main only)

On main only (not release-*), after base image bumps, reads go version from the ubi9/go-toolset image in .rhdh/docker/Dockerfile and updates go.mod:

go 1.26.0
toolchain go1.26.4

Anti-patterns

  • Pushing without human review.
  • Running on a branch that does not exist in one of the three repos.
  • Omitting registry.redhat.io login before base image updates.
  • Committing rpms.lock.yaml without checking the base image minor (e.g. UBI 9.8) still matches rpms.in.yaml repo URLs.

Additional resources

© 2026 YourAI.tools. Every skill from an identity-verified publisher.

Independent catalog. Not affiliated with, endorsed by, or sponsored by Anthropic or any listed publisher. All trademarks belong to their respective owners.