Skip to content

RHIDP-14790: Add OLM v1 code path to install-rhdh-catalog-source.sh#3047

Open
Fortune-Ndlovu wants to merge 20 commits into
redhat-developer:mainfrom
Fortune-Ndlovu:RHIDP-14790-operator-add-olm-v-1-code-path-to-install-rhdh-catalog-source-sh
Open

RHIDP-14790: Add OLM v1 code path to install-rhdh-catalog-source.sh#3047
Fortune-Ndlovu wants to merge 20 commits into
redhat-developer:mainfrom
Fortune-Ndlovu:RHIDP-14790-operator-add-olm-v-1-code-path-to-install-rhdh-catalog-source-sh

Conversation

@Fortune-Ndlovu

@Fortune-Ndlovu Fortune-Ndlovu commented Jun 23, 2026

Copy link
Copy Markdown
Member

Adds an --olm-version v0|v1|auto CLI flag (default: auto) to install-rhdh-catalog-source.sh with CRD-based OLM v1 detection. When OLM v1 is detected (or forced), the script creates a ClusterCatalog and ClusterExtension with a ServiceAccount and ClusterRoleBinding, instead of the OLM v0 CatalogSource, Subscription, and OperatorGroup. Resolution is pinned to the custom catalog via selector.matchLabels, and CRD upgrade safety preflight is disabled (enforcement: None) per the known blocker RHIDP-8656. The OLM v0 path is fully preserved for backward compatibility on older clusters.

Which issue(s) does this PR fix or relate to

Resolves: https://redhat.atlassian.net/browse/RHIDP-14790

PR acceptance criteria

  • Tests
  • Documentation

How to test changes / Special notes to the reviewer

# launch clusterbot
launch 4.21.0-0.nightly aws,techpreview

# OLM v0 (or auto-detect on a cluster without OLM v1):
bash .rhdh/scripts/install-rhdh-catalog-source.sh --latest --install-operator rhdh 2>&1 | tee /tmp/olmv0-test.log

# OLM v0 (forced, on a cluster that has OLM v1):
bash .rhdh/scripts/install-rhdh-catalog-source.sh --latest --install-operator rhdh --olm-version v0 2>&1 | tee
/tmp/olmv0-test.log

# OLM v1 (forced):
bash .rhdh/scripts/install-rhdh-catalog-source.sh --latest --install-operator rhdh --olm-version v1 2>&1 | tee
  /tmp/olmv1-test.log

# OLM auto-detect (picks v1 if CRD exists, v0 otherwise):
bash .rhdh/scripts/install-rhdh-catalog-source.sh --latest --install-operator rhdh 2>&1 | tee /tmp/olm-auto-test.log

Signed-off-by: Fortune-Ndlovu fndlovu@redhat.com
Assisted-by: Claude (claude-opus-4-6)

Add --olm-version v0|v1|auto flag (default: auto) with CRD-based
detection of OLM v1. When OLM v1 is detected, creates ClusterCatalog,
ServiceAccount, ClusterRoleBinding, and ClusterExtension instead of
OLM v0 CatalogSource, OperatorGroup, and Subscription. The IIB
rendering/rebuild phase is shared by both paths. OLM v0 behavior
is fully preserved for backward compatibility.

Signed-off-by: Fortune-Ndlovu <fndlovu@redhat.com>
Assisted-by: Claude (claude-opus-4-6)
@rhdh-qodo-merge

Copy link
Copy Markdown

PR Summary by Qodo

Add OLM v1 support to install-rhdh-catalog-source.sh
✨ Enhancement 🕐 40+ Minutes

Grey Divider

Description

• Add --olm-version v0|v1|auto with CRD-based auto-detection on OpenShift.
• When OLM v1 is available, install via ClusterCatalog + ClusterExtension and installer RBAC.
• Preserve OLM v0 CatalogSource/OperatorGroup/Subscription flow for older clusters and Kubernetes.
Diagram

graph TD
A["install-rhdh-catalog-source.sh"] --> B{"Resolve OLM version"}
B -->|"v1"| C["Apply ClusterCatalog"] --> D["Create SA + CRB"] --> E["Apply ClusterExtension"]
B -->|"v0"| F["Apply CatalogSource"] --> G["Apply OperatorGroup"] --> H["Apply Subscription"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Detect OLM v1 via API discovery instead of CRD existence
  • ➕ More robust against CRD name/version changes and partial installs
  • ➕ Can validate required resources (catalogd API group, ClusterCatalog kind) not just ClusterExtension CRD
  • ➖ More code and more cluster calls; harder to keep the script simple
  • ➖ Still needs careful handling across OCP versions and permissions
2. Avoid cluster-admin ClusterRoleBinding by using least-privilege RBAC
  • ➕ Reduces security risk of granting cluster-admin to an installer ServiceAccount
  • ➕ Easier to pass security reviews / safer default behavior
  • ➖ Requires identifying the exact permissions OLM v1 installer needs, which may change
  • ➖ Higher maintenance cost and risk of under-permissioning across versions
3. Split v0 and v1 into separate scripts (thin wrapper chooses which)
  • ➕ Reduces branching complexity and makes each flow easier to reason about
  • ➕ Allows different documentation and guardrails per OLM generation
  • ➖ More files to maintain; duplicated shared steps unless refactored
  • ➖ User experience becomes more fragmented if wrapper behavior isn’t clear

Recommendation: The current approach (single script with --olm-version and CRD-based auto-detection) is a pragmatic way to preserve v0 compatibility while enabling v1. The main strategic concern is the cluster-admin binding for the installer ServiceAccount; if this is unavoidable for now, consider clearly documenting the privilege elevation and, longer-term, tightening RBAC to least privilege. If v1 detection becomes flaky across OCP versions, consider upgrading detection to API discovery of required groups/kinds.

Files changed (1) +244 / -51

Enhancement (1) +244 / -51
install-rhdh-catalog-source.shAdd OLM v1 (ClusterCatalog/ClusterExtension) install path with auto-detection +244/-51

Add OLM v1 (ClusterCatalog/ClusterExtension) install path with auto-detection

• Introduces '--olm-version v0|v1|auto' and resolves the effective OLM version via ClusterExtension CRD presence (OpenShift-only). Adds an OLM v1 code path that creates ClusterCatalog, a pull secret in the catalogd namespace, an installer ServiceAccount + cluster-admin ClusterRoleBinding, and a ClusterExtension pinned to the custom catalog via 'selector.matchLabels'. Keeps the existing OLM v0 CatalogSource/OperatorGroup/Subscription behavior intact and gates OperatorGroup checks to the v0 path.

.rhdh/scripts/install-rhdh-catalog-source.sh

@rhdh-qodo-merge

rhdh-qodo-merge Bot commented Jun 23, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📜 Skill insights (0)

Context used
⚠️ Tickets: not configured — ticket URL found in PR but could not be fetched — check ticket provider credentials
✅ Compliance rules (platform): 18 rules

Grey Divider


Action required

1. Cluster-admin installer binding 🐞 Bug ⛨ Security
Description
In the OLM v1 path, the script creates a ClusterRoleBinding that grants the installer ServiceAccount
the built-in cluster-admin ClusterRole, giving it full cluster-wide privileges. This leaves a
highly privileged credential in-cluster and substantially increases impact if the ServiceAccount
token is leaked or the namespace is compromised.
Code

.rhdh/scripts/install-rhdh-catalog-source.sh[R937-951]

+  # ClusterRoleBinding granting cluster-admin to the installer SA
+  CRB_NAME="${OPERATOR_NAME_TO_INSTALL}-installer-binding"
+  echo "apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: ${CRB_NAME}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: cluster-admin
+subjects:
+- kind: ServiceAccount
+  name: ${SA_NAME}
+  namespace: ${NAMESPACE_SUBSCRIPTION}
+" > "$TMPDIR"/ClusterRoleBinding.yml && invoke_cluster_cli apply -f "$TMPDIR"/ClusterRoleBinding.yml
Relevance

⭐⭐ Medium

Repo favors least-privilege RBAC (e.g., removed unused rules in PR #1320/#1374), but no precedent
for installer SA needs.

PR-#1320
PR-#1374

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The OLM v1 branch writes and applies a ClusterRoleBinding manifest that sets `roleRef.name:
cluster-admin` for the installer ServiceAccount, making it cluster-admin cluster-wide.

.rhdh/scripts/install-rhdh-catalog-source.sh[928-951]

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

### Issue description
The OLM v1 install flow creates a `ClusterRoleBinding` to `cluster-admin` for the `${OPERATOR_NAME_TO_INSTALL}-installer` ServiceAccount. This grants broad, persistent cluster-admin privileges, which is an unnecessary security risk for a script-driven install path.

### Issue Context
The new OLM v1 code path creates a ServiceAccount and binds it to `cluster-admin` before creating the `ClusterExtension`.

### Fix Focus Areas
- Replace the `cluster-admin` ClusterRoleBinding with least-privilege permissions required by the OLM v1 ClusterExtension installer (use an existing purpose-built ClusterRole if available, otherwise define a custom ClusterRole with only needed verbs/resources).
- If elevated privileges are truly required, gate them behind an explicit flag (e.g. `--grant-cluster-admin`) and/or clean them up after installation completes (delete the ClusterRoleBinding/ServiceAccount once the ClusterExtension is installed).

- .rhdh/scripts/install-rhdh-catalog-source.sh[928-951]

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



Remediation recommended

2. Stale v1 RBAC undetected ✓ Resolved 🐞 Bug ⛨ Security
Description
When RESOLVED_OLM_VERSION is v0, the new stale-resource guard only checks for leftover
ClusterCatalog/ClusterExtension and does not detect the OLM v1 installer
ServiceAccount/ClusterRoleBinding created by the v1 path. This allows switching back to OLM v0 while
leaving cluster-scoped RBAC behind, making cleanup/error diagnosis harder and unnecessarily
retaining elevated access.
Code

.rhdh/scripts/install-rhdh-catalog-source.sh[R832-843]

+elif [[ "${RESOLVED_OLM_VERSION}" == "v0" ]]; then
+  stale_v1=""
+  if invoke_cluster_cli get clustercatalog "${CATALOGSOURCE_NAME}" &>/dev/null; then
+    stale_v1="${stale_v1}  - ClusterCatalog/${CATALOGSOURCE_NAME}\n"
+  fi
+  if invoke_cluster_cli get clusterextension "${OPERATOR_NAME_TO_INSTALL}" &>/dev/null; then
+    stale_v1="${stale_v1}  - ClusterExtension/${OPERATOR_NAME_TO_INSTALL}\n"
+  fi
+  if [[ -n "$stale_v1" ]]; then
+    errorf "Found leftover OLM v1 resources from a previous installation:\n${stale_v1}Please remove them before installing with OLM v0."
+    exit 1
+  fi
Relevance

⭐⭐⭐ High

Team historically accepts install-script preflight guards/fail-fast cleanup checks (e.g., unexpected
OperatorGroups) in install script.

PR-#1037
PR-#2870

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The stale-resource guard for v0 mode only checks for ClusterCatalog and ClusterExtension, but the v1
install path also creates an installer ServiceAccount and a ClusterRoleBinding; these can remain
even when the guard passes.

.rhdh/scripts/install-rhdh-catalog-source.sh[812-843]
.rhdh/scripts/install-rhdh-catalog-source.sh[1001-1026]

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

### Issue description
The v0 stale-resource detection only blocks on `ClusterCatalog` and `ClusterExtension`, but the v1 install path also creates an installer `ServiceAccount` and a cluster-scoped `ClusterRoleBinding`. Switching from OLM v1 to v0 can therefore leave these RBAC resources behind.

### Issue Context
- v0 stale detection currently checks only `clustercatalog` and `clusterextension`.
- v1 path creates `${OPERATOR_NAME_TO_INSTALL}-installer` (ServiceAccount in `${NAMESPACE_SUBSCRIPTION}`) and `${OPERATOR_NAME_TO_INSTALL}-installer-binding` (ClusterRoleBinding).

### Fix Focus Areas
- .rhdh/scripts/install-rhdh-catalog-source.sh[812-845]

Suggested change:
- In the `RESOLVED_OLM_VERSION == v0` stale check, also probe for:
 - `serviceaccount/${OPERATOR_NAME_TO_INSTALL}-installer` in `${NAMESPACE_SUBSCRIPTION}`
 - `clusterrolebinding/${OPERATOR_NAME_TO_INSTALL}-installer-binding`
- If found, include them in the `stale_v1` message (and/or optionally offer to delete them automatically, consistent with the script’s current “please remove them” behavior).

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


3. v1 usage misleads install ✓ Resolved 🐞 Bug ≡ Correctness
Description
The help text says OLM v1 creates both a ClusterCatalog and a ClusterExtension, but the script only
creates ClusterExtension when --install-operator is provided and otherwise exits after creating
only the ClusterCatalog. This can mislead users into expecting an operator install to happen (or
expecting ClusterExtension to exist) when they only created the catalog.
Code

.rhdh/scripts/install-rhdh-catalog-source.sh[R58-59]

+as a catalog source. On OLM v0, a CatalogSource is created in 'openshift-marketplace' (OpenShift) or 'olm' (Kubernetes). On OLM v1
+(OpenShift only), a ClusterCatalog and ClusterExtension are created instead. By default, the OLM version is auto-detected based on the
Relevance

⭐⭐⭐ High

They routinely accept fixing misleading usage/docs about what resources are created in each mode
(see accepted help clarifications in PR #1646).

PR-#1646

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The help text claims both resources are created on OLM v1, but the OLM v1 code path exits early when
TO_INSTALL is empty (no --install-operator), after creating only the ClusterCatalog and before
creating any ClusterExtension.

.rhdh/scripts/install-rhdh-catalog-source.sh[55-60]
.rhdh/scripts/install-rhdh-catalog-source.sh[944-960]

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

### Issue description
The `usage()` output currently states that on OLM v1 the script creates both `ClusterCatalog` and `ClusterExtension`, but in the implementation the `ClusterExtension` is created only when `--install-operator` is set; otherwise the script creates only the `ClusterCatalog` and exits.

### Issue Context
This is user-facing CLI documentation in `usage()` and should accurately reflect conditional behavior so users don’t look for resources that were never created.

### Fix Focus Areas
- .rhdh/scripts/install-rhdh-catalog-source.sh[55-60]

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


4. OLM v1 namespaces undocumented ✓ Resolved 📘 Rule violation ✧ Quality
Description
The updated usage() text describes where OLM v0 creates the CatalogSource but does not state where
the OLM v1 path creates/targets resources (e.g., ServiceAccount in NAMESPACE_SUBSCRIPTION and
ClusterExtension targeting spec.namespace). This can mislead users about where to look for created
resources and how to clean them up.
Code

.rhdh/scripts/install-rhdh-catalog-source.sh[R58-60]

+as a catalog source. On OLM v0, a CatalogSource is created in 'openshift-marketplace' (OpenShift) or 'olm' (Kubernetes). On OLM v1
+(OpenShift only), a ClusterCatalog and ClusterExtension are created instead. By default, the OLM version is auto-detected based on the
+presence of the ClusterExtension CRD. The catalog/resource name is 'operatorName-channelName', eg., rhdh-fast
Relevance

⭐⭐⭐ High

Team has accepted clarifying help text about resource behavior/locations in scripts (usage updates
accepted in PR #1646).

PR-#1646

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The compliance rule requires documenting the namespace where resources are created when it matters.
The usage() text mentions OLM v0 namespaces but not the OLM v1 namespace/targeting behavior, while
the OLM v1 implementation creates a ServiceAccount in ${NAMESPACE_SUBSCRIPTION} and sets
ClusterExtension.spec.namespace to ${NAMESPACE_SUBSCRIPTION}.

Rule 5: Document resource creation namespace when behaviorally relevant
.rhdh/scripts/install-rhdh-catalog-source.sh[58-60]
.rhdh/scripts/install-rhdh-catalog-source.sh[84-86]
.rhdh/scripts/install-rhdh-catalog-source.sh[962-975]
.rhdh/scripts/install-rhdh-catalog-source.sh[999-1006]

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

## Issue description
The `usage()` output documents OLM v0 namespace behavior, but for OLM v1 it does not clearly document the namespace behavior for created/targeted resources.

## Issue Context
In the OLM v1 path, the script creates a namespaced `ServiceAccount` in `${NAMESPACE_SUBSCRIPTION}` and sets `ClusterExtension.spec.namespace: ${NAMESPACE_SUBSCRIPTION}`. Users need this spelled out because it affects where they inspect resources and how they clean them up.

## Fix Focus Areas
- .rhdh/scripts/install-rhdh-catalog-source.sh[58-60]
- .rhdh/scripts/install-rhdh-catalog-source.sh[84-86]

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


View more (1)
5. --olm-version missing arg ✓ Resolved 🐞 Bug ☼ Reliability
Description
The new --olm-version option dereferences $2 without checking it exists; with set -u, calling
the script as --olm-version (no value) aborts with an unbound variable error instead of emitting a
controlled usage error. This makes the script fail in a brittle, non-user-friendly way for a common
CLI mistake.
Code

.rhdh/scripts/install-rhdh-catalog-source.sh[R747-755]

+    '--olm-version')
+      if [[ "$2" != "v0" && "$2" != "v1" && "$2" != "auto" ]]; then
+        errorf "Unknown OLM version: $2. Must be v0, v1, or auto."
+        usage
+        exit 1
+      fi
+      OLM_VERSION="$2"
+      shift 1
+      ;;
Relevance

⭐⭐⭐ High

Team frequently hardens shell scripts with input validation under set -euo (e.g., MAX_PARALLEL guard
in PR #2870).

PR-#2870

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new --olm-version parsing branch directly evaluates $2 in a conditional and assigns it, with
no check that a second argument is present.

.rhdh/scripts/install-rhdh-catalog-source.sh[719-755]

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

### Issue description
The `--olm-version` flag handler uses `$2` unconditionally. Under `set -u`, if the user forgets to pass a value, the script terminates with an unbound variable error rather than printing a clear message.

### Issue Context
Argument parsing is done in a `while`/`case` loop and the new `--olm-version` case checks `$2` directly.

### Fix Focus Areas
- Add a guard before reading `$2` (e.g., `if [[ $# -lt 2 ]]; then errorf "--olm-version requires v0|v1|auto"; usage; exit 1; fi`) or use a safe expansion like `${2:-}`.

- .rhdh/scripts/install-rhdh-catalog-source.sh[719-755]

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



Informational

6. Fragile v1 namespace defaults 🐞 Bug ☼ Reliability ⭐ New
Description
In the OLM v1 path, controller namespaces fall back to hard-coded values when deployment discovery
returns empty, which can cause image-puller grants to target the wrong ServiceAccounts and lead to
image pull/install failures on clusters with non-default OLM v1 namespaces or restricted list
permissions.
Code

.rhdh/scripts/install-rhdh-catalog-source.sh[R961-965]

+    if [[ "${IS_OPENSHIFT}" = "true" ]]; then
+      NAMESPACE_CATALOGD="openshift-catalogd"
+    else
+      NAMESPACE_CATALOGD="olmv1-system"
+    fi
Relevance

⭐ Low

Team often keeps hard-coded namespace defaults in scripts; no prior review insisting on failing
instead of defaulting.

PR-#1305
PR-#2126
PR-#2870

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The script explicitly assigns hard-coded namespace defaults when the discovery query yields an empty
namespace, and then uses those namespaces to grant system:image-puller to controller
ServiceAccounts; if defaults are wrong, the grants won’t apply to the real controllers.

.rhdh/scripts/install-rhdh-catalog-source.sh[958-965]
.rhdh/scripts/install-rhdh-catalog-source.sh[975-992]

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

### Issue description
The OLM v1 path falls back to hard-coded namespaces (`openshift-catalogd`, `openshift-operator-controller`, `olmv1-system`) when `get deployment -A -l ...` returns no items. If the deployments are installed in different namespaces, use different labels, or the user lacks permission to list deployments cluster-wide, the script can apply RBAC/image-puller grants to the wrong subjects and then proceed, resulting in hard-to-diagnose image pull / installation failures.

### Issue Context
Namespace discovery is best-effort today (`|| true` + fallback). Only the fallback namespace existence is checked (for catalogd), not that the expected deployment/serviceaccount actually exists in that namespace.

### Fix Focus Areas
- .rhdh/scripts/install-rhdh-catalog-source.sh[958-992]

Suggested approach:
- If the discovery query returns empty, do **not** assume a default namespace. Instead:
 - Re-run discovery with clearer errors; optionally check `invoke_cluster_cli auth can-i list deployments --all-namespaces` and error if not permitted.
 - Or validate the fallback by confirming the expected deployment exists in the candidate namespace (e.g., `get deploy -n "$ns" -l app.kubernetes.io/name=catalogd` has at least one item), otherwise error with actionable guidance.
- Apply the same validation for both catalogd and operator-controller namespaces (not just catalogd).

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


7. Catalog name claim incorrect ✓ Resolved 🐞 Bug ≡ Correctness
Description
The help text claims the catalog/resource name is always operatorName-channelName, but the script
sometimes uses a different fixed name (brew-registry-stage) when a brew IIB override is used. This
can cause confusion when users try to get/delete the catalog resource by the name suggested in the
help text.
Code

.rhdh/scripts/install-rhdh-catalog-source.sh[60]

+presence of the ClusterExtension CRD. The catalog/resource name is 'operatorName-channelName', eg., rhdh-fast
Relevance

⭐⭐⭐ High

Accuracy fixes to script examples/usage are commonly accepted (usage/example adjustments accepted in
PR #1480 and PR #1646).

PR-#1480
PR-#1646

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The help text states a universal naming pattern, but the script explicitly overrides
CATALOGSOURCE_NAME to brew-registry-stage under a brew override condition, making the help text
inaccurate in that mode.

.rhdh/scripts/install-rhdh-catalog-source.sh[55-60]
.rhdh/scripts/install-rhdh-catalog-source.sh[802-808]

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

### Issue description
The `usage()` text asserts a single naming convention (`operatorName-channelName`) for the catalog/resource name, but the script sets `CATALOGSOURCE_NAME` to `brew-registry-stage` for a specific override case.

### Issue Context
This is user-facing help; the simplest fix is to describe the default naming convention and mention the override/special-case naming.

### Fix Focus Areas
- .rhdh/scripts/install-rhdh-catalog-source.sh[55-60]
- .rhdh/scripts/install-rhdh-catalog-source.sh[802-808]

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


8. Suppressed oc policy errors ✓ Resolved 🐞 Bug ☼ Reliability
Description
The OLM v1 path suppresses failures from oc policy add-role-to-user ... via || true, so missing
privileges/incorrect namespaces/other errors won’t stop the script even though
catalogd/operator-controller (and the installer SA) may then be unable to pull IIB/operator images
from the internal rhdh project. This can cause later ClusterCatalog/ClusterExtension install
failures with harder-to-diagnose image pull errors instead of failing at the real root cause.
Code

.rhdh/scripts/install-rhdh-catalog-source.sh[R931-932]

+  oc policy add-role-to-user system:image-puller "system:serviceaccount:${NAMESPACE_CATALOGD}:catalogd-controller-manager" -n rhdh || true
+  oc policy add-role-to-user system:image-puller "system:serviceaccount:${NAMESPACE_OLM_CONTROLLER}:operator-controller-controller-manager" -n rhdh || true
Relevance

⭐ Low

Similar “don’t suppress errors” change was rejected in install script (kept skipping failures).

PR-#2870

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new OLM v1 path adds image-puller grants for catalogd/operator-controller and the installer
ServiceAccount but forces them to succeed via || true. Elsewhere, the script builds/pushes images
into the internal registry under the rhdh project and already applies image-puller grants for
other service accounts, indicating these permissions are expected to be important for pulling
internal images.

.rhdh/scripts/install-rhdh-catalog-source.sh[930-932]
.rhdh/scripts/install-rhdh-catalog-source.sh[989-990]
.rhdh/scripts/install-rhdh-catalog-source.sh[333-380]

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

## Issue description
In the OLM v1 code path, the script runs `oc policy add-role-to-user ... || true`, which hides failures applying required image-puller grants. If these grants fail, controllers/SAs may not be able to pull images from the internal OpenShift registry project and the install can fail later with less actionable errors.

## Issue Context
The script builds/pushes IIB content into the `rhdh` project in the internal OpenShift registry and already relies on image-puller grants for other SAs. The new OLM v1 SAs should be treated similarly, but failures should be explicitly handled.

## Fix Focus Areas
- .rhdh/scripts/install-rhdh-catalog-source.sh[930-932]
- .rhdh/scripts/install-rhdh-catalog-source.sh[989-991]

### Suggested implementation direction
- Replace `|| true` with explicit handling:
 - `if ! oc policy add-role-to-user ...; then errorf "..."; exit 1; fi`
 - or at minimum `warnf` with a clear message that install may fail due to missing pull permissions (include the exact command to re-run).
- If you want to keep best-effort behavior, gate the “hard fail” only when `newIIBImage` points at the internal registry / internal `rhdh` project, where these grants are actually required.

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


Grey Divider

Previous review results

Review updated until commit 2990296

Results up to commit 5cfa994


🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Action required
1. Cluster-admin installer binding 🐞 Bug ⛨ Security
Description
In the OLM v1 path, the script creates a ClusterRoleBinding that grants the installer ServiceAccount
the built-in cluster-admin ClusterRole, giving it full cluster-wide privileges. This leaves a
highly privileged credential in-cluster and substantially increases impact if the ServiceAccount
token is leaked or the namespace is compromised.
Code

.rhdh/scripts/install-rhdh-catalog-source.sh[R937-951]

+  # ClusterRoleBinding granting cluster-admin to the installer SA
+  CRB_NAME="${OPERATOR_NAME_TO_INSTALL}-installer-binding"
+  echo "apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: ${CRB_NAME}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: cluster-admin
+subjects:
+- kind: ServiceAccount
+  name: ${SA_NAME}
+  namespace: ${NAMESPACE_SUBSCRIPTION}
+" > "$TMPDIR"/ClusterRoleBinding.yml && invoke_cluster_cli apply -f "$TMPDIR"/ClusterRoleBinding.yml
Relevance

⭐⭐ Medium

Repo favors least-privilege RBAC (e.g., removed unused rules in PR #1320/#1374), but no precedent
for installer SA needs.

PR-#1320
PR-#1374

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The OLM v1 branch writes and applies a ClusterRoleBinding manifest that sets `roleRef.name:
cluster-admin` for the installer ServiceAccount, making it cluster-admin cluster-wide.

.rhdh/scripts/install-rhdh-catalog-source.sh[928-951]

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

### Issue description
The OLM v1 install flow creates a `ClusterRoleBinding` to `cluster-admin` for the `${OPERATOR_NAME_TO_INSTALL}-installer` ServiceAccount. This grants broad, persistent cluster-admin privileges, which is an unnecessary security risk for a script-driven install path.

### Issue Context
The new OLM v1 code path creates a ServiceAccount and binds it to `cluster-admin` before creating the `ClusterExtension`.

### Fix Focus Areas
- Replace the `cluster-admin` ClusterRoleBinding with least-privilege permissions required by the OLM v1 ClusterExtension installer (use an existing purpose-built ClusterRole if available, otherwise define a custom ClusterRole with only needed verbs/resources).
- If elevated privileges are truly required, gate them behind an explicit flag (e.g. `--grant-cluster-admin`) and/or clean them up after installation completes (delete the ClusterRoleBinding/ServiceAccount once the ClusterExtension is installed).

- .rhdh/scripts/install-rhdh-catalog-source.sh[928-951]

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



Remediation recommended
2. --olm-version missing arg ✓ Resolved 🐞 Bug ☼ Reliability
Description
The new --olm-version option dereferences $2 without checking it exists; with set -u, calling
the script as --olm-version (no value) aborts with an unbound variable error instead of emitting a
controlled usage error. This makes the script fail in a brittle, non-user-friendly way for a common
CLI mistake.
Code

.rhdh/scripts/install-rhdh-catalog-source.sh[R747-755]

+    '--olm-version')
+      if [[ "$2" != "v0" && "$2" != "v1" && "$2" != "auto" ]]; then
+        errorf "Unknown OLM version: $2. Must be v0, v1, or auto."
+        usage
+        exit 1
+      fi
+      OLM_VERSION="$2"
+      shift 1
+      ;;
Relevance

⭐⭐⭐ High

Team frequently hardens shell scripts with input validation under set -euo (e.g., MAX_PARALLEL guard
in PR #2870).

PR-#2870

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new --olm-version parsing branch directly evaluates $2 in a conditional and assigns it, with
no check that a second argument is present.

.rhdh/scripts/install-rhdh-catalog-source.sh[719-755]

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

### Issue description
The `--olm-version` flag handler uses `$2` unconditionally. Under `set -u`, if the user forgets to pass a value, the script terminates with an unbound variable error rather than printing a clear message.

### Issue Context
Argument parsing is done in a `while`/`case` loop and the new `--olm-version` case checks `$2` directly.

### Fix Focus Areas
- Add a guard before reading `$2` (e.g., `if [[ $# -lt 2 ]]; then errorf "--olm-version requires v0|v1|auto"; usage; exit 1; fi`) or use a safe expansion like `${2:-}`.

- .rhdh/scripts/install-rhdh-catalog-source.sh[719-755]

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


Results up to commit 9e42c86


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Informational
1. Suppressed oc policy errors ✓ Resolved 🐞 Bug ☼ Reliability
Description
The OLM v1 path suppresses failures from oc policy add-role-to-user ... via || true, so missing
privileges/incorrect namespaces/other errors won’t stop the script even though
catalogd/operator-controller (and the installer SA) may then be unable to pull IIB/operator images
from the internal rhdh project. This can cause later ClusterCatalog/ClusterExtension install
failures with harder-to-diagnose image pull errors instead of failing at the real root cause.
Code

.rhdh/scripts/install-rhdh-catalog-source.sh[R931-932]

+  oc policy add-role-to-user system:image-puller "system:serviceaccount:${NAMESPACE_CATALOGD}:catalogd-controller-manager" -n rhdh || true
+  oc policy add-role-to-user system:image-puller "system:serviceaccount:${NAMESPACE_OLM_CONTROLLER}:operator-controller-controller-manager" -n rhdh || true
Relevance

⭐ Low

Similar “don’t suppress errors” change was rejected in install script (kept skipping failures).

PR-#2870

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new OLM v1 path adds image-puller grants for catalogd/operator-controller and the installer
ServiceAccount but forces them to succeed via || true. Elsewhere, the script builds/pushes images
into the internal registry under the rhdh project and already applies image-puller grants for
other service accounts, indicating these permissions are expected to be important for pulling
internal images.

.rhdh/scripts/install-rhdh-catalog-source.sh[930-932]
.rhdh/scripts/install-rhdh-catalog-source.sh[989-990]
.rhdh/scripts/install-rhdh-catalog-source.sh[333-380]

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

## Issue description
In the OLM v1 code path, the script runs `oc policy add-role-to-user ... || true`, which hides failures applying required image-puller grants. If these grants fail, controllers/SAs may not be able to pull images from the internal OpenShift registry project and the install can fail later with less actionable errors.

## Issue Context
The script builds/pushes IIB content into the `rhdh` project in the internal OpenShift registry and already relies on image-puller grants for other SAs. The new OLM v1 SAs should be treated similarly, but failures should be explicitly handled.

## Fix Focus Areas
- .rhdh/scripts/install-rhdh-catalog-source.sh[930-932]
- .rhdh/scripts/install-rhdh-catalog-source.sh[989-991]

### Suggested implementation direction
- Replace `|| true` with explicit handling:
 - `if ! oc policy add-role-to-user ...; then errorf "..."; exit 1; fi`
 - or at minimum `warnf` with a clear message that install may fail due to missing pull permissions (include the exact command to re-run).
- If you want to keep best-effort behavior, gate the “hard fail” only when `newIIBImage` points at the internal registry / internal `rhdh` project, where these grants are actually required.

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


Results up to commit db777b0


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Remediation recommended
1. v1 usage misleads install ✓ Resolved 🐞 Bug ≡ Correctness
Description
The help text says OLM v1 creates both a ClusterCatalog and a ClusterExtension, but the script only
creates ClusterExtension when --install-operator is provided and otherwise exits after creating
only the ClusterCatalog. This can mislead users into expecting an operator install to happen (or
expecting ClusterExtension to exist) when they only created the catalog.
Code

.rhdh/scripts/install-rhdh-catalog-source.sh[R58-59]

+as a catalog source. On OLM v0, a CatalogSource is created in 'openshift-marketplace' (OpenShift) or 'olm' (Kubernetes). On OLM v1
+(OpenShift only), a ClusterCatalog and ClusterExtension are created instead. By default, the OLM version is auto-detected based on the
Relevance

⭐⭐⭐ High

They routinely accept fixing misleading usage/docs about what resources are created in each mode
(see accepted help clarifications in PR #1646).

PR-#1646

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The help text claims both resources are created on OLM v1, but the OLM v1 code path exits early when
TO_INSTALL is empty (no --install-operator), after creating only the ClusterCatalog and before
creating any ClusterExtension.

.rhdh/scripts/install-rhdh-catalog-source.sh[55-60]
.rhdh/scripts/install-rhdh-catalog-source.sh[944-960]

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

### Issue description
The `usage()` output currently states that on OLM v1 the script creates both `ClusterCatalog` and `ClusterExtension`, but in the implementation the `ClusterExtension` is created only when `--install-operator` is set; otherwise the script creates only the `ClusterCatalog` and exits.

### Issue Context
This is user-facing CLI documentation in `usage()` and should accurately reflect conditional behavior so users don’t look for resources that were never created.

### Fix Focus Areas
- .rhdh/scripts/install-rhdh-catalog-source.sh[55-60]

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


2. OLM v1 namespaces undocumented ✓ Resolved 📘 Rule violation ✧ Quality
Description
The updated usage() text describes where OLM v0 creates the CatalogSource but does not state where
the OLM v1 path creates/targets resources (e.g., ServiceAccount in NAMESPACE_SUBSCRIPTION and
ClusterExtension targeting spec.namespace). This can mislead users about where to look for created
resources and how to clean them up.
Code

.rhdh/scripts/install-rhdh-catalog-source.sh[R58-60]

+as a catalog source. On OLM v0, a CatalogSource is created in 'openshift-marketplace' (OpenShift) or 'olm' (Kubernetes). On OLM v1
+(OpenShift only), a ClusterCatalog and ClusterExtension are created instead. By default, the OLM version is auto-detected based on the
+presence of the ClusterExtension CRD. The catalog/resource name is 'operatorName-channelName', eg., rhdh-fast
Relevance

⭐⭐⭐ High

Team has accepted clarifying help text about resource behavior/locations in scripts (usage updates
accepted in PR #1646).

PR-#1646

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The compliance rule requires documenting the namespace where resources are created when it matters.
The usage() text mentions OLM v0 namespaces but not the OLM v1 namespace/targeting behavior, while
the OLM v1 implementation creates a ServiceAccount in ${NAMESPACE_SUBSCRIPTION} and sets
ClusterExtension.spec.namespace to ${NAMESPACE_SUBSCRIPTION}.

Rule 5: Document resource creation namespace when behaviorally relevant
.rhdh/scripts/install-rhdh-catalog-source.sh[58-60]
.rhdh/scripts/install-rhdh-catalog-source.sh[84-86]
.rhdh/scripts/install-rhdh-catalog-source.sh[962-975]
.rhdh/scripts/install-rhdh-catalog-source.sh[999-1006]

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

## Issue description
The `usage()` output documents OLM v0 namespace behavior, but for OLM v1 it does not clearly document the namespace behavior for created/targeted resources.

## Issue Context
In the OLM v1 path, the script creates a namespaced `ServiceAccount` in `${NAMESPACE_SUBSCRIPTION}` and sets `ClusterExtension.spec.namespace: ${NAMESPACE_SUBSCRIPTION}`. Users need this spelled out because it affects where they inspect resources and how they clean them up.

## Fix Focus Areas
- .rhdh/scripts/install-rhdh-catalog-source.sh[58-60]
- .rhdh/scripts/install-rhdh-catalog-source.sh[84-86]

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



Informational
3. Catalog name claim incorrect ✓ Resolved 🐞 Bug ≡ Correctness
Description
The help text claims the catalog/resource name is always operatorName-channelName, but the script
sometimes uses a different fixed name (brew-registry-stage) when a brew IIB override is used. This
can cause confusion when users try to get/delete the catalog resource by the name suggested in the
help text.
Code

.rhdh/scripts/install-rhdh-catalog-source.sh[60]

+presence of the ClusterExtension CRD. The catalog/resource name is 'operatorName-channelName', eg., rhdh-fast
Relevance

⭐⭐⭐ High

Accuracy fixes to script examples/usage are commonly accepted (usage/example adjustments accepted in
PR #1480 and PR #1646).

PR-#1480
PR-#1646

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The help text states a universal naming pattern, but the script explicitly overrides
CATALOGSOURCE_NAME to brew-registry-stage under a brew override condition, making the help text
inaccurate in that mode.

.rhdh/scripts/install-rhdh-catalog-source.sh[55-60]
.rhdh/scripts/install-rhdh-catalog-source.sh[802-808]

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

### Issue description
The `usage()` text asserts a single naming convention (`operatorName-channelName`) for the catalog/resource name, but the script sets `CATALOGSOURCE_NAME` to `brew-registry-stage` for a specific override case.

### Issue Context
This is user-facing help; the simplest fix is to describe the default naming convention and mention the override/special-case naming.

### Fix Focus Areas
- .rhdh/scripts/install-rhdh-catalog-source.sh[55-60]
- .rhdh/scripts/install-rhdh-catalog-source.sh[802-808]

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


Results up to commit 44e36f1


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Remediation recommended
1. Stale v1 RBAC undetected ✓ Resolved 🐞 Bug ⛨ Security
Description
When RESOLVED_OLM_VERSION is v0, the new stale-resource guard only checks for leftover
ClusterCatalog/ClusterExtension and does not detect the OLM v1 installer
ServiceAccount/ClusterRoleBinding created by the v1 path. This allows switching back to OLM v0 while
leaving cluster-scoped RBAC behind, making cleanup/error diagnosis harder and unnecessarily
retaining elevated access.
Code

.rhdh/scripts/install-rhdh-catalog-source.sh[R832-843]

+elif [[ "${RESOLVED_OLM_VERSION}" == "v0" ]]; then
+  stale_v1=""
+  if invoke_cluster_cli get clustercatalog "${CATALOGSOURCE_NAME}" &>/dev/null; then
+    stale_v1="${stale_v1}  - ClusterCatalog/${CATALOGSOURCE_NAME}\n"
+  fi
+  if invoke_cluster_cli get clusterextension "${OPERATOR_NAME_TO_INSTALL}" &>/dev/null; then
+    stale_v1="${stale_v1}  - ClusterExtension/${OPERATOR_NAME_TO_INSTALL}\n"
+  fi
+  if [[ -n "$stale_v1" ]]; then
+    errorf "Found leftover OLM v1 resources from a previous installation:\n${stale_v1}Please remove them before installing with OLM v0."
+    exit 1
+  fi
Relevance

⭐⭐⭐ High

Team historically accepts install-script preflight guards/fail-fast cleanup checks (e.g., unexpected
OperatorGroups) in install script.

PR-#1037
PR-#2870

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The stale-resource guard for v0 mode only checks for ClusterCatalog and ClusterExtension, but the v1
install path also creates an installer ServiceAccount and a ClusterRoleBinding; these can remain
even when the guard passes.

.rhdh/scripts/install-rhdh-catalog-source.sh[812-843]
.rhdh/scripts/install-rhdh-catalog-source.sh[1001-1026]

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

### Issue description
The v0 stale-resource detection only blocks on `ClusterCatalog` and `ClusterExtension`, but the v1 install path also creates an installer `ServiceAccount` and a cluster-scoped `ClusterRoleBinding`. Switching from OLM v1 to v0 can therefore leave these RBAC resources behind.

### Issue Context
- v0 stale detection currently checks only `clustercatalog` and `clusterextension`.
- v1 path creates `${OPERATOR_NAME_TO_INSTALL}-installer` (ServiceAccount in `${NAMESPACE_SUBSCRIPTION}`) and `${OPERATOR_NAME_TO_INSTALL}-installer-binding` (ClusterRoleBinding).

### Fix Focus Areas
- .rhdh/scripts/install-rhdh-catalog-source.sh[812-845]

Suggested change:
- In the `RESOLVED_OLM_VERSION == v0` stale check, also probe for:
 - `serviceaccount/${OPERATOR_NAME_TO_INSTALL}-installer` in `${NAMESPACE_SUBSCRIPTION}`
 - `clusterrolebinding/${OPERATOR_NAME_TO_INSTALL}-installer-binding`
- If found, include them in the `stale_v1` message (and/or optionally offer to delete them automatically, consistent with the script’s current “please remove them” behavior).

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


Qodo Logo

Comment thread .rhdh/scripts/install-rhdh-catalog-source.sh Outdated
@rhdh-qodo-merge rhdh-qodo-merge Bot added documentation Improvements or additions to documentation enhancement New feature or request labels Jun 23, 2026
… the operator-controller namespace and granting image-puller access to necessary service accounts. Update ClusterCatalog and ClusterRoleBinding creation to align with OLM v1 specifications.
Comment thread .rhdh/scripts/install-rhdh-catalog-source.sh Fixed
Comment thread .rhdh/scripts/install-rhdh-catalog-source.sh Fixed
Comment thread .rhdh/scripts/install-rhdh-catalog-source.sh Fixed
@Fortune-Ndlovu

Fortune-Ndlovu commented Jun 23, 2026

Copy link
Copy Markdown
Member Author
image
apiVersion: olm.operatorframework.io/v1
kind: ClusterExtension
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"olm.operatorframework.io/v1","kind":"ClusterExtension","metadata":{"annotations":{},"name":"rhdh"},"spec":{"install":{"preflight":{"crdUpgradeSafety":{"enforcement":"None"}}},"namespace":"rhdh-operator","serviceAccount":{"name":"rhdh-installer"},"source":{"catalog":{"channels":["fast"],"packageName":"rhdh","selector":{"matchLabels":{"olm.operatorframework.io/metadata.name":"rhdh-fast"}}},"sourceType":"Catalog"}}}
  creationTimestamp: '2026-06-23T05:57:28Z'
  finalizers:
    - olm.operatorframework.io/cleanup-unpack-cache
    - olm.operatorframework.io/cleanup-contentmanager-cache
  generation: 1
  managedFields:
    - apiVersion: olm.operatorframework.io/v1
      fieldsType: FieldsV1
      fieldsV1:
        'f:spec':
          .: {}
          'f:install':
            .: {}
            'f:preflight':
              .: {}
              'f:crdUpgradeSafety':
                .: {}
                'f:enforcement': {}
          'f:namespace': {}
          'f:serviceAccount':
            .: {}
            'f:name': {}
          'f:source':
            .: {}
            'f:catalog':
              .: {}
              'f:channels': {}
              'f:packageName': {}
              'f:selector': {}
              'f:upgradeConstraintPolicy': {}
            'f:sourceType': {}
      manager: kubectl-client-side-apply
      operation: Update
      time: '2026-06-23T05:57:28Z'
    - apiVersion: olm.operatorframework.io/v1
      fieldsType: FieldsV1
      fieldsV1:
        'f:metadata':
          'f:finalizers':
            .: {}
            'v:"olm.operatorframework.io/cleanup-contentmanager-cache"': {}
            'v:"olm.operatorframework.io/cleanup-unpack-cache"': {}
      manager: operator-controller
      operation: Update
      time: '2026-06-23T05:57:28Z'
    - apiVersion: olm.operatorframework.io/v1
      fieldsType: FieldsV1
      fieldsV1:
        'f:status':
          .: {}
          'f:conditions':
            .: {}
            'k:{"type":"BundleDeprecated"}':
              .: {}
              'f:lastTransitionTime': {}
              'f:message': {}
              'f:observedGeneration': {}
              'f:reason': {}
              'f:status': {}
              'f:type': {}
            'k:{"type":"ChannelDeprecated"}':
              .: {}
              'f:lastTransitionTime': {}
              'f:message': {}
              'f:observedGeneration': {}
              'f:reason': {}
              'f:status': {}
              'f:type': {}
            'k:{"type":"Deprecated"}':
              .: {}
              'f:lastTransitionTime': {}
              'f:message': {}
              'f:observedGeneration': {}
              'f:reason': {}
              'f:status': {}
              'f:type': {}
            'k:{"type":"Installed"}':
              .: {}
              'f:lastTransitionTime': {}
              'f:message': {}
              'f:observedGeneration': {}
              'f:reason': {}
              'f:status': {}
              'f:type': {}
            'k:{"type":"PackageDeprecated"}':
              .: {}
              'f:lastTransitionTime': {}
              'f:message': {}
              'f:observedGeneration': {}
              'f:reason': {}
              'f:status': {}
              'f:type': {}
            'k:{"type":"Progressing"}':
              .: {}
              'f:lastTransitionTime': {}
              'f:message': {}
              'f:observedGeneration': {}
              'f:reason': {}
              'f:status': {}
              'f:type': {}
          'f:install':
            .: {}
            'f:bundle':
              .: {}
              'f:name': {}
              'f:version': {}
      manager: operator-controller
      operation: Update
      subresource: status
      time: '2026-06-23T05:57:30Z'
  name: rhdh
  resourceVersion: '68186'
  uid: 2d7d5cc0-00f2-4e39-88e2-e2beb6435ef4
spec:
  install:
    preflight:
      crdUpgradeSafety:
        enforcement: None
  namespace: rhdh-operator
  serviceAccount:
    name: rhdh-installer
  source:
    catalog:
      channels:
        - fast
      packageName: rhdh
      selector:
        matchLabels:
          olm.operatorframework.io/metadata.name: rhdh-fast
      upgradeConstraintPolicy: CatalogProvided
    sourceType: Catalog
status:
  conditions:
    - lastTransitionTime: '2026-06-23T05:57:28Z'
      message: ''
      observedGeneration: 1
      reason: Deprecated
      status: 'False'
      type: Deprecated
    - lastTransitionTime: '2026-06-23T05:57:28Z'
      message: ''
      observedGeneration: 1
      reason: Deprecated
      status: 'False'
      type: PackageDeprecated
    - lastTransitionTime: '2026-06-23T05:57:28Z'
      message: ''
      observedGeneration: 1
      reason: Deprecated
      status: 'False'
      type: ChannelDeprecated
    - lastTransitionTime: '2026-06-23T05:57:28Z'
      message: ''
      observedGeneration: 1
      reason: Deprecated
      status: 'False'
      type: BundleDeprecated
    - lastTransitionTime: '2026-06-23T05:57:30Z'
      message: 'Installed bundle image-registry.openshift-image-registry.svc:5000/rhdh/rhdh-operator-bundle:1c0403295d17349851e0ddc12124b93fb18780c1f6869c27eddcf1ced8c1b673 successfully'
      observedGeneration: 1
      reason: Succeeded
      status: 'True'
      type: Installed
    - lastTransitionTime: '2026-06-23T05:57:30Z'
      message: Desired state reached
      observedGeneration: 1
      reason: Succeeded
      status: 'True'
      type: Progressing
  install:
    bundle:
      name: rhdh-operator.v1.10.2
      version: 1.10.2

…m-v-1-code-path-to-install-rhdh-catalog-source-sh

@Fortune-Ndlovu Fortune-Ndlovu left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

script also works with olmv0

@Fortune-Ndlovu Fortune-Ndlovu left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

reminder to run the script in an aro cluster also for testing!

Comment thread .rhdh/scripts/install-rhdh-catalog-source.sh
Comment thread .rhdh/scripts/install-rhdh-catalog-source.sh Outdated
…mpatibility and a sample Custom Resource definition. Update role binding commands for clarity and consistency.
@Fortune-Ndlovu

Fortune-Ndlovu commented Jun 24, 2026

Copy link
Copy Markdown
Member Author

/agentic_review

@Fortune-Ndlovu

Copy link
Copy Markdown
Member Author

/review

@rhdh-qodo-merge

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Warning

/review is deprecated. Use /agentic_review instead (removal date not yet scheduled).

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 Security concerns

Privilege escalation:
The script creates a ClusterRoleBinding granting the installer ServiceAccount cluster-admin in the OLM v1 path. If the ServiceAccount token is compromised or misused, this provides full cluster control. Consider using least-privilege RBAC or adding prominent warnings/guardrails (e.g., confirmation prompt or optional flag) when creating cluster-admin bindings.

⚡ Recommended focus areas for review

Shell Options

resolve_olm_version calls set -euo pipefail, which changes shell options for the remainder of the script (since set is not scoped to the function). Confirm this is intended and doesn’t introduce new failures due to unset variables or non-zero exit codes in later commands.

function resolve_olm_version() {
  set -euo pipefail

  if [[ "${IS_OPENSHIFT}" != "true" ]]; then
    if [[ "${OLM_VERSION}" == "v1" ]]; then
      warnf "OLM v1 is not supported on Kubernetes clusters; falling back to v0"
    fi
    RESOLVED_OLM_VERSION="v0"
    return
  fi

  if [[ "${OLM_VERSION}" == "v0" ]]; then
    RESOLVED_OLM_VERSION="v0"
    infof "Using OLM v0 (forced via --olm-version)"
  elif [[ "${OLM_VERSION}" == "v1" ]]; then
    if ! detect_olm_v1; then
      errorf "OLM v1 requested but ClusterExtension CRD not found on this cluster"
      exit 1
    fi
    RESOLVED_OLM_VERSION="v1"
    infof "Using OLM v1 (forced via --olm-version)"
  else
    # auto-detect
    if detect_olm_v1; then
      RESOLVED_OLM_VERSION="v1"
      infof "Auto-detected OLM v1 (ClusterExtension CRD found)"
    else
      RESOLVED_OLM_VERSION="v0"
      infof "Auto-detected OLM v0 (ClusterExtension CRD not found)"
    fi
  fi
}
RBAC Scope

The OLM v1 path creates a ClusterRoleBinding that grants cluster-admin to the installer ServiceAccount. Validate that this level of privilege is required for ClusterExtension installation and consider tightening permissions or clearly documenting why full cluster-admin is necessary.

  # ClusterRoleBinding granting cluster-admin to the installer SA
  CRB_NAME="${OPERATOR_NAME_TO_INSTALL}-installer-binding"
  echo "apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: ${CRB_NAME}
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: ${SA_NAME}
  namespace: ${NAMESPACE_SUBSCRIPTION}
" > "$TMPDIR"/ClusterRoleBinding.yml && invoke_cluster_cli apply -f "$TMPDIR"/ClusterRoleBinding.yml

  # Grant installer SA image-puller access so it can pull operator images from the internal registry
  oc policy add-role-to-user system:image-puller "system:serviceaccount:${NAMESPACE_SUBSCRIPTION}:${SA_NAME}" -n rhdh || true

  # Create ClusterExtension
  echo "apiVersion: olm.operatorframework.io/v1
kind: ClusterExtension
metadata:
  name: ${OPERATOR_NAME_TO_INSTALL}
spec:
  namespace: ${NAMESPACE_SUBSCRIPTION}
  serviceAccount:
    name: ${SA_NAME}
  source:
    sourceType: Catalog
    catalog:
      packageName: ${OPERATOR_NAME_IN_CS}
      channels:
      - ${OLM_CHANNEL}
      selector:
        matchLabels:
          olm.operatorframework.io/metadata.name: ${CATALOGSOURCE_NAME}
  install:
    preflight:
      crdUpgradeSafety:
        enforcement: None
" > "$TMPDIR"/ClusterExtension.yml && invoke_cluster_cli apply -f "$TMPDIR"/ClusterExtension.yml
📚 Focus areas based on broader codebase context

Prerequisites

The OLM v1 path invokes oc policy add-role-to-user ... directly, but this script doesn’t appear to validate that oc is installed/available before using it. On systems where IS_OPENSHIFT=true but oc isn’t present (or PATH differs), the v1 path will fail mid-run. Add an explicit prerequisite check for oc (and potentially gate oc usage behind invoke_cluster_cli where possible). (Ref 2, Ref 6)

  # Grant image-puller access to OLM v1 controller SAs so they can pull images from the internal registry
  oc policy add-role-to-user system:image-puller "system:serviceaccount:${NAMESPACE_CATALOGD}:catalogd-controller-manager" -n rhdh || true
  oc policy add-role-to-user system:image-puller "system:serviceaccount:${NAMESPACE_OLM_CONTROLLER}:operator-controller-controller-manager" -n rhdh || true

  # Delete existing ClusterCatalog to force re-index
  invoke_cluster_cli delete clustercatalog "${CATALOGSOURCE_NAME}" --ignore-not-found

  echo "apiVersion: olm.operatorframework.io/v1
kind: ClusterCatalog
metadata:
  name: ${CATALOGSOURCE_NAME}
spec:
  source:
    type: Image
    image:
      ref: ${newIIBImage}
" > "$TMPDIR"/ClusterCatalog.yml && invoke_cluster_cli apply -f "$TMPDIR"/ClusterCatalog.yml

  if [ -z "${TO_INSTALL}" ]; then
    echo
    echo "Done. ClusterCatalog '${CATALOGSOURCE_NAME}' created."
    echo "To install the operator, create a ClusterExtension, ServiceAccount, and ClusterRoleBinding."
    exit 0
  fi

  # Create namespace if needed
  if ! invoke_cluster_cli get namespace "$NAMESPACE_SUBSCRIPTION" > /dev/null 2>&1; then
    debugf "Namespace $NAMESPACE_SUBSCRIPTION does not exist; creating it"
    invoke_cluster_cli create namespace "$NAMESPACE_SUBSCRIPTION"
  fi

  # ServiceAccount for ClusterExtension installer
  SA_NAME="${OPERATOR_NAME_TO_INSTALL}-installer"
  echo "apiVersion: v1
kind: ServiceAccount
metadata:
  name: ${SA_NAME}
  namespace: ${NAMESPACE_SUBSCRIPTION}
" > "$TMPDIR"/ServiceAccount.yml && invoke_cluster_cli apply -f "$TMPDIR"/ServiceAccount.yml

  # ClusterRoleBinding granting cluster-admin to the installer SA
  CRB_NAME="${OPERATOR_NAME_TO_INSTALL}-installer-binding"
  echo "apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: ${CRB_NAME}
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: ${SA_NAME}
  namespace: ${NAMESPACE_SUBSCRIPTION}
" > "$TMPDIR"/ClusterRoleBinding.yml && invoke_cluster_cli apply -f "$TMPDIR"/ClusterRoleBinding.yml

  # Grant installer SA image-puller access so it can pull operator images from the internal registry
  oc policy add-role-to-user system:image-puller "system:serviceaccount:${NAMESPACE_SUBSCRIPTION}:${SA_NAME}" -n rhdh || true

Reference reasoning: Other bash scripts in the codebase use a dedicated checkPrerequisite function to verify oc exists and exit with a clear error message before performing any oc operations. Reusing that pattern here would make failures deterministic and user-friendly, especially since oc is called explicitly rather than via a wrapper.

📄 References
  1. redhat-developer/rhdh-operator/config/profile/rhdh/plugin-infra/plugin-infra.sh [1-49]
  2. redhat-developer/rhdh-operator/config/profile/rhdh/plugin-infra/gitops-secret-setup.sh [133-182]
  3. redhat-developer/rhdh/scripts/rhdh-openshift-setup/quick-start-rhdh.sh [133-155]
  4. redhat-developer/rhdh/e2e-tests/local-run.sh [392-411]
  5. redhat-developer/rhdh/e2e-tests/local-test-setup.sh [103-119]
  6. redhat-developer/rhdh-chart/hack/orchestrator-templates-setup.sh [249-254]
  7. redhat-developer/rhdh/scripts/rhdh-openshift-setup/quick-start-rhdh.sh [234-287]
  8. redhat-developer/rhdh/scripts/rhdh-openshift-setup/quick-start-rhdh.sh [187-232]

…inding usage for testing. Ensure proper error handling for unsupported OLM versions.
@Fortune-Ndlovu

Copy link
Copy Markdown
Member Author

/agentic_review

@Fortune-Ndlovu

Copy link
Copy Markdown
Member Author

/agentic_review

@rhdh-qodo-merge

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 9e42c86

…d image-puller role grants to service accounts. This ensures better visibility of potential issues with image pulls from the internal registry.
@Fortune-Ndlovu

Copy link
Copy Markdown
Member Author

/agentic_review

@rhdh-qodo-merge

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 5a67b28

… in the install script, clarifying that this is intended for testing purposes only.
… The script now auto-detects OLM version and provides options for forcing OLM v1, improving usability for users configuring catalog sources.
@Fortune-Ndlovu

Copy link
Copy Markdown
Member Author

/agentic_review

@rhdh-qodo-merge

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit db777b0

Comment thread .rhdh/scripts/install-rhdh-catalog-source.sh
Comment thread .rhdh/scripts/install-rhdh-catalog-source.sh
Comment thread .rhdh/scripts/install-rhdh-catalog-source.sh Outdated
Comment thread .rhdh/scripts/install-rhdh-catalog-source.sh Outdated
Comment thread .rhdh/scripts/install-rhdh-catalog-source.sh Outdated
…cted OLM version. This ensures users are informed of any existing resources that may interfere with new installations, enhancing error handling and installation reliability.
…ment for improved readability and maintainability. This change enhances error handling for unsupported OLM versions.
…ed version checks for non-OpenShift environments. The auto-detection logic is now based solely on CRD presence, improving clarity and functionality.
OLM v1 detection is now platform-agnostic via CRD presence,
so the usage description should not restrict it to OpenShift.

Signed-off-by: Fortune Ndlovu <fndlovu@redhat.com>
@Fortune-Ndlovu

Copy link
Copy Markdown
Member Author

/agentic_review

@rhdh-qodo-merge

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 44e36f1

The oc policy add-role-to-user commands are OpenShift-specific and
would fail on plain Kubernetes clusters with OLM v1. Wrap them in
IS_OPENSHIFT guards so the OLM v1 path works on non-OpenShift clusters.

Signed-off-by: Fortune Ndlovu <fndlovu@redhat.com>
The early OLM presence check on non-OpenShift clusters only looked for
the CatalogSource CRD (OLM v0). Kubernetes clusters with only OLM v1
would be rejected before reaching auto-detection. Now accept either
CatalogSource or ClusterExtension CRD as evidence of OLM.

Signed-off-by: Fortune Ndlovu <fndlovu@redhat.com>
The catalogd and operator-controller namespace fallbacks were
hard-coded to OpenShift-specific names. Use olmv1-system as the
fallback on non-OpenShift clusters to match upstream conventions.

Signed-off-by: Fortune Ndlovu <fndlovu@redhat.com>
Makes the implicit global set by resolve_olm_version() visible
alongside the other script-level variables for easier discoverability.

Signed-off-by: Fortune Ndlovu <fndlovu@redhat.com>
… resource check

The v0 stale-resource guard only checked for ClusterCatalog and
ClusterExtension, missing the installer ServiceAccount and
ClusterRoleBinding created by the v1 path. Switching from v1 to v0
could leave these RBAC resources behind with elevated privileges.

Signed-off-by: Fortune Ndlovu <fndlovu@redhat.com>
…and catalog naming

The usage text incorrectly implied ClusterExtension is always created
on OLM v1 (it requires --install-operator), did not document the
namespace where v1 resources are created, and claimed the catalog name
is always operatorName-channelName without mentioning the brew override.

Signed-off-by: Fortune Ndlovu <fndlovu@redhat.com>
@sonarqubecloud

sonarqubecloud Bot commented Jul 7, 2026

Copy link
Copy Markdown

@Fortune-Ndlovu

Copy link
Copy Markdown
Member Author

/agentic_review

@rhdh-qodo-merge

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 2990296

@Fortune-Ndlovu

Copy link
Copy Markdown
Member Author
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request Possible security concern Review effort 3/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants