refactor: replace install-common.sh with declarative artifact system - #473
Conversation
Make the upstream build's file download mechanism consistent with what is done for downstream Konflux hermetic builds. Replaces install-common.sh (which used runtime tools like hf download, docling-tools, and tiktoken) with a shared declarative artifact system: - artifacts.lock.yaml: declares all ML model artifacts with download URLs and SHA256 checksums, pinned to specific revisions for reproducibility - fetch_artifacts.py: async Python downloader with checksum verification - copy-artifacts.sh: copies fetched artifacts into correct cache layouts, used by both standard and Konflux builds Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The HuggingFace hub cache was placed under ${HOME} during build, but the
container runs as user 1001 with a different HOME, so SentenceTransformer
could not find the prefetched embedding model at runtime.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Validate artifact filenames before downloading to reject absolute paths and directory traversal attempts. Pin httpx and pyyaml version bounds in the PEP 723 script metadata. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Compute the SHA-1 hash at copy time so the cache filename stays in sync with the download URL rather than being a separately maintained constant. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The opencv-python<0 constraint in constraints.txt silently caused the resolver to drop rapidocr and downgrade docling. Replace it with an explicit uninstall/install step in the Containerfile. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Capture the exact version from uv pip show before uninstalling, so the headless variant matches what the resolver chose for rapidocr. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 2 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Central YAML (base), Organization UI (inherited) Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThis PR replaces install-common.sh's inline model provisioning with a lockfile-driven artifact pipeline: a new artifacts.lock.yaml pins download URLs, SHA-256 checksums, and filenames; fetch_artifacts.py asynchronously downloads and verifies these artifacts with path-traversal checks; copy-artifacts.sh places them into the app cache and bootstraps a Hugging Face refs/main file. Containerfile and Containerfile.in are updated to invoke this pipeline and to swap opencv-python for a version-pinned opencv-python-headless, plus set DOCLING_ARTIFACTS_PATH and HF_HOME. Estimated code review effort: 4 (Complex) | ~45 minutes Security Notes
🚥 Pre-merge checks | ✅ 8 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (8 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
|
nathan-weinberg
left a comment
There was a problem hiding this comment.
One quick question - if we want to add or remove any hermetic artifacts, do we have some path to do so that aligns with this new system?
derekhiggins
left a comment
There was a problem hiding this comment.
So I guess doesn't streat we'll have a downstream version of fetch_artifacts.py?
| # tiktoken cl100k_base | ||
| - download_url: https://openaipublic.blob.core.windows.net/encodings/cl100k_base.tiktoken | ||
| checksum: "sha256:223921b76ee99bde995b7ff738513eef100fb51d18c93597a113bcffe865b2a7" | ||
| filename: tiktoken/cl100k_base.tiktoken |
There was a problem hiding this comment.
I wonder distribution/copy-artifacts.sh could be avoided completely if we stored the absolute path for the destination here ? distribution/fetch_artifacts.py could then put them where they are needed
We wouldn't then need different copy functions for each model ?
There was a problem hiding this comment.
Yes, this is much better. Maybe we could have a staged file tree in the tmp dir (or the cache dir in the case of Hermeto) and simply copy this tree to the app root. That would simplify things quite a bit.
Yes, any new files that need to be downloaded at build time must be added to EDIT: the copy script has been improved and is now a generic |
No, Hermeto is configured to fetch all files in See the draft RHDS PR red-hat-data-services#124 for an indication of how it will look downsteam, and the Hermeto docs for more detail on the generic pre-fetcher: https://github.com/hermetoproject/hermeto/blob/main/docs/generic.md |
…y script Make the filename field in artifacts.lock.yaml encode the final destination path relative to APP_ROOT, eliminating all per-model copy functions from copy-artifacts.sh in favour of a single cp -r. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The docling provider only reads pre-fetched model weights at runtime; no writes to the models directory occur. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The OGX server creates this directory at startup, and APP_ROOT is group-writable (1001:0, g+w) so any UID in group 0 can create it at runtime on OpenShift. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@distribution/copy-artifacts.sh`:
- Line 12: The copy step in copy-artifacts.sh is copying the .cache directory
node instead of its contents, which can nest a second .cache under an existing
destination. Update the copy logic around the cp command to copy only the
contents of ${ARTIFACTS_DIR}/.cache into ${APP_ROOT}/.cache so the existing
cache tree is preserved and the HF_HOME, TIKTOKEN_CACHE_DIR, and
DOCLING_ARTIFACTS_PATH paths remain correct.
In `@distribution/fetch_artifacts.py`:
- Around line 1-6: The inline uv dependency list in fetch_artifacts.py is too
loose and can drift during image builds. Update the script’s dependency
declarations to use exact pinned versions for httpx and pyyaml, or switch this
script to a lockfile-backed setup so Containerfile and Containerfile.in builds
resolve deterministic packages. Keep the fix local to the fetch_artifacts.py
dependency metadata so the build environment remains reproducible.
🪄 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: Central YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Enterprise
Run ID: 9eef236a-dcb9-4e17-ae26-cf5e3aa71b7e
📒 Files selected for processing (6)
ContainerfileContainerfile.indistribution/artifacts.lock.yamldistribution/copy-artifacts.shdistribution/fetch_artifacts.pydistribution/install-common.sh
💤 Files with no reviewable changes (1)
- distribution/install-common.sh
|
lgtm, one nice followup would be to only download files if they didn't exist, we could then mount a cache dir into the build container when building locally (to avoid downloading each time) |
Use a BuildKit/Buildah cache mount to persist downloaded artifacts between builds. fetch_artifacts.py now skips files whose SHA-256 already matches the lockfile, reducing rebuild time from ~43s to ~2s. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@derekhiggins good call. Implemented cached mount dir in eecbac6 |
Artemon-line
left a comment
There was a problem hiding this comment.
lgtm, thank you @eoinfennessy
|
Tick the box to add this pull request to the merge queue (same as
|
Summary
install-common.sh(which used runtime tools likehf download,docling-tools,tiktoken) with a shared declarative artifact system consistent with how downstream Konflux hermetic builds fetch artifactsartifacts.lock.yamldeclaring all ML model artifacts with download URLs and SHA256 checksums, pinned to specific revisionsfetch_artifacts.py(async downloader with checksum verification) andcopy-artifacts.sh(copies artifacts into correct cache layouts for both standard and Konflux builds)opencv-python<0constraint silently dropped rapidocr and downgraded docling; replaced with a post-install swap pinned to the resolved versionAPP_ROOTinstead ofHOME(build-time vs runtime user mismatch)fetch_artifacts.pySupersedes #470 (pushed to upstream branch for CI).
Test plan
cl100k_base)DocumentConverterinitializes and processes a PDF end-to-end (layout analysis, RapidOCR, text extraction all using prefetched models)opencv-pythonis absent andopencv-python-headlessis installed at the same version (4.13.0.92)🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes