| name | base-images-and-rpms |
| 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. |
Base images and RPMs
Goal
Refresh base images and RPM lockfiles in the three upstream GitHub repos:
| Repo | Node / Go source | RPM containerfile |
|---|
| rhdh | build/containerfiles/Containerfile or docker/Dockerfile (release-1.9) | build/containerfiles/Containerfile or .rhdh/docker/Dockerfile |
| rhdh-operator | go.mod aligned with ubi9/go-toolset on main only | .rhdh/docker/Dockerfile |
| rhdh-must-gather | — | Containerfile |
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) |
|---|
main | rhdh-1-rhel-9 |
release-X.Y | rhdh-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
chmod +x "${SKILL}/scripts/base-images-and-rpms.sh"
"${SKILL}/scripts/base-images-and-rpms.sh" -b release-1.10 --parent-dir ~/RHDH
"${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
| Flag | Purpose |
|---|
-b, --branch | Required. main or release-* |
--update-base-images-script PATH | Use local updateBaseImages.sh (expects createPR.sh alongside; fetches if missing) |
--rpm-lockfile-prototype PATH | Use local binary; otherwise ~/.local/bin/rpm-lockfile-prototype or pip install |
--parent-dir PATH | Auto-discover 1-rhdh, 1-rhdh-operator, 1-must-gather (and common aliases) |
REPO_DIR ... | Explicit repo checkouts |
--skip-base / --skip-rpm | Run only one half of the workflow |
--dirty | Allow dirty trees for updateBaseImages.sh |
--push | Let updateBaseImages.sh push when branch policy allows (still uses --pr fallback) |
--no-pr | Commit locally with --no-push only |
--dry-run | Print commands without executing |
--analyze | Read-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
"${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
- Pick branch (
-b).
- Ensure local clones are fetched and clean enough for
updateBaseImages.sh (or pass --dirty).
- Run the script on all three repos.
- Review open PRs — each should include base image,
rpms.lock.yaml, and (for rhdh) node header updates when applicable.
- 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-*>
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:
- Reads
node --version from the updated builder image (podman/docker)
- Downloads
https://nodejs.org/dist/<version>/node-<version>-headers.tar.gz into .nvm/releases/
- Updates
.nvmrc (version without v prefix) and .nvm/releases/README.adoc (date + version)
- 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