Skip to content

build: standardize container image - #371

Merged
myakove merged 5 commits into
RedHatQE:mainfrom
rgolangh:container-image-improvements
Mar 24, 2026
Merged

myakove merged 5 commits into
RedHatQE:mainfrom
rgolangh:container-image-improvements

Conversation

@rgolangh

@rgolangh rgolangh commented Mar 24, 2026 •

Copy link
Copy Markdown
Contributor
  • Base the image on UBI 10.1
  • Make the container image able to run with user 1001 so special security
    context change. Standard /app directory structure
  • Lock the uv version for reproducible builds
  • Ignore python caches

Signed-off-by: Roy Golan rgolan@redhat.com

Summary by CodeRabbit

  • Chores
    • Base image switched to a minimal UBI; dependency install and cache behavior simplified; Python runtime env vars set for consistent logging and bytecode handling; build layout adjusted to include docs and prepare outputs; image configured for non-root execution and OpenShift-friendly group permissions.
  • Documentation
    • README updated with guidance for running containers as UID 1001 and handling writable vs read-only mounts across container runtimes.

- Base the image on UBI 10.1
- Make the container image able to run with user 1001 so special security
  context change. Standard /app directory structure
- Lock the uv version for reproducible builds
- Ignore python caches

Signed-off-by: Roy Golan <rgolan@redhat.com>
@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Standardize container image with UBI 10.1 and non-root user

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Switch base image from Fedora 41 to UBI 10.1 minimal
• Enable container to run as non-root user 1001
• Lock uv version to 0.10.9 for reproducible builds
• Add Python cache prevention and logging environment variables
• Replace dnf with microdnf and install uv via pip
• Add proper group permissions for OpenShift compatibility
Diagram
flowchart LR
  A["Fedora 41 Base Image"] -->|"Switch to"| B["UBI 10.1 Minimal"]
  C["dnf Package Manager"] -->|"Replace with"| D["microdnf"]
  E["Copy uv Binary"] -->|"Replace with"| F["pip install uv==0.10.9"]
  G["Root User"] -->|"Change to"| H["User 1001"]
  I["No Cache Control"] -->|"Add"| J["PYTHONDONTWRITEBYTECODE & PYTHONUNBUFFERED"]
  B --> K["Optimized Container"]
  D --> K
  F --> K
  H --> K
  J --> K
Loading

Grey Divider

File Changes

1. Dockerfile ✨ Enhancement +21/-13

Standardize Dockerfile with UBI 10.1 and non-root user

• Changed base image from Fedora 41 to UBI 10.1 minimal for standardization
• Replaced dnf with microdnf and simplified package cleanup
• Locked uv version to 0.10.9 installed via pip instead of copying binary
• Added environment variables for Python cache prevention and unbuffered output
• Configured container to run as non-root user 1001 with proper group permissions
• Added git to package dependencies and docs directory to COPY commands
• Moved ARG declarations to top and added proper quoting for git URLs

Dockerfile


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Mar 24, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (6) 📘 Rule violations (1) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider


Action required

1. Mutable uv toolchain 🐞 Bug ⛯ Reliability
Description
The image copies uv from ghcr.io/astral-sh/uv:latest, so rebuilding the same git revision can
produce different runtime behavior over time, breaking the PR’s reproducibility goal.
Code

Dockerfile[29]

+COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/
Evidence
The Dockerfile explicitly uses a mutable :latest tag for the build-stage image, which changes
independently of this repo. The PR description states “Lock the uv version for reproducible builds”,
but the current Dockerfile does not pin uv by version or digest.

Dockerfile[18-31]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Container builds are not reproducible because the Dockerfile copies `uv` from `ghcr.io/astral-sh/uv:latest`, which is mutable.
### Issue Context
The PR explicitly aims to lock uv for reproducible builds.
### Fix Focus Areas
- Dockerfile[18-31]
### Suggested change
Replace `ghcr.io/astral-sh/uv:latest` with a pinned version tag and/or an immutable digest, e.g.:
- `ghcr.io/astral-sh/uv:<version>@sha256:<digest>`
(Prefer digest pinning to guarantee immutability.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Empty xargs build failure ☑ 🐞 Bug ⛯ Reliability
Description
The Dockerfile uses find ... | xargs rm -rfv without --no-run-if-empty, so when no __pycache__
directories exist the command runs rm -rfv with no operands and fails the image build. This is
more likely now because PYTHONDONTWRITEBYTECODE=1 is set before uv sync, reducing/avoiding
__pycache__ creation during the build layer.
Code

Dockerfile[R48-51]

RUN uv sync --locked\
-  && if [ -n "${OPENSHIFT_PYTHON_WRAPPER_COMMIT}" ]; then uv pip install git+https://github.com/RedHatQE/openshift-python-wrapper.git@$OPENSHIFT_PYTHON_WRAPPER_COMMIT; fi \
-  && if [ -n "${OPENSHIFT_PYTHON_UTILITIES_COMMIT}" ]; then uv pip install git+https://github.com/RedHatQE/openshift-python-utilities.git@$OPENSHIFT_PYTHON_UTILITIES_COMMIT; fi \
-  && find ${APP_DIR}/ -type d -name "__pycache__" -print0 | xargs -0 rm -rfv \
-  && rm -rf ${APP_DIR}/.cache
+  && if [ -n "${OPENSHIFT_PYTHON_WRAPPER_COMMIT}" ]; then uv pip install "git+https://github.com/RedHatQE/openshift-python-wrapper.git@${OPENSHIFT_PYTHON_WRAPPER_COMMIT}"; fi \
+  && if [ -n "${OPENSHIFT_PYTHON_UTILITIES_COMMIT}" ]; then uv pip install "git+https://github.com/RedHatQE/openshift-python-utilities.git@${OPENSHIFT_PYTHON_UTILITIES_COMMIT}"; fi \
+  && find ${APP_DIR}/ -type d -name "__pycache__" -print0 | xargs -0 rm -rfv
Evidence
On the PR branch, PYTHONDONTWRITEBYTECODE=1 is set globally and the build layer ends with a `find
... __pycache__ ... | xargs -0 rm -rfv pipeline. If find emits nothing, xargs` still executes
rm -rfv (without -r/--no-run-if-empty), and rm errors on missing operands, which fails the
RUN layer and breaks the container build.

Dockerfile[12-16]
Dockerfile[48-51]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Dockerfile cleanup step can fail the image build because `xargs` runs `rm -rfv` even when `find` returns no matches.
### Issue Context
The image sets `PYTHONDONTWRITEBYTECODE=1`, so `__pycache__` directories may not exist during build, making the `find | xargs rm` pipeline receive empty input.
### Fix Focus Areas
- Dockerfile[12-16]
- Dockerfile[48-51]
### Suggested fix
Replace the pipeline with one of:
- `... | xargs -0 -r rm -rfv` (preferred if `xargs` supports `-r`)
- `find ... -name '__pycache__' -prune -exec rm -rfv '{}' +`
- or guard with `if` (e.g., `if find ... | grep -q .; then ...; fi`)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Container now runs as 1001 📘 Rule violation ⚙ Maintainability
Description
The Dockerfile now sets USER 1001, which can change how users must run the image (especially
bind-mount permissions), but README instructions are not updated to reflect this. This can cause
runtime failures (e.g., inability to write reports to mounted directories) for users following
current documentation.
Code

Dockerfile[R44-46]

+RUN chgrp -R 0 ${APP_DIR} && chmod -R g=u ${APP_DIR}
+
+USER 1001
Evidence
PR Compliance ID 1 requires README updates when usage/requirements change. The PR changes container
runtime behavior by forcing UID 1001 (USER 1001), while README container run examples show bind
mounts but do not mention any required permission/ownership considerations for a non-root container
user.

CLAUDE.md
Dockerfile[44-46]
README.md[208-237]
README.md[640-671]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The container image now runs as `USER 1001`, which can require additional guidance for users (notably around bind-mount permissions for writable output directories). README container run examples do not mention this change.
## Issue Context
`Dockerfile` was updated to run as a non-root UID (`1001`). Users following README examples that mount `./results:/app/results` may hit permission errors unless the host directory permissions/ownership are compatible.
## Fix Focus Areas
- Dockerfile[44-46]
- README.md[208-237]
- README.md[640-671]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
4. UID 1001 cannot write /app 🐞 Bug ✓ Correctness
Description
The Dockerfile makes /app group-writable for GID 0, then switches to USER 1001 and runs `uv
sync; with the default primary group of 1001, the process won’t have write permissions in /app`,
so the build (and later runtime writes like JUnit output) can fail.
Code

Dockerfile[R45-51]

+RUN chgrp -R 0 ${APP_DIR} && chmod -R g=u ${APP_DIR}
+
+USER 1001
RUN uv sync --locked\
-  && if [ -n "${OPENSHIFT_PYTHON_WRAPPER_COMMIT}" ]; then uv pip install git+https://github.com/RedHatQE/openshift-python-wrapper.git@$OPENSHIFT_PYTHON_WRAPPER_COMMIT; fi \
-  && if [ -n "${OPENSHIFT_PYTHON_UTILITIES_COMMIT}" ]; then uv pip install git+https://github.com/RedHatQE/openshift-python-utilities.git@$OPENSHIFT_PYTHON_UTILITIES_COMMIT; fi \
+  && if [ -n "${OPENSHIFT_PYTHON_WRAPPER_COMMIT}" ]; then uv pip install "git+https://github.com/RedHatQE/openshift-python-wrapper.git@${OPENSHIFT_PYTHON_WRAPPER_COMMIT}"; fi \
+  && if [ -n "${OPENSHIFT_PYTHON_UTILITIES_COMMIT}" ]; then uv pip install "git+https://github.com/RedHatQE/openshift-python-utilities.git@${OPENSHIFT_PYTHON_UTILITIES_COMMIT}"; fi \
Evidence
chgrp -R 0 + chmod -R g=u only helps if the running user is in group 0. The Dockerfile sets only
USER 1001 (no :0), so uv sync --locked runs without guaranteed write access to /app even
though it needs to create/update environment artifacts in the working directory. Separately, pytest
is configured to write junit-report.xml in the CWD (/app), which also requires /app to be
writable at runtime.

Dockerfile[33-53]
pytest.ini[1-16]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The image sets `/app` permissions for group 0, but runs `uv sync` as `USER 1001` without ensuring the process is in group 0. This can break the image build and runtime writes under `/app`.
### Issue Context
- `/app` is made group-owned by 0 (`chgrp -R 0`) and group perms mirrored from user (`chmod -R g=u`).
- `uv sync --locked` runs after `USER 1001`.
### Fix Focus Areas
- Ensure the build steps that write into `${APP_DIR}` run with GID 0 (e.g., `USER 1001:0`), and/or ensure `${APP_DIR}` is owned/writable by UID 1001.
- Keep the final runtime user as 1001 while maintaining write access to `/app`.
- Dockerfile[45-53]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

5. Runtime group assumption undocumented ☑ 🐞 Bug ⛯ Reliability
Description
The Dockerfile relies on GID 0 group-writable permissions (chgrp -R 0 + chmod -R g=u) but runs
as USER 1001; in environments that don't add the process to supplemental group 0, the suite can
fail writing under /app during normal (non-collect-only) runs.
Code

Dockerfile[R44-46]

+RUN chgrp -R 0 ${APP_DIR} && chmod -R g=u ${APP_DIR}
+
+USER 1001
Evidence
The test suite creates and writes to directories relative to the working directory (which is /app
in the image). If /app is not writable to the runtime identity, these operations fail early. While
OpenShift commonly supplies supplemental group 0 (and README calls this out), other runtimes may
not, so adding an explicit note or a more portable permission strategy reduces execution failures
outside OpenShift.

Dockerfile[42-51]
conftest.py[85-86]
conftest.py[366-403]
utilities/pytest_utils.py[52-59]
README.md[673-680]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The image sets `/app` to be writable via group 0 permissions but then runs as `USER 1001`. This works in OpenShift when supplemental group 0 is provided, but can fail in other runtimes where UID 1001 is not in GID 0.
## Issue Context
The suite writes under the working directory (`/app`) at runtime (e.g., `./.xdist_results/`, `.data-collector`). If the runtime user cannot write to `/app`, runs will fail.
## Fix Focus Areas
- Dockerfile[42-51]
- conftest.py[85-86]
- utilities/pytest_utils.py[52-59]
- README.md[673-680]
## Suggested fixes (choose one)
- Add an explicit Dockerfile comment documenting the requirement that the runtime should include supplemental group 0 (or use `--group-add 0` / OpenShift default behavior).
- If acceptable for your targets, set an explicit group in the Dockerfile (e.g., `USER 1001:0`) or otherwise ensure group membership is consistent.
- Alternatively, choose a different writable path for runtime artifacts (e.g., `/tmp` or a dedicated volume mount point) and update code/docs accordingly.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Unused JUNITFILE env 🐞 Bug ✓ Correctness
Description
Dockerfile sets ENV JUNITFILE=/app/output but pytest is configured to write JUnit XML to
/app/junit-report.xml by default, and JUNITFILE is not referenced anywhere else. This environment
variable is misleading and suggests outputs go to /app/output when they do not.
Code

Dockerfile[R7-8]

ENV JUNITFILE=${APP_DIR}/output/
Evidence
The only occurrences of JUNITFILE in the repo are the Dockerfile and a docs excerpt; pytest’s
actual JUnit output location is controlled by pytest.ini (--junit-xml=junit-report.xml), which
places it in the working directory (/app) unless overridden. This mismatch can confuse users and
automation expecting /app/output/ to contain the report.

Dockerfile[7-8]
pytest.ini[1-12]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ENV JUNITFILE=${APP_DIR}/output/` is set but unused; pytest writes JUnit to `junit-report.xml` in WORKDIR by default.
### Issue Context
This is misleading for users/automation and may cause incorrect artifact collection assumptions.
### Fix Focus Areas
- Dockerfile[7-8]
- pytest.ini[4-12]
### Options
1) Remove `JUNITFILE` entirely.
2) If you want a default output directory, update `pytest.ini` to write JUnit into `${JUNITFILE}` (or `/app/output/junit-report.xml`) and ensure docs match.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Bash usage not guaranteed 🐞 Bug ✓ Correctness
Description
The image no longer guarantees /bin/bash exists (UBI minimal base and no bash install), but repo
docs and OpenShift Job templates invoke /bin/bash -c, which can break documented container/job
execution.
Code

Dockerfile[R1-28]

+FROM registry.access.redhat.com/ubi10/ubi-minimal:10.1@sha256:c858c2eb5bd336d8c400f6ee976a9d731beccf3351fa7a6f485dced24ae4af17
ARG APP_DIR=/app
+ARG OPENSHIFT_PYTHON_WRAPPER_COMMIT=''
+ARG OPENSHIFT_PYTHON_UTILITIES_COMMIT=''
ENV JUNITFILE=${APP_DIR}/output/
ENV UV_PYTHON=python3.12
ENV UV_COMPILE_BYTECODE=1
ENV UV_NO_SYNC=1
-ENV UV_CACHE_DIR=${APP_DIR}/.cache
+ENV UV_NO_CACHE=1
+# Prevents Python from writing .pyc files to disk
+ENV PYTHONDONTWRITEBYTECODE=1
+# Ensures Python output is logged straight to the terminal (useful for OpenShift logs)
+ENV PYTHONUNBUFFERED=1
-RUN dnf -y install \
+RUN microdnf -y install \
libxml2-devel \
libcurl-devel \
openssl \
openssl-devel \
-  libcurl-devel \
gcc \
clang \
+  git \
python3-devel \
-  && dnf clean all \
-  && rm -rf /var/cache/dnf \
-  && rm -rf /var/lib/dnf \
-  && truncate -s0 /var/log/*.log && rm -rf /var/cache/yum
+  python3-pip \
+  && microdnf clean all
Evidence
The Dockerfile now uses a UBI minimal base and the package install list does not include bash, yet
multiple repo docs/templates run commands via /bin/bash -c. The image should either install bash
or docs/templates should be updated to use /bin/sh -c (or exec-form commands) to match what the
image actually provides.

Dockerfile[1-31]
README.md[356-366]
guides/copyoffload/how-to-run-copyoffload-tests.md[315-325]
docs/container-and-openshift-job-execution.md[131-153]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Documentation and Job templates invoke `/bin/bash -c`, but the container image no longer guarantees `/bin/bash` exists.
### Issue Context
The Dockerfile switched to UBI minimal and does not install `bash`, while README and guides use `/bin/bash` in `command:` sections.
### Fix Focus Areas
- Dockerfile[18-28]
- README.md[356-366]
- guides/copyoffload/how-to-run-copyoffload-tests.md[315-325]
- docs/container-and-openshift-job-execution.md[131-153]
### Suggested changes (choose one)
1) **Image fix**: Add `bash` to `microdnf -y install ...` so `/bin/bash` is present.
2) **Docs fix**: Replace `/bin/bash` with `/bin/sh` in docs/job templates (and ensure the shell syntax used is POSIX-compatible), or switch to exec-form commands that avoid a shell entirely.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
8. Docs describe old Dockerfile 🐞 Bug ⚙ Maintainability
Description
Docs embed and describe the previous Fedora 41 + dnf + copied-uv Dockerfile, but the Dockerfile now
uses UBI 10.1 + microdnf + pip-installed uv, so the docs are incorrect and will mislead users.
Code

Dockerfile[R1-31]

+FROM registry.access.redhat.com/ubi10/ubi-minimal:10.1
ARG APP_DIR=/app
+ARG OPENSHIFT_PYTHON_WRAPPER_COMMIT=''
+ARG OPENSHIFT_PYTHON_UTILITIES_COMMIT=''
ENV JUNITFILE=${APP_DIR}/output/
ENV UV_PYTHON=python3.12
ENV UV_COMPILE_BYTECODE=1
ENV UV_NO_SYNC=1
ENV UV_CACHE_DIR=${APP_DIR}/.cache
+ENV UV_NO_CACHE=1
+# Prevents Python from writing .pyc files to disk
+ENV PYTHONDONTWRITEBYTECODE=1
+# Ensures Python output is logged straight to the terminal (useful for OpenShift logs)
+ENV PYTHONUNBUFFERED=1
-RUN dnf -y install \
+RUN microdnf -y install \
libxml2-devel \
libcurl-devel \
openssl \
openssl-devel \
-  libcurl-devel \
gcc \
clang \
+  git \
python3-devel \
-  && dnf clean all \
-  && rm -rf /var/cache/dnf \
-  && rm -rf /var/lib/dnf \
-  && truncate -s0 /var/log/*.log && rm -rf /var/cache/yum
+  python3-pip \
+  && microdnf clean all
+
+RUN pip install --no-cache-dir uv==0.10.9
Evidence
The Dockerfile now uses UBI minimal and installs packages with microdnf and uv via pip, but multiple
documentation pages still show the old FROM quay.io/fedora/fedora:41, dnf, and `COPY
--from=ghcr.io/astral-sh/uv:latest` approach and describe the image as Fedora-based. This is an
inconsistency introduced by the Dockerfile change in this PR.

Dockerfile[1-31]
docs/automation-and-release.md[256-317]
docs/development-workflow.md[267-283]
docs/project-structure.md[508-518]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Several docs pages embed the old Fedora/dnf/uv-copy Dockerfile snippet and description, which no longer matches the Dockerfile.
### Issue Context
The Dockerfile was changed to UBI 10.1 and now uses `microdnf` and `pip install uv==...`.
### Fix Focus Areas
- Update embedded Dockerfile snippets and descriptive bullets (Fedora → UBI, dnf → microdnf, uv copy-stage → pip install with pinned version, note new build args and user/permissions model).
- docs/automation-and-release.md[256-325]
- docs/development-workflow.md[267-310]
- docs/project-structure.md[512-518]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

9. Non-root install uses git 🐞 Bug ⛯ Reliability
Description
Dockerfile conditionally installs git-based dependencies via uv pip install git+https://... but
does not pin those installs to a hash when the commit args are unset, and the image includes git
enabling network-based builds. This weakens reproducibility compared to the locked `uv sync
--locked` intent.
Code

Dockerfile[R48-50]

RUN uv sync --locked\
-  && if [ -n "${OPENSHIFT_PYTHON_WRAPPER_COMMIT}" ]; then uv pip install git+https://github.com/RedHatQE/openshift-python-wrapper.git@$OPENSHIFT_PYTHON_WRAPPER_COMMIT; fi \
-  && if [ -n "${OPENSHIFT_PYTHON_UTILITIES_COMMIT}" ]; then uv pip install git+https://github.com/RedHatQE/openshift-python-utilities.git@$OPENSHIFT_PYTHON_UTILITIES_COMMIT; fi \
-  && find ${APP_DIR}/ -type d -name "__pycache__" -print0 | xargs -0 rm -rfv \
-  && rm -rf ${APP_DIR}/.cache
+  && if [ -n "${OPENSHIFT_PYTHON_WRAPPER_COMMIT}" ]; then uv pip install "git+https://github.com/RedHatQE/openshift-python-wrapper.git@${OPENSHIFT_PYTHON_WRAPPER_COMMIT}"; fi \
+  && if [ -n "${OPENSHIFT_PYTHON_UTILITIES_COMMIT}" ]; then uv pip install "git+https://github.com/RedHatQE/openshift-python-utilities.git@${OPENSHIFT_PYTHON_UTILITIES_COMMIT}"; fi \
Evidence
uv sync --locked provides a reproducible environment from uv.lock, but the subsequent
conditional uv pip install git+https://...@${COMMIT} introduces network dependency when args are
set. When args are unset it is fine, but when used it bypasses the lock file and build determinism
unless consumers consistently pass immutable commits (and ideally verify).

Dockerfile[48-50]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Optional git-based installs bypass the lockfile and reduce determinism when enabled.
### Issue Context
This is an intentional escape hatch, but should be clearly documented as non-reproducible unless pinned to immutable commits.
### Fix Focus Areas
- Dockerfile[48-50]
- README.md (section describing build args / overrides)
### What to change
- Ensure docs explicitly say these args must be set to an immutable commit SHA (not a branch/tag) for reproducibility.
- Optionally add a build-time guard that rejects non-SHA values.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@coderabbitai

coderabbitai Bot commented Mar 24, 2026 •

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Switched the Docker base image to UBI minimal 10.1 (pinned by digest) and replaced dnf with microdnf; added git to system packages. Changed UV handling to copy /uv and /uvx into the image and set UV_NO_CACHE=1. Added PYTHONDONTWRITEBYTECODE=1 and PYTHONUNBUFFERED=1. Reordered project file copies and output creation, added COPY docs docs, made OpenShift-friendly permission changes (chgrp -R 0 && chmod -R g=u) and set USER 1001. README updated with non-root (UID 1001) runtime guidance and writable-mount instructions.

Changes

Cohort / File(s) Summary
Base image & package manager
Dockerfile
Base changed to registry.access.redhat.com/ubi10/ubi-minimal:10.1@sha256:...; switched package manager to microdnf, added git, adjusted package install/cleanup commands.
UV install & caching
Dockerfile
Replaced prior UV install flow with direct copy of /uv and /uvx into image and switched cache behavior from UV_CACHE_DIR=${APP_DIR}/.cache to UV_NO_CACHE=1; removed explicit .cache deletion.
Runtime env, filesystem, permissions & user
Dockerfile
Added PYTHONDONTWRITEBYTECODE=1 and PYTHONUNBUFFERED=1; created ${APP_DIR}/output after copying project files; added COPY docs docs; applied chgrp -R 0 and chmod -R g=u for OpenShift and set USER 1001.
Dependency & cleanup tweaks
Dockerfile
Optional git-based deps now use quoted git+https://...@${COMMIT} spec strings; __pycache__ removal made tolerant of no matches (via xargs ... -r).
Documentation
README.md
Added instructions for running container as non-root UID 1001, clarifying read-only mounts unaffected and writable bind mounts must be accessible to UID 1001; notes for Podman/Docker modes and OpenShift permission handling.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'build: standardize container image' is concise and directly related to the main changes, which focus on updating the Dockerfile base image (Fedora→UBI 10.1), dependency management (uv setup), security configuration (UID 1001), and standardizing directory structure (/app layout).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@rh-bot-1

Copy link
Copy Markdown

Report bugs in Issues

Welcome! 🎉

This pull request will be automatically processed with the following features:

🔄 Automatic Actions

  • Reviewer Assignment: Reviewers are automatically assigned based on the OWNERS file in the repository root
  • Size Labeling: PR size labels (XS, S, M, L, XL, XXL) are automatically applied based on changes
  • Issue Creation: Disabled for this repository
  • Branch Labeling: Branch-specific labels are applied to track the target branch
  • Auto-verification: Auto-verified users have their PRs automatically marked as verified
  • Labels: All label categories are enabled (default configuration)

📋 Available Commands

PR Status Management

  • /wip - Mark PR as work in progress (adds WIP: prefix to title)
  • /wip cancel - Remove work in progress status
  • /hold - Block PR merging (approvers only)
  • /hold cancel - Unblock PR merging
  • /verified - Mark PR as verified
  • /verified cancel - Remove verification status
  • /reprocess - Trigger complete PR workflow reprocessing (useful if webhook failed or configuration changed)
  • /regenerate-welcome - Regenerate this welcome message

Review & Approval

  • /lgtm - Approve changes (looks good to me)
  • /approve - Approve PR (approvers only)
  • /automerge - Enable automatic merging when all requirements are met (maintainers and approvers only)
  • /assign-reviewers - Assign reviewers based on OWNERS file
  • /assign-reviewer @username - Assign specific reviewer
  • /check-can-merge - Check if PR meets merge requirements

Testing & Validation

  • /retest tox - Run Python test suite with tox
  • /retest build-container - Rebuild and test container image
  • /retest conventional-title - Validate commit message format
  • /retest all - Run all available tests

Container Operations

  • /build-and-push-container - Build and push container image (tagged with PR number)
    • Supports additional build arguments: /build-and-push-container --build-arg KEY=value

Cherry-pick Operations

  • /cherry-pick <branch> - Schedule cherry-pick to target branch when PR is merged
    • Multiple branches: /cherry-pick branch1 branch2 branch3

Label Management

  • /<label-name> - Add a label to the PR
  • /<label-name> cancel - Remove a label from the PR

✅ Merge Requirements

This PR will be automatically approved when the following conditions are met:

  1. Approval: /approve from at least one approver
  2. Status Checks: All required status checks must pass
  3. No Blockers: No wip, hold, has-conflicts labels and PR must be mergeable (no conflicts)
  4. Verified: PR must be marked as verified

📊 Review Process

Approvers and Reviewers

Approvers:

  • myakove
  • solenoci

Reviewers:

  • krcmarik
  • myakove
  • solenoci
Available Labels
  • hold
  • verified
  • wip
  • lgtm
  • approve
  • automerge

💡 Tips

  • WIP Status: Use /wip when your PR is not ready for review
  • Verification: The verified label is automatically removed on each new commit
  • Cherry-picking: Cherry-pick labels are processed when the PR is merged
  • Container Builds: Container images are automatically tagged with the PR number
  • Permission Levels: Some commands require approver permissions
  • Auto-verified Users: Certain users have automatic verification and merge privileges

For more information, please refer to the project documentation or contact the maintainers.

@rh-bot-1
rh-bot-1 requested a review from myakove March 24, 2026 09:08
@rh-bot-1
rh-bot-1 requested a review from solenoci March 24, 2026 09:08
@rh-bot-1
rh-bot-1 requested a review from krcmarik March 24, 2026 09:08
@rh-bot-1 rh-bot-1 changed the title Standardize container image build: standardize container image Mar 24, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Dockerfile`:
- Around line 19-29: The Dockerfile currently installs build-time packages (gcc,
clang, lib*-devel, git, python3-pip) in the final image within the RUN layer,
increasing image size and CVE surface; convert to a multi-stage build by moving
those build-only packages and any build artifacts into a builder stage
(installing libxml2-devel, libcurl-devel, openssl-devel, gcc, clang, git,
python3-pip there), produce the built artifacts/wheels, and in the final stage
only install runtime packages (openssl, python3-devel if needed) and COPY the
outputs from the builder stage so the final RUN that currently lists
libxml2-devel, libcurl-devel, openssl-devel, gcc, clang, git, python3-pip is
removed and replaced with minimal runtime packages.
- Line 1: Replace the mutable tag in the Dockerfile's FROM instruction
(currently "registry.access.redhat.com/ubi10/ubi-minimal:10.1") with a pinned
digest form ("registry.access.redhat.com/ubi10/ubi-minimal@sha256:<DIGEST>");
obtain the correct sha256 digest for that tag (e.g., via podman inspect or the
registry UI) and update the FROM line to use the `@sha256` value to ensure
reproducible builds.
- Line 31: The RUN pip install --no-cache-dir uv==0.10.9 invocation should
explicitly use the same Python interpreter referenced by UV_PYTHON=python3.12;
update the Dockerfile to call the interpreter from UV_PYTHON with the -m pip
module (so the install runs with the exact python used elsewhere) rather than
relying on the implicit pip on PATH.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bde3f4fe-1aef-41f2-a6f8-78438c91f0fb

📥 Commits

Reviewing files that changed from the base of the PR and between be50043 and 3b5fe41.

📒 Files selected for processing (1)
  • Dockerfile

Comment thread Dockerfile Resolved
Comment thread Dockerfile Resolved
Comment thread Dockerfile Resolved
Comment thread Dockerfile Resolved
Comment thread Dockerfile Resolved
- Pin ubi-minimal:10.1 by sha256 digest for reproducible builds
- Use python3 -m pip instead of bare pip for explicit interpreter binding
- Remove redundant UV_CACHE_DIR (UV_NO_CACHE=1 already disables caching)
- Remove unnecessary cache cleanup step
@qodo-code-review

qodo-code-review Bot commented Mar 24, 2026 •

Copy link
Copy Markdown

Persistent review updated to latest commit 88d05af

@myakove
myakove merged commit 9c97d68 into RedHatQE:main Mar 24, 2026
7 checks passed
@rgolangh

Copy link
Copy Markdown
Contributor Author

/cherry-pick v2.11 v2.10

@rh-bot-1

Copy link
Copy Markdown

New container for ghcr.io/redhatqe/mtv-api-tests:latest published

redhat-qe-bot2 pushed a commit that referenced this pull request Mar 24, 2026
* Standardize container image

- Base the image on UBI 10.1
- Make the container image able to run with user 1001 so special security
  context change. Standard /app directory structure
- Lock the uv version for reproducible builds
- Ignore python caches

Signed-off-by: Roy Golan <rgolan@redhat.com>

* fix: pin UBI base image by digest and use explicit pip invocation

- Pin ubi-minimal:10.1 by sha256 digest for reproducible builds
- Use python3 -m pip instead of bare pip for explicit interpreter binding
- Remove redundant UV_CACHE_DIR (UV_NO_CACHE=1 already disables caching)
- Remove unnecessary cache cleanup step

* docs: add non-root container guidance for bind-mount permissions

Document that the container runs as UID 1001 and provide guidance
for writable bind mounts across podman rootless, rootful, and OpenShift.

* fix: add --no-run-if-empty flag to xargs in Dockerfile

Prevents build failure when no __pycache__ directories exist,
which is more likely with PYTHONDONTWRITEBYTECODE=1 set.

* fix: install uv via COPY --from instead of pip

Use COPY --from=ghcr.io/astral-sh/uv:latest for cleaner uv installation.
Drop python3-pip dependency since pip is no longer needed.

---------

Signed-off-by: Roy Golan <rgolan@redhat.com>
@redhat-qe-bot2

Copy link
Copy Markdown

Cherry-pick branch created, but PR creation failed
Branch CherryPicked-container-image-improvements-ZNLPT was pushed to the repository.
Create the PR manually:

gh pr create --repo RedHatQE/mtv-api-tests --base v2.11 --head CherryPicked-container-image-improvements-ZNLPT --label CherryPicked-from-main --title 'CherryPicked: [v2.11] build: standardize container image' --body 'Cherry-pick from `main` branch, original PR: https://github.com/RedHatQE/mtv-api-tests/pull/371, PR owner: rgolangh'

redhat-qe-bot2 pushed a commit that referenced this pull request Mar 24, 2026
* Standardize container image

- Base the image on UBI 10.1
- Make the container image able to run with user 1001 so special security
  context change. Standard /app directory structure
- Lock the uv version for reproducible builds
- Ignore python caches

Signed-off-by: Roy Golan <rgolan@redhat.com>

* fix: pin UBI base image by digest and use explicit pip invocation

- Pin ubi-minimal:10.1 by sha256 digest for reproducible builds
- Use python3 -m pip instead of bare pip for explicit interpreter binding
- Remove redundant UV_CACHE_DIR (UV_NO_CACHE=1 already disables caching)
- Remove unnecessary cache cleanup step

* docs: add non-root container guidance for bind-mount permissions

Document that the container runs as UID 1001 and provide guidance
for writable bind mounts across podman rootless, rootful, and OpenShift.

* fix: add --no-run-if-empty flag to xargs in Dockerfile

Prevents build failure when no __pycache__ directories exist,
which is more likely with PYTHONDONTWRITEBYTECODE=1 set.

* fix: install uv via COPY --from instead of pip

Use COPY --from=ghcr.io/astral-sh/uv:latest for cleaner uv installation.
Drop python3-pip dependency since pip is no longer needed.

---------

Signed-off-by: Roy Golan <rgolan@redhat.com>
@redhat-qe-bot2

Copy link
Copy Markdown

Cherry-pick branch created, but PR creation failed
Branch CherryPicked-container-image-improvements-9QQsH was pushed to the repository.
Create the PR manually:

gh pr create --repo RedHatQE/mtv-api-tests --base v2.10 --head CherryPicked-container-image-improvements-9QQsH --label CherryPicked-from-main --title 'CherryPicked: [v2.10] build: standardize container image' --body 'Cherry-pick from `main` branch, original PR: https://github.com/RedHatQE/mtv-api-tests/pull/371, PR owner: rgolangh'

@rgolangh

Copy link
Copy Markdown
Contributor Author

/cherry-pick v2.11 v2.10

redhat-qe-bot2 pushed a commit that referenced this pull request Mar 24, 2026
* Standardize container image

- Base the image on UBI 10.1
- Make the container image able to run with user 1001 so special security
  context change. Standard /app directory structure
- Lock the uv version for reproducible builds
- Ignore python caches

Signed-off-by: Roy Golan <rgolan@redhat.com>

* fix: pin UBI base image by digest and use explicit pip invocation

- Pin ubi-minimal:10.1 by sha256 digest for reproducible builds
- Use python3 -m pip instead of bare pip for explicit interpreter binding
- Remove redundant UV_CACHE_DIR (UV_NO_CACHE=1 already disables caching)
- Remove unnecessary cache cleanup step

* docs: add non-root container guidance for bind-mount permissions

Document that the container runs as UID 1001 and provide guidance
for writable bind mounts across podman rootless, rootful, and OpenShift.

* fix: add --no-run-if-empty flag to xargs in Dockerfile

Prevents build failure when no __pycache__ directories exist,
which is more likely with PYTHONDONTWRITEBYTECODE=1 set.

* fix: install uv via COPY --from instead of pip

Use COPY --from=ghcr.io/astral-sh/uv:latest for cleaner uv installation.
Drop python3-pip dependency since pip is no longer needed.

---------

Signed-off-by: Roy Golan <rgolan@redhat.com>
@redhat-qe-bot2

Copy link
Copy Markdown

Cherry-pick branch created, but PR creation failed
Branch CherryPicked-container-image-improvements-MczpD was pushed to the repository.
Create the PR manually:

gh pr create --repo RedHatQE/mtv-api-tests --base v2.11 --head CherryPicked-container-image-improvements-MczpD --label CherryPicked-from-main --title 'CherryPicked: [v2.11] build: standardize container image' --body 'Cherry-pick from `main` branch, original PR: https://github.com/RedHatQE/mtv-api-tests/pull/371, PR owner: rgolangh'

redhat-qe-bot2 pushed a commit that referenced this pull request Mar 24, 2026
* Standardize container image

- Base the image on UBI 10.1
- Make the container image able to run with user 1001 so special security
  context change. Standard /app directory structure
- Lock the uv version for reproducible builds
- Ignore python caches

Signed-off-by: Roy Golan <rgolan@redhat.com>

* fix: pin UBI base image by digest and use explicit pip invocation

- Pin ubi-minimal:10.1 by sha256 digest for reproducible builds
- Use python3 -m pip instead of bare pip for explicit interpreter binding
- Remove redundant UV_CACHE_DIR (UV_NO_CACHE=1 already disables caching)
- Remove unnecessary cache cleanup step

* docs: add non-root container guidance for bind-mount permissions

Document that the container runs as UID 1001 and provide guidance
for writable bind mounts across podman rootless, rootful, and OpenShift.

* fix: add --no-run-if-empty flag to xargs in Dockerfile

Prevents build failure when no __pycache__ directories exist,
which is more likely with PYTHONDONTWRITEBYTECODE=1 set.

* fix: install uv via COPY --from instead of pip

Use COPY --from=ghcr.io/astral-sh/uv:latest for cleaner uv installation.
Drop python3-pip dependency since pip is no longer needed.

---------

Signed-off-by: Roy Golan <rgolan@redhat.com>
@redhat-qe-bot2

Copy link
Copy Markdown

Cherry-pick branch created, but PR creation failed
Branch CherryPicked-container-image-improvements-Dkm78 was pushed to the repository.
Create the PR manually:

gh pr create --repo RedHatQE/mtv-api-tests --base v2.10 --head CherryPicked-container-image-improvements-Dkm78 --label CherryPicked-from-main --title 'CherryPicked: [v2.10] build: standardize container image' --body 'Cherry-pick from `main` branch, original PR: https://github.com/RedHatQE/mtv-api-tests/pull/371, PR owner: rgolangh'

rgolangh added a commit to rgolangh/mtv-api-tests-1 that referenced this pull request Mar 24, 2026
* Standardize container image

- Base the image on UBI 10.1
- Make the container image able to run with user 1001 so special security
  context change. Standard /app directory structure
- Lock the uv version for reproducible builds
- Ignore python caches

Signed-off-by: Roy Golan <rgolan@redhat.com>

* fix: pin UBI base image by digest and use explicit pip invocation

- Pin ubi-minimal:10.1 by sha256 digest for reproducible builds
- Use python3 -m pip instead of bare pip for explicit interpreter binding
- Remove redundant UV_CACHE_DIR (UV_NO_CACHE=1 already disables caching)
- Remove unnecessary cache cleanup step

* docs: add non-root container guidance for bind-mount permissions

Document that the container runs as UID 1001 and provide guidance
for writable bind mounts across podman rootless, rootful, and OpenShift.

* fix: add --no-run-if-empty flag to xargs in Dockerfile

Prevents build failure when no __pycache__ directories exist,
which is more likely with PYTHONDONTWRITEBYTECODE=1 set.

* fix: install uv via COPY --from instead of pip

Use COPY --from=ghcr.io/astral-sh/uv:latest for cleaner uv installation.
Drop python3-pip dependency since pip is no longer needed.

---------

Signed-off-by: Roy Golan <rgolan@redhat.com>
myakove added a commit to myk-org/github-webhook-server that referenced this pull request Mar 24, 2026
## Summary

- Remove `--assignee` flag from `gh pr create` command in cherry-pick
flow
- Add post-creation assignee logic via PyGithub `add_to_assignees()`
- If PR author cannot be assigned (not a collaborator), fall back to
first root approver from OWNERS file
- Assignment failure no longer blocks cherry-pick PR creation

## Root Cause

When cherry-picking a PR, the `gh pr create --assignee {pr_author}`
command would fail entirely if the PR author wasn't a collaborator on
the target repo (e.g., fork contributors). Error: `could not assign
user: 'username' not found`

Triggered by: RedHatQE/mtv-api-tests#371

Closes #1050

## Test plan

- [x] Updated `test_cherry_pick_assigns_pr_author` to verify
post-creation assignment
- [x] Updated `test_cherry_pick_requested_by_uses_pr_owner` to verify no
`--assignee` in command
- [x] Added `test_cherry_pick_assignee_fallback_to_approver` for
fallback path
- [x] All 139 runner handler tests pass

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **Bug Fixes**
* Cherry-pick pull requests now attempt to assign ownership to the
original PR author after creation, with automatic fallback to the first
root approver from the OWNERS configuration if the primary assignment
fails.
* Improved error handling and logging for pull request assignment
failures during cherry-pick operations.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants