Add CPU Ray image for Python 3.11 and 3.12 Power Support#640
Add CPU Ray image for Python 3.11 and 3.12 Power Support#640puneetsharma21 wants to merge 9 commits intoopendatahub-io:mainfrom
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
📝 WalkthroughWalkthroughThis pull request adds two Ray CPU runtime images for OpenShift AI: Python 3.11 and Python 3.12 variants under images/runtime/ray/cpu/2.52.1-py311-cpu and images/runtime/ray/cpu/2.52.1-py312-cpu. Each variant includes a Dockerfile (based on Red Hat UBI9) that installs ray==2.52.1 with extras (default,data,train,tune,serve) using a provided constraints file and an extra pip index, plus a README and a fully pinned requirements_compiled.txt (222 lines) enumerating transitive dependencies. The PR also adds a Tekton PipelineRun manifest (.tekton/ray-cpu-pull-request.yaml) to build the multi-arch image and wire pull-request triggers. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Security findings
Only actionable items listed above. 🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (2)
images/runtime/ray/cpu/2.52.1-py312-cpu/Dockerfile (1)
15-27: Convert to multi-stage build to reduce runtime attack surface.Keep build dependencies in a builder stage and ship only runtime artifacts in the final stage.
As per coding guidelines,
**/Dockerfile*: "Use multi-stage builds".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@images/runtime/ray/cpu/2.52.1-py312-cpu/Dockerfile` around lines 15 - 27, The Dockerfile currently runs package installs (RUN yum install ... openblas openblas-devel make findutils) in the final image which increases attack surface; refactor it into a multi-stage build: create a builder stage (e.g., FROM <base> AS builder) that performs the yum upgrade/install and any compilation or artifact preparation, keep RUN cleanup steps (yum clean all && rm -rf /var/cache/yum/*) in that stage, then create a minimal final stage (FROM <runtime-base>) that sets USER 0 and WORKDIR /opt/app-root/bin and uses COPY --from=builder to copy only the required runtime artifacts (libraries/binaries) into the final image so build deps are not present at runtime.images/runtime/ray/cpu/2.52.1-py311-cpu/Dockerfile (1)
15-27: Convert to multi-stage build to keep toolchain out of runtime image.Current single-stage build leaves build-time packages in the final runtime layer. Split builder/runtime stages and copy only runtime artifacts.
As per coding guidelines,
**/Dockerfile*: "Use multi-stage builds".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@images/runtime/ray/cpu/2.52.1-py311-cpu/Dockerfile` around lines 15 - 27, Split this Dockerfile into a multi-stage build: add a builder stage FROM the existing base (e.g. "AS builder") where you perform yum upgrade and install build-time packages (openblas-devel, make, findutils, etc.), perform any compilation/artifact creation in /opt/app-root/bin, then create a final runtime stage FROM a minimal base image that only contains runtime deps (openblas and runtime files), COPY the built artifacts from the builder stage into the final image, and set USER 0 and WORKDIR /opt/app-root/bin in the final stage; ensure build-only packages are removed from the final image by installing them only in the builder stage and only installing runtime packages in the final stage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@images/runtime/ray/cpu/2.52.1-py311-cpu/README.md`:
- Line 3: Update the user-facing description text in README.md where it
currently reads "CPU enabled container image for Ray in OpenShift AI." — change
"CPU enabled" to the hyphenated compound "CPU-enabled" so the sentence reads
"CPU-enabled container image for Ray in OpenShift AI." Ensure the edited line in
the README.md is the only change.
In `@images/runtime/ray/cpu/2.52.1-py311-cpu/requirements_compiled.txt`:
- Around line 1-222: The lockfile requirements_compiled.txt lacks artifact
hashes; regenerate it with pip-compile --generate-hashes to produce SHA256
entries for every package, replace the existing requirements_compiled.txt with
the hashed output, and then update the image build step that currently uses a
constraints install flag (-c ${CONSTRAINTS_FILE}) to use a requirements install
(-r ${CONSTRAINTS_FILE}) and add the --require-hashes option to the pip install
command in the Dockerfile/build script so pip enforces the hashes at install
time.
In `@images/runtime/ray/cpu/2.52.1-py312-cpu/Dockerfile`:
- Around line 31-34: The current Dockerfile RUN pip install using -c
${CONSTRAINTS_FILE} and an extra-index-url lacks hash verification; generate a
hash-locked requirements file (e.g., run pip-compile --generate-hashes against
your constraints and explicit dependencies like
ray[default,data,train,tune,serve]==2.52.1 and include any extra-index-url
configuration) and update the Dockerfile to COPY that generated requirements.txt
into the image and replace the pip install line with pip install
--require-hashes -r requirements.txt (removing the insecure -c
${CONSTRAINTS_FILE} usage), ensuring all packages are installed only if their
cryptographic hashes match.
In `@images/runtime/ray/cpu/2.52.1-py312-cpu/README.md`:
- Line 3: Update the user-facing text in README.md by replacing the phrase "CPU
enabled container image for Ray in OpenShift AI." with "CPU-enabled container
image for Ray in OpenShift AI." so the compound adjective is hyphenated
correctly; locate the sentence in the README.md (the line containing "CPU
enabled container image for Ray in OpenShift AI.") and apply the hyphenation
change.
In `@images/runtime/ray/cpu/2.52.1-py312-cpu/requirements_compiled.txt`:
- Around line 1-222: The requirements_compiled.txt lockfile lacks per-artifact
--hash=sha256 entries; regenerate the lock (the artifact represented by
requirements_compiled.txt) using pip-compile with --generate-hashes so each
dependency line includes --hash=sha256:... and then update Dockerfile(s) that
run pip installs (the root-phase pip install command) to use pip install
--require-hashes (and point at the regenerated requirements_compiled.txt) so pip
will enforce those hashes at build time.
---
Nitpick comments:
In `@images/runtime/ray/cpu/2.52.1-py311-cpu/Dockerfile`:
- Around line 15-27: Split this Dockerfile into a multi-stage build: add a
builder stage FROM the existing base (e.g. "AS builder") where you perform yum
upgrade and install build-time packages (openblas-devel, make, findutils, etc.),
perform any compilation/artifact creation in /opt/app-root/bin, then create a
final runtime stage FROM a minimal base image that only contains runtime deps
(openblas and runtime files), COPY the built artifacts from the builder stage
into the final image, and set USER 0 and WORKDIR /opt/app-root/bin in the final
stage; ensure build-only packages are removed from the final image by installing
them only in the builder stage and only installing runtime packages in the final
stage.
In `@images/runtime/ray/cpu/2.52.1-py312-cpu/Dockerfile`:
- Around line 15-27: The Dockerfile currently runs package installs (RUN yum
install ... openblas openblas-devel make findutils) in the final image which
increases attack surface; refactor it into a multi-stage build: create a builder
stage (e.g., FROM <base> AS builder) that performs the yum upgrade/install and
any compilation or artifact preparation, keep RUN cleanup steps (yum clean all
&& rm -rf /var/cache/yum/*) in that stage, then create a minimal final stage
(FROM <runtime-base>) that sets USER 0 and WORKDIR /opt/app-root/bin and uses
COPY --from=builder to copy only the required runtime artifacts
(libraries/binaries) into the final image so build deps are not present at
runtime.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Central YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro
Run ID: 5376d7dd-fb9b-403a-8e20-8e7d94c5dfda
📒 Files selected for processing (6)
images/runtime/ray/cpu/2.52.1-py311-cpu/Dockerfileimages/runtime/ray/cpu/2.52.1-py311-cpu/README.mdimages/runtime/ray/cpu/2.52.1-py311-cpu/requirements_compiled.txtimages/runtime/ray/cpu/2.52.1-py312-cpu/Dockerfileimages/runtime/ray/cpu/2.52.1-py312-cpu/README.mdimages/runtime/ray/cpu/2.52.1-py312-cpu/requirements_compiled.txt
| @@ -0,0 +1,10 @@ | |||
| # Ray Runtime Container Image | |||
|
|
|||
| CPU enabled container image for Ray in OpenShift AI. | |||
There was a problem hiding this comment.
Fix hyphenation in user-facing text on Line 3.
Use CPU-enabled instead of CPU enabled for correct compound adjective formatting.
🧰 Tools
🪛 LanguageTool
[grammar] ~3-~3: Use a hyphen to join words.
Context: # Ray Runtime Container Image CPU enabled container image for Ray in OpenS...
(QB_NEW_EN_HYPHEN)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@images/runtime/ray/cpu/2.52.1-py311-cpu/README.md` at line 3, Update the
user-facing description text in README.md where it currently reads "CPU enabled
container image for Ray in OpenShift AI." — change "CPU enabled" to the
hyphenated compound "CPU-enabled" so the sentence reads "CPU-enabled container
image for Ray in OpenShift AI." Ensure the edited line in the README.md is the
only change.
| aiohappyeyeballs==2.6.1 | ||
| # via aiohttp | ||
| aiohttp==3.13.3 | ||
| # via | ||
| # aiohttp-cors | ||
| # ray | ||
| aiohttp-cors==0.8.1 | ||
| # via ray | ||
| aiosignal==1.4.0 | ||
| # via aiohttp | ||
| annotated-doc==0.0.4 | ||
| # via fastapi | ||
| annotated-types==0.7.0 | ||
| # via pydantic | ||
| anyio==4.12.1 | ||
| # via | ||
| # starlette | ||
| # watchfiles | ||
| attrs==25.4.0 | ||
| # via | ||
| # aiohttp | ||
| # jsonschema | ||
| # referencing | ||
| certifi==2026.2.25 | ||
| # via requests | ||
| cffi==2.0.0 | ||
| # via cryptography | ||
| charset-normalizer==3.4.4 | ||
| # via requests | ||
| click==8.2.1 | ||
| # via | ||
| # ray | ||
| # uvicorn | ||
| colorful==0.5.8 | ||
| # via ray | ||
| cryptography==46.0.5 | ||
| # via google-auth | ||
| distlib==0.4.0 | ||
| # via virtualenv | ||
| fastapi==0.133.0 | ||
| # via ray | ||
| filelock==3.24.3 | ||
| # via | ||
| # ray | ||
| # virtualenv | ||
| frozenlist==1.8.0 | ||
| # via | ||
| # aiohttp | ||
| # aiosignal | ||
| fsspec==2026.2.0 | ||
| # via ray | ||
| google-api-core==2.30.0 | ||
| # via opencensus | ||
| google-auth==2.48.0 | ||
| # via google-api-core | ||
| googleapis-common-protos==1.72.0 | ||
| # via google-api-core | ||
| grpcio==1.75.0 | ||
| # via ray | ||
| h11==0.16.0 | ||
| # via uvicorn | ||
| httptools==0.7.1 | ||
| # via uvicorn | ||
| idna==3.11 | ||
| # via | ||
| # anyio | ||
| # requests | ||
| # yarl | ||
| importlib-metadata==8.7.1 | ||
| # via opentelemetry-api | ||
| jsonschema==4.26.0 | ||
| # via ray | ||
| jsonschema-specifications==2025.9.1 | ||
| # via jsonschema | ||
| msgpack==1.1.2 | ||
| # via ray | ||
| multidict==6.7.1 | ||
| # via | ||
| # aiohttp | ||
| # yarl | ||
| numpy==2.4.2 | ||
| # via | ||
| # pandas | ||
| # ray | ||
| # tensorboardx | ||
| opencensus==0.11.4 | ||
| # via ray | ||
| opencensus-context==0.1.3 | ||
| # via opencensus | ||
| opentelemetry-api==1.39.1 | ||
| # via | ||
| # opentelemetry-exporter-prometheus | ||
| # opentelemetry-sdk | ||
| # opentelemetry-semantic-conventions | ||
| opentelemetry-exporter-prometheus==0.60b1 | ||
| # via ray | ||
| opentelemetry-proto==1.39.1 | ||
| # via ray | ||
| opentelemetry-sdk==1.39.1 | ||
| # via | ||
| # opentelemetry-exporter-prometheus | ||
| # ray | ||
| opentelemetry-semantic-conventions==0.60b1 | ||
| # via opentelemetry-sdk | ||
| packaging==26.0 | ||
| # via | ||
| # ray | ||
| # tensorboardx | ||
| pandas==3.0.1 | ||
| # via ray | ||
| platformdirs==4.9.2 | ||
| # via virtualenv | ||
| prometheus-client==0.24.1 | ||
| # via | ||
| # opentelemetry-exporter-prometheus | ||
| # ray | ||
| propcache==0.4.1 | ||
| # via | ||
| # aiohttp | ||
| # yarl | ||
| proto-plus==1.27.1 | ||
| # via google-api-core | ||
| protobuf==6.33.5 | ||
| # via | ||
| # google-api-core | ||
| # googleapis-common-protos | ||
| # opentelemetry-proto | ||
| # proto-plus | ||
| # ray | ||
| # tensorboardx | ||
| py-spy==0.4.1 | ||
| # via ray | ||
| pyarrow==20.0.0 | ||
| # via ray | ||
| pyasn1==0.6.2 | ||
| # via | ||
| # pyasn1-modules | ||
| # rsa | ||
| pyasn1-modules==0.4.2 | ||
| # via google-auth | ||
| pycparser==3.0 | ||
| # via cffi | ||
| pydantic==2.12.5 | ||
| # via | ||
| # fastapi | ||
| # ray | ||
| pydantic-core==2.41.5 | ||
| # via pydantic | ||
| python-dateutil==2.9.0.post0 | ||
| # via pandas | ||
| python-dotenv==1.2.1 | ||
| # via uvicorn | ||
| pyyaml==6.0.3 | ||
| # via | ||
| # ray | ||
| # uvicorn | ||
| ray==2.52.1 | ||
| # via -r req.txt | ||
| referencing==0.37.0 | ||
| # via | ||
| # jsonschema | ||
| # jsonschema-specifications | ||
| requests==2.32.5 | ||
| # via | ||
| # google-api-core | ||
| # ray | ||
| rpds-py==0.30.0 | ||
| # via | ||
| # jsonschema | ||
| # referencing | ||
| rsa==4.9.1 | ||
| # via google-auth | ||
| six==1.17.0 | ||
| # via | ||
| # opencensus | ||
| # python-dateutil | ||
| smart-open==7.5.1 | ||
| # via ray | ||
| starlette==0.52.1 | ||
| # via | ||
| # fastapi | ||
| # ray | ||
| tensorboardx==2.6.4 | ||
| # via ray | ||
| typing-extensions==4.15.0 | ||
| # via | ||
| # aiosignal | ||
| # anyio | ||
| # fastapi | ||
| # grpcio | ||
| # opentelemetry-api | ||
| # opentelemetry-sdk | ||
| # opentelemetry-semantic-conventions | ||
| # pydantic | ||
| # pydantic-core | ||
| # referencing | ||
| # starlette | ||
| # typing-inspection | ||
| typing-inspection==0.4.2 | ||
| # via | ||
| # fastapi | ||
| # pydantic | ||
| urllib3==2.6.3 | ||
| # via requests | ||
| uvicorn==0.41.0 | ||
| # via ray | ||
| uvloop==0.22.1 | ||
| # via uvicorn | ||
| virtualenv==20.39.0 | ||
| # via ray | ||
| watchfiles==1.1.1 | ||
| # via | ||
| # ray | ||
| # uvicorn | ||
| websockets==16.0 | ||
| # via uvicorn | ||
| wrapt==2.1.1 | ||
| # via smart-open | ||
| yarl==1.22.0 | ||
| # via aiohttp | ||
| zipp==3.23.0 | ||
| # via importlib-metadata |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, check the file itself and understand its format
head -20 images/runtime/ray/cpu/2.52.1-py311-cpu/requirements_compiled.txt
wc -l images/runtime/ray/cpu/2.52.1-py311-cpu/requirements_compiled.txt
# Check if there are any .in files (pip-compile source)
find images -name "*.in" -type f | head -20
# Check if any other requirements files in the repo use hashes
find images -name "requirements*.txt" -type f | head -20Repository: opendatahub-io/distributed-workloads
Length of output: 970
🏁 Script executed:
# Check the git history or comments to understand how this file is generated
head -50 images/runtime/ray/cpu/2.52.1-py311-cpu/requirements_compiled.txt | cat -n
# Look for pip-compile directives or generation comments
grep -i "pip-compile\|generated\|hash\|--generate-hashes" images/runtime/ray/cpu/2.52.1-py311-cpu/requirements_compiled.txt || echo "No pip-compile metadata found"Repository: opendatahub-io/distributed-workloads
Length of output: 1296
🏁 Script executed:
# Check if there are any Dockerfile references that show how this file is used
find images -name "Dockerfile*" -type f | xargs grep -l "requirements" 2>/dev/null | head -5Repository: opendatahub-io/distributed-workloads
Length of output: 397
🏁 Script executed:
# Look for any documentation about supply-chain security or hash verification
find . -name "*.md" -o -name "*.rst" | xargs grep -l "hash\|pip.*require" 2>/dev/null | head -10Repository: opendatahub-io/distributed-workloads
Length of output: 117
🏁 Script executed:
cat -n images/runtime/ray/cpu/2.52.1-py311-cpu/Dockerfile | head -100Repository: opendatahub-io/distributed-workloads
Length of output: 1502
🏁 Script executed:
# Search for pip install commands in the Dockerfile
grep -A 5 -B 5 "pip install.*requirements" images/runtime/ray/cpu/2.52.1-py311-cpu/DockerfileRepository: opendatahub-io/distributed-workloads
Length of output: 62
🏁 Script executed:
# Check if there's a .in file (source for pip-compile)
find images/runtime/ray/cpu/2.52.1-py311-cpu -name "*.in" -o -name "*.txt" | sortRepository: opendatahub-io/distributed-workloads
Length of output: 145
🏁 Script executed:
# Check if pip-compile was used with --generate-hashes flag by looking for any build/generate scripts
find images -name "*.sh" -o -name "Makefile" -o -name "pyproject.toml" | xargs grep -l "pip-compile\|generate.*hash" 2>/dev/null || echo "No build scripts found"
# Check if there's a requirements.in file elsewhere or documentation
find . -name "*.in" -type f | head -20Repository: opendatahub-io/distributed-workloads
Length of output: 220
🏁 Script executed:
# Verify pip's hash support with constraints vs requirements
# Let's check if there are any other constraint files in the repo
find . -name "*constraint*" -type f | head -10Repository: opendatahub-io/distributed-workloads
Length of output: 62
🌐 Web query:
pip install --require-hashes constraint files CWE-494 artifact integrity verification
💡 Result:
The command pip install --require-hashes -r requirements.txt (or with constraint files via -c constraints.txt) enables pip's hash-checking mode to mitigate CWE-494 (Download of Code Without Integrity Check). This prevents installation of tampered packages by verifying cryptographic hashes (preferably SHA256) of all downloaded artifacts against pre-computed values listed in the file. Key requirements for success: - All packages and dependencies must be explicitly listed and pinned with == (exact versions). - Each must include at least one --hash=sha256:... (multiple hashes for different wheels/sdists). - Automatically activates if any hash is present; --require-hashes forces it. Example requirements.txt: FooProject==1.2 \ --hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 \ --hash=sha256:486ea46224d1bb4fb680f34f7c9ad96a8f24ec88be73ea8e5a6c65260e9cb8a7 Generate hashes: 1. Run pip install -r requirements.in --require-hashes (fails but outputs missing hashes). 2. Add them manually or use pip-tools (pip-compile --generate-hashes). With constraints: Hashes in constraints.txt are not used by pip for verification; generate fully hashed requirements.txt instead. Combine with --no-deps for project installs to avoid unhashed downloads. This protects against supply chain attacks, PyPI compromise, or transit tampering beyond TLS. Common pitfalls: - Unpinned deps or extras trigger "all requirements must have their versions pinned with ==". - Resolver issues (fixed in modern pip); use --no-deps if needed. - Network errors mimic hash mismatch; retry with --no-cache-dir. Official pip docs (v26.0.1, current as of 2026) confirm this workflow for secure, repeatable installs.
Citations:
- 1: https://pip.pypa.io/en/stable/topics/secure-installs.html
- 2: https://pip.pypa.io/en/stable/user_guide/?highlight=--constraint
- 3: https://pip.pypa.io/en/stable/topics/repeatable-installs.html
- 4: https://pip.pypa.io/en/stable/cli/pip_hash.html
- 5: https://cwe.mitre.org/data/definitions/494.html
Lockfile missing artifact hashes (CWE-494, High severity).
Exploit scenario: a malicious or compromised PyPI index can return a substituted artifact for a pinned version; install-time code runs during image build.
Remediation: regenerate with pip-compile --generate-hashes to add SHA256 hashes to each package. Then in the Dockerfile, change from -c ${CONSTRAINTS_FILE} to -r ${CONSTRAINTS_FILE} and add --require-hashes to the pip install command. Constraint files (-c) do not enforce hash verification; only requirements files (-r) support the --require-hashes flag.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@images/runtime/ray/cpu/2.52.1-py311-cpu/requirements_compiled.txt` around
lines 1 - 222, The lockfile requirements_compiled.txt lacks artifact hashes;
regenerate it with pip-compile --generate-hashes to produce SHA256 entries for
every package, replace the existing requirements_compiled.txt with the hashed
output, and then update the image build step that currently uses a constraints
install flag (-c ${CONSTRAINTS_FILE}) to use a requirements install (-r
${CONSTRAINTS_FILE}) and add the --require-hashes option to the pip install
command in the Dockerfile/build script so pip enforces the hashes at install
time.
| RUN pip install --no-cache-dir \ | ||
| -c ${CONSTRAINTS_FILE} \ | ||
| ray[default,data,train,tune,serve]==2.52.1 \ | ||
| --extra-index-url https://wheels.developerfirst.ibm.com/ppc64le/linux/+simple/ |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -type f -name "Dockerfile" | grep -E "ray.*cpu.*2\.52\.1" | head -20Repository: opendatahub-io/distributed-workloads
Length of output: 185
🏁 Script executed:
cd images/runtime/ray/cpu/2.52.1-py312-cpu 2>/dev/null && pwd && ls -laRepository: opendatahub-io/distributed-workloads
Length of output: 444
🏁 Script executed:
cat -n images/runtime/ray/cpu/2.52.1-py312-cpu/Dockerfile | head -50Repository: opendatahub-io/distributed-workloads
Length of output: 1502
🏁 Script executed:
cat -n images/runtime/ray/cpu/2.52.1-py312-cpu/requirements_compiled.txt | head -30Repository: opendatahub-io/distributed-workloads
Length of output: 811
🏁 Script executed:
wc -l images/runtime/ray/cpu/2.52.1-py312-cpu/requirements_compiled.txtRepository: opendatahub-io/distributed-workloads
Length of output: 149
🏁 Script executed:
grep -E "^[a-zA-Z0-9].*==.*#" images/runtime/ray/cpu/2.52.1-py312-cpu/requirements_compiled.txt | head -5Repository: opendatahub-io/distributed-workloads
Length of output: 62
🏁 Script executed:
grep -E "sha256|hash" images/runtime/ray/cpu/2.52.1-py312-cpu/requirements_compiled.txt | head -5Repository: opendatahub-io/distributed-workloads
Length of output: 62
🏁 Script executed:
cat images/runtime/ray/cpu/2.52.1-py312-cpu/requirements_compiled.txt | head -40Repository: opendatahub-io/distributed-workloads
Length of output: 765
🌐 Web query:
pip install -c constraints flag hash verification behavior
💡 Result:
When using pip install -c constraints.txt (or -c constraints_file), if the constraints file contains entries with --hash options (e.g., package==1.0 --hash=sha256:...), pip activates hash-checking mode automatically, just as it does for requirements files with hashes. This is because hash-checking is triggered by the presence of any --hash in the input files processed by pip. In this mode: - pip verifies downloaded packages against the specified hashes in the constraints. - All top-level requirements (from command line, -r files, etc.) must be pinned with == (exact version). - All dependencies resolved must also have matching entries with hashes in the constraints file (or requirements), as hash-checking is all-or-nothing: every installed package requires a hash. - Constraints files can provide version pins and hashes for dependencies without installing them directly. Example constraints.txt with hashes: numpy==1.21.0 \ --hash=sha256:... pandas==1.3.0 \ --hash=sha256:... \ --hash=sha256:... # multiple hashes for different wheels Command: pip install some-package -c constraints.txt - some-package must be == pinned if --require-hashes explicit or mode active. - Dependencies like numpy/pandas will use the versions/hashes from constraints.txt. - If a dependency lacks a hash entry, pip errors: "Hashes are required in --require-hashes mode, but they are missing..." This behavior is documented in pip's secure installs guide (hash-checking mode applies to requirements files, but extends to constraints as they are parsed similarly). Since pip 22.2 (PR #10962 merged), the new resolver properly filters candidates using hashes from constraints files. Earlier versions (pre-22.x new resolver) had bugs where hashes in constraints were ignored or mishandled, leading to errors like unresolved pins. Note: Constraints syntax supports --hash per official requirements file format (pip docs confirm --hash as per-requirement option). However, combining unpinned top-level reqs with hashed constraints often fails due to the pinning requirement in hash mode. Best practice: generate full pinned+hashed requirements.txt via pip-compile --generate-hashes for secure repeatable installs, use constraints for shared dep pinning across projects.
Citations:
- 1: https://pip.pypa.io/en/stable/topics/secure-installs.html
- 2: https://pip.pypa.io/en/stable/user_guide/?highlight=--constraint
- 3: Filter available distributions using hash declarations from constraints files pypa/pip#10962
- 4: 2020 resolver does not consider hashes in the constraints file pypa/pip#8792
- 5: https://discuss.python.org/t/constraints-files-with-hashes/18612
- 6: https://pip.pypa.io/en/stable/reference/requirements-file-format.html
- 7: https://pip.pypa.io/en/stable/cli/pip_install.html
- 8: https://pip.pypa.io/en/stable/news.html
🌐 Web query:
CWE-610 CWE-494 package integrity supply chain attacks
💡 Result:
CWE-610 and CWE-494 are weaknesses that enable package integrity issues in software supply chain attacks. CWE-610: Externally Controlled Reference to a Resource in Another Sphere is a class weakness where a product uses an externally controlled name or reference that resolves to a resource outside the intended control sphere. This can allow adversaries to access unintended resources, such as directing a package manager to fetch from a malicious repository via manipulated URLs or references. Consequences include reading/modifying data and privilege escalation. It is discouraged for direct vulnerability mapping, as it is abstract; more specific children like CWE-829 (Inclusion of Functionality from Untrusted Control Sphere) apply to supply chain scenarios. CWE-494: Download of Code Without Integrity Check is a base weakness where a product downloads and executes code from a remote location without verifying origin and integrity (e.g., no hashes, signatures). Attackers can compromise servers, spoof DNS, or alter code in transit, leading to unauthorized code execution. Examples include firmware updates without validation (CVE-2023-5984) and unverified auto-updates. Relation to Package Integrity and Supply Chain Attacks: These CWEs are key enablers in supply chain compromises (MITRE ATT&CK T1195), where attackers tamper with dependencies or updates. CWE-494 directly causes execution of tampered packages (e.g., malicious npm/PyPI uploads, dependency confusion CVE-2021-24105). CWE-610 facilitates pulling malicious packages via controlled references. OWASP links CWE-494 to supply chain risks (e.g., AST02, CICD-SEC-3), and broader contexts like OWASP Top 10 2025 A03: Software Supply Chain Failures emphasize such integrity failures. Mitigations: Verify signatures/hashes (avoid CWE-295/320), use trusted proxies/registries, SBOMs, and pinned versions.
Citations:
- 1: https://cwe.mitre.org/data/definitions/610.html
- 2: https://cwe.mitre.org/data/definitions/494.html
- 3: https://attack.mitre.org/techniques/T1195/
- 4: https://owasp.org/www-project-agentic-skills-top-10/ast02.html
- 5: https://owasp.org/www-project-top-10-ci-cd-security-risks/CICD-SEC-03-Dependency-Chain-Abuse
- 6: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-24105
🏁 Script executed:
cat images/runtime/ray/cpu/2.52.1-py311-cpu/Dockerfile | grep -A 5 "pip install"Repository: opendatahub-io/distributed-workloads
Length of output: 299
🏁 Script executed:
grep "requires-hashes\|require-hashes\|--hash" images/runtime/ray/cpu/2.52.1-py311-cpu/requirements_compiled.txtRepository: opendatahub-io/distributed-workloads
Length of output: 62
🌐 Web query:
IBM Developer First ppc64le wheels source repository trustworthiness
💡 Result:
The IBM Developer First ppc64le wheels source repository at https://wheels.developerfirst.ibm.com/ppc64le/linux is a trustworthy, official IBM-hosted DevPi server providing pre-built, optimized Python wheels for the ppc64le (IBM Power) architecture. IBM's Power team builds these open-source packages natively on Power hardware, focusing on AI/ML and data science libraries (e.g., torch, vllm, numpy), supporting Python 3.10-3.12. Usage: pip install --prefer-binary --extra-index-url=https://wheels.developerfirst.ibm.com/ppc64le/linux. Supporting resources include IBM community blogs by developers like Nikhil Kalbande and Gerrit Huizenga (2025 posts), GitHub ppc64le/pyeco repo for demos/issues, and ppc64le/build-scripts for related open-source builds. No security issues specific to this repo found; wheels carry original OSS licenses (e.g., Apache-2.0, MIT per IBM license doc). As an official IBM initiative under "Developer First" for Power, with active maintenance and community collaboration, it is highly trustworthy for production use on ppc64le systems.
Citations:
- 1: https://wheels.developerfirst.ibm.com/ppc64le/linux
- 2: https://wheels.developerfirst.ibm.com/ppc64le
- 3: https://community.ibm.com/community/user/blogs/nikhil-kalbande/2025/08/01/install-wheels-from-ibm-python-wheel-repository
- 4: https://community.ibm.com/community/user/discussion/unleash-the-power-of-ai-with-optimized-python-packages-for-ibm-power
- 5: https://community.ibm.com/community/user/blogs/gerrit-huizenga/2025/09/16/python-for-power-is-here
- 6: https://github.com/ppc64le/pyeco
- 7: https://github.com/ppc64le/build-scripts
Add hash verification to dependency resolution on lines 31-34 (CWE-494).
Exploit scenario: Version pinning in the constraints file provides no integrity protection; a compromised extra-index-url source or MITM attack can inject malicious wheels with matching versions.
Remediation: Generate a hash-locked requirements file using pip-compile --generate-hashes and use pip install --require-hashes -r requirements.txt to enforce cryptographic verification of all downloaded packages.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@images/runtime/ray/cpu/2.52.1-py312-cpu/Dockerfile` around lines 31 - 34, The
current Dockerfile RUN pip install using -c ${CONSTRAINTS_FILE} and an
extra-index-url lacks hash verification; generate a hash-locked requirements
file (e.g., run pip-compile --generate-hashes against your constraints and
explicit dependencies like ray[default,data,train,tune,serve]==2.52.1 and
include any extra-index-url configuration) and update the Dockerfile to COPY
that generated requirements.txt into the image and replace the pip install line
with pip install --require-hashes -r requirements.txt (removing the insecure -c
${CONSTRAINTS_FILE} usage), ensuring all packages are installed only if their
cryptographic hashes match.
| @@ -0,0 +1,10 @@ | |||
| # Ray Runtime Container Image | |||
|
|
|||
| CPU enabled container image for Ray in OpenShift AI. | |||
There was a problem hiding this comment.
Fix hyphenation in user-facing text on Line 3.
Use CPU-enabled instead of CPU enabled for correct compound adjective formatting.
🧰 Tools
🪛 LanguageTool
[grammar] ~3-~3: Use a hyphen to join words.
Context: # Ray Runtime Container Image CPU enabled container image for Ray in OpenS...
(QB_NEW_EN_HYPHEN)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@images/runtime/ray/cpu/2.52.1-py312-cpu/README.md` at line 3, Update the
user-facing text in README.md by replacing the phrase "CPU enabled container
image for Ray in OpenShift AI." with "CPU-enabled container image for Ray in
OpenShift AI." so the compound adjective is hyphenated correctly; locate the
sentence in the README.md (the line containing "CPU enabled container image for
Ray in OpenShift AI.") and apply the hyphenation change.
| aiohappyeyeballs==2.6.1 | ||
| # via aiohttp | ||
| aiohttp==3.13.3 | ||
| # via | ||
| # aiohttp-cors | ||
| # ray | ||
| aiohttp-cors==0.8.1 | ||
| # via ray | ||
| aiosignal==1.4.0 | ||
| # via aiohttp | ||
| annotated-doc==0.0.4 | ||
| # via fastapi | ||
| annotated-types==0.7.0 | ||
| # via pydantic | ||
| anyio==4.12.1 | ||
| # via | ||
| # starlette | ||
| # watchfiles | ||
| attrs==25.4.0 | ||
| # via | ||
| # aiohttp | ||
| # jsonschema | ||
| # referencing | ||
| certifi==2026.2.25 | ||
| # via requests | ||
| cffi==2.0.0 | ||
| # via cryptography | ||
| charset-normalizer==3.4.4 | ||
| # via requests | ||
| click==8.2.1 | ||
| # via | ||
| # ray | ||
| # uvicorn | ||
| colorful==0.5.8 | ||
| # via ray | ||
| cryptography==46.0.5 | ||
| # via google-auth | ||
| distlib==0.4.0 | ||
| # via virtualenv | ||
| fastapi==0.133.0 | ||
| # via ray | ||
| filelock==3.24.3 | ||
| # via | ||
| # ray | ||
| # virtualenv | ||
| frozenlist==1.8.0 | ||
| # via | ||
| # aiohttp | ||
| # aiosignal | ||
| fsspec==2026.2.0 | ||
| # via ray | ||
| google-api-core==2.30.0 | ||
| # via opencensus | ||
| google-auth==2.48.0 | ||
| # via google-api-core | ||
| googleapis-common-protos==1.72.0 | ||
| # via google-api-core | ||
| grpcio==1.75.1 | ||
| # via ray | ||
| h11==0.16.0 | ||
| # via uvicorn | ||
| httptools==0.7.1 | ||
| # via uvicorn | ||
| idna==3.11 | ||
| # via | ||
| # anyio | ||
| # requests | ||
| # yarl | ||
| importlib-metadata==8.7.1 | ||
| # via opentelemetry-api | ||
| jsonschema==4.26.0 | ||
| # via ray | ||
| jsonschema-specifications==2025.9.1 | ||
| # via jsonschema | ||
| msgpack==1.1.2 | ||
| # via ray | ||
| multidict==6.7.1 | ||
| # via | ||
| # aiohttp | ||
| # yarl | ||
| numpy==2.4.2 | ||
| # via | ||
| # pandas | ||
| # ray | ||
| # tensorboardx | ||
| opencensus==0.11.4 | ||
| # via ray | ||
| opencensus-context==0.1.3 | ||
| # via opencensus | ||
| opentelemetry-api==1.39.1 | ||
| # via | ||
| # opentelemetry-exporter-prometheus | ||
| # opentelemetry-sdk | ||
| # opentelemetry-semantic-conventions | ||
| opentelemetry-exporter-prometheus==0.60b1 | ||
| # via ray | ||
| opentelemetry-proto==1.39.1 | ||
| # via ray | ||
| opentelemetry-sdk==1.39.1 | ||
| # via | ||
| # opentelemetry-exporter-prometheus | ||
| # ray | ||
| opentelemetry-semantic-conventions==0.60b1 | ||
| # via opentelemetry-sdk | ||
| packaging==26.0 | ||
| # via | ||
| # ray | ||
| # tensorboardx | ||
| pandas==3.0.1 | ||
| # via ray | ||
| platformdirs==4.9.2 | ||
| # via virtualenv | ||
| prometheus-client==0.24.1 | ||
| # via | ||
| # opentelemetry-exporter-prometheus | ||
| # ray | ||
| propcache==0.4.1 | ||
| # via | ||
| # aiohttp | ||
| # yarl | ||
| proto-plus==1.27.1 | ||
| # via google-api-core | ||
| protobuf==6.33.5 | ||
| # via | ||
| # google-api-core | ||
| # googleapis-common-protos | ||
| # opentelemetry-proto | ||
| # proto-plus | ||
| # ray | ||
| # tensorboardx | ||
| py-spy==0.4.1 | ||
| # via ray | ||
| pyarrow==21.0.0 | ||
| # via ray | ||
| pyasn1==0.6.2 | ||
| # via | ||
| # pyasn1-modules | ||
| # rsa | ||
| pyasn1-modules==0.4.2 | ||
| # via google-auth | ||
| pycparser==3.0 | ||
| # via cffi | ||
| pydantic==2.12.5 | ||
| # via | ||
| # fastapi | ||
| # ray | ||
| pydantic-core==2.41.5 | ||
| # via pydantic | ||
| python-dateutil==2.9.0.post0 | ||
| # via pandas | ||
| python-dotenv==1.2.1 | ||
| # via uvicorn | ||
| pyyaml==6.0.3 | ||
| # via | ||
| # ray | ||
| # uvicorn | ||
| ray==2.52.1 | ||
| # via -r req.txt | ||
| referencing==0.37.0 | ||
| # via | ||
| # jsonschema | ||
| # jsonschema-specifications | ||
| requests==2.32.5 | ||
| # via | ||
| # google-api-core | ||
| # ray | ||
| rpds-py==0.30.0 | ||
| # via | ||
| # jsonschema | ||
| # referencing | ||
| rsa==4.9.1 | ||
| # via google-auth | ||
| six==1.17.0 | ||
| # via | ||
| # opencensus | ||
| # python-dateutil | ||
| smart-open==7.5.1 | ||
| # via ray | ||
| starlette==0.52.1 | ||
| # via | ||
| # fastapi | ||
| # ray | ||
| tensorboardx==2.6.4 | ||
| # via ray | ||
| typing-extensions==4.15.0 | ||
| # via | ||
| # aiosignal | ||
| # anyio | ||
| # fastapi | ||
| # grpcio | ||
| # opentelemetry-api | ||
| # opentelemetry-sdk | ||
| # opentelemetry-semantic-conventions | ||
| # pydantic | ||
| # pydantic-core | ||
| # referencing | ||
| # starlette | ||
| # typing-inspection | ||
| typing-inspection==0.4.2 | ||
| # via | ||
| # fastapi | ||
| # pydantic | ||
| urllib3==2.6.3 | ||
| # via requests | ||
| uvicorn==0.41.0 | ||
| # via ray | ||
| uvloop==0.22.1 | ||
| # via uvicorn | ||
| virtualenv==20.39.0 | ||
| # via ray | ||
| watchfiles==1.1.1 | ||
| # via | ||
| # ray | ||
| # uvicorn | ||
| websockets==16.0 | ||
| # via uvicorn | ||
| wrapt==2.1.1 | ||
| # via smart-open | ||
| yarl==1.22.0 | ||
| # via aiohttp | ||
| zipp==3.23.0 | ||
| # via importlib-metadata |
There was a problem hiding this comment.
Lockfile is missing artifact hashes (High, CWE-494).
Exploit scenario: if a package index/mirror serves a tampered wheel for a pinned version, build-time install can execute attacker-controlled code (currently during root phase in the Dockerfile).
Remediation: regenerate this lockfile with --hash=sha256:... entries and enforce pip install --require-hashes.
Remediation snippet
-# current lock entries (version-only)
-aiohttp==3.13.3
+# hash-locked entry format
+aiohttp==3.13.3 \
+ --hash=sha256:<hash1> \
+ --hash=sha256:<hash2># regenerate with hashes (from the input requirements file used for compilation)
pip-compile --generate-hashes -o requirements_compiled.txt req.txt#!/bin/bash
# Verify that lockfiles contain hashes and Dockerfiles enforce them.
fd -a 'requirements_compiled.txt' images/runtime/ray/cpu | while read -r f; do
echo "== $f =="
rg -n -- '--hash=sha256:' "$f" || echo "NO_HASHES_FOUND"
done
fd -a 'Dockerfile' images/runtime/ray/cpu | while read -r f; do
echo "== $f =="
rg -n -- '--require-hashes|pip install|--extra-index-url' "$f"
doneAs per coding guidelines, **: "REVIEW PRIORITIES: 1. Security vulnerabilities (provide severity, exploit scenario, and remediation code)".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@images/runtime/ray/cpu/2.52.1-py312-cpu/requirements_compiled.txt` around
lines 1 - 222, The requirements_compiled.txt lockfile lacks per-artifact
--hash=sha256 entries; regenerate the lock (the artifact represented by
requirements_compiled.txt) using pip-compile with --generate-hashes so each
dependency line includes --hash=sha256:... and then update Dockerfile(s) that
run pip installs (the root-phase pip install command) to use pip install
--require-hashes (and point at the regenerated requirements_compiled.txt) so pip
will enforce those hashes at build time.
There was a problem hiding this comment.
🧹 Nitpick comments (2)
.tekton/ray-cpu-pull-request.yaml (2)
45-46:skip-checks: truedisables security scanning.Acceptable for PR preview builds, but ensure the release/push pipeline has this set to
falseto enforce vulnerability scanning before production images are published.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.tekton/ray-cpu-pull-request.yaml around lines 45 - 46, The pipeline currently sets the Tekton parameter "skip-checks" to true which disables security scanning; change this value to false in the release/push pipeline configuration (leave PR preview pipelines with skip-checks: true if desired) so that vulnerability scanning runs before publishing production images, and verify the release/push task or pipeline that consumes the "skip-checks" parameter (e.g., the step referencing skip-checks) honors the boolean and triggers the scanning steps when false.
10-12: MissingpathChanged()condition in trigger - builds won't auto-trigger on relevant file changes.Unlike
ray-rocm-pull-request.yamlwhich uses a CEL expression withpathChanged()to auto-trigger on file changes, this configuration only triggers via:
- Manual comment
/build-ray-cpu- Label
build-all- Generic pull_request event
Consider adding a CEL-based trigger or supplementing with
on-path-changeto automatically build when files underimages/runtime/ray/cpu/**or this manifest change.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.tekton/ray-cpu-pull-request.yaml around lines 10 - 12, The trigger currently only includes the labels/events keys (pipelinesascode.tekton.dev/on-comment, on-label, on-event) and is missing a path-change condition, so add a CEL/path-change trigger to auto-run on relevant file edits by introducing a CEL expression (using pathChanged()) or an on-path-change entry that checks images/runtime/ray/cpu/** and this manifest (referencing the existing keys pipelinesascode.tekton.dev/on-comment, pipelinesascode.tekton.dev/on-label, and pipelinesascode.tekton.dev/on-event); ensure the new expression ORs the pathChanged checks with any manual triggers so builds run automatically when files under images/runtime/ray/cpu/** or .tekton/ray-cpu-pull-request.yaml change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In @.tekton/ray-cpu-pull-request.yaml:
- Around line 45-46: The pipeline currently sets the Tekton parameter
"skip-checks" to true which disables security scanning; change this value to
false in the release/push pipeline configuration (leave PR preview pipelines
with skip-checks: true if desired) so that vulnerability scanning runs before
publishing production images, and verify the release/push task or pipeline that
consumes the "skip-checks" parameter (e.g., the step referencing skip-checks)
honors the boolean and triggers the scanning steps when false.
- Around line 10-12: The trigger currently only includes the labels/events keys
(pipelinesascode.tekton.dev/on-comment, on-label, on-event) and is missing a
path-change condition, so add a CEL/path-change trigger to auto-run on relevant
file edits by introducing a CEL expression (using pathChanged()) or an
on-path-change entry that checks images/runtime/ray/cpu/** and this manifest
(referencing the existing keys pipelinesascode.tekton.dev/on-comment,
pipelinesascode.tekton.dev/on-label, and pipelinesascode.tekton.dev/on-event);
ensure the new expression ORs the pathChanged checks with any manual triggers so
builds run automatically when files under images/runtime/ray/cpu/** or
.tekton/ray-cpu-pull-request.yaml change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Central YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro
Run ID: 55889432-b92a-4576-874f-25f4be86d0db
📒 Files selected for processing (1)
.tekton/ray-cpu-pull-request.yaml
|
/build-konflux |
|
/build-ray-cpu |
Description
How Has This Been Tested?
Merge criteria:
Summary by CodeRabbit
New Features
Documentation
Chores