From 5b9bf57c23e73641974ca5c6ef8ffc3a889b6f06 Mon Sep 17 00:00:00 2001 From: Yakov Beder Date: Fri, 17 Jul 2026 20:17:02 +0000 Subject: [PATCH 1/2] Migrate container images from Debian node:22-slim to UBI9 Node.js minimal. Align Dockerfiles and entrypoint with Red Hat UBI conventions (microdnf, uid 1001/default) for disconnected/enterprise environments. Co-authored-by: Cursor --- .ci-operator/build-root/Dockerfile | 9 ++++---- Dockerfile | 36 +++++++++++++++++------------- Dockerfile.catalog-sync | 10 +++++---- entrypoint.sh | 13 ++++++----- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/.ci-operator/build-root/Dockerfile b/.ci-operator/build-root/Dockerfile index 99fd441..bf3f9d3 100644 --- a/.ci-operator/build-root/Dockerfile +++ b/.ci-operator/build-root/Dockerfile @@ -1,5 +1,6 @@ -FROM node:22-slim +FROM registry.access.redhat.com/ubi9/nodejs-22-minimal -RUN apt-get update && \ - apt-get install -y --no-install-recommends git ca-certificates && \ - rm -rf /var/lib/apt/lists/* +USER root + +RUN microdnf install -y --nodocs git && \ + microdnf clean all diff --git a/Dockerfile b/Dockerfile index c31cb90..fd850e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,6 @@ -FROM node:22-slim AS builder +FROM registry.access.redhat.com/ubi9/nodejs-22-minimal AS builder + +USER root ARG BUILD_DATE="" ARG VCS_REF="" @@ -35,15 +37,14 @@ RUN mkdir -p /app/catalog-data-minimal && \ RUN npx vite build # Fetch oc-mirror only; wget/tar stay in this stage (not copied to production). -FROM node:22-slim AS downloader +FROM registry.access.redhat.com/ubi9/nodejs-22-minimal AS downloader + +USER root ARG TARGETARCH -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - wget ca-certificates tar libgpgme11 && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +RUN microdnf install -y --nodocs wget tar gzip gpgme && \ + microdnf clean all ENV OCMIRROR_URL_AMD64="https://mirror.openshift.com/pub/openshift-v4/clients/ocp/stable/oc-mirror.tar.gz" ENV OCMIRROR_URL_ARM64="https://mirror.openshift.com/pub/openshift-v4/aarch64/clients/ocp/stable/oc-mirror.rhel9.tar.gz" @@ -61,7 +62,9 @@ RUN set -eux; \ which oc-mirror; \ oc-mirror version -FROM node:22-slim AS production +FROM registry.access.redhat.com/ubi9/nodejs-22-minimal AS production + +USER root ENV NODE_ENV=production @@ -71,12 +74,14 @@ ARG VERSION=1.0 COPY --from=downloader /usr/local/bin/oc-mirror /usr/local/bin/oc-mirror -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - bash ca-certificates libgpgme11 \ - python3 python3-yaml jq wget && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +RUN microdnf install -y --nodocs \ + bash tar gzip wget gpgme \ + python3 python3-pyyaml jq \ + util-linux shadow-utils && \ + microdnf clean all && \ + # nodejs-22-minimal has no named app user; create UBI convention uid 1001 (default). + useradd --uid 1001 --gid 0 --home-dir /app --no-create-home \ + --shell /sbin/nologin default # Install oc CLI for runtime catalog sync (oc image extract) ARG TARGETARCH @@ -126,7 +131,8 @@ RUN chmod +x ./sync-catalogs.sh COPY --from=builder /app/catalog-data-minimal ./catalog-data -RUN mkdir -p /app/data && chown -R node:node /app +# UBI Node images use uid 1001 (user "default"), not Debian's "node" user. +RUN mkdir -p /app/data && chown -R 1001:0 /app LABEL org.opencontainers.image.created="${BUILD_DATE}" \ org.opencontainers.image.version="${VERSION}" \ diff --git a/Dockerfile.catalog-sync b/Dockerfile.catalog-sync index 547c752..02bdbb6 100644 --- a/Dockerfile.catalog-sync +++ b/Dockerfile.catalog-sync @@ -35,12 +35,14 @@ FROM registry.redhat.io/redhat/community-operator-index:v4.20 AS community-4-20 FROM registry.redhat.io/redhat/community-operator-index:v4.21 AS community-4-21 # --- Stage 2: Extract and process catalog data --- -FROM node:22-slim AS processor +FROM registry.access.redhat.com/ubi9/nodejs-22-minimal AS processor + +USER root + WORKDIR /app -RUN apt-get update && \ - apt-get install -y --no-install-recommends jq python3 python3-yaml && \ - rm -rf /var/lib/apt/lists/* +RUN microdnf install -y --nodocs bash jq python3 python3-pyyaml && \ + microdnf clean all COPY scripts/catalog_metadata.py ./scripts/catalog_metadata.py diff --git a/entrypoint.sh b/entrypoint.sh index fe140e5..5d37ac5 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,6 +1,7 @@ #!/bin/bash set -e +APP_USER="default" APP_DATA="/app/data" DIRS="$APP_DATA/configs $APP_DATA/operations $APP_DATA/logs $APP_DATA/cache $APP_DATA/mirrors/default $APP_DATA/catalog-data" @@ -8,21 +9,21 @@ for d in $DIRS; do mkdir -p "$d" done -chown -R node:node "$APP_DATA" +chown -R "${APP_USER}:0" "$APP_DATA" chmod -R 775 "$APP_DATA" AUTHFILE="${OC_MIRROR_AUTHFILE:-/app/pull-secret.json}" if [ -f "$AUTHFILE" ]; then - chown node:node "$AUTHFILE" + chown "${APP_USER}:0" "$AUTHFILE" chmod 664 "$AUTHFILE" fi -if su -s /bin/sh node -c "test -w $APP_DATA/configs"; then +if su -s /bin/sh "$APP_USER" -c "test -w $APP_DATA/configs"; then echo "[ENTRYPOINT] Permissions OK" else - echo "[ENTRYPOINT] ERROR: $APP_DATA/configs not writable by node user" - echo "[ENTRYPOINT] Host fix: sudo chown -R 1000:1000 data/ && sudo chmod -R 775 data/" + echo "[ENTRYPOINT] ERROR: $APP_DATA/configs not writable by ${APP_USER} user" + echo "[ENTRYPOINT] Host fix: sudo chown -R 1001:0 data/ && sudo chmod -R 775 data/" exit 1 fi -exec runuser -u node -- "$@" +exec runuser -u "$APP_USER" -- "$@" From c65ea399d3e121ebf8a75caf03d83ecd653a6a79 Mon Sep 17 00:00:00 2001 From: Yakov Beder Date: Fri, 17 Jul 2026 21:14:01 +0000 Subject: [PATCH 2/2] fix: use timezone.utc for Python 3.9 compatibility on UBI9 datetime.UTC requires Python 3.11+, but UBI9 ships Python 3.9, which broke catalog-sync CI when processing catalog metadata. Co-authored-by: Cursor --- scripts/catalog_metadata.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/catalog_metadata.py b/scripts/catalog_metadata.py index 1308cfe..abfb817 100644 --- a/scripts/catalog_metadata.py +++ b/scripts/catalog_metadata.py @@ -7,7 +7,7 @@ import re import sys from collections import Counter -from datetime import UTC, datetime +from datetime import datetime, timezone from functools import cmp_to_key from pathlib import Path from typing import Any @@ -735,7 +735,7 @@ def audit_catalog_data(catalog_data_dir: Path, output_dir: Path) -> dict[str, An ) report = { - "generatedAt": datetime.now(UTC).replace(microsecond=0).isoformat().replace("+00:00", "Z"), + "generatedAt": datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z"), "catalogDataDir": str(catalog_data_dir), "summary": { "catalogSnapshots": len(snapshots),