feat: add FBC catalog Dockerfile for CI without operator-sdk#2204
feat: add FBC catalog Dockerfile for CI without operator-sdk#2204kaovilai wants to merge 3 commits into
Conversation
Add build/Dockerfile.catalog that renders a bundle image into an FBC (File-Based Catalog) catalog image servable via gRPC CatalogSource. This enables CI to install the operator without operator-sdk, using only opm (actively maintained by OLM team). The Dockerfile uses opm render to generate FBC content from a bundle image passed as BUNDLE_IMG build arg, appends OLM package/channel metadata, validates with opm validate, and serves via opm serve. Pattern follows networking-incubator/coraza-kubernetes-operator and migrationqe/oadp-release-info ROSA_HCP tooling. Closes: openshift#2203 Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering> Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
WalkthroughAdds ChangesOLM File-Based Catalog (FBC) image + OPM version bump
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 12✅ Passed checks (12 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: kaovilai The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Reviewed all 45 releases between v1.23.0 and v1.68.0. No breaking changes affect the opm render, opm validate, or opm generate dockerfile commands used in the Makefile catalog-build target. Notable changes absorbed: - v1.53.0: requires policy.json for registry access (Dockerfile already sets insecureAcceptAnything for CI registries) - v1.58.0: stricter opm validate (no impact on single-bundle catalog) - v1.51.0: file permissions ratcheted to o600 (Makefile deletes generated files after build anyway) Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering> Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
There was a problem hiding this comment.
🧹 Nitpick comments (2)
build/Dockerfile.catalog (2)
44-54: ⚡ Quick winConsider adding a non-root USER directive.
The container runs as root by default. Adding a non-root user improves security posture, especially if this image is used outside CI contexts.
OPM catalog images typically support running as non-root. The cache directory
/tmp/cacheshould remain writable for non-root users.🔒 Proposed fix to run as non-root
FROM opm COPY --from=builder /configs /configs RUN ["/bin/opm", "serve", "/configs", "--cache-dir=/tmp/cache", "--cache-only"] LABEL operators.operatorframework.io.index.configs.v1=/configs EXPOSE 50051 + +USER 1001 + ENTRYPOINT ["/bin/opm"] CMD ["serve", "/configs", "--cache-dir=/tmp/cache"]🤖 Prompt for 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. In `@build/Dockerfile.catalog` around lines 44 - 54, Add a non-root USER and ensure runtime dirs are writable: create or switch to a dedicated unprivileged user (e.g., "opmuser") in the Dockerfile, chown /tmp/cache and any config directories copied from builder (referenced by COPY --from=builder /configs /configs and the /tmp/cache used by RUN and CMD/ENTRYPOINT) to that user's UID:GID, and add a USER instruction before ENTRYPOINT so the container runs non-root while preserving write access to /tmp/cache and /configs.
14-16: 💤 Low valueConsider updating OPM to a more recent version.
OPM v1.23.0 is significantly outdated; the latest available version is v1.66.0. Updating would include numerous bug fixes, security improvements, and feature enhancements released over the intervening versions.
🤖 Prompt for 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. In `@build/Dockerfile.catalog` around lines 14 - 16, Update the OPM base image version by changing the ARG OPM_VERSION value from v1.23.0 to a more recent stable release (e.g., v1.66.0) so the FROM quay.io/operator-framework/opm:${OPM_VERSION} AS opm stage pulls the newer OPM; ensure any downstream compatibility tests are run after bumping ARG OPM_VERSION to confirm no breaking changes.
🤖 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.
Nitpick comments:
In `@build/Dockerfile.catalog`:
- Around line 44-54: Add a non-root USER and ensure runtime dirs are writable:
create or switch to a dedicated unprivileged user (e.g., "opmuser") in the
Dockerfile, chown /tmp/cache and any config directories copied from builder
(referenced by COPY --from=builder /configs /configs and the /tmp/cache used by
RUN and CMD/ENTRYPOINT) to that user's UID:GID, and add a USER instruction
before ENTRYPOINT so the container runs non-root while preserving write access
to /tmp/cache and /configs.
- Around line 14-16: Update the OPM base image version by changing the ARG
OPM_VERSION value from v1.23.0 to a more recent stable release (e.g., v1.66.0)
so the FROM quay.io/operator-framework/opm:${OPM_VERSION} AS opm stage pulls the
newer OPM; ensure any downstream compatibility tests are run after bumping ARG
OPM_VERSION to confirm no breaking changes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 4b612c57-f06f-4173-a272-4fab17b35b17
📒 Files selected for processing (1)
build/Dockerfile.catalog
| echo 'package: oadp-operator' >> /configs/oadp-operator/index.yaml && \ | ||
| echo 'entries:' >> /configs/oadp-operator/index.yaml && \ | ||
| echo " - name: oadp-operator.v${VERSION}" >> /configs/oadp-operator/index.yaml && \ | ||
| /bin/opm validate /configs/ |
There was a problem hiding this comment.
line 30 - 42 seems pretty ugly to me.
alternatives?
There was a problem hiding this comment.
one could create a yaml file outside then sed inside here.. etc.. either way.. up to you.. more moving parts.
There was a problem hiding this comment.
https://github.com/networking-incubator/coraza-kubernetes-operator/blob/main/catalog/Dockerfile check this example.. if this is fine we can replicate
There was a problem hiding this comment.
Ours vs coraza-kubernetes-operator catalog/Dockerfile
| Aspect | Coraza | Ours |
|---|---|---|
| FBC metadata | Pre-committed in repo (coraza-kubernetes-operator/ dir with package/channel YAML). Dockerfile just copies it. |
Generated inline via heredoc. No files to maintain in repo. |
| Bundle rendering | for img in ${BUNDLE_IMGS} loop — supports multiple bundles |
Single BUNDLE_IMG — we only have one bundle |
| Fail-fast | None — silently fails if BUNDLE_IMGS empty |
test -n "${BUNDLE_IMG}" guard with error message |
| Non-root USER | Not set | Explicit USER 65532 |
| OPM version | v1.64.0 |
v1.68.0 |
| Bundles dir | COPY bundles/ /tmp/bundles/ — copies local bundle content (unused by opm render though) |
No local bundle content — purely image-based |
| Cache warmup | Yes (--cache-dir=/tmp/cache --cache-only) |
Same |
| policy.json | Yes (insecureAcceptAnything) |
Same |
| Multi-stage | opm → ubi-minimal → opm (3 stages) | Same pattern |
Main difference: coraza pre-commits their FBC package/channel metadata as files, we generate it at build time. Theirs is cleaner if metadata changes rarely. Ours is zero-maintenance — no files to keep in sync with Makefile variables.
There was a problem hiding this comment.
Replaced echo chains with a heredoc in the latest push. Much cleaner now. Also added fail-fast guard for missing BUNDLE_IMG and dropped the USER 65532 / chown lines (opm base image is distroless — no /bin/sh, and already runs as non-root USER 1001 since v1.23.2).
Tested locally — catalog builds, serves gRPC, and returns correct package/channel/bundle data. See test results comment above.
Note
Responses generated with Claude
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 `@build/Dockerfile.catalog`:
- Around line 26-31: The Dockerfile should fail fast and avoid word-splitting
when BUNDLE_IMG is empty: add a guard after ARG BUNDLE_IMG that checks the
variable is set and exits with a clear error if not, and quote the variable in
the opm render invocation (i.e., change the /bin/opm render ${BUNDLE_IMG} call
to use a quoted expansion) so the command uses a single argument and errors are
clearer while still writing to /configs/oadp-operator/index.yaml.
- Around line 44-54: Add an explicit non-root runtime user and make /tmp/cache
writable for it: in the final Dockerfile stage (the stage that contains COPY
--from=builder /configs, ENTRYPOINT ["/bin/opm"], and CMD ["serve", "/configs",
"--cache-dir=/tmp/cache"]) create or ensure /tmp/cache exists and is owned by a
pinned non-root UID (e.g., 65532) and then set USER 65532; specifically, add
commands to mkdir -p /tmp/cache and chown -R 65532:65532 /tmp/cache (and
/configs if needed) before setting USER 65532 so the opm serve process can run
as the non-root user.
🪄 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: openshift/coderabbit/.coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 670b4c7e-91bf-4742-8264-aebdfd41a157
📒 Files selected for processing (2)
Makefilebuild/Dockerfile.catalog
✅ Files skipped from review due to trivial changes (1)
- Makefile
- Replace echo chains with heredoc for OLM metadata (cleaner) - Add fail-fast guard for missing BUNDLE_IMG build arg - Quote BUNDLE_IMG in opm render to prevent word-splitting - Add explicit non-root USER 65532 in final stage - Ensure /tmp/cache is writable for non-root user Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering> Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
14532d9 to
be69539
Compare
|
Note Responses generated with Claude Local sanity check — catalog image builds and serves ✅Build stepsBuild log shows Runtime verificationgRPC queriesAll three gRPC APIs return valid data. The catalog correctly serves the Review feedback addressed
|
There was a problem hiding this comment.
♻️ Duplicate comments (1)
build/Dockerfile.catalog (1)
48-58:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAdd explicit non-root USER in the final stage.
Trivy flags this image as running as root (DS-0002). The
opmbase image does not guarantee a non-root USER across versions. To harden the image, pin a non-root UID and ensure/tmp/cacheis writable for that user before switching.Note: A previous review suggested this fix and marked it as addressed, but the directive appears to be missing from the current code.
🔒 Suggested hardening patch
FROM opm COPY --from=builder /configs /configs +RUN mkdir -p /tmp/cache && chown -R 65532:0 /configs /tmp/cache +USER 65532 RUN ["/bin/opm", "serve", "/configs", "--cache-dir=/tmp/cache", "--cache-only"] LABEL operators.operatorframework.io.index.configs.v1=/configs🤖 Prompt for 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. In `@build/Dockerfile.catalog` around lines 48 - 58, Final Dockerfile stage currently runs as root; add an explicit non-root user and ensure /tmp/cache is writable before switching. In the final stage (the block that uses FROM opm, COPY --from=builder, RUN ["/bin/opm", "serve", ...], ENTRYPOINT ["/bin/opm"], CMD ["serve", ...]) create a dedicated user/group with a fixed UID/GID, mkdir /tmp/cache and chown it to that user, and then add a USER instruction to switch to that non-root account so the container runs non-root while preserving the current ENTRYPOINT/CMD.
🤖 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.
Duplicate comments:
In `@build/Dockerfile.catalog`:
- Around line 48-58: Final Dockerfile stage currently runs as root; add an
explicit non-root user and ensure /tmp/cache is writable before switching. In
the final stage (the block that uses FROM opm, COPY --from=builder, RUN
["/bin/opm", "serve", ...], ENTRYPOINT ["/bin/opm"], CMD ["serve", ...]) create
a dedicated user/group with a fixed UID/GID, mkdir /tmp/cache and chown it to
that user, and then add a USER instruction to switch to that non-root account so
the container runs non-root while preserving the current ENTRYPOINT/CMD.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 109a4894-79b2-4323-a384-7ac866e1a500
📒 Files selected for processing (1)
build/Dockerfile.catalog
|
@rayfordj do you by chance have an example dockerfile for the FBC containers? |
|
CI config PR updated: openshift/release#79327 replaces openshift/release#79152. Uses Note Responses generated with Claude |
|
This needs to be cherry-picked to oadp-1.3, oadp-1.4, oadp-1.5, oadp-1.6, and oadp-dev branches. Index image building is deprecated and will be removed from ci-operator, so all branches need Note Responses generated with Claude |
|
@kaovilai: all tests passed! Full PR test history. Your PR dashboard. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
Summary
Add
build/Dockerfile.catalogthat renders a bundle image into an FBC (File-Based Catalog) catalog image servable via gRPC CatalogSource. This enables CI to install the operator without operator-sdk, using onlyopm(actively maintained by OLM team).opm→ubi-minimal(builder) →opm(final)BUNDLE_IMGas required build arg, runsopm renderto generate FBC/etc/containers/policy.jsonfor pulling from CI registries without signature verification--cache-dir+--cache-only)make catalog-buildMakefile logicCloses #2203
Reference implementations
catalog/Dockerfile— sameARG BUNDLE_IMG+opm renderpattern--cache-dir/--cache-onlypatternFollow-up PRs needed
1. openshift/release CI config update (replaces #79152)
PR #79152 migrated to
operator-sdk run bundleworkflow. With this Dockerfile, we revert to the standardoptional-operators-ci-awsworkflow instead. Per-variant diff from current:2. OLMv1 tests PR #2160
Once the CI config switch lands, #2160 can be rebased. No code changes needed in #2160 itself — it just needs the CI infrastructure (this Dockerfile + the release config update) to be in place first.
Test plan
make bundle-build BUNDLE_IMG=ttl.sh/oadp-bundle-test:1hmake bundle-push BUNDLE_IMG=ttl.sh/oadp-bundle-test:1hpodman build -f build/Dockerfile.catalog --build-arg BUNDLE_IMG=ttl.sh/oadp-bundle-test:1h -t localhost/oadp-catalog:test .podman run --rm -p 50051:50051 localhost/oadp-catalog:testNote
Responses generated with Claude
Summary by CodeRabbit