Repository navigation
Conversation
…cience deps into subprojects (#2796) Add 3 new dependency subprojects to reduce duplication across pyproject.toml files: - odh-notebooks-meta-db-connectors-deps (pymongo, psycopg, pyodbc, mysql-connector-python) - odh-notebooks-meta-jupyterlab-deps (jupyterlab, jupyter-server, extensions) - odh-notebooks-meta-jupyterlab-datascience-deps (odh-elyra, jupyter-bokeh, jupyterlab-lsp, etc.) Existing subprojects are unchanged. Updated 14 pyproject.toml files and regenerated lock files. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dockerfile2LLB now returns (*Result, error) instead of 5 values. Access the LLB state via result.State. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix FAILED tests/containers/runtimes/runtime_test.py::TestRuntimeImage::test_feast_version[ghcr.io/opendatahub-io/notebooks/workbench-images:runtime-datascience-ubi9-python-3.12-3217_merge_2f8909d91201e3197d82286ad72206b98e5f9ee9] - AssertionError: 'feast version' failed: qemu: uncaught target signal 11 (Segmentation fault) - core dumped - Remove collect_ignore from pytest.ini (unsupported there; pytest 9+ warns) - Set collect_ignore in tests/conftest.py relative to tests/ - Skip feast version runtime test on s390x (PyArrow/Feast flaky under CI QEMU)
- jupyter/minimal: extend RPM prefetch (protobuf, unixODBC-devel, s390x build toolchain) and refresh locks / pylocks - jupyter/pytorch+llmcompressor: uv bump, protobuf in image, prefetch refresh - runtimes/datascience: Dockerfile.cpu / konflux.cpu updates for hermetic base
test: fix pytest collect_ignore; skip Feast CLI on s390x
chore: minimal RPM prefetch, pytorch CUDA alignment, runtime datascience
Build Jupyter datascience heretically, by prefetch the rpms, pip and gomod. Install openshift-clients from rpm, build mongocli from shared submodule sources. Also update .tekton files.
…mertic-datascience RHAIENG-2856: Hermetic build for Jupyter datascience CPU
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add tsconfig.json with nodenext module resolution, excluding cypress/. Fix type errors surfaced by strict mode: - k8s client-node 1.x object-param API for getNamespacedCustomObject - Add Page/TestInfo type annotations in utils.ts - Type custom Playwright fixtures in defineConfig<MyFixtures>() - Fix Page | undefined in start_browser.ts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Throw a descriptive error if the selector doesn't match, instead of a generic TypeError from the non-null assertion. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use `{ url: string; image?: never } | { image: string; url?: never }`
to make invalid states (empty object, both undefined) unrepresentable
at compile time. Fix CI config to only override fixture default when
TEST_TARGET env var is set.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
chore(tests/browser): update all pnpm dependencies and adopt more of typescript
…edora builds (#3223) * chore: update Go to 1.26 and fix Makefile for Fedora builds (#3026) Update go directive to 1.26.0 in all Go modules. Add GOTOOLCHAIN=auto and GONOSUMCHECK=golang.org/toolchain to Makefile go commands so Fedora users (who have GOTOOLCHAIN=local and GOSUMDB=off by default) can build without manual env setup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add Go toolchain section to CONTRIBUTING.md Document Go 1.26 requirement and Fedora GOSUMDB=off workaround. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use GONOSUMDB (not GONOSUMCHECK) and pin go 1.26.1 GONOSUMCHECK is not a real Go env var — GONOSUMDB is the correct one. Pin go 1.26.1 since go 1.26.5 doesn't exist yet. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
[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 shifts many images and pipelines to hermetic builds by introducing prefetch-input parameters, adding a prefetch-dependencies task with fixed resources, and wiring prefetched RPM/pip/gomod sources into Dockerfiles (via /cachi2/output/deps) guarded by a LOCAL_BUILD flag. It consolidates explicit DB-connector and JupyterLab pins into three local meta-packages under dependencies/, bumps uv to 0.11.0 and Go to 1.26.1, regenerates numerous RPM lockfiles (adds build/toolchain packages and protobuf), updates Tekton PipelineRun triggers/params for prefetching, and tightens several TypeScript test typings. Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Detailed FindingsArchitecture & DesignHermetic Build Introduction: Dockerfiles and Tekton now depend on prefetched artifacts and a prefetch task. Verify:
Actionable: validate prefetch artifact coverage against lockfiles and the Dockerfile install commands. Meta-Package Consolidation: Many pyproject.toml files now depend on three local meta-packages. Risk: ensure meta-packages are acyclic and their uv lockfiles include full transitive closure for offline builds. Actionable: run uv resolution for each meta-package and confirm resulting uv.lock contains all transitive packages. RPM Prefetch Manifests: Large additions (protobuf, build toolchain, openblas-devel, etc.) and many lockfile deltas across arches. Actionable: verify s390x entries are complete and that added build-tool RPMs are available in the targeted repos for all arches. Code Quality IssuesDockerfile Variable Scope: Actionable: confirm BuildKit/CI invocation sets Go nil-check: Actionable: add nil-checks on TypeScript fixture changes: Discriminated union for Actionable: run TypeScript compilation for tests and update any legacy usages that pass both Security & OperationsRemoved network fetches: curl/dnf upgrade and runtime downloads removed—reduces attack surface (positive). No praise; factual. GPG key imports: Multiple GPG keys imported with Actionable: ensure keys are included in prefetch artifacts; consider failing fast if critical keys are absent (CWE-295: Improper Certificate Validation risk if keys missing). Offline mode dependency risk: Actionable: audit uv.lock.* and rpms.lock.yaml files for completeness. Add CI validation step that runs a hermetic build using only prefetched artifacts and fails on missing items (CWE-110: Missing Release of Resource? more precisely dependency integrity risk). Go toolchain bump: go 1.26.1 in go.mod without go.sum changes shown. Actionable: run Tests & CIs390x test skip: pytest collection: Playwright/test updates: Type changes in fixtures and helper signatures require updating test callers. Actionable: run test typechecks and Playwright runs in CI to catch mismatches. Actionable Security Citations
Only actionable issues flagged above; address those before merging. 🚥 Pre-merge checks | ❌ 3❌ Failed checks (3 warnings)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
❌ 1 Tests Failed:
View the top 1 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
There was a problem hiding this comment.
Actionable comments posted: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
tests/browser/tests/utils.ts (2)
31-45:⚠️ Potential issue | 🔴 CriticalCritical bug:
setIntervalinside loop creates exponential interval spawning.Line 42 uses
setIntervalinsideloop(). Each call toloop()schedules another repeating interval, causing exponential growth in callbacks, memory exhaustion, and likely browser tab crash.Fix: use `setTimeout` for single delayed callback
return new Promise<void>((resolve, reject) => { let loop = () => { let now = performance.now(); if (now - mutated > checkPeriod) { observer.disconnect(); resolve(); } if (now - started > timeout) { observer.disconnect(); reject(); } - window.setInterval(loop, checkPeriod); + window.setTimeout(loop, checkPeriod); }; loop() })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/browser/tests/utils.ts` around lines 31 - 45, The loop inside the Promise schedules a repeating setInterval on every invocation causing exponential intervals; change the scheduling call in the loop function to use window.setTimeout(loop, checkPeriod) (single-shot) so only one delayed callback is queued each iteration, keep the existing observer.disconnect()/resolve()/reject() logic intact, and ensure the initial loop() call still starts the cycle; reference the loop function and the observer variable in tests/browser/tests/utils.ts when making this change.
38-41:⚠️ Potential issue | 🟡 MinorPromise never resolves if timeout triggers after stability check passes.
If
now - mutated > checkPeriodresolves the promise, the subsequent timeout check on lines 38-41 still executes and may callreject()on an already-resolved promise. Addreturnstatements afterresolve()/reject().Add early returns
let loop = () => { let now = performance.now(); if (now - mutated > checkPeriod) { observer.disconnect(); resolve(); + return; } if (now - started > timeout) { observer.disconnect(); reject(); + return; } window.setTimeout(loop, checkPeriod); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/browser/tests/utils.ts` around lines 38 - 41, The timeout branch can call reject() after the promise was already resolved by the stability check; update the check handling so you exit immediately after resolving or rejecting: after the stability branch that calls resolve() when (now - mutated > checkPeriod) and after the timeout branch that calls reject() when (now - started > timeout), add immediate returns (ensuring observer.disconnect() is still called before the return) so no further checks run and the promise cannot be settled twice; look for the uses of resolve(), reject(), observer.disconnect(), now - mutated > checkPeriod and now - started > timeout to locate the exact spots to update.runtimes/datascience/ubi9-python-3.12/Dockerfile.konflux.cpu (2)
123-124:⚠️ Potential issue | 🟠 MajorNetwork access to GitHub in Konflux build.
Line 123-124 downloads
bootstrapper.pyfrom raw.githubusercontent.com at build time. This breaks hermetic build requirements for Konflux. The Elyra bootstrapper should be prefetched or vendored.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@runtimes/datascience/ubi9-python-3.12/Dockerfile.konflux.cpu` around lines 123 - 124, The Dockerfile currently fetches the Elyra bootstrapper at build time via the RUN curl line (downloading bootstrapper.py), which violates hermetic build rules; replace that network fetch by vendoring or prefetching the file into the build context and change the Dockerfile to use COPY/ADD to bring ./utils/bootstrapper.py into the image instead of the curl command. Ensure the repository contains the exact bootstrapper.py (or a pinned vendor snapshot) and update the Dockerfile location that referenced the bootstrapper (the RUN curl line) to a COPY ./utils/bootstrapper.py ./utils/bootstrapper.py so the image build no longer requires external network access.
97-101:⚠️ Potential issue | 🟠 MajorNetwork access in Konflux Dockerfile may break hermetic build guarantees.
Lines 97-100 use
curlto download the OpenShift client frommirror.openshift.comat build time. For a Konflux (hermetic) build, external network access is typically disallowed or should use prefetched artifacts like theopenshift-clientsRPM in the manifests.The RPM prefetch manifests already include
openshift-clients. Consider installing viadnffrom prefetched RPMs instead of curl.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@runtimes/datascience/ubi9-python-3.12/Dockerfile.konflux.cpu` around lines 97 - 101, The Dockerfile currently fetches the OpenShift client with the curl/tar sequence (curl ... -o /tmp/openshift-client-linux.tar.gz; tar -xzvf /tmp/openshift-client-linux.tar.gz; rm -f /tmp/openshift-client-linux.tar.gz), which breaks hermetic builds; replace that block by installing the prefetched openshift-clients RPM (package name openshift-clients) via dnf (e.g., dnf install -y /path/to/prefetched/openshift-clients-*.rpm or dnf install -y openshift-clients if the manifests repo is enabled) and remove the curl/tar lines so the Dockerfile uses the pre-fetched RPM artifact instead of downloading from mirror.openshift.com.jupyter/pytorch+llmcompressor/ubi9-python-3.12/Dockerfile.konflux.cuda (1)
191-196:⚠️ Potential issue | 🟡 Minor
--no-verify-hashesdisables integrity verification.Line 194 uses
--no-verify-hasheswhile installing from prefetched dependencies. For hermetic builds, hash verification should typically be enforced to ensure reproducibility and detect tampering. The lockfile (pylock.toml) contains SHA256 hashes.If hashes are intentionally skipped due to Cachi2 prefetch mechanics (e.g., wheels renamed or reprocessed), document this in a comment. Otherwise, consider using
--require-hashesfor stronger supply chain security.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@jupyter/pytorch`+llmcompressor/ubi9-python-3.12/Dockerfile.konflux.cuda around lines 191 - 196, The pip install invocation using the UV wrapper (the command starting with "UV_NO_CACHE=true UV_LINK_MODE=copy UV_PREVIEW_FEATURES=pylock uv pip install ... --no-verify-hashes") disables package hash verification; either enable strict hash checking by replacing "--no-verify-hashes" with "--require-hashes" (and ensure ./requirements.txt / pylock.toml contains hashes) or, if Cachi2 prefetching prevents exact hashes, add a clear comment above this UV pip install line explaining why hashes are intentionally omitted (describe the Cachi2 renaming/reprocessing behavior) so future maintainers understand the tradeoff.
🧹 Nitpick comments (10)
tests/browser/tests/utils.ts (1)
13-14: Useletinstead ofvarfor block-scoped variables.
varhoists to function scope and is discouraged in modern TypeScript.- var started = performance.now(); - var mutated = started; + let started = performance.now(); + let mutated = started;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/browser/tests/utils.ts` around lines 13 - 14, Replace the function-scoped declarations using "var" for the timing variables with block-scoped "let": change "var started = performance.now();" and "var mutated = started;" to use "let" so that started and mutated are block-scoped (update both declarations in tests/browser/tests/utils.ts where these variables are defined).tests/browser/tests/codeserver.spec.ts (2)
40-46: Unnecessary optional chaining and verbose error throw.
codeServerSourceis always provided by the fixture system. The?.on line 41 is redundant. The IIFE-throw pattern on lines 44-46 works but is verbose.Simplified fixture
codeServer: [async ({ page, codeServerSource }, use) => { - if (codeServerSource?.url) { + if ('url' in codeServerSource) { await use(new CodeServer(page, codeServerSource.url)) } else { - const image = codeServerSource.image ?? (() => { - throw new Error("invalid config: codeserver image not specified") - })() + // Type guarantees `image` exists when `url` is absent + const image = codeServerSource.image; const container = await new GenericContainer(image)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/browser/tests/codeserver.spec.ts` around lines 40 - 46, Remove the unnecessary optional chaining on codeServerSource (it is always provided) and replace the verbose IIFE throw with a simple guard: in the codeServer fixture block, change "if (codeServerSource?.url)" to "if (codeServerSource.url)" and replace the "const image = codeServerSource.image ?? (() => { throw new Error('invalid config: codeserver image not specified') })()" pattern with "const image = codeServerSource.image; if (!image) throw new Error('invalid config: codeserver image not specified')", keeping the rest of the logic using new CodeServer(page, codeServerSource.url) intact.
16-22:MyFixturestype duplicated inplaywright.config.ts.The same
MyFixturestype is defined in both files. Extract to a shared module to avoid drift.Extract to shared types file
Create
tests/browser/tests/types.ts:export type MyFixtures = { connectCDP: false | number; codeServerSource: | { url: string; image?: never } | { image: string; url?: never }; };Then import in both files:
import type { MyFixtures } from './types';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/browser/tests/codeserver.spec.ts` around lines 16 - 22, The MyFixtures type is duplicated; extract it into a single shared types module named types.ts that exports the MyFixtures type (keeping the connectCDP and codeServerSource union but removing the per-test-only codeServer property), then remove the local MyFixtures definitions in both files and import the shared type (import type { MyFixtures } from './types') in each place where MyFixtures was previously declared so both tests reference the single canonical type.tests/browser/scripts/start_browser.ts (1)
62-70: Redundantnullchecks—pagecan only bePage | undefined.The type is
Page | undefined, andcontext?.pages()[0]returnsundefined(notnull) when absent. The=== nullchecks on lines 63 and 66 are dead code.Simplified condition
- while ((page === null || page === undefined) && Date.now() - started < timeout) { + while (page === undefined && Date.now() - started < timeout) { const context = browser.contexts()[0]; page = context?.pages()[0]; - if (page !== null && page !== undefined) { + if (page !== undefined) { return page; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/browser/scripts/start_browser.ts` around lines 62 - 70, The loop contains redundant null checks for the local variable page (declared as Page | undefined) and for context?.pages()[0], which can only be undefined; remove the === null checks and simplify the conditions to check only undefined (e.g., use page === undefined or page !== undefined) and likewise rely on optional chaining result being undefined, updating the while condition and the if that returns page (references: page, started, timeout, browser.contexts(), context?.pages()[0]).jupyter/minimal/ubi9-python-3.12/prefetch-input/odh/rpms.lock.yaml (1)
28-41: Build toolchain packages increase attack surface for "minimal" image.New additions include autoconf, automake, cmake, libtool, m4, openblas-devel, pybind11-devel, and gcc runtime libraries. For a "minimal" Jupyter image, consider whether these belong in a separate build stage or multi-stage build to reduce the final image attack surface. If these are required at runtime for pip-installing packages with native extensions, document this requirement.
Also applies to: 2240-2295, 2289-2295, 2331-2351
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@jupyter/minimal/ubi9-python-3.12/prefetch-input/odh/rpms.lock.yaml` around lines 28 - 41, The rpms.lock.yaml adds build-toolchain packages (autoconf, automake, cmake, libtool, m4, openblas-devel, pybind11-devel, gcc runtime libs) which increase the attack surface of the "minimal" Jupyter image; either move these packages out of the final runtime package list into a separate build-stage/multi-stage image (so they are installed only during build and not present in the final image) or, if they are required at runtime for pip-installing native extensions, explicitly document that requirement in the repo (e.g., in README or image documentation) and mark these entries as build-time dependencies—update the entries for autoconf, automake, cmake, libtool, m4, openblas-devel, pybind11-devel, and gcc-related packages accordingly across the referenced sections (around lines 2240-2351) to reflect the chosen approach.runtimes/datascience/ubi9-python-3.12/Dockerfile.cpu (1)
91-91: uv version inconsistency: 0.10.8 here vs 0.11.0 in Konflux Dockerfiles.This file pins
uv==0.10.8whilejupyter/pytorch+llmcompressor/ubi9-python-3.12/Dockerfile.cudaandDockerfile.konflux.cudauseuv==0.11.0. Drift between non-Konflux and Konflux builds may cause subtle differences.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@runtimes/datascience/ubi9-python-3.12/Dockerfile.cpu` at line 91, The RUN pip install line currently pins "uv==0.10.8" causing version drift; update that package pin in the RUN command (the pip install statement that includes "micropipenv[toml]==1.10.0" and "uv==0.10.8") to match the Konflux Dockerfiles by changing "uv==0.10.8" to "uv==0.11.0" so all builds use the same uv version.Makefile (1)
144-145:GONOSUMDBis ignored for toolchain downloads.Go treats
golang.org/toolchainspecially:GONOSUMDBdoes not apply here, andGOSUMDB=offstill blocksGOTOOLCHAIN=autofrom fetching the toolchain. Keeping this env var is misleading because it suggests a compatibility path that Go will ignore. Drop it, and if you need checksum-db-disabled environments to work, handle that with an explicit guard or documentation instead. (go.dev)Do `GONOSUMDB` patterns apply to `golang.org/toolchain` downloads when using `GOTOOLCHAIN=auto`, and what happens if `GOSUMDB=off`?Proposed fix
bin/buildinputs: scripts/buildinputs/buildinputs.go scripts/buildinputs/go.mod scripts/buildinputs/go.sum $(info Building a Go helper for Dockerfile dependency analysis...) - GOTOOLCHAIN=auto GONOSUMDB=golang.org/toolchain \ + GOTOOLCHAIN=auto \ go build -C "scripts/buildinputs" -o "$(ROOT_DIR)/$@" ./... test-unit: `@echo` "Running Python unit tests" ./uv run pytest -m 'not buildonlytest' --ignore=tests/containers tests/ ntb/ `@echo` "Running Go unit tests" - GOTOOLCHAIN=auto GONOSUMDB=golang.org/toolchain \ + GOTOOLCHAIN=auto \ go test -C scripts/buildinputs -cover ./...Also applies to: 503-504
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Makefile` around lines 144 - 145, The Makefile sets GONOSUMDB when invoking go build for the toolchain (GOTOOLCHAIN=auto) but GONOSUMDB is ignored for golang.org/toolchain downloads and is misleading; remove the GONOSUMDB=golang.org/toolchain assignment from the go build invocation (the line that exports/uses GOTOOLCHAIN=auto and runs go build -C "scripts/buildinputs" -o "$(ROOT_DIR)/$@" ./...), and if you need to support environments with GOSUMDB=off, add an explicit guard or documented check that handles GOSUMDB rather than relying on GONOSUMDB.jupyter/datascience/ubi9-python-3.12/Dockerfile.cpu (1)
29-32: Go cache directories overlap may cause build issues.
GOCACHE,GOMODCACHE, andGOPATHall point to/cachi2/output/deps/gomodor subdirectories thereof. WhileGOMODCACHEunder$GOPATH/pkg/modis standard,GOCACHE(build cache) sharing the same root asGOPATHis unconventional and may cause cache pollution between module downloads and build artifacts.Consider separating GOCACHE
- export GOCACHE=/cachi2/output/deps/gomod + export GOCACHE=/tmp/go-build-cache export GOMODCACHE=/cachi2/output/deps/gomod/pkg/mod export GOPATH=/cachi2/output/deps/gomod🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@jupyter/datascience/ubi9-python-3.12/Dockerfile.cpu` around lines 29 - 32, The current Dockerfile sets GOCACHE, GOMODCACHE and GOPATH to overlapping locations which can cause cache pollution; change GOCACHE to a separate directory (e.g., /cachi2/output/deps/gocache) while leaving GOMODCACHE as /cachi2/output/deps/gomod/pkg/mod and GOPATH as /cachi2/output/deps/gomod, and update GOPROXY only if needed; modify the export of GOCACHE in the Dockerfile.cpu so it points to a distinct path from GOPATH/GOMODCACHE to isolate build cache from module cache.jupyter/datascience/ubi9-python-3.12/Dockerfile.konflux.cpu (2)
52-53: Duplicated GPG key import with silent failure.Same
|| truepattern in multiple stages. The repeated imports (lines 52-53, 95-97) could be consolidated into a single reusable script, and the silent failure handling should be reconsidered per the comment onDockerfile.cpu.Also applies to: 95-97
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@jupyter/datascience/ubi9-python-3.12/Dockerfile.konflux.cpu` around lines 52 - 53, The Dockerfile duplicates GPG key imports with a silent-failure "|| true" (seen in the RUN lines importing /cachi2/output/deps/generic/RPM-GPG-KEY-CentOS-Official and /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release and again at lines ~95-97); extract these import commands into a small reusable script (e.g., import-gpg-keys.sh) and call it from each stage, and remove the blanket "|| true" so the script performs explicit checks and logs or exits on failure (return non-zero) to surface errors instead of silencing them. Ensure the script idempotently checks for an existing key before importing to avoid duplicate failures.
1-187: Reduce Dockerfile duplication: consolidate with build-arg-controlled labels.These two Dockerfiles are 92% identical with only the LABEL section differing:
- Dockerfile.cpu: 189 lines
- Dockerfile.konflux.cpu: 187 lines
- 173 lines unchanged; 16 lines changed (all in LABEL block)
Both use identical Konflux/hermetic build logic (12 cachi2 references each, same [HERMETIC] patterns, identical LOCAL_BUILD behavior). The only variation is image naming/metadata:
- Dockerfile.cpu uses
odh-notebook-jupyter-datascience-ubi9-python-3.12and Quay.io registry- Dockerfile.konflux.cpu uses
rhoai/odh-workbench-jupyter-datascience-cpu-py312-rhel9and Red Hat license termsConsolidate into a single Dockerfile with a
BUILD_VARIANTorREGISTRY_TARGETbuild-arg to switch label values. This eliminates maintenance drift and avoids future misalignment between variants.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@jupyter/datascience/ubi9-python-3.12/Dockerfile.konflux.cpu` around lines 1 - 187, The Dockerfiles are nearly identical except for LABEL metadata; consolidate into one Dockerfile and drive variant-specific LABEL values via a build-arg (e.g., BUILD_VARIANT or REGISTRY_TARGET). Edit the existing Dockerfile.konflux.cpu/jupyter-datascience stage: introduce ARG BUILD_VARIANT (or REGISTRY_TARGET) near the top, replace the hard-coded LABEL block in the jupyter-datascience stage with conditional value selection based on that arg (set descriptive name, component, display-name, summary, description, license_terms) and default to the current konflux values; ensure Docker build invocation can pass the alternative variant to produce the other image. Keep all hermetic LOCAL_BUILD logic, mongocli-builder and stage names (mongocli-builder, cpu-base, jupyter-minimal, jupyter-datascience) unchanged so only LABELs are parameterized.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
@.tekton/odh-workbench-jupyter-datascience-cpu-py312-ubi9-odh-main-pull-request.yaml:
- Line 16: The CEL filter in the PR trigger is missing the shared meta-project
paths used by the datascience image; update the condition inside
".tekton/odh-workbench-jupyter-datascience-cpu-py312-ubi9-odh-main-pull-request.yaml"
so the OR list includes .pathChanged() checks for the three new projects:
"dependencies/odh-notebooks-meta-db-connectors-deps",
"dependencies/odh-notebooks-meta-jupyterlab-deps", and
"dependencies/odh-notebooks-meta-jupyterlab-datascience-deps" (add each as e.g.
"dependencies/odh-notebooks-meta-db-connectors-deps".pathChanged()) so a PR
touching any of those shared inputs will trigger the PipelineRun.
In @.tekton/odh-workbench-jupyter-datascience-cpu-py312-ubi9-odh-main-push.yaml:
- Line 11: The trigger's CEL expression for
pipelinesascode.tekton.dev/on-cel-expression omits the shared meta-project
directories that now affect jupyter/datascience/ubi9-python-3.12/pyproject.toml,
so add OR conditions to the existing pathChanged() list to include the
dependency projects (e.g.,
"dependencies/odh-notebooks-meta-db-connectors-deps".pathChanged(),
"dependencies/odh-notebooks-meta-jupyterlab-deps".pathChanged(), and
"dependencies/odh-notebooks-meta-jupyterlab-datascience-deps".pathChanged()) so
changes in those shared projects will also cause the PipelineRun to execute;
update the expression that currently lists the
jupyter/datascience/ubi9-python-3.12/** paths under the same OR group.
In `@jupyter/datascience/ubi9-python-3.12/Dockerfile.cpu`:
- Around line 52-53: The RUN command that imports the CentOS GPG key ("RUN rpm
--import /cachi2/output/deps/generic/RPM-GPG-KEY-CentOS-Official || true") is
silencing failures with "|| true"; remove the silent suppression and instead
ensure the build fails or logs a clear warning when the key is missing or
invalid. Replace the silent suppression by checking the key import result for
the "rpm --import /cachi2/output/deps/generic/RPM-GPG-KEY-CentOS-Official" step
(or test for file existence first) and emit a descriptive error/warning or exit
non‑zero so unsigned packages are not allowed; keep the second import ("RUN rpm
--import /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release") consistent with this
behavior.
In `@jupyter/datascience/ubi9-python-3.12/uv.lock.d/pylock.cpu.toml`:
- Around line 1874-1883: The "uv" package entry declares a broad marker
(implementation_name == 'cpython' and sys_platform == 'linux') but only supplies
wheels for linux_aarch64, linux_s390x and linux_x86_64; narrow the marker for
the uv package or add the missing ppc64le wheel: either change the uv
[[packages]] marker to explicitly restrict architectures (e.g. include
platform_machine in ("x86_64","aarch64","s390x")) so the resolver won't attempt
ppc64le, or add a wheels entry for linux_ppc64le with the correct URL,
upload-time, size and sha256 hash to match the other wheel entries. Ensure you
update the package block for name = "uv" and its wheels list accordingly.
In `@jupyter/minimal/ubi9-python-3.12/prefetch-input/odh/rpms.lock.yaml`:
- Around line 1428-1434: The python3-pip entry (name: python3-pip, evr:
21.3.1-1.el9) in the rpms.lock.yaml is vulnerable to CVE-2023-5752 for Mercurial
(hg+) installs; verify whether your build or downstreams actually perform
Mercurial VCS installs and, if they do, either (a) replace or override this
package with a non-vulnerable pip (version >=23.3 or vendor-supplied RHEL
backport when available) or (b) document and mitigate the risk by disabling VCS
installs or blocking hg+ URLs in your pipelines; update the lock entry or add a
clear comment/mitigation note referencing python3-pip 21.3.1 and CVE-2023-5752
accordingly.
In `@jupyter/minimal/ubi9-python-3.12/prefetch-input/rhds/rpms.in.yaml`:
- Line 43: The shared RPM manifest currently lists compiler and -devel packages
(e.g., unixODBC-devel) and an s390x toolchain block; remove those entries from
this shared runtime manifest and place them into an s390x-only builder manifest
or a dedicated build-stage manifest so they are only installed for the s390x
builder path; update the manifests referenced around the same section (also
applies to the package group in lines ~91-102) to ensure minimal runtime images
no longer include compilers/headers.
In `@jupyter/minimal/ubi9-python-3.12/prefetch-input/rhds/rpms.lock.yaml`:
- Around line 56-57: The lockfile rpms.lock.yaml contains many entries where the
URL architecture (e.g., "aarch64", "ppc64le", "s390x") does not match the
hardcoded repoid value "rhel-9-for-x86_64-appstream-rpms"; regenerate the
lockfile or update the repoid fields so each package entry's repoid corresponds
to the URL architecture (or remove repoid entirely if your consumer resolves
strictly from URL). Locate and fix the repoid key entries (search for "repoid"
and sample URLs like the autoconf URL) so that for each architecture block you
set the correct repository id (e.g., rhel-9-for-aarch64-appstream-rpms,
rhel-9-for-ppc64le-appstream-rpms, rhel-9-for-s390x-appstream-rpms) or strip
repoid generation in the producing script to avoid mismatches.
- Around line 17547-17560: The lockfile pins unversioned RHEL 9 Python packages
(entries named python3-devel and python3-pip with sourcerpm python3.9-...) into
the ubi9-python-3.12 variant; update the rpms.lock.yaml entries so they
reference version-matched Python 3.12 RPMs (e.g., replace
python3-devel/python3-pip entries whose sourcerpm starts with "python3.9-" or
"python-pip-" with the corresponding python3.12-devel/python3.12-pip RPMs and
correct repoid/checksum/evr), or remove them if they are only transitive
artifacts and must not be installed; after changing the lockfile, re-run the
provided verification script and grep the manifests/Dockerfiles (e.g.,
odh/rpms.in.yaml, Dockerfile.cpu, Dockerfile.konflux.cpu) to ensure no
references remain to python3-devel -> python3.9 or unversioned python3-pip so
native extensions will use Python 3.12 headers.
In `@jupyter/pytorch`+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml:
- Line 2: The lock-generation command uses the flag
--index-strategy=unsafe-best-match which can cause cross-index package selection
when mixing CUDA and CPU indexes; update the invocation that builds
uv.lock.d/pylock.cuda.toml to use --index-strategy=first-index (or alternatively
split CUDA/CPU index sets) so the resolver prefers the primary CUDA index
deterministically; locate the command string containing
--index-strategy=unsafe-best-match and replace it with
--index-strategy=first-index in the pylock generation invocation.
In `@jupyter/rocm/pytorch/ubi9-python-3.12/uv.lock.d/pylock.rocm.toml`:
- Line 2: The commented pip-compile command in pylock.rocm.toml uses
--index-strategy=unsafe-best-match which enables cross-index version selection;
update that flag to --index-strategy=first-index in the commented command (the
long uv pip compile invocation) so the resolver uses the first index containing
a package instead of unsafe-best-match.
In `@tests/browser/tests/openshift_console.spec.ts`:
- Around line 14-16: The call to customApi.getNamespacedCustomObject is using an
options object but the `@kubernetes/client-node` API expects positional arguments;
update the invocation of getNamespacedCustomObject (where route is assigned) to
pass the five parameters in order: group, version, namespace, plural, name
(i.e., 'route.openshift.io', 'v1', 'openshift-console', 'routes', 'console')
instead of the object form so the function signature matches the client library.
In `@tests/browser/tsconfig.json`:
- Line 4: The tsconfig setting "target": "es2025" is incompatible with the
Playwright/base Node.js 22 runtime; update the tsconfig.json target to "es2024"
(replace the "target": "es2025" entry) so TypeScript type-checks against the
actual runtime, or alternatively update the CI/Playwright base image to one that
includes Node.js 24+; edit the "target" field in tests/browser/tsconfig.json
(the "target" property) to ensure it matches the chosen runtime.
---
Outside diff comments:
In `@jupyter/pytorch`+llmcompressor/ubi9-python-3.12/Dockerfile.konflux.cuda:
- Around line 191-196: The pip install invocation using the UV wrapper (the
command starting with "UV_NO_CACHE=true UV_LINK_MODE=copy
UV_PREVIEW_FEATURES=pylock uv pip install ... --no-verify-hashes") disables
package hash verification; either enable strict hash checking by replacing
"--no-verify-hashes" with "--require-hashes" (and ensure ./requirements.txt /
pylock.toml contains hashes) or, if Cachi2 prefetching prevents exact hashes,
add a clear comment above this UV pip install line explaining why hashes are
intentionally omitted (describe the Cachi2 renaming/reprocessing behavior) so
future maintainers understand the tradeoff.
In `@runtimes/datascience/ubi9-python-3.12/Dockerfile.konflux.cpu`:
- Around line 123-124: The Dockerfile currently fetches the Elyra bootstrapper
at build time via the RUN curl line (downloading bootstrapper.py), which
violates hermetic build rules; replace that network fetch by vendoring or
prefetching the file into the build context and change the Dockerfile to use
COPY/ADD to bring ./utils/bootstrapper.py into the image instead of the curl
command. Ensure the repository contains the exact bootstrapper.py (or a pinned
vendor snapshot) and update the Dockerfile location that referenced the
bootstrapper (the RUN curl line) to a COPY ./utils/bootstrapper.py
./utils/bootstrapper.py so the image build no longer requires external network
access.
- Around line 97-101: The Dockerfile currently fetches the OpenShift client with
the curl/tar sequence (curl ... -o /tmp/openshift-client-linux.tar.gz; tar -xzvf
/tmp/openshift-client-linux.tar.gz; rm -f /tmp/openshift-client-linux.tar.gz),
which breaks hermetic builds; replace that block by installing the prefetched
openshift-clients RPM (package name openshift-clients) via dnf (e.g., dnf
install -y /path/to/prefetched/openshift-clients-*.rpm or dnf install -y
openshift-clients if the manifests repo is enabled) and remove the curl/tar
lines so the Dockerfile uses the pre-fetched RPM artifact instead of downloading
from mirror.openshift.com.
In `@tests/browser/tests/utils.ts`:
- Around line 31-45: The loop inside the Promise schedules a repeating
setInterval on every invocation causing exponential intervals; change the
scheduling call in the loop function to use window.setTimeout(loop, checkPeriod)
(single-shot) so only one delayed callback is queued each iteration, keep the
existing observer.disconnect()/resolve()/reject() logic intact, and ensure the
initial loop() call still starts the cycle; reference the loop function and the
observer variable in tests/browser/tests/utils.ts when making this change.
- Around line 38-41: The timeout branch can call reject() after the promise was
already resolved by the stability check; update the check handling so you exit
immediately after resolving or rejecting: after the stability branch that calls
resolve() when (now - mutated > checkPeriod) and after the timeout branch that
calls reject() when (now - started > timeout), add immediate returns (ensuring
observer.disconnect() is still called before the return) so no further checks
run and the promise cannot be settled twice; look for the uses of resolve(),
reject(), observer.disconnect(), now - mutated > checkPeriod and now - started >
timeout to locate the exact spots to update.
---
Nitpick comments:
In `@jupyter/datascience/ubi9-python-3.12/Dockerfile.cpu`:
- Around line 29-32: The current Dockerfile sets GOCACHE, GOMODCACHE and GOPATH
to overlapping locations which can cause cache pollution; change GOCACHE to a
separate directory (e.g., /cachi2/output/deps/gocache) while leaving GOMODCACHE
as /cachi2/output/deps/gomod/pkg/mod and GOPATH as /cachi2/output/deps/gomod,
and update GOPROXY only if needed; modify the export of GOCACHE in the
Dockerfile.cpu so it points to a distinct path from GOPATH/GOMODCACHE to isolate
build cache from module cache.
In `@jupyter/datascience/ubi9-python-3.12/Dockerfile.konflux.cpu`:
- Around line 52-53: The Dockerfile duplicates GPG key imports with a
silent-failure "|| true" (seen in the RUN lines importing
/cachi2/output/deps/generic/RPM-GPG-KEY-CentOS-Official and
/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release and again at lines ~95-97); extract
these import commands into a small reusable script (e.g., import-gpg-keys.sh)
and call it from each stage, and remove the blanket "|| true" so the script
performs explicit checks and logs or exits on failure (return non-zero) to
surface errors instead of silencing them. Ensure the script idempotently checks
for an existing key before importing to avoid duplicate failures.
- Around line 1-187: The Dockerfiles are nearly identical except for LABEL
metadata; consolidate into one Dockerfile and drive variant-specific LABEL
values via a build-arg (e.g., BUILD_VARIANT or REGISTRY_TARGET). Edit the
existing Dockerfile.konflux.cpu/jupyter-datascience stage: introduce ARG
BUILD_VARIANT (or REGISTRY_TARGET) near the top, replace the hard-coded LABEL
block in the jupyter-datascience stage with conditional value selection based on
that arg (set descriptive name, component, display-name, summary, description,
license_terms) and default to the current konflux values; ensure Docker build
invocation can pass the alternative variant to produce the other image. Keep all
hermetic LOCAL_BUILD logic, mongocli-builder and stage names (mongocli-builder,
cpu-base, jupyter-minimal, jupyter-datascience) unchanged so only LABELs are
parameterized.
In `@jupyter/minimal/ubi9-python-3.12/prefetch-input/odh/rpms.lock.yaml`:
- Around line 28-41: The rpms.lock.yaml adds build-toolchain packages (autoconf,
automake, cmake, libtool, m4, openblas-devel, pybind11-devel, gcc runtime libs)
which increase the attack surface of the "minimal" Jupyter image; either move
these packages out of the final runtime package list into a separate
build-stage/multi-stage image (so they are installed only during build and not
present in the final image) or, if they are required at runtime for
pip-installing native extensions, explicitly document that requirement in the
repo (e.g., in README or image documentation) and mark these entries as
build-time dependencies—update the entries for autoconf, automake, cmake,
libtool, m4, openblas-devel, pybind11-devel, and gcc-related packages
accordingly across the referenced sections (around lines 2240-2351) to reflect
the chosen approach.
In `@Makefile`:
- Around line 144-145: The Makefile sets GONOSUMDB when invoking go build for
the toolchain (GOTOOLCHAIN=auto) but GONOSUMDB is ignored for
golang.org/toolchain downloads and is misleading; remove the
GONOSUMDB=golang.org/toolchain assignment from the go build invocation (the line
that exports/uses GOTOOLCHAIN=auto and runs go build -C "scripts/buildinputs" -o
"$(ROOT_DIR)/$@" ./...), and if you need to support environments with
GOSUMDB=off, add an explicit guard or documented check that handles GOSUMDB
rather than relying on GONOSUMDB.
In `@runtimes/datascience/ubi9-python-3.12/Dockerfile.cpu`:
- Line 91: The RUN pip install line currently pins "uv==0.10.8" causing version
drift; update that package pin in the RUN command (the pip install statement
that includes "micropipenv[toml]==1.10.0" and "uv==0.10.8") to match the Konflux
Dockerfiles by changing "uv==0.10.8" to "uv==0.11.0" so all builds use the same
uv version.
In `@tests/browser/scripts/start_browser.ts`:
- Around line 62-70: The loop contains redundant null checks for the local
variable page (declared as Page | undefined) and for context?.pages()[0], which
can only be undefined; remove the === null checks and simplify the conditions to
check only undefined (e.g., use page === undefined or page !== undefined) and
likewise rely on optional chaining result being undefined, updating the while
condition and the if that returns page (references: page, started, timeout,
browser.contexts(), context?.pages()[0]).
In `@tests/browser/tests/codeserver.spec.ts`:
- Around line 40-46: Remove the unnecessary optional chaining on
codeServerSource (it is always provided) and replace the verbose IIFE throw with
a simple guard: in the codeServer fixture block, change "if
(codeServerSource?.url)" to "if (codeServerSource.url)" and replace the "const
image = codeServerSource.image ?? (() => { throw new Error('invalid config:
codeserver image not specified') })()" pattern with "const image =
codeServerSource.image; if (!image) throw new Error('invalid config: codeserver
image not specified')", keeping the rest of the logic using new CodeServer(page,
codeServerSource.url) intact.
- Around line 16-22: The MyFixtures type is duplicated; extract it into a single
shared types module named types.ts that exports the MyFixtures type (keeping the
connectCDP and codeServerSource union but removing the per-test-only codeServer
property), then remove the local MyFixtures definitions in both files and import
the shared type (import type { MyFixtures } from './types') in each place where
MyFixtures was previously declared so both tests reference the single canonical
type.
In `@tests/browser/tests/utils.ts`:
- Around line 13-14: Replace the function-scoped declarations using "var" for
the timing variables with block-scoped "let": change "var started =
performance.now();" and "var mutated = started;" to use "let" so that started
and mutated are block-scoped (update both declarations in
tests/browser/tests/utils.ts where these variables are defined).
🪄 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: Repository YAML (base), Central YAML (inherited), Repository UI (inherited)
Review profile: CHILL
Plan: Pro
Run ID: d59c8083-5a7e-461d-8ad4-da1ee75f0374
⛔ Files ignored due to path filters (2)
scripts/buildinputs/go.sumis excluded by!**/*.sum,!**/*.sumtests/browser/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (74)
.tekton/odh-workbench-jupyter-datascience-cpu-py312-ubi9-odh-main-pull-request.yaml.tekton/odh-workbench-jupyter-datascience-cpu-py312-ubi9-odh-main-push.yamlCONTRIBUTING.mdMakefilecodeserver/ubi9-python-3.12/uv.lock.d/pylock.cpu.tomldependencies/odh-notebooks-meta-db-connectors-deps/pyproject.tomldependencies/odh-notebooks-meta-jupyterlab-datascience-deps/pyproject.tomldependencies/odh-notebooks-meta-jupyterlab-deps/pyproject.tomljupyter/datascience/ubi9-python-3.12/Dockerfile.cpujupyter/datascience/ubi9-python-3.12/Dockerfile.konflux.cpujupyter/datascience/ubi9-python-3.12/prefetch-inputjupyter/datascience/ubi9-python-3.12/pyproject.tomljupyter/datascience/ubi9-python-3.12/requirements.cpu.txtjupyter/datascience/ubi9-python-3.12/uv.lock.d/pylock.cpu.tomljupyter/minimal/ubi9-python-3.12/prefetch-input/odh/rpms.in.yamljupyter/minimal/ubi9-python-3.12/prefetch-input/odh/rpms.lock.yamljupyter/minimal/ubi9-python-3.12/prefetch-input/rhds/rpms.in.yamljupyter/minimal/ubi9-python-3.12/prefetch-input/rhds/rpms.lock.yamljupyter/minimal/ubi9-python-3.12/pyproject.tomljupyter/minimal/ubi9-python-3.12/uv.lock.d/pylock.cpu.tomljupyter/minimal/ubi9-python-3.12/uv.lock.d/pylock.cuda.tomljupyter/minimal/ubi9-python-3.12/uv.lock.d/pylock.rocm.tomljupyter/pytorch+llmcompressor/ubi9-python-3.12/Dockerfile.cudajupyter/pytorch+llmcompressor/ubi9-python-3.12/Dockerfile.konflux.cudajupyter/pytorch+llmcompressor/ubi9-python-3.12/prefetch-input/odh/rpms.in.yamljupyter/pytorch+llmcompressor/ubi9-python-3.12/prefetch-input/odh/rpms.lock.yamljupyter/pytorch+llmcompressor/ubi9-python-3.12/prefetch-input/rhds/rpms.in.yamljupyter/pytorch+llmcompressor/ubi9-python-3.12/prefetch-input/rhds/rpms.lock.yamljupyter/pytorch+llmcompressor/ubi9-python-3.12/pyproject.tomljupyter/pytorch+llmcompressor/ubi9-python-3.12/requirements.cuda.txtjupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.tomljupyter/pytorch/ubi9-python-3.12/pyproject.tomljupyter/pytorch/ubi9-python-3.12/uv.lock.d/pylock.cuda.tomljupyter/rocm/pytorch/ubi9-python-3.12/pyproject.tomljupyter/rocm/pytorch/ubi9-python-3.12/uv.lock.d/pylock.rocm.tomljupyter/rocm/tensorflow/ubi9-python-3.12/pylock.tomljupyter/rocm/tensorflow/ubi9-python-3.12/pyproject.tomljupyter/tensorflow/ubi9-python-3.12/pyproject.tomljupyter/tensorflow/ubi9-python-3.12/uv.lock.d/pylock.cuda.tomljupyter/trustyai/ubi9-python-3.12/pyproject.tomljupyter/trustyai/ubi9-python-3.12/uv.lock.d/pylock.cpu.tomlpytest.inirstudio/c9s-python-3.12/uv.lock.d/pylock.cpu.tomlrstudio/c9s-python-3.12/uv.lock.d/pylock.cuda.tomlrstudio/rhel9-python-3.12/uv.lock.d/pylock.cpu.tomlrstudio/rhel9-python-3.12/uv.lock.d/pylock.cuda.tomlruntimes/datascience/ubi9-python-3.12/Dockerfile.cpuruntimes/datascience/ubi9-python-3.12/Dockerfile.konflux.cpuruntimes/datascience/ubi9-python-3.12/pyproject.tomlruntimes/datascience/ubi9-python-3.12/uv.lock.d/pylock.cpu.tomlruntimes/minimal/ubi9-python-3.12/uv.lock.d/pylock.cpu.tomlruntimes/pytorch+llmcompressor/ubi9-python-3.12/pyproject.tomlruntimes/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.tomlruntimes/pytorch/ubi9-python-3.12/pyproject.tomlruntimes/pytorch/ubi9-python-3.12/uv.lock.d/pylock.cuda.tomlruntimes/rocm-pytorch/ubi9-python-3.12/pyproject.tomlruntimes/rocm-pytorch/ubi9-python-3.12/uv.lock.d/pylock.rocm.tomlruntimes/rocm-tensorflow/ubi9-python-3.12/pylock.tomlruntimes/rocm-tensorflow/ubi9-python-3.12/pyproject.tomlruntimes/tensorflow/ubi9-python-3.12/pyproject.tomlruntimes/tensorflow/ubi9-python-3.12/uv.lock.d/pylock.cuda.tomlscripts/buildinputs/dockerfile.goscripts/buildinputs/go.modscripts/check-payload/go.modscripts/pylocks_generator.pytests/browser/package.json5tests/browser/playwright.config.tstests/browser/scripts/start_browser.tstests/browser/tests/codeserver.spec.tstests/browser/tests/openshift_console.spec.tstests/browser/tests/utils.tstests/browser/tsconfig.jsontests/conftest.pytests/containers/runtimes/runtime_test.py
👮 Files not reviewed due to content moderation or server errors (2)
- runtimes/rocm-tensorflow/ubi9-python-3.12/pylock.toml
- jupyter/rocm/tensorflow/ubi9-python-3.12/pylock.toml
| pipelinesascode.tekton.dev/on-comment: ^/kfbuild\s+(all|odh\-workbench\-jupyter\-datascience\-cpu\-py312\-ubi9|jupyter/datascience/ubi9\-python\-3\.12) | ||
| pipelinesascode.tekton.dev/on-cel-expression: | | ||
| event == "pull_request" && target_branch == "main" && !("manifests/base/params-latest.env".pathChanged()) && ( ".tekton/odh-workbench-jupyter-datascience-cpu-py312-ubi9-odh-main-pull-request.yaml".pathChanged() || "jupyter/utils/**".pathChanged() || "jupyter/datascience/ubi9-python-3.12/**".pathChanged() || "jupyter/datascience/ubi9-python-3.12/start-notebook.sh".pathChanged() || "jupyter/datascience/ubi9-python-3.12/build-args/cpu.conf".pathChanged() ) | ||
| event == "pull_request" && target_branch == "main" && !("manifests/base/params-latest.env".pathChanged()) && ( ".tekton/odh-workbench-jupyter-datascience-cpu-py312-ubi9-odh-main-pull-request.yaml".pathChanged() || "jupyter/utils/**".pathChanged() || "jupyter/datascience/ubi9-python-3.12/**".pathChanged() || "jupyter/datascience/ubi9-python-3.12/start-notebook.sh".pathChanged() || "jupyter/datascience/ubi9-python-3.12/build-args/cpu.conf".pathChanged() || "jupyter/minimal/ubi9-python-3.12/prefetch-input/odh/**".pathChanged() || "jupyter/pytorch+llmcompressor/ubi9-python-3.12/prefetch-input/mongocli/**".pathChanged() ) |
There was a problem hiding this comment.
Add the new shared meta-project paths to this PR trigger.
The datascience image now consumes local dependencies/odh-notebooks-meta-{db-connectors,jupyterlab,jupyterlab-datascience}-deps projects, but this PR CEL filter still ignores those paths. A PR that only changes one of those shared inputs will not run this PipelineRun for the image that depends on it.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
@.tekton/odh-workbench-jupyter-datascience-cpu-py312-ubi9-odh-main-pull-request.yaml
at line 16, The CEL filter in the PR trigger is missing the shared meta-project
paths used by the datascience image; update the condition inside
".tekton/odh-workbench-jupyter-datascience-cpu-py312-ubi9-odh-main-pull-request.yaml"
so the OR list includes .pathChanged() checks for the three new projects:
"dependencies/odh-notebooks-meta-db-connectors-deps",
"dependencies/odh-notebooks-meta-jupyterlab-deps", and
"dependencies/odh-notebooks-meta-jupyterlab-datascience-deps" (add each as e.g.
"dependencies/odh-notebooks-meta-db-connectors-deps".pathChanged()) so a PR
touching any of those shared inputs will trigger the PipelineRun.
| pipelinesascode.tekton.dev/max-keep-runs: '3' | ||
| build.appstudio.openshift.io/build-nudge-files: manifests/base/params-latest.env | ||
| pipelinesascode.tekton.dev/on-cel-expression: event == "push" && target_branch == "main" && !("manifests/base/params-latest.env".pathChanged()) && ( ".tekton/odh-workbench-jupyter-datascience-cpu-py312-ubi9-odh-main-push.yaml".pathChanged() || "jupyter/utils/**".pathChanged() || "jupyter/datascience/ubi9-python-3.12/**".pathChanged() || "jupyter/datascience/ubi9-python-3.12/start-notebook.sh".pathChanged() || "jupyter/datascience/ubi9-python-3.12/build-args/cpu.conf".pathChanged() ) | ||
| pipelinesascode.tekton.dev/on-cel-expression: event == "push" && target_branch == "main" && !("manifests/base/params-latest.env".pathChanged()) && ( ".tekton/odh-workbench-jupyter-datascience-cpu-py312-ubi9-odh-main-push.yaml".pathChanged() || "jupyter/utils/**".pathChanged() || "jupyter/datascience/ubi9-python-3.12/**".pathChanged() || "jupyter/datascience/ubi9-python-3.12/start-notebook.sh".pathChanged() || "jupyter/datascience/ubi9-python-3.12/build-args/cpu.conf".pathChanged() || "jupyter/minimal/ubi9-python-3.12/prefetch-input/odh/**".pathChanged() || "jupyter/pytorch+llmcompressor/ubi9-python-3.12/prefetch-input/mongocli/**".pathChanged() ) |
There was a problem hiding this comment.
Add the new shared meta-project paths to this trigger.
jupyter/datascience/ubi9-python-3.12/pyproject.toml now resolves through local dependencies/odh-notebooks-meta-{db-connectors,jupyterlab,jupyterlab-datascience}-deps projects, but this CEL filter still ignores those directories. If one of those shared projects changes without a matching edit under jupyter/datascience/ubi9-python-3.12/**, this PipelineRun never executes for the consuming image.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.tekton/odh-workbench-jupyter-datascience-cpu-py312-ubi9-odh-main-push.yaml
at line 11, The trigger's CEL expression for
pipelinesascode.tekton.dev/on-cel-expression omits the shared meta-project
directories that now affect jupyter/datascience/ubi9-python-3.12/pyproject.toml,
so add OR conditions to the existing pathChanged() list to include the
dependency projects (e.g.,
"dependencies/odh-notebooks-meta-db-connectors-deps".pathChanged(),
"dependencies/odh-notebooks-meta-jupyterlab-deps".pathChanged(), and
"dependencies/odh-notebooks-meta-jupyterlab-datascience-deps".pathChanged()) so
changes in those shared projects will also cause the PipelineRun to execute;
update the expression that currently lists the
jupyter/datascience/ubi9-python-3.12/** paths under the same OR group.
| RUN rpm --import /cachi2/output/deps/generic/RPM-GPG-KEY-CentOS-Official || true | ||
| RUN rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release |
There was a problem hiding this comment.
Silent failure on GPG key import may mask integrity issues.
|| true suppresses errors if the CentOS GPG key is missing or corrupt. This could allow unsigned packages to be installed without detection. Consider logging a warning or failing explicitly in production builds.
Proposed fix
-RUN rpm --import /cachi2/output/deps/generic/RPM-GPG-KEY-CentOS-Official || true
+RUN rpm --import /cachi2/output/deps/generic/RPM-GPG-KEY-CentOS-Official || echo "Warning: CentOS GPG key not found, skipping"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| RUN rpm --import /cachi2/output/deps/generic/RPM-GPG-KEY-CentOS-Official || true | |
| RUN rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release | |
| RUN rpm --import /cachi2/output/deps/generic/RPM-GPG-KEY-CentOS-Official || echo "Warning: CentOS GPG key not found, skipping" | |
| RUN rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@jupyter/datascience/ubi9-python-3.12/Dockerfile.cpu` around lines 52 - 53,
The RUN command that imports the CentOS GPG key ("RUN rpm --import
/cachi2/output/deps/generic/RPM-GPG-KEY-CentOS-Official || true") is silencing
failures with "|| true"; remove the silent suppression and instead ensure the
build fails or logs a clear warning when the key is missing or invalid. Replace
the silent suppression by checking the key import result for the "rpm --import
/cachi2/output/deps/generic/RPM-GPG-KEY-CentOS-Official" step (or test for file
existence first) and emit a descriptive error/warning or exit non‑zero so
unsigned packages are not allowed; keep the second import ("RUN rpm --import
/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release") consistent with this behavior.
| [[packages]] | ||
| name = "uv" | ||
| version = "0.11.0" | ||
| marker = "implementation_name == 'cpython' and sys_platform == 'linux'" | ||
| wheels = [ | ||
| { url = "https://packages.redhat.com/api/pulp-content/public-rhai/rhoai/3.4/cpu-ubi9/uv-0.11.0-2-py3-none-linux_aarch64.whl", upload-time = 2026-03-24T11:53:57Z, size = 22442657, hashes = { sha256 = "f902f3d954de9e0e39c7eeb058c2da250c7d809b173130ff087bfe99a137edb2" } }, | ||
| { url = "https://packages.redhat.com/api/pulp-content/public-rhai/rhoai/3.4/cpu-ubi9/uv-0.11.0-2-py3-none-linux_s390x.whl", upload-time = 2026-03-24T12:35:51Z, size = 27179975, hashes = { sha256 = "a259a9095423a02688578766e27ea749eb675f3f5ca762468384413e2fd8393e" } }, | ||
| { url = "https://packages.redhat.com/api/pulp-content/public-rhai/rhoai/3.4/cpu-ubi9/uv-0.11.0-2-py3-none-linux_x86_64.whl", upload-time = 2026-03-24T11:54:56Z, size = 23969786, hashes = { sha256 = "85055bffcaef68f91a7965d2ad014e0557107e452cc432dcd855c715084f6715" } }, | ||
| ] | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify lock intent vs uv wheel coverage in this file.
# Expected: if ppc64le is a target in this lock, uv should either provide ppc64le wheel
# or its marker should explicitly exclude ppc64le.
python - <<'PY'
from pathlib import Path
import re
p = Path("jupyter/datascience/ubi9-python-3.12/uv.lock.d/pylock.cpu.toml")
txt = p.read_text()
# Check if lock appears multi-arch (ppc64le wheels present at all)
multi_arch_ppc = "linux_ppc64le.whl" in txt
# Extract uv package block
m = re.search(r"\[\[packages\]\]\nname = \"uv\".*?(?=\n\[\[packages\]\]|\Z)", txt, re.S)
if not m:
print("uv package block not found")
raise SystemExit(1)
block = m.group(0)
has_uv_ppc = "linux_ppc64le.whl" in block
marker = re.search(r"marker = \"([^\"]+)\"", block)
marker = marker.group(1) if marker else "<missing>"
print("lock_has_ppc64le_anywhere:", multi_arch_ppc)
print("uv_has_ppc64le_wheel:", has_uv_ppc)
print("uv_marker:", marker)
if multi_arch_ppc and (not has_uv_ppc) and ("ppc64le" not in marker):
print("FAIL: uv marker is too broad for declared wheel set.")
raise SystemExit(2)
print("PASS")
PYRepository: opendatahub-io/notebooks
Length of output: 252
Constrain uv marker to supported arches or add missing wheel coverage
Line 1877 declares uv for all Linux CPython targets, but wheels are provided only for linux_aarch64, linux_s390x, and linux_x86_64 (Lines 1879–1881). Since the lock file includes linux_ppc64le wheels for other packages, installation on ppc64le will fail during dependency resolution.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@jupyter/datascience/ubi9-python-3.12/uv.lock.d/pylock.cpu.toml` around lines
1874 - 1883, The "uv" package entry declares a broad marker (implementation_name
== 'cpython' and sys_platform == 'linux') but only supplies wheels for
linux_aarch64, linux_s390x and linux_x86_64; narrow the marker for the uv
package or add the missing ppc64le wheel: either change the uv [[packages]]
marker to explicitly restrict architectures (e.g. include platform_machine in
("x86_64","aarch64","s390x")) so the resolver won't attempt ppc64le, or add a
wheels entry for linux_ppc64le with the correct URL, upload-time, size and
sha256 hash to match the other wheel entries. Ensure you update the package
block for name = "uv" and its wheels list accordingly.
| - url: https://cdn-ubi.redhat.com/content/public/ubi/dist/ubi9/9/aarch64/appstream/os/Packages/p/python3-pip-21.3.1-1.el9.noarch.rpm | ||
| repoid: ubi-9-for-aarch64-appstream-rpms | ||
| size: 2133958 | ||
| checksum: sha256:2ff41d5bbfb5bf09378a499b56d9854e9389e3a8648897426d144f4b385f8730 | ||
| name: python3-pip | ||
| evr: 21.3.1-1.el9 | ||
| sourcerpm: python-pip-21.3.1-1.el9.src.rpm |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check pip security advisories
gh api graphql -f query='
{
securityVulnerabilities(first: 10, ecosystem: PIP, package: "pip") {
nodes {
advisory {
summary
severity
publishedAt
identifiers {
type
value
}
}
vulnerableVersionRange
firstPatchedVersion {
identifier
}
}
}
}'Repository: opendatahub-io/notebooks
Length of output: 228
🌐 Web query:
CVE-2023-5752 pip wheel command injection vulnerability
💡 Result:
CVE-2023-5752 is a command injection vulnerability in pip versions prior to 23.3. It affects users installing packages from Mercurial VCS URLs (e.g., "pip install hg+..."). The specified Mercurial revision can inject arbitrary "--config" options into the "hg clone" command, allowing control over the repository cloned and installed. This does not impact users not using Mercurial installs. CVSS v3.1 base scores: NIST 3.3 (Low, AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N); PSF 5.5 (Medium, AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N). Fixed in pip 23.3 via pypa/pip#12306. Upgrade to pip 23.3 or later. Official advisory: https://mail.python.org/archives/list/security-announce@python.org/thread/F4PL35U6X4VVHZ5ILJU3PWUWN7H7LZXL/. No public exploits known; low real-world risk as Mercurial usage is rare.
Citations:
- 1: https://nvd.nist.gov/vuln/detail/cve-2023-5752
- 2: https://security.snyk.io/vuln/SNYK-PYTHON-PIP-6036008
- 3: https://advisories.gitlab.com/pkg/pypi/pip/CVE-2023-5752
- 4: Release 23.3 pypa/pip#12296
- 5: https://data.safetycli.com/packages/pypi/pip/changelog?page=4
- 6: https://raw.githubusercontent.com/pypa/pip/master/NEWS.rst
🏁 Script executed:
#!/bin/bash
# Get context about the lock file and check if RHEL packages mention backported patches
head -20 jupyter/minimal/ubi9-python-3.12/prefetch-input/odh/rpms.lock.yamlRepository: opendatahub-io/notebooks
Length of output: 988
🏁 Script executed:
#!/bin/bash
# Search for any documentation about this lock file and its purpose
find . -type f \( -name "*.md" -o -name "*.txt" -o -name "README*" \) | xargs grep -l "rpms.lock" 2>/dev/null | head -5Repository: opendatahub-io/notebooks
Length of output: 172
🌐 Web query:
RHEL 9 python3-pip 21.3.1 security patches backport CVE
💡 Result:
In RHEL 9, the python3-pip package provides pip version 21.3.1, which is backpatched with security fixes following Red Hat's standard backporting practice for maintaining older versions with isolated security patches. Confirmed security backports include RHSA-2023:6694 for CVE-2007-4559 (tarfile directory traversal vulnerability), where Red Hat backported the fix to the pip 21.x series used in RHEL 9. The RHBA-2024:9321 advisory confirms python3-pip remains at version 21.3.1-1.el9 as of RHEL 9.5. Amazon Linux 2023 (RHEL 9 derivative) also backported CVE-2025-8869 to python3-pip 21.3.1-2.amzn2023.0.14, demonstrating the approach for this version. Red Hat does not upgrade pip to newer upstream versions to preserve stability and compatibility; instead, they backport fixes as needed throughout the RHEL 9 lifecycle (until May 2032). No comprehensive list of all backported CVEs specific to python3-pip 21.3.1 was found in public errata up to 2026-04-01, but users should apply all relevant RHSA updates via dnf update python3-pip to ensure the latest backports are installed. Check https://access.redhat.com/errata/search/?q=python3-pip for the latest advisories.
Citations:
- 1: https://access.redhat.com/security/updates/backporting
- 2: https://www.tenable.com/plugins/nessus/185137
- 3: https://access.redhat.com/errata/RHBA-2024:9321
- 4: https://lwn.net/Articles/950643/
- 5: https://errata.almalinux.org/9/ALSA-2023-6694.html
- 6: https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/considerations_in_adopting_rhel_9/assembly_changes-to-packages_considerations-in-adopting-rhel-9
- 7: https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/considerations_in_adopting_rhel_9/assembly_dynamic-programming-languages-web-servers-database-servers_considerations-in-adopting-rhel-9
- 8: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/installing_and_using_dynamic_programming_languages/index
🏁 Script executed:
#!/bin/bash
# Check the lock file's README to understand its purpose and update mechanism
cat scripts/lockfile-generators/README.mdRepository: opendatahub-io/notebooks
Length of output: 39644
🌐 Web query:
RHEL 9 python3-pip CVE-2023-5752 RHSA errata backport fix
💡 Result:
No, there is no RHSA errata providing a backport fix for CVE-2023-5752 in the RHEL 9 python3-pip package. The CVE is tracked in Red Hat Bugzilla (ID 2250765) with status NEW (as of 2025-09-15), indicating it remains unaddressed in RHEL products. It is fixed upstream in pip 23.3 and backported in Fedora (e.g., python-pip-23.3.2), but no specific RHSA for RHEL 9 python3-pip addresses this CVE. RHSA-2024:3781 addresses it in Red Hat Ansible Automation Platform 2.4 for RHEL 9 (BZ 2250765 listed in fixes), but not the base OS python3-pip package. As of 2026-04-01, RHEL 9 users should avoid installing packages from Mercurial VCS URLs with pip or upgrade pip via other means if possible, pending an official fix.
Citations:
- 1: https://bugzilla.redhat.com/show_bug.cgi?id=2250765
- 2: https://access.redhat.com/errata/RHSA-2024:3781
- 3: https://access.redhat.com/security/cve/cve-2023-5752
- 4: https://bugzilla.redhat.com/show_bug.cgi?id=2263291
- 5: https://www.tenable.com/cve/CVE-2023-5752/plugins
CVE-2023-5752 is unfixed in RHEL 9's python3-pip 21.3.1; verify necessity of Mercurial VCS installs.
CVE-2023-5752 (Mercurial VCS command injection, not wheel injection as originally stated) affects pip <23.3 and remains unpatched in RHEL 9 (Bugzilla 2250765: status NEW). However, the attack surface is narrow: only users installing packages directly from Mercurial URLs (e.g., pip install hg+...) are at risk, and no public exploits exist (CVSS 3.3 Low).
This lock file is RHEL-vendor-controlled; pip 21.3.1 is intentionally maintained via selective backports for stability. If Mercurial installs are not used in your build or downstream, this is a low-risk issue. If they are needed, consider evaluating whether RHEL 9.6+ includes a future backport or if an alternate package source can mitigate the risk.
Also applies to: 6479-6485, 11558-11564, 16602-16608
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@jupyter/minimal/ubi9-python-3.12/prefetch-input/odh/rpms.lock.yaml` around
lines 1428 - 1434, The python3-pip entry (name: python3-pip, evr: 21.3.1-1.el9)
in the rpms.lock.yaml is vulnerable to CVE-2023-5752 for Mercurial (hg+)
installs; verify whether your build or downstreams actually perform Mercurial
VCS installs and, if they do, either (a) replace or override this package with a
non-vulnerable pip (version >=23.3 or vendor-supplied RHEL backport when
available) or (b) document and mitigate the risk by disabling VCS installs or
blocking hg+ URLs in your pipelines; update the lock entry or add a clear
comment/mitigation note referencing python3-pip 21.3.1 and CVE-2023-5752
accordingly.
| - url: https://cdn.redhat.com/content/dist/rhel9/9.6/x86_64/appstream/os/Packages/p/python3-devel-3.9.21-2.el9_6.2.x86_64.rpm | ||
| repoid: rhel-9-for-x86_64-appstream-rpms | ||
| size: 249990 | ||
| checksum: sha256:11f8ba100e932d42a3204b0ee08c51fbdbc5b9434df07ebb156e369ea2979df4 | ||
| name: python3-devel | ||
| evr: 3.9.21-2.el9_6.2 | ||
| sourcerpm: python3.9-3.9.21-2.el9_6.2.src.rpm | ||
| - url: https://cdn.redhat.com/content/dist/rhel9/9.6/x86_64/appstream/os/Packages/p/python3-pip-21.3.1-1.el9.noarch.rpm | ||
| repoid: rhel-9-for-x86_64-appstream-rpms | ||
| size: 2133958 | ||
| checksum: sha256:2ff41d5bbfb5bf09378a499b56d9854e9389e3a8648897426d144f4b385f8730 | ||
| name: python3-pip | ||
| evr: 21.3.1-1.el9 | ||
| sourcerpm: python-pip-21.3.1-1.el9.src.rpm |
There was a problem hiding this comment.
Don’t pin the unversioned Python 3.9 RPM stack in a ubi9-python-3.12 lockfile.
This variant is for Python 3.12, but these additions resolve to the unversioned RHEL 9 Python stack, including python3-devel from python3.9-3.9.21-2.el9_6.2.src.rpm. If these RPMs are installed during build, native extensions and tooling can pick up 3.9 headers/site-packages instead of 3.12. Use version-matched 3.12 RPMs, or verify these are only prefetched transitive artifacts that never get installed.
Run this to confirm the lock is pulling 3.9 RPMs and to inspect the related input manifests/Dockerfiles for versioned 3.12 package usage:
#!/bin/bash
set -euo pipefail
python - <<'PY'
from pathlib import Path
path = Path("jupyter/minimal/ubi9-python-3.12/prefetch-input/rhds/rpms.lock.yaml")
targets = {
"name: python3-devel",
"name: python3-pip",
"name: python3-setuptools",
}
print("lockfile hits:")
text = path.read_text().splitlines()
for lineno, raw in enumerate(text, 1):
line = raw.strip()
if (
line in targets
or line.startswith("sourcerpm: python3.9-")
or line.startswith("sourcerpm: python-pip-")
or line.startswith("sourcerpm: python-setuptools-")
):
print(f"{lineno}: {line}")
full = "\n".join(text)
print(f"\ncontains python3.12-devel in lockfile: {'python3.12-devel' in full}")
PY
for p in \
"jupyter/minimal/ubi9-python-3.12/prefetch-input/odh/rpms.in.yaml" \
"runtimes/datascience/ubi9-python-3.12/Dockerfile.cpu" \
"jupyter/pytorch+llmcompressor/ubi9-python-3.12/Dockerfile.konflux.cpu"
do
if [ -f "$p" ]; then
echo "== $p =="
rg -n -C2 'python3-devel|python3\.12-devel|python3-pip|python3\.12-pip|python3-setuptools|python3\.12-setuptools|pybind11-devel' "$p" || true
fi
doneAlso applies to: 19934-19940
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@jupyter/minimal/ubi9-python-3.12/prefetch-input/rhds/rpms.lock.yaml` around
lines 17547 - 17560, The lockfile pins unversioned RHEL 9 Python packages
(entries named python3-devel and python3-pip with sourcerpm python3.9-...) into
the ubi9-python-3.12 variant; update the rpms.lock.yaml entries so they
reference version-matched Python 3.12 RPMs (e.g., replace
python3-devel/python3-pip entries whose sourcerpm starts with "python3.9-" or
"python-pip-" with the corresponding python3.12-devel/python3.12-pip RPMs and
correct repoid/checksum/evr), or remove them if they are only transitive
artifacts and must not be installed; after changing the lockfile, re-run the
provided verification script and grep the manifests/Dockerfiles (e.g.,
odh/rpms.in.yaml, Dockerfile.cpu, Dockerfile.konflux.cpu) to ensure no
references remain to python3-devel -> python3.9 or unversioned python3-pip so
native extensions will use Python 3.12 headers.
| @@ -1,5 +1,5 @@ | |||
| # This file was autogenerated by uv via the following command: | |||
| # uv pip compile pyproject.toml --output-file uv.lock.d/pylock.cuda.toml --format pylock.toml --generate-hashes --emit-index-url --python-version=3.12 --universal --no-annotate --no-emit-package odh-notebooks-meta-llmcompressor-deps --no-emit-package odh-notebooks-meta-runtime-elyra-deps --no-emit-package odh-notebooks-meta-runtime-datascience-deps --no-emit-package odh-notebooks-meta-workbench-datascience-deps --constraints ../../../dependencies/cve-constraints.txt --exclude-newer=2026-03-31T09:07:59Z --default-index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cuda12.9-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cuda12.9-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cpu-ubi9/simple/?format=json --index-strategy=unsafe-best-match | |||
| # uv pip compile pyproject.toml --output-file uv.lock.d/pylock.cuda.toml --format pylock.toml --generate-hashes --emit-index-url --python-version=3.12 --universal --no-annotate --no-emit-package odh-notebooks-meta-db-connectors-deps --no-emit-package odh-notebooks-meta-jupyterlab-datascience-deps --no-emit-package odh-notebooks-meta-jupyterlab-deps --no-emit-package odh-notebooks-meta-llmcompressor-deps --no-emit-package odh-notebooks-meta-runtime-elyra-deps --no-emit-package odh-notebooks-meta-runtime-datascience-deps --no-emit-package odh-notebooks-meta-workbench-datascience-deps --constraints ../../../dependencies/cve-constraints.txt --exclude-newer=2026-03-31T14:27:32Z --default-index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cuda12.9-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cuda12.9-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cpu-ubi9/simple/?format=json --index-strategy=unsafe-best-match | |||
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Find CUDA lockfiles that still use unsafe index strategy
rg -n --fixed-strings -- '--index-strategy=unsafe-best-match' '**/uv.lock.d/pylock.cuda.toml' || true
# 2) Detect whether any CUDA lock actually resolved packages from cpu index
rg -n '/cpu-ubi9/' '**/uv.lock.d/pylock.cuda.toml' || true
# Expected:
# - No unsafe-best-match in CUDA lock generation commands.
# - No /cpu-ubi9/ package URLs in CUDA locks.Repository: opendatahub-io/notebooks
Length of output: 207
🏁 Script executed:
#!/bin/bash
# Find actual lock file paths
fd -t f "pylock.cuda.toml" || echo "Pattern: no pylock.cuda.toml found"
# Also check the directory structure
fd -t d "uv.lock.d" | head -20
# Check if the directory mentioned exists
[ -d "jupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d" ] && echo "DIR EXISTS" || echo "DIR DOES NOT EXIST"Repository: opendatahub-io/notebooks
Length of output: 1381
🏁 Script executed:
#!/bin/bash
# Read the first 5 lines of the specific file to see line 2
echo "=== Target file line 2 ==="
head -n 5 jupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml | cat -n
# Search for unsafe-best-match in ALL cuda lock files
echo -e "\n=== Searching for unsafe-best-match in CUDA locks ==="
rg -l 'unsafe-best-match' '**/uv.lock.d/pylock.cuda.toml' || echo "No matches found"
# Count how many CUDA locks have this pattern
echo -e "\n=== Count of unsafe-best-match in CUDA locks ==="
rg 'unsafe-best-match' '**/uv.lock.d/pylock.cuda.toml' 2>/dev/null | wc -l
# Search for cpu-ubi9 references in the target CUDA lock
echo -e "\n=== Checking for cpu-ubi9 references in target CUDA lock ==="
rg '/cpu-ubi9/' jupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml | head -5 || echo "No cpu-ubi9 found"Repository: opendatahub-io/notebooks
Length of output: 2577
🏁 Script executed:
#!/bin/bash
# Check if any actual package URLs in the lock file use /cpu-ubi9/
echo "=== Actual packages from cpu-ubi9 in target CUDA lock ==="
rg '/cpu-ubi9/' jupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml --invert-match '^\s*#' | head -10 || echo "No packages from cpu-ubi9 index found"
# Get line count of the file
wc -l jupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml
# Count packages from each index
echo -e "\n=== Package sources in CUDA lock ==="
echo "CUDA packages:"
rg 'url = "https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cuda' jupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml | wc -l
echo "CPU packages:"
rg 'url = "https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cpu' jupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml | wc -lRepository: opendatahub-io/notebooks
Length of output: 1640
🏁 Script executed:
#!/bin/bash
# More careful search for CPU vs CUDA packages
echo "=== Checking package URLs in lock file ==="
rg 'url = "' jupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml | head -20
# Check if any packages are actually from cpu-ubi9
echo -e "\n=== CPU packages found? ==="
grep -c 'cpu-ubi9' jupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml || echo "0"
# Check CUDA packages
echo -e "\n=== CUDA packages found? ==="
grep -c 'cuda12.9' jupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml || echo "0"
# Check if this is a recent change or pre-existing
echo -e "\n=== Check git history if available ==="
cd jupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d && git log -1 --oneline pylock.cuda.toml 2>/dev/null || echo "No git history available"Repository: opendatahub-io/notebooks
Length of output: 5974
🏁 Script executed:
#!/bin/bash
# Check git status and recent changes to this file
git diff HEAD~1 jupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml --stat 2>/dev/null || echo "No diff available"
# Check if file is in the current PR changes
git status jupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml 2>/dev/null || echo "Git status check failed"
# Check last few commits that touch this file
git log --oneline -10 -- jupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml 2>/dev/null | head -5 || echo "No history"
# Check if unsafe-best-match appears anywhere in LOCK files (not just CUDA)
echo -e "\n=== unsafe-best-match in all pylock files ==="
find . -name 'pylock.*.toml' -exec grep -l 'unsafe-best-match' {} \; | head -20 || echo "None found"Repository: opendatahub-io/notebooks
Length of output: 1073
Replace unsafe-best-match with first-index in lock generation to prevent cross-index dependency confusion (CWE-829).
Line 2 uses --index-strategy=unsafe-best-match while mixing CUDA and CPU indexes. With unsafe-best-match, if a higher-version package appears on the secondary CPU index during future regeneration, the resolver will select it over the CUDA variant, poisoning the lock. Use --index-strategy=first-index to enforce deterministic CUDA-first resolution, or split locks by index class. This pattern affects 12+ lock files system-wide (CUDA and ROCM variants).
Suggested change
-# uv pip compile pyproject.toml --output-file uv.lock.d/pylock.cuda.toml --format pylock.toml --generate-hashes --emit-index-url --python-version=3.12 --universal --no-annotate --no-emit-package odh-notebooks-meta-db-connectors-deps --no-emit-package odh-notebooks-meta-jupyterlab-datascience-deps --no-emit-package odh-notebooks-meta-jupyterlab-deps --no-emit-package odh-notebooks-meta-llmcompressor-deps --no-emit-package odh-notebooks-meta-runtime-elyra-deps --no-emit-package odh-notebooks-meta-runtime-datascience-deps --no-emit-package odh-notebooks-meta-workbench-datascience-deps --constraints ../../../dependencies/cve-constraints.txt --exclude-newer=2026-03-31T14:27:32Z --default-index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cuda12.9-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cuda12.9-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cpu-ubi9/simple/?format=json --index-strategy=unsafe-best-match
+# uv pip compile pyproject.toml --output-file uv.lock.d/pylock.cuda.toml --format pylock.toml --generate-hashes --emit-index-url --python-version=3.12 --universal --no-annotate --no-emit-package odh-notebooks-meta-db-connectors-deps --no-emit-package odh-notebooks-meta-jupyterlab-datascience-deps --no-emit-package odh-notebooks-meta-jupyterlab-deps --no-emit-package odh-notebooks-meta-llmcompressor-deps --no-emit-package odh-notebooks-meta-runtime-elyra-deps --no-emit-package odh-notebooks-meta-runtime-datascience-deps --no-emit-package odh-notebooks-meta-workbench-datascience-deps --constraints ../../../dependencies/cve-constraints.txt --exclude-newer=2026-03-31T14:27:32Z --default-index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cuda12.9-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cuda12.9-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cpu-ubi9/simple/?format=json --index-strategy=first-index📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # uv pip compile pyproject.toml --output-file uv.lock.d/pylock.cuda.toml --format pylock.toml --generate-hashes --emit-index-url --python-version=3.12 --universal --no-annotate --no-emit-package odh-notebooks-meta-db-connectors-deps --no-emit-package odh-notebooks-meta-jupyterlab-datascience-deps --no-emit-package odh-notebooks-meta-jupyterlab-deps --no-emit-package odh-notebooks-meta-llmcompressor-deps --no-emit-package odh-notebooks-meta-runtime-elyra-deps --no-emit-package odh-notebooks-meta-runtime-datascience-deps --no-emit-package odh-notebooks-meta-workbench-datascience-deps --constraints ../../../dependencies/cve-constraints.txt --exclude-newer=2026-03-31T14:27:32Z --default-index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cuda12.9-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cuda12.9-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cpu-ubi9/simple/?format=json --index-strategy=unsafe-best-match | |
| # uv pip compile pyproject.toml --output-file uv.lock.d/pylock.cuda.toml --format pylock.toml --generate-hashes --emit-index-url --python-version=3.12 --universal --no-annotate --no-emit-package odh-notebooks-meta-db-connectors-deps --no-emit-package odh-notebooks-meta-jupyterlab-datascience-deps --no-emit-package odh-notebooks-meta-jupyterlab-deps --no-emit-package odh-notebooks-meta-llmcompressor-deps --no-emit-package odh-notebooks-meta-runtime-elyra-deps --no-emit-package odh-notebooks-meta-runtime-datascience-deps --no-emit-package odh-notebooks-meta-workbench-datascience-deps --constraints ../../../dependencies/cve-constraints.txt --exclude-newer=2026-03-31T14:27:32Z --default-index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cuda12.9-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cuda12.9-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cpu-ubi9/simple/?format=json --index-strategy=first-index |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@jupyter/pytorch`+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml at
line 2, The lock-generation command uses the flag
--index-strategy=unsafe-best-match which can cause cross-index package selection
when mixing CUDA and CPU indexes; update the invocation that builds
uv.lock.d/pylock.cuda.toml to use --index-strategy=first-index (or alternatively
split CUDA/CPU index sets) so the resolver prefers the primary CUDA index
deterministically; locate the command string containing
--index-strategy=unsafe-best-match and replace it with
--index-strategy=first-index in the pylock generation invocation.
| @@ -1,5 +1,5 @@ | |||
| # This file was autogenerated by uv via the following command: | |||
| # uv pip compile pyproject.toml --output-file uv.lock.d/pylock.rocm.toml --format pylock.toml --generate-hashes --emit-index-url --python-version=3.12 --universal --no-annotate --no-emit-package odh-notebooks-meta-llmcompressor-deps --no-emit-package odh-notebooks-meta-runtime-elyra-deps --no-emit-package odh-notebooks-meta-runtime-datascience-deps --no-emit-package odh-notebooks-meta-workbench-datascience-deps --constraints ../../../../dependencies/cve-constraints.txt --exclude-newer=2026-03-31T09:07:59Z --default-index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/rocm6.4-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/rocm6.4-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cpu-ubi9/simple/?format=json --index-strategy=unsafe-best-match | |||
| # uv pip compile pyproject.toml --output-file uv.lock.d/pylock.rocm.toml --format pylock.toml --generate-hashes --emit-index-url --python-version=3.12 --universal --no-annotate --no-emit-package odh-notebooks-meta-db-connectors-deps --no-emit-package odh-notebooks-meta-jupyterlab-datascience-deps --no-emit-package odh-notebooks-meta-jupyterlab-deps --no-emit-package odh-notebooks-meta-llmcompressor-deps --no-emit-package odh-notebooks-meta-runtime-elyra-deps --no-emit-package odh-notebooks-meta-runtime-datascience-deps --no-emit-package odh-notebooks-meta-workbench-datascience-deps --constraints ../../../../dependencies/cve-constraints.txt --exclude-newer=2026-03-31T11:02:33Z --default-index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/rocm6.4-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/rocm6.4-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cpu-ubi9/simple/?format=json --index-strategy=unsafe-best-match | |||
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In uv pip compile, what are the exact semantics and recommended secure default for --index-strategy values (first-index, unsafe-first-match, unsafe-best-match) when multiple indexes are configured?
💡 Result:
In uv pip compile, the --index-strategy option controls how packages are resolved when multiple indexes (e.g., via --index, --extra-index-url, or [[tool.uv.index]] in pyproject.toml) are configured. Indexes are prioritized in declaration order, with configured indexes before the default (PyPI). The values are: - first-index (default, recommended secure default): For each package, search all indexes in order. Use only versions from the first index containing the package name, ignoring versions from later indexes. This prevents dependency confusion attacks (e.g., malicious PyPI packages shadowing internal ones) by ensuring packages from trusted indexes aren't superseded. - unsafe-first-match: Search all indexes. Prefer the first index with any compatible version, even if later indexes have newer compatible versions. Allows some cross-index resolution but still limits to first compatible index. - unsafe-best-match: Search all indexes and consider all versions across them. Select the highest compatible version from the combined set (pip-like). If the same version appears in multiple indexes, prefer the first index. Exposes to dependency confusion risks, as malicious newer versions from untrusted indexes could be chosen. The secure default is first-index, prioritizing safety over pip compatibility. Use unsafe-* only when needed (e.g., pip workflows), preferring explicit package-index pinning via tool.uv.sources for security.
Citations:
- 1: https://docs.astral.sh/uv/pip/compatibility/
- 2: https://docs.astral.sh/uv/concepts/indexes/
- 3: https://docs.astral.sh/uv/configuration/indexes/
- 4: https://www.exactpressuregauge.com
Use --index-strategy=first-index instead of unsafe-best-match to prevent dependency confusion (CWE-829).
The unsafe-best-match strategy resolves to the highest compatible version across all indexes, allowing an attacker to publish a malicious package to any configured index and have it selected over legitimate versions. The secure default is first-index, which restricts each package to versions from the first index containing it, eliminating cross-index shadowing.
Suggested fix
-# uv pip compile pyproject.toml --output-file uv.lock.d/pylock.rocm.toml --format pylock.toml --generate-hashes --emit-index-url --python-version=3.12 --universal --no-annotate --no-emit-package odh-notebooks-meta-db-connectors-deps --no-emit-package odh-notebooks-meta-jupyterlab-datascience-deps --no-emit-package odh-notebooks-meta-jupyterlab-deps --no-emit-package odh-notebooks-meta-llmcompressor-deps --no-emit-package odh-notebooks-meta-runtime-elyra-deps --no-emit-package odh-notebooks-meta-runtime-datascience-deps --no-emit-package odh-notebooks-meta-workbench-datascience-deps --constraints ../../../../dependencies/cve-constraints.txt --exclude-newer=2026-03-31T11:02:33Z --default-index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/rocm6.4-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/rocm6.4-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cpu-ubi9/simple/?format=json --index-strategy=unsafe-best-match
+# uv pip compile pyproject.toml --output-file uv.lock.d/pylock.rocm.toml --format pylock.toml --generate-hashes --emit-index-url --python-version=3.12 --universal --no-annotate --no-emit-package odh-notebooks-meta-db-connectors-deps --no-emit-package odh-notebooks-meta-jupyterlab-datascience-deps --no-emit-package odh-notebooks-meta-jupyterlab-deps --no-emit-package odh-notebooks-meta-llmcompressor-deps --no-emit-package odh-notebooks-meta-runtime-elyra-deps --no-emit-package odh-notebooks-meta-runtime-datascience-deps --no-emit-package odh-notebooks-meta-workbench-datascience-deps --constraints ../../../../dependencies/cve-constraints.txt --exclude-newer=2026-03-31T11:02:33Z --default-index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/rocm6.4-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/rocm6.4-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cpu-ubi9/simple/?format=json --index-strategy=first-index📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # uv pip compile pyproject.toml --output-file uv.lock.d/pylock.rocm.toml --format pylock.toml --generate-hashes --emit-index-url --python-version=3.12 --universal --no-annotate --no-emit-package odh-notebooks-meta-db-connectors-deps --no-emit-package odh-notebooks-meta-jupyterlab-datascience-deps --no-emit-package odh-notebooks-meta-jupyterlab-deps --no-emit-package odh-notebooks-meta-llmcompressor-deps --no-emit-package odh-notebooks-meta-runtime-elyra-deps --no-emit-package odh-notebooks-meta-runtime-datascience-deps --no-emit-package odh-notebooks-meta-workbench-datascience-deps --constraints ../../../../dependencies/cve-constraints.txt --exclude-newer=2026-03-31T11:02:33Z --default-index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/rocm6.4-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/rocm6.4-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cpu-ubi9/simple/?format=json --index-strategy=unsafe-best-match | |
| # uv pip compile pyproject.toml --output-file uv.lock.d/pylock.rocm.toml --format pylock.toml --generate-hashes --emit-index-url --python-version=3.12 --universal --no-annotate --no-emit-package odh-notebooks-meta-db-connectors-deps --no-emit-package odh-notebooks-meta-jupyterlab-datascience-deps --no-emit-package odh-notebooks-meta-jupyterlab-deps --no-emit-package odh-notebooks-meta-llmcompressor-deps --no-emit-package odh-notebooks-meta-runtime-elyra-deps --no-emit-package odh-notebooks-meta-runtime-datascience-deps --no-emit-package odh-notebooks-meta-workbench-datascience-deps --constraints ../../../../dependencies/cve-constraints.txt --exclude-newer=2026-03-31T11:02:33Z --default-index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/rocm6.4-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/rocm6.4-ubi9/simple/?format=json --index=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.4/cpu-ubi9/simple/?format=json --index-strategy=first-index |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@jupyter/rocm/pytorch/ubi9-python-3.12/uv.lock.d/pylock.rocm.toml` at line 2,
The commented pip-compile command in pylock.rocm.toml uses
--index-strategy=unsafe-best-match which enables cross-index version selection;
update that flag to --index-strategy=first-index in the commented command (the
long uv pip compile invocation) so the resolver uses the first index containing
a package instead of unsafe-best-match.
| route = await customApi.getNamespacedCustomObject({ | ||
| group: 'route.openshift.io', version: 'v1', namespace: 'openshift-console', plural: 'routes', name: 'console' | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check the actual API signature in `@kubernetes/client-node`
echo "=== Checking CustomObjectsApi method signatures ==="
npm view `@kubernetes/client-node`@1.4.0 repository.url 2>/dev/null
# Search for getNamespacedCustomObject signature in type definitions
cat << 'EOF'
Manual verification needed: Check `@kubernetes/client-node` changelog or TypeScript definitions
for getNamespacedCustomObject to confirm it accepts { group, version, namespace, plural, name } object.
EOFRepository: opendatahub-io/notebooks
Length of output: 373
🏁 Script executed:
#!/bin/bash
# Find and check the `@kubernetes/client-node` version
echo "=== Searching for package files ==="
find . -name "package.json*" -type f | head -20
echo ""
echo "=== Checking for `@kubernetes/client-node` dependency ==="
rg '@kubernetes/client-node' -A 1 || trueRepository: opendatahub-io/notebooks
Length of output: 1712
🏁 Script executed:
#!/bin/bash
# Read the test file to see the actual implementation
echo "=== Reading the test file ==="
cat -n tests/browser/tests/openshift_console.spec.ts | head -40Repository: opendatahub-io/notebooks
Length of output: 1839
🌐 Web query:
@kubernetes/client-node CustomObjectsApi getNamespacedCustomObject signature options object vs positional
💡 Result:
In the @kubernetes/client-node JavaScript/TypeScript Kubernetes client library, the CustomObjectsApi.getNamespacedCustomObject method uses positional arguments for the required parameters: getNamespacedCustomObject(group: string, version: string, namespace: string, plural: string, name: string, options?: any): Promise<V1KubernetesObject>. The core required parameters (group, version, namespace, plural, name) are passed positionally. Optional query parameters and request configuration (such as pretty, dryRun, fieldSelector, labelSelector, resourceVersion, timeoutSeconds, etc.) are passed in an optional trailing options object. This follows the standard pattern seen across Kubernetes client libraries and confirmed in usage examples from StackOverflow and GitHub issues. For example: k8sApi.getNamespacedCustomObject('monitoring.coreos.com','v1','default', 'prometheusrules', 'prometheus-kube-prometheus-etcd-rules') No sources show an options-object-only signature without positional args; positional is primary for the 5 required params, with options for extras. The generated API code (from kubernetes-client/javascript repo) uses this signature, matching other generated methods like CoreV1Api.listNamespacedPod({namespace: 'default'}), but CustomObjectsApi methods use positional for core params per examples and Java/Python analogs.
Citations:
- 1: https://stackoverflow.com/questions/68192463/javascript-kubernetes-client-list-and-read-custom-resource-definition
- 2: https://stackoverflow.com/questions/68060456/how-do-i-create-a-kubernetes-custom-resource-using-javascript-client
- 3: https://github.com/kubernetes-client/javascript
- 4: https://raw.githubusercontent.com/kubernetes-client/javascript/master/src/gen/api/coreV1Api.ts
- 5: https://javadoc.io/static/io.kubernetes/client-java-api/12.0.0/io/kubernetes/client/openapi/apis/CustomObjectsApi.html
- 6: CustomObjectsApi.deleteCollectionNamespacedCustomObject does not support several OpenAPI query parameters kubernetes-client/javascript#1778
Fix API call: getNamespacedCustomObject requires positional arguments, not an options object.
The @kubernetes/client-node 1.4.0 API signature requires the 5 core parameters (group, version, namespace, plural, name) to be passed as positional arguments, not as a named options object. Change line 14–16 to:
route = await customApi.getNamespacedCustomObject(
'route.openshift.io', 'v1', 'openshift-console', 'routes', 'console'
);
The current code will fail at runtime with a type/argument mismatch error.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/browser/tests/openshift_console.spec.ts` around lines 14 - 16, The call
to customApi.getNamespacedCustomObject is using an options object but the
`@kubernetes/client-node` API expects positional arguments; update the invocation
of getNamespacedCustomObject (where route is assigned) to pass the five
parameters in order: group, version, namespace, plural, name (i.e.,
'route.openshift.io', 'v1', 'openshift-console', 'routes', 'console') instead of
the object form so the function signature matches the client library.
| { | ||
| // tsconfig.json natively supports comments (JSONC format) | ||
| "compilerOptions": { | ||
| "target": "es2025", |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
What ECMAScript features are included in ES2025 and does Node.js 22+ support them?
💡 Result:
ES2025 (ECMAScript 2025, the 16th edition) includes the following new features: - New Iterator global with static and prototype methods (e.g., Iterator.prototype.map, filter, flatMap) - New Set.prototype methods: intersection(other), union(other), difference(other), symmetricDifference(other), isSubsetOf(other), isSupersetOf(other) - Import attributes (with { type: 'json' }) for JSON modules and syntax for module import attributes - RegExp.escape(str) static method - RegExp inline modifier flags (e.g., /foo(?i:bar)/ for inline case-insensitive) - Promise.try(fn) static method - Float16Array typed array + DataView.prototype.getFloat16/setFloat16 + Math.f16round Node.js 22+ (specifically Node.js 24+, released May 2025 with V8 13.6) supports several ES2025 features via V8, including: - RegExp.escape - Float16Array (enabled on global object) - Explicit resource management (using / await using declarations, though primarily Stage 4 in 2025, aligned with ES2025) Node.js 22 (V8 12.4) supports up to ES2024 features like Array.fromAsync but lacks the ES2025-specific ones listed above. Full ES2025 support requires Node.js 24+. As of 2026-04-01, Node.js 24 is LTS ("Krypton"), ensuring ongoing support.
Citations:
- 1: https://tc39.es/ecma262/2025/multipage/
- 2: https://tc39.es/ecma262/2025/
- 3: https://nodejs.org/en/blog/release/v24.0.0/
- 4: https://nodejs.org/en/blog/release/v24.0.0
- 5: deps: update V8 to 13.6 nodejs/node#58070
🏁 Script executed:
#!/bin/bash
# Check Node.js version constraints in package.json
cat package.json | jq '.engines' 2>/dev/null || cat package.json | grep -A 5 '"engines"' || echo "No engines field found"Repository: opendatahub-io/notebooks
Length of output: 112
🏁 Script executed:
#!/bin/bash
# Look for Node.js version specification files
fd -E '.git' '\.node-version|\.nvmrc|\.tool-versions' -t fRepository: opendatahub-io/notebooks
Length of output: 50
🏁 Script executed:
#!/bin/bash
# Check CI workflows for Node.js version specifications
find .github/workflows -name '*.yml' -o -name '*.yaml' 2>/dev/null | head -20Repository: opendatahub-io/notebooks
Length of output: 890
🏁 Script executed:
#!/bin/bash
# Check TypeScript version in package.json
cat package.json | jq '.devDependencies.typescript, .dependencies.typescript' 2>/dev/null || grep -i 'typescript' package.json | head -5Repository: opendatahub-io/notebooks
Length of output: 112
🏁 Script executed:
#!/bin/bash
# Explore repository structure
ls -laRepository: opendatahub-io/notebooks
Length of output: 3097
🏁 Script executed:
#!/bin/bash
# Check tests/browser directory
ls -la tests/browser/ 2>/dev/null || echo "Directory not found"Repository: opendatahub-io/notebooks
Length of output: 805
🏁 Script executed:
#!/bin/bash
# Look for all package.json files
fd 'package.json' -t fRepository: opendatahub-io/notebooks
Length of output: 899
🏁 Script executed:
#!/bin/bash
# Check the build-browser-tests workflow
cat .github/workflows/build-browser-tests.yamlRepository: opendatahub-io/notebooks
Length of output: 3047
🏁 Script executed:
#!/bin/bash
# Read package.json5
cat tests/browser/package.json5Repository: opendatahub-io/notebooks
Length of output: 847
🏁 Script executed:
#!/bin/bash
# Read Dockerfile
cat tests/browser/DockerfileRepository: opendatahub-io/notebooks
Length of output: 1022
🏁 Script executed:
#!/bin/bash
# Read complete tsconfig.json
cat tests/browser/tsconfig.jsonRepository: opendatahub-io/notebooks
Length of output: 715
🏁 Script executed:
#!/bin/bash
# Check if there are any references to Node.js version constraints or Playwright compatibility
grep -r "node" tests/browser/ --include="*.md" --include="*.txt" -i || echo "No Node.js docs found"Repository: opendatahub-io/notebooks
Length of output: 712
🏁 Script executed:
#!/bin/bash
# Check the README for Node.js/Playwright version info
cat tests/browser/README.mdRepository: opendatahub-io/notebooks
Length of output: 3454
Node.js 22 (likely in Playwright base image) does not support ES2025; verify image or change target to es2024.
TypeScript 6.0.2 supports es2025, but the Dockerfile uses mcr.microsoft.com/playwright:v1.58.1-noble (Ubuntu 24.04 LTS), which typically includes Node.js 22. According to the ES2025 specification, Node.js 22 (V8 12.4) only supports ES2024 features. Full ES2025 support (RegExp.escape, Promise.try, Float16Array, Iterator methods) requires Node.js 24+ (V8 13.6).
Even with "noEmit": true, TypeScript will type-check code assuming the runtime supports ES2025 features. If test code uses ES2025-specific features, runtime errors will occur on Node.js 22.
Either upgrade the Playwright base image to include Node.js 24+, or change "target" to "es2024" to match the actual runtime environment.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/browser/tsconfig.json` at line 4, The tsconfig setting "target":
"es2025" is incompatible with the Playwright/base Node.js 22 runtime; update the
tsconfig.json target to "es2024" (replace the "target": "es2025" entry) so
TypeScript type-checks against the actual runtime, or alternatively update the
CI/Playwright base image to one that includes Node.js 24+; edit the "target"
field in tests/browser/tsconfig.json (the "target" property) to ensure it
matches the chosen runtime.
Co-authored-by: GitHub Actions <github-actions[bot]@users.noreply.github.com>
There was a problem hiding this comment.
♻️ Duplicate comments (1)
jupyter/rocm/pytorch/ubi9-python-3.12/uv.lock.d/pylock.rocm.toml (1)
2-2:⚠️ Potential issue | 🟠 MajorReplace
unsafe-best-matchto prevent dependency confusion (CWE-829).Line 2 still uses
--index-strategy=unsafe-best-match. With multiple indexes, a malicious higher-version package on a less-trusted index can be selected during lock regeneration and poison the supply chain.Suggested fix
-# ... --index-strategy=unsafe-best-match +# ... --index-strategy=first-indexIn the latest uv documentation, what is the recommended secure `--index-strategy` for multi-index resolution, and does `unsafe-best-match` increase dependency-confusion risk?As 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 `@jupyter/rocm/pytorch/ubi9-python-3.12/uv.lock.d/pylock.rocm.toml` at line 2, The command line uses the insecure flag --index-strategy=unsafe-best-match which can enable dependency-confusion; update the uv pip compile invocation to use a secure, deterministic index strategy instead (replace --index-strategy=unsafe-best-match with a safer strategy such as --index-strategy=prefer-index or another non-unsafe option supported by uv) and regenerate the lockfile so resolution always favors the intended trusted index; ensure you update the invocation that includes --index-strategy in the pylock.rocm.toml comment line.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@jupyter/rocm/pytorch/ubi9-python-3.12/uv.lock.d/pylock.rocm.toml`:
- Line 2: The command line uses the insecure flag
--index-strategy=unsafe-best-match which can enable dependency-confusion; update
the uv pip compile invocation to use a secure, deterministic index strategy
instead (replace --index-strategy=unsafe-best-match with a safer strategy such
as --index-strategy=prefer-index or another non-unsafe option supported by uv)
and regenerate the lockfile so resolution always favors the intended trusted
index; ensure you update the invocation that includes --index-strategy in the
pylock.rocm.toml comment line.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Central YAML (inherited), Repository UI (inherited)
Review profile: CHILL
Plan: Pro
Run ID: 6722ccc4-ea7a-450a-9b75-105e09c3dd34
📒 Files selected for processing (22)
codeserver/ubi9-python-3.12/uv.lock.d/pylock.cpu.tomljupyter/datascience/ubi9-python-3.12/uv.lock.d/pylock.cpu.tomljupyter/minimal/ubi9-python-3.12/uv.lock.d/pylock.cpu.tomljupyter/minimal/ubi9-python-3.12/uv.lock.d/pylock.cuda.tomljupyter/minimal/ubi9-python-3.12/uv.lock.d/pylock.rocm.tomljupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.tomljupyter/pytorch/ubi9-python-3.12/uv.lock.d/pylock.cuda.tomljupyter/rocm/pytorch/ubi9-python-3.12/uv.lock.d/pylock.rocm.tomljupyter/rocm/tensorflow/ubi9-python-3.12/pylock.tomljupyter/tensorflow/ubi9-python-3.12/uv.lock.d/pylock.cuda.tomljupyter/trustyai/ubi9-python-3.12/uv.lock.d/pylock.cpu.tomlrstudio/c9s-python-3.12/uv.lock.d/pylock.cpu.tomlrstudio/c9s-python-3.12/uv.lock.d/pylock.cuda.tomlrstudio/rhel9-python-3.12/uv.lock.d/pylock.cpu.tomlrstudio/rhel9-python-3.12/uv.lock.d/pylock.cuda.tomlruntimes/datascience/ubi9-python-3.12/uv.lock.d/pylock.cpu.tomlruntimes/minimal/ubi9-python-3.12/uv.lock.d/pylock.cpu.tomlruntimes/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.tomlruntimes/pytorch/ubi9-python-3.12/uv.lock.d/pylock.cuda.tomlruntimes/rocm-pytorch/ubi9-python-3.12/uv.lock.d/pylock.rocm.tomlruntimes/rocm-tensorflow/ubi9-python-3.12/pylock.tomlruntimes/tensorflow/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml
✅ Files skipped from review due to trivial changes (7)
- rstudio/rhel9-python-3.12/uv.lock.d/pylock.cuda.toml
- jupyter/minimal/ubi9-python-3.12/uv.lock.d/pylock.rocm.toml
- runtimes/rocm-pytorch/ubi9-python-3.12/uv.lock.d/pylock.rocm.toml
- runtimes/minimal/ubi9-python-3.12/uv.lock.d/pylock.cpu.toml
- jupyter/minimal/ubi9-python-3.12/uv.lock.d/pylock.cpu.toml
- rstudio/rhel9-python-3.12/uv.lock.d/pylock.cpu.toml
- runtimes/tensorflow/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml
🚧 Files skipped from review as they are similar to previous changes (9)
- rstudio/c9s-python-3.12/uv.lock.d/pylock.cuda.toml
- runtimes/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml
- rstudio/c9s-python-3.12/uv.lock.d/pylock.cpu.toml
- runtimes/pytorch/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml
- jupyter/datascience/ubi9-python-3.12/uv.lock.d/pylock.cpu.toml
- jupyter/tensorflow/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml
- codeserver/ubi9-python-3.12/uv.lock.d/pylock.cpu.toml
- jupyter/pytorch+llmcompressor/ubi9-python-3.12/uv.lock.d/pylock.cuda.toml
- runtimes/datascience/ubi9-python-3.12/uv.lock.d/pylock.cpu.toml
👮 Files not reviewed due to content moderation or server errors (2)
- jupyter/rocm/tensorflow/ubi9-python-3.12/pylock.toml
- runtimes/rocm-tensorflow/ubi9-python-3.12/pylock.toml
Description
How Has This Been Tested?
Self checklist (all need to be checked):
make test(gmakeon macOS) before asking for reviewDockerfile.konfluxfiles should be done inodh/notebooksand automatically synced torhds/notebooks. For Konflux-specific changes, modifyDockerfile.konfluxfiles directly inrhds/notebooksas these require special attention in the downstream repository and flow to the upcoming RHOAI release.Merge criteria:
Summary by CodeRabbit
New Features
Improvements
Testing
Documentation