Skip to content

OPRUN-4666,OPRUN-4671,OPRUN-4672,OPRUN-4673,OPRUN-4674,OPRUN-4659: Synchronize From Upstream Repositories + Remove spec.serviceAccount tests + remove demo e2e - #772

Closed
tmshort wants to merge 143 commits into
openshift:mainfrom
tmshort:PR-762-new-plus-demo
Closed

OPRUN-4666,OPRUN-4671,OPRUN-4672,OPRUN-4673,OPRUN-4674,OPRUN-4659: Synchronize From Upstream Repositories + Remove spec.serviceAccount tests + remove demo e2e#772
tmshort wants to merge 143 commits into
openshift:mainfrom
tmshort:PR-762-new-plus-demo

Conversation

@tmshort

@tmshort tmshort commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Added dynamic GraphQL catalog queries with pagination, schema discovery, caching, request timeouts, and query-complexity safeguards.
    • Added end-to-end demos with recorded terminal sessions and SVG conversion.
    • Added admission controls for fine-grained ClusterExtension API access.
  • Changes

    • ClusterExtension serviceAccount configuration is now optional, deprecated, and ignored; setting it produces a warning.
    • Installation examples no longer require dedicated installer permissions.
  • Documentation

    • Updated guides, API references, navigation, and quickstart demos to reflect the revised installation and access model.

tmshort and others added 30 commits July 2, 2026 07:57
…back (#2791)

- Upgrade go.opentelemetry.io/otel/exporters/otlp/otlptrace,
  otlptracegrpc, and otel/sdk from v1.43.0 to v1.44.0 to match otel,
  otel/metric, and otel/trace already at v1.44.0
- Move E2E_TIMEOUT fallback from target-specific ?= into the e2e-run-%
  recipe via $(or $(E2E_TIMEOUT),20m) so the 20m default is explicit
  and the 25m override from test-experimental-e2e is unambiguous

Signed-off-by: Todd Short <tshort@redhat.com>
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Bumps [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) from 0.21.6 to 0.21.7.
- [Release notes](https://github.com/google/go-containerregistry/releases)
- [Commits](google/go-containerregistry@v0.21.6...v0.21.7)

---
updated-dependencies:
- dependency-name: github.com/google/go-containerregistry
  dependency-version: 0.21.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Convert terminal demos from standalone shell scripts recorded via
asciinema to Godog BDD scenarios that generate asciicast v2 files
programmatically. This makes demos into verified tests that can
never silently break while producing terminal recordings.

The recording infrastructure captures kubectl commands and their
stdout/stderr with real execution timing during @demo-tagged
scenario execution. Per-step dedup handles polling transparently
so only successful results appear in the recording. Step text is
emitted as comments and commands are colored for readability.

Demo scenarios:
- ClusterCatalog Quickstart: queries the operatorhubio catalog API
- SingleNamespace Install Mode: installs mariadb-operator with a
  separate watch namespace, verifies rolebindings
- OwnNamespace Install Mode: installs mariadb-operator with
  watch namespace equal to install namespace
- Webhook Support: installs telegraf-operator, verifies mutating
  webhook injects sidecar container into test pod

Not converted (no matching demo scenarios):
- Synthetic User Permissions: feature gate disabled in experimental
- Helm Chart Support: blocked by OCPBUGS-95281

The update-demos Makefile target now builds OLM from source using the
experimental e2e infrastructure, deploys with all feature gates and
operatorhubio catalog, runs demo scenarios, converts recordings to
SVG via svg-term-cli, and tears down the cluster. Demo recordings
are embedded in docs via the mkdocs-asciinema-player plugin and
served from GitHub Pages, removing the dependency on asciinema.org
for hosting recordings. Demo scenarios are excluded from regular
e2e test runs via ~@demo filter.

CI workflow (update-demos.yaml):
- On PR: generates demos, uploads asciicast and SVG files as job
  artifacts
- On merge to main: generates demos, deploys docs with updated
  recordings via make deploy-docs

Old demo shell scripts, the asciinema generate-asciidemo.sh wrapper,
and hack/demo/ resource files have been removed.

Co-authored-by: Claude <noreply@anthropic.com>
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.38.0 to 0.55.0.
- [Commits](golang/net@v0.38.0...v0.55.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.55.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [github.com/sigstore/fulcio](https://github.com/sigstore/fulcio) from 1.8.5 to 1.8.6.
- [Release notes](https://github.com/sigstore/fulcio/releases)
- [Changelog](https://github.com/sigstore/fulcio/blob/main/CHANGELOG.md)
- [Commits](sigstore/fulcio@v1.8.5...v1.8.6)

---
updated-dependencies:
- dependency-name: github.com/sigstore/fulcio
  dependency-version: 1.8.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: jjaruszewski <jjaruszewski@man.poznan.pl>
GitHub Actions does not support expressions in the permissions block.
The dynamic expression was causing every workflow run to fail with
"workflow file issue" before any job could start.

Use static contents:write (matching pages.yaml convention). The deploy
step is already gated by `if: github.event_name == 'push'`.

Co-authored-by: Claude <noreply@anthropic.com>
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6.4.0 to 6.5.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](actions/setup-go@v6.4.0...v6.5.0)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: 6.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 10.21.3 to 11.0.
- [Release notes](https://github.com/facelessuser/pymdown-extensions/releases)
- [Commits](facelessuser/pymdown-extensions@10.21.3...11.0)

---
updated-dependencies:
- dependency-name: pymdown-extensions
  dependency-version: '11.0'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [helm.sh/helm/v3](https://github.com/helm/helm) from 3.21.1 to 3.21.2.
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](helm/helm@v3.21.1...v3.21.2)

---
updated-dependencies:
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.21.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.2.0 to 6.3.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](actions/setup-python@v6.2.0...v6.3.0)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: 6.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Track ClusterObjectSets in addedResources when applied, matching
the pattern established for ClusterExtensions in #2783. This removes
the special-case cleanup block in ScenarioCleanup and ensures multiple
ClusterObjectSets per scenario are all cleaned up correctly.

Co-authored-by: Per G. da Silva <pegoncal@redhat.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The HelmChartSupport feature gate (alpha, default off) and all code for
detecting, pulling, caching, and loading native Helm chart bundles from
OCI registries is removed. The path forward on the next bundle format is
unclear and may not be Helm, so maintaining this code is not justified.

The Helm backend that converts registry+v1 bundles into Helm chart
objects for installation (RegistryV1HelmChartProvider) is unaffected.

Co-authored-by: Claude <noreply@anthropic.com>
Bumps [click](https://github.com/pallets/click) from 8.4.1 to 8.4.2.
- [Release notes](https://github.com/pallets/click/releases)
- [Changelog](https://github.com/pallets/click/blob/main/CHANGES.md)
- [Commits](pallets/click@8.4.1...8.4.2)

---
updated-dependencies:
- dependency-name: click
  dependency-version: 8.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [github.com/cert-manager/cert-manager](https://github.com/cert-manager/cert-manager) from 1.20.2 to 1.20.3.
- [Release notes](https://github.com/cert-manager/cert-manager/releases)
- [Changelog](https://github.com/cert-manager/cert-manager/blob/master/RELEASE.md)
- [Commits](cert-manager/cert-manager@v1.20.2...v1.20.3)

---
updated-dependencies:
- dependency-name: github.com/cert-manager/cert-manager
  dependency-version: 1.20.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.46.0 to 0.47.0.
- [Release notes](https://github.com/golang/tools/releases)
- [Commits](golang/tools@v0.46.0...v0.47.0)

---
updated-dependencies:
- dependency-name: golang.org/x/tools
  dependency-version: 0.47.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [regex](https://github.com/mrabarnett/mrab-regex) from 2026.5.9 to 2026.6.28.
- [Changelog](https://github.com/mrabarnett/mrab-regex/blob/hg/changelog.txt)
- [Commits](mrabarnett/mrab-regex@2026.5.9...2026.6.28)

---
updated-dependencies:
- dependency-name: regex
  dependency-version: 2026.6.28
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [github.com/klauspost/compress](https://github.com/klauspost/compress) from 1.18.6 to 1.19.0.
- [Release notes](https://github.com/klauspost/compress/releases)
- [Commits](klauspost/compress@v1.18.6...v1.19.0)

---
updated-dependencies:
- dependency-name: github.com/klauspost/compress
  dependency-version: 1.19.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [docker/login-action](https://github.com/docker/login-action) from 4.2.0 to 4.3.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](docker/login-action@v4.2.0...v4.3.0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 4.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [dorny/paths-filter](https://github.com/dorny/paths-filter) from 4.0.1 to 4.0.2.
- [Release notes](https://github.com/dorny/paths-filter/releases)
- [Changelog](https://github.com/dorny/paths-filter/blob/master/CHANGELOG.md)
- [Commits](dorny/paths-filter@v4.0.1...v4.0.2)

---
updated-dependencies:
- dependency-name: dorny/paths-filter
  dependency-version: 4.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.21.0 to 0.22.0.
- [Commits](golang/sync@v0.21.0...v0.22.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  dependency-version: 0.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* shift to file-based cache, leveraging existing metas indexer

* review comments

Signed-off-by: grokspawn <jordan@nimblewidget.com>

* bounds-protect type evaluation depth

Signed-off-by: grokspawn <jordan@nimblewidget.com>

* more review comments

Signed-off-by: grokspawn <jordan@nimblewidget.com>

---------

Signed-off-by: grokspawn <jordan@nimblewidget.com>
Bumps [docker/login-action](https://github.com/docker/login-action) from 4.3.0 to 4.4.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](docker/login-action@v4.3.0...v4.4.0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 4.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 11.0 to 11.0.1.
- [Release notes](https://github.com/facelessuser/pymdown-extensions/releases)
- [Commits](facelessuser/pymdown-extensions@11.0...11.0.1)

---
updated-dependencies:
- dependency-name: pymdown-extensions
  dependency-version: 11.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* feat(api): deprecate spec.serviceAccount and adopt cluster-admin scope

Mark spec.serviceAccount as deprecated in the ClusterExtension API.
Remove PreAuthorizer integration, SA-scoped RBAC templates, and
restconfig action. Simplify the controller to use cluster-admin
scope directly.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Daniel Franz <dfranz@redhat.com>

* feat: add ValidatingAdmissionPolicy for serviceAccount deprecation warning

Create VAP and VAPB resources that emit a warning when
spec.serviceAccount is set on a ClusterExtension. Add integration
test infrastructure for warning collection.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Daniel Franz <dfranz@redhat.com>

* test: clean up e2e tests for serviceAccount deprecation

Remove SA-specific e2e test scenarios, SA RBAC templates, and the
extension developer test suite. Simplify test steps to use
cluster-admin scope.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Daniel Franz <dfranz@redhat.com>

* refactor: remove per-SA infrastructure and feature gates

Delete authentication and authorization packages, feature gates,
k8smaintainer tool, SA demo scripts, and documentation. Remove
k8s.io/kubernetes dependency and unnecessary k8s staging replace
directives.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Daniel Franz <dfranz@redhat.com>

* refactor: replace contentmanager with shared TrackingCache

Delete the contentmanager package and replace it with boxcutter's
shared TrackingCache. Simplify revision engine factory to use
the base config directly. Remove SA label constants.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Daniel Franz <dfranz@redhat.com>

* docs: update documentation for cluster-admin scope

Remove SA-related documentation, tutorials, and demo scripts.
Clean up remaining ServiceAccount references from unit tests.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Daniel Franz <dfranz@redhat.com>

* Add documentation examples for using ValidatingAdmissionPolicy to protect OLMv1 API access.

Signed-off-by: Daniel Franz <dfranz@redhat.com>
Co-Authored-By: Predrag Knezevic <pknezevi@redhat.com>
Co-Authored-By: Daniel Franz <dfranz@redhat.com>
Co-Authored-By: Claude <noreply@anthropic.com>

* docs: rewrite cluster-admin scope section in design decisions doc

Also updates go.mod/go.sum to fix k8s.io/client-go version.

---------

Signed-off-by: Daniel Franz <dfranz@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Daniel Franz <dfranz@redhat.com>
Co-authored-by: Joe Lanford <joe.lanford@gmail.com>
Bumps [marocchino/sticky-pull-request-comment](https://github.com/marocchino/sticky-pull-request-comment) from 3.0.4 to 3.0.5.
- [Release notes](https://github.com/marocchino/sticky-pull-request-comment/releases)
- [Commits](marocchino/sticky-pull-request-comment@v3.0.4...v3.0.5)

---
updated-dependencies:
- dependency-name: marocchino/sticky-pull-request-comment
  dependency-version: 3.0.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the k8s-dependencies group with 1 update: [sigs.k8s.io/structured-merge-diff/v6](https://github.com/kubernetes-sigs/structured-merge-diff).


Updates `sigs.k8s.io/structured-merge-diff/v6` from 6.4.0 to 6.4.1
- [Changelog](https://github.com/kubernetes-sigs/structured-merge-diff/blob/master/RELEASE.md)
- [Commits](kubernetes-sigs/structured-merge-diff@v6.4.0...v6.4.1)

---
updated-dependencies:
- dependency-name: sigs.k8s.io/structured-merge-diff/v6
  dependency-version: 6.4.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: k8s-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/stale](https://github.com/actions/stale) from 10.3.0 to 10.4.0.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](actions/stale@v10.3.0...v10.4.0)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: 10.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.47.0 to 0.48.0.
- [Release notes](https://github.com/golang/tools/releases)
- [Commits](golang/tools@v0.47.0...v0.48.0)

---
updated-dependencies:
- dependency-name: golang.org/x/tools
  dependency-version: 0.48.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [github.com/cert-manager/cert-manager](https://github.com/cert-manager/cert-manager) from 1.20.3 to 1.21.0.
- [Release notes](https://github.com/cert-manager/cert-manager/releases)
- [Changelog](https://github.com/cert-manager/cert-manager/blob/master/RELEASE.md)
- [Commits](cert-manager/cert-manager@v1.20.3...v1.21.0)

---
updated-dependencies:
- dependency-name: github.com/cert-manager/cert-manager
  dependency-version: 1.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
tmshort and others added 18 commits July 24, 2026 00:16
- Replace broken test-experimental-e2e target (test/experimental-e2e no
  longer exists) with /bin/true so triggered jobs always succeed
- Pass -timeout=60m to go test; the previous invocation relied on Go's
  10m default which is too short for BoxcutterRuntime clusters
- Set E2E_STEP_TIMEOUT=15m; BoxcutterRuntime applies resources through
  sequential phases (CRD must reach Established before the deploy phase
  starts), making installations slower than the upstream 5m default
- Skip ~@CatalogdHA scenarios (require multiple catalogd replicas not
  present in standard topology)
- Skip ~@ProgressDeadline scenarios (require progressDeadlineMinutes < 10
  but the OpenShift CRD enforces a minimum of 10)
- Skip ~@httpproxy scenarios (too disruptive to cluster networking)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Todd Short <tshort@redhat.com>
The e2e-test-registry image is no longer built by CI after
openshift/release#78581 removed it from the CI config. The dynamic
per-scenario catalog system replaced the pre-built registry image,
making this Dockerfile dead code.
It's no longer bring used.

Signed-off-by: Todd Short <tshort@redhat.com>
Adds a new test that verifies cluster-olm-operator correctly configures
operator-controller and catalogd deployments based on the cluster's
control plane topology:
- HA topologies (HighlyAvailable, HighlyAvailableArbiter, DualReplica):
  replicas=2 with a PodDisruptionBudget present
- Non-HA topologies (SingleReplica/SNO, External): replicas=1, no PDB

Also registers policyv1 in the test scheme to support PDB list queries.

Assisted-by: claude
Signed-off-by: Todd Short <tshort@redhat.com>
… builders

Signed-off-by: Todd Short <tshort@redhat.com>
Set catalog image tags to v5.0 for the 4.23/5.0 release.

Dynamically discover an installable package from the serving catalogs
instead of hardcoding quay-operator v3.13.10, preferring quay-operator,
cluster-logging, serverless-operator, logic-operator in that order then
alling back to the first available package.

Signed-off-by: Todd Short <tshort@redhat.com>
…ntal manifests

HelmChartSupport was removed upstream in dbc9b4a but the downstream
experimental.yaml values file and its generated manifest still referenced
it, causing operator-controller to crash on startup with:

  invalid argument "HelmChartSupport=false" for "--feature-gates" flag:
  unrecognized feature gate: HelmChartSupport

This made the OLM cluster operator Degraded/Unavailable and caused cluster
installation to time out (exit code 6).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…cluster version

Add a second ReleaseGate-eligible OTE test verifying that an operator
whose olm.maxOpenShiftVersion exceeds the current cluster version does
not block cluster upgrade (InstalledOLMOperatorsUpgradeable stays True).

The existing test only covered the blocking path (maxOCPVersion ==
current version → False). This covers the complementary allow path
(maxOCPVersion == next minor → True), directly exercising the
normalization logic introduced for the 4.23/5.0 co-release boundary.

A nextMinorVersion() helper mirrors the 4.23→5.1 special case so the
bundle annotation is always set to the correct next upgrade target.

Run 'make build-update' to register the new allow-case test in the
extension metadata after adding it to olmv1-incompatible.go.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Todd Short <tshort@redhat.com>
Automate the ClusterExtension rollout failure coverage for OCP-88331 and OCP-88332 by building in-cluster bundle and catalog images for successful and failing bundle versions.

The new QE specs verify ProgressDeadlineExceeded on an initial failed rollout and ProbeFailure while upgrading to a bad revision under the BoxCutter runtime.

Signed-off-by: Daniel Franz <dfranz@redhat.com>
Co-authored-by: Bruno Andrade <bruno.balint@gmail.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Todd Short <tshort@redhat.com>
…eAccount usage in ClusterExtension API, Synthetic Permissions, and PreFlight Admissions

Signed-off-by: Daniel Franz <dfranz@redhat.com>
Signed-off-by: Todd Short <tshort@redhat.com>
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 24, 2026
@openshift-ci-robot

openshift-ci-robot commented Jul 24, 2026

Copy link
Copy Markdown

@tmshort: This pull request references OPRUN-4666 which is a valid jira issue.

This pull request references OPRUN-4671 which is a valid jira issue.

This pull request references OPRUN-4672 which is a valid jira issue.

This pull request references OPRUN-4673 which is a valid jira issue.

This pull request references OPRUN-4674 which is a valid jira issue.

This pull request references OPRUN-4659 which is a valid jira issue.

Details

In response to this:

Instructions 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 openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci
openshift-ci Bot requested review from dtfranz and perdasilva July 24, 2026 17:52
@openshift-ci

openshift-ci Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: tmshort

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 24, 2026
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Walkthrough

The change deprecates and ignores ClusterExtension.spec.serviceAccount, removes service-account-scoped installation and preflight authorization, grants the controller cluster-admin access, adds persisted dynamic GraphQL loading and query limits, and introduces end-to-end demo recording and admission-policy coverage.

Changes

OLMv1 service-account model

Layer / File(s) Summary
API, CRD, and admission contract
api/v1/*, helm/olmv1/..., manifests/*, openshift/operator-controller/*
spec.serviceAccount becomes optional, deprecated, and ignored; populated values produce warnings, while names remain immutable once set but may be cleared.
Controller and applier wiring
cmd/operator-controller/main.go, internal/operator-controller/applier/*, internal/operator-controller/controllers/*, internal/operator-controller/revision_engine_factory.go
Service-account token, impersonation, pre-authorization, and content-manager paths are removed; shared tracking-cache wiring replaces per-extension cache setup.
OpenShift and E2E migration
openshift/tests-extension/*, test/e2e/features/*, test/extension-developer-e2e/*
ClusterExtension fixtures and scenarios stop creating service accounts and RBAC bindings, and new deprecation-warning and API-access policy scenarios are added.
Documentation and generated examples
docs/*, README.md, config/samples/*, mkdocs.yml
Service-account installation guidance is removed or revised, API-access protection guidance is added, and demo embeds use Asciinema/SVG assets.

Catalogd GraphQL and image handling

Layer / File(s) Summary
Dynamic schema and query execution
internal/catalogd/graphql/*, internal/catalogd/service/*, internal/catalogd/server/*
Schema discovery uses bounded sampling and serializable metadata; resolvers load objects on demand, query complexity is bounded, and execution uses context-aware provider-backed caching.
Persistent catalog loading
internal/catalogd/storage/*
Catalog storage persists GraphQL schemas, exposes schema byte sections, and loads requested JSONL objects through indexed offsets.
Image and Helm cleanup
internal/shared/util/image/*
Helm-specific image-layer detection, chart loading, and chart cache handling are removed; image layers use the standard archive path.

Demo and build workflow

Layer / File(s) Summary
Demo recording and execution
Makefile, test/e2e/features/demos.feature, test/e2e/steps/*
Tagged demo scenarios record Asciinema casts, query catalogs through port-forwarding, validate install modes and webhook behavior, and convert casts to SVG.
Build, installation, and dependency updates
.gitignore, scripts/install.tpl.sh, requirements.txt, go.mod, openshift/Makefile
Generated demo output is ignored, legacy RBAC resources are cleaned up during installation, demo tags are excluded from normal E2E runs, and module/tool versions are refreshed.

Generated annotations

Layer / File(s) Summary
Deployment metadata propagation
internal/operator-controller/rukpak/render/registryv1/generators/*, test/regression/convert/testdata/*
Generated deployment templates now include olm.operatorNamespace derived from the installation namespace, with updated expected manifests.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

@tmshort

tmshort commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

/test unit

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/catalogd/service/graphql_service.go (1)

47-80: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

ctx passed into GetSchema is never used — schema build has no timeout.

GetSchema accepts a context.Context but never reads it; the underlying buildGroup.Do/buildSchema/provider.LoadCatalogSchema/NewObjectLoader calls take no context either (verified golang.org/x/sync/singleflight.Do itself has no context-aware overload). ExecuteQuery only wraps graphql.Do in a 5s timeout (Line 96) — the GetSchema(ctx, catalog) call right before it (Line 91) can block indefinitely if catalog loading is slow, with no deadline enforcement despite the surrounding code clearly intending timeout-bounded execution.

Wrap the schema-build phase with its own timeout (e.g., derive it from ctx similarly to the query timeout) or thread the context through to the provider so cancellation/deadlines actually apply to catalog IO.

As per path instructions for **/*.go, **/*.go: "context.Context for cancellation and timeouts" — the unused ctx parameter here doesn't fulfill that guidance.

Also applies to: 82-106

🤖 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 `@internal/catalogd/service/graphql_service.go` around lines 47 - 80, Make
GetSchema honor its ctx by applying a bounded timeout or cancellation to the
schema-build operation, including the buildGroup.Do/buildSchema path, so slow
catalog loads cannot block indefinitely. Prefer threading ctx through
buildSchema and the provider.LoadCatalogSchema/NewObjectLoader calls; otherwise
enforce timeout completion around buildGroup.Do. Preserve cache behavior and
return context cancellation/deadline errors.

Source: Path instructions

🧹 Nitpick comments (2)
test/e2e/features/revision.feature (1)

9-16: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Drop the unused pvc-probe-sa setup
These scenarios no longer reference pvc-probe-sa in the ClusterObjectSet manifest, so the shared Given ServiceAccount ... step now creates an unused ServiceAccount/RBAC pair. Switch to the namespace-only setup used by the migrated scenarios below.

🤖 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 `@test/e2e/features/revision.feature` around lines 9 - 16, Remove the unused
“Given ServiceAccount "pvc-probe-sa" with needed permissions” step from the
affected scenarios in revision.feature, and use the namespace-only setup
established by the migrated scenarios below. Keep the ClusterObjectSet manifests
and scenario behavior unchanged.
test/e2e/steps/asciicast_recorder.go (1)

139-147: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Unhandled error from f.Close().

defer f.Close() discards the close error. For a file write path, a failed close can mean data wasn't flushed to disk, so this should ideally be captured with a named return / explicit check rather than silently dropped.

As per path instructions for **/*.go: "Never ignore error returns."

♻️ Proposed fix
 	f, err := os.Create(r.castPath)
 	if err != nil {
 		return fmt.Errorf("failed to create cast file %s: %w", r.castPath, err)
 	}
-	defer f.Close()
+	defer func() {
+		if cerr := f.Close(); cerr != nil && err == nil {
+			err = fmt.Errorf("failed to close cast file %s: %w", r.castPath, cerr)
+		}
+	}()
🤖 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 `@test/e2e/steps/asciicast_recorder.go` around lines 139 - 147, Update
AsciiCastRecorder.Stop to handle the error returned by f.Close instead of
discarding it via defer. Use a named return or explicit close handling so close
failures are propagated while preserving existing errors from directory
creation, file creation, and recording.

Source: Path instructions

🤖 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 `@docs/howto/how-to-protect-olmv1-api-access.md`:
- Around line 39-44: Update the RBAC verb lists in the installer role
documentation to include patch for both resource entries, alongside the existing
create, update, delete, get, list, and watch verbs. Ensure both resources
support declarative kubectl apply workflows.
- Line 71: Update the Markdown link in the ValidatingAdmissionPolicy discussion
to replace the vague “here” anchor with descriptive text identifying the
Kubernetes ValidatingAdmissionPolicy documentation, while preserving the
existing destination URL.

In `@internal/catalogd/graphql/validation.go`:
- Around line 16-21: Update query complexity traversal around
queryComplexity.visited and the fragment-recursion logic in validateQuery to
treat visited as a per-path set: mark a fragment before traversing its
definition, remove it after recursion completes, and skip only fragments already
active on the current path. Preserve cycle protection while allowing each
non-overlapping fragment spread to contribute its fields and aliases to the
operation totals.

In `@internal/catalogd/storage/localdir_test.go`:
- Around line 711-712: Update the test setup around NewLocalDirV1 and the
corresponding setup at the other URL parsing occurrence to capture the error
returned by url.Parse and assert it with require.NoError before using rootURL.
Do not discard the parsing error, including for constant URLs.

In `@internal/catalogd/storage/localdir.go`:
- Around line 344-356: Validate offset and limit before slicing sections in the
surrounding schema-section retrieval method, returning a validation error when
either pagination value is negative. Preserve the existing nil returns for
missing or exhausted sections and the current slicing behavior for non-negative
values.
- Around line 97-106: Update storeAtomicSwap’s schema warm-up flow to avoid
deleting the previously healthy catalog before validation completes. Either
validate the temporary catalog before replacing the existing directory, or
retain the old directory and restore it when graphqlSvc.GetSchema fails; ensure
rollback removes the new directory and leaves the prior catalog available.
- Around line 124-128: Update the cleanup paths in the local catalog storage
flow, including the deferred RemoveAll around MkdirTemp and the f.Close path
referenced by the comment, so their returned errors are explicitly handled
rather than discarded. Propagate cleanup or close failures when the surrounding
function can return an error; otherwise log them using the existing logging
mechanism, while preserving the current successful cleanup behavior.
- Around line 332-340: Update NewObjectLoader so the closure no longer captures
an index loaded before locking; acquire the snapshot RLock first, then load the
index through the lock-held helper before reading the catalog file. Preserve the
existing error handling and ensure both index and JSONL data come from the same
snapshot.

In `@openshift/operator-controller/manifests.yaml`:
- Around line 736-740: Replace the cluster-admin role reference in the
operator-controller-cluster-admin-rolebinding with a least-privilege custom or
aggregated ClusterRole that grants only the manager’s required permissions in
openshift/operator-controller/manifests.yaml:736-740 and
openshift/operator-controller/manifests-experimental.yaml:887-891. Apply the
same scoped RBAC change in both standard and experimental manifests, preserving
the Controller ServiceAccount binding.

---

Outside diff comments:
In `@internal/catalogd/service/graphql_service.go`:
- Around line 47-80: Make GetSchema honor its ctx by applying a bounded timeout
or cancellation to the schema-build operation, including the
buildGroup.Do/buildSchema path, so slow catalog loads cannot block indefinitely.
Prefer threading ctx through buildSchema and the
provider.LoadCatalogSchema/NewObjectLoader calls; otherwise enforce timeout
completion around buildGroup.Do. Preserve cache behavior and return context
cancellation/deadline errors.

---

Nitpick comments:
In `@test/e2e/features/revision.feature`:
- Around line 9-16: Remove the unused “Given ServiceAccount "pvc-probe-sa" with
needed permissions” step from the affected scenarios in revision.feature, and
use the namespace-only setup established by the migrated scenarios below. Keep
the ClusterObjectSet manifests and scenario behavior unchanged.

In `@test/e2e/steps/asciicast_recorder.go`:
- Around line 139-147: Update AsciiCastRecorder.Stop to handle the error
returned by f.Close instead of discarding it via defer. Use a named return or
explicit close handling so close failures are propagated while preserving
existing errors from directory creation, file creation, and recording.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

Comment on lines +39 to +44
- create
- update
- delete
- get
- list
- watch

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Grant patch to the installer role.

kubectl apply and other declarative clients use PATCH for existing resources, so this role cannot perform the documented modification workflow. Add patch for both resources.

🤖 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 `@docs/howto/how-to-protect-olmv1-api-access.md` around lines 39 - 44, Update
the RBAC verb lists in the installer role documentation to include patch for
both resource entries, alongside the existing create, update, delete, get, list,
and watch verbs. Ensure both resources support declarative kubectl apply
workflows.


## Validating Admission Policy

A `ValidatingAdmissionPolicy` provides much more flexibility than simple RBAC when it comes to managing access to `ClusterExtensions`. For more detailed instructions on the fundamentals of the `ValidatingAdmissionPolicy` API, take a look at the Kubernetes docs [here](https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use descriptive link text.

Replace “here” with text such as “Kubernetes ValidatingAdmissionPolicy documentation.”

🧰 Tools
🪛 markdownlint-cli2 (0.23.0)

[warning] 71-71: Link text should be descriptive

(MD059, descriptive-link-text)

🤖 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 `@docs/howto/how-to-protect-olmv1-api-access.md` at line 71, Update the
Markdown link in the ValidatingAdmissionPolicy discussion to replace the vague
“here” anchor with descriptive text identifying the Kubernetes
ValidatingAdmissionPolicy documentation, while preserving the existing
destination URL.

Source: Linters/SAST tools

Comment on lines +16 to +21
type queryComplexity struct {
aliases int
fields int
fragments map[string]*ast.FragmentDefinition
visited map[string]bool
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Fragment-spread dedup lets query cost bypass the complexity limits it's meant to enforce.

c.visited is a single map reused for the whole operation and a fragment name is never unmarked once counted (Lines 79-84). This only guards against fragments that self-reference (cycles), but it also silently skips re-counting a fragment the second, third, ... Nth time it's spread in different, non-overlapping branches of the same query — even though the GraphQL executor (graphql.Do) will actually resolve that fragment's fields at every one of those spread sites. An attacker can define one deep/wide fragment and reuse it across many sibling fields to keep the reported fields/aliases counts under maxQueryFields/maxQueryAliases while the real execution cost multiplies — defeating the DoS protection this validator exists to provide.

Use a per-path "currently visiting" set (added before recursing into a fragment, removed after) instead of a permanent per-operation set, so cycles are still blocked but each distinct spread occurrence is fully counted.

🔒 Proposed fix: track visiting fragments per traversal path
 type queryComplexity struct {
 	aliases   int
 	fields    int
 	fragments map[string]*ast.FragmentDefinition
-	visited   map[string]bool
 }
@@
 	for _, def := range doc.Definitions {
 		if op, ok := def.(*ast.OperationDefinition); ok {
-			// Reset per operation so shared fragments are counted for each operation.
-			c.visited = make(map[string]bool)
-			if err := c.walkSelectionSet(op.SelectionSet, 1); err != nil {
+			if err := c.walkSelectionSet(op.SelectionSet, 1, make(map[string]bool)); err != nil {
 				return err
 			}
 		}
 	}
@@
-func (c *queryComplexity) walkSelectionSet(ss *ast.SelectionSet, depth int) error {
+func (c *queryComplexity) walkSelectionSet(ss *ast.SelectionSet, depth int, visiting map[string]bool) error {
 	...
-			if err := c.walkSelectionSet(s.SelectionSet, depth+1); err != nil {
+			if err := c.walkSelectionSet(s.SelectionSet, depth+1, visiting); err != nil {
 				return err
 			}
 		case *ast.InlineFragment:
-			if err := c.walkSelectionSet(s.SelectionSet, depth+1); err != nil {
+			if err := c.walkSelectionSet(s.SelectionSet, depth+1, visiting); err != nil {
 				return err
 			}
 		case *ast.FragmentSpread:
 			name := s.Name.Value
-			if c.visited[name] {
+			if visiting[name] {
 				continue
 			}
-			c.visited[name] = true
+			visiting[name] = true
 			if frag, ok := c.fragments[name]; ok {
-				if err := c.walkSelectionSet(frag.SelectionSet, depth+1); err != nil {
+				if err := c.walkSelectionSet(frag.SelectionSet, depth+1, visiting); err != nil {
 					return err
 				}
 			}
+			delete(visiting, name)
 		}

Also applies to: 41-42, 79-89

🤖 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 `@internal/catalogd/graphql/validation.go` around lines 16 - 21, Update query
complexity traversal around queryComplexity.visited and the fragment-recursion
logic in validateQuery to treat visited as a per-path set: mark a fragment
before traversing its definition, remove it after recursion completes, and skip
only fragments already active on the current path. Preserve cycle protection
while allowing each non-overlapping fragment spread to contribute its fields and
aliases to the operation totals.

Comment on lines +711 to +712
rootURL, _ := url.Parse("http://localhost/catalogs/")
s := NewLocalDirV1(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Check the URL parsing errors.

Do not discard url.Parse errors, even for constants; assert them with require.NoError. As per path instructions, “Never ignore error returns.”

Also applies to: 764-765

🤖 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 `@internal/catalogd/storage/localdir_test.go` around lines 711 - 712, Update
the test setup around NewLocalDirV1 and the corresponding setup at the other URL
parsing occurrence to capture the error returned by url.Parse and assert it with
require.NoError before using rootURL. Do not discard the parsing error,
including for constant URLs.

Source: Path instructions

Comment on lines +97 to +106
if s.graphqlSvc != nil {
if _, err := s.graphqlSvc.GetSchema(ctx, catalog); err != nil {
s.graphqlSvc.InvalidateCache(catalog)
s.m.Lock()
removeErr := os.RemoveAll(catalogDir)
s.m.Unlock()
if removeErr != nil {
return fmt.Errorf("failed to pre-build GraphQL schema for catalog %q: %w (rollback also failed: %v)", catalog, err, removeErr)
}
return fmt.Errorf("failed to pre-build GraphQL schema for catalog %q: %w", catalog, err)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Preserve the previous catalog if schema warm-up fails.

storeAtomicSwap has already deleted the prior directory. This rollback only deletes the new directory, leaving a previously healthy catalog unavailable. Retain and restore the old directory, or validate the temporary catalog before replacing it.

🤖 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 `@internal/catalogd/storage/localdir.go` around lines 97 - 106, Update
storeAtomicSwap’s schema warm-up flow to avoid deleting the previously healthy
catalog before validation completes. Either validate the temporary catalog
before replacing the existing directory, or retain the old directory and restore
it when graphqlSvc.GetSchema fails; ensure rollback removes the new directory
and leaves the prior catalog available.

Comment on lines 124 to 128
tmpCatalogDir, err := os.MkdirTemp(s.RootDir, fmt.Sprintf(".%s-*", catalog))
if err != nil {
return err
return "", err
}
defer os.RemoveAll(tmpCatalogDir)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Handle deferred cleanup and close errors.

os.RemoveAll and f.Close errors are discarded. Propagate or log them so failed cleanup does not silently accumulate stale catalog data. As per path instructions, “Never ignore error returns.”

Also applies to: 358-362

🤖 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 `@internal/catalogd/storage/localdir.go` around lines 124 - 128, Update the
cleanup paths in the local catalog storage flow, including the deferred
RemoveAll around MkdirTemp and the f.Close path referenced by the comment, so
their returned errors are explicitly handled rather than discarded. Propagate
cleanup or close failures when the surrounding function can return an error;
otherwise log them using the existing logging mechanism, while preserving the
current successful cleanup behavior.

Source: Path instructions

Comment on lines +332 to +340
func (s *LocalDirV1) NewObjectLoader(catalog string) (gql.ObjectLoader, error) {
idx, err := s.loadIndex(catalog)
if err != nil {
return nil, fmt.Errorf("error loading index for catalog %q: %w", catalog, err)
}

catalogPath := catalogFilePath(s.catalogDir(catalog))

return func(schemaName string, offset, limit int) ([]map[string]interface{}, error) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Load the index under the same snapshot lock as the catalog file.

The closure captures idx before it takes RLock. A loader retained from the previous cached schema can therefore apply old byte offsets to newly swapped JSONL data, returning incorrect objects or read errors. Load the index after acquiring the closure lock, using a lock-held helper.

🤖 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 `@internal/catalogd/storage/localdir.go` around lines 332 - 340, Update
NewObjectLoader so the closure no longer captures an index loaded before
locking; acquire the snapshot RLock first, then load the index through the
lock-held helper before reading the catalog file. Preserve the existing error
handling and ensure both index and JSONL data come from the same snapshot.

Comment on lines +344 to +356
sections := idx.GetSchemaSections(schemaName)
if sections == nil {
return nil, nil
}

if offset >= len(sections) {
return nil, nil
}
sections = sections[offset:]

if limit < len(sections) {
sections = sections[:limit]
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Reject negative pagination values before slicing.

offset = -1 reaches sections[offset:], and limit = -1 reaches sections[:limit]; both panic. Return a validation error when either value is negative.

🤖 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 `@internal/catalogd/storage/localdir.go` around lines 344 - 356, Validate
offset and limit before slicing sections in the surrounding schema-section
retrieval method, returning a validation error when either pagination value is
negative. Preserve the existing nil returns for missing or exhausted sections
and the current slicing behavior for non-negative values.

Comment on lines +736 to +740
name: operator-controller-cluster-admin-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: operator-controller-manager-role
name: cluster-admin

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Controller ServiceAccount bound to cluster-admin in both standard and experimental manifests. The scoped operator-controller-manager-role binding was replaced by a cluster-admin ClusterRoleBinding. This is a deliberate consequence of removing SA-scoped installs (documented in the CRD deprecation text), but it broadens the workload's blast radius and conflicts with the least-privilege guideline. Confirm this is the accepted design and, if possible, scope to a custom/aggregated ClusterRole instead of cluster-admin.

  • openshift/operator-controller/manifests.yaml#L736-L740: operator-controller-cluster-admin-rolebinding binds the manager SA to cluster-admin.
  • openshift/operator-controller/manifests-experimental.yaml#L887-L891: identical cluster-admin binding for the experimental feature-set.

As per path instructions: "RBAC: least privilege; no cluster-admin for workloads".

📍 Affects 2 files
  • openshift/operator-controller/manifests.yaml#L736-L740 (this comment)
  • openshift/operator-controller/manifests-experimental.yaml#L887-L891
🤖 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 `@openshift/operator-controller/manifests.yaml` around lines 736 - 740, Replace
the cluster-admin role reference in the
operator-controller-cluster-admin-rolebinding with a least-privilege custom or
aggregated ClusterRole that grants only the manager’s required permissions in
openshift/operator-controller/manifests.yaml:736-740 and
openshift/operator-controller/manifests-experimental.yaml:887-891. Apply the
same scoped RBAC change in both standard and experimental manifests, preserving
the Controller ServiceAccount binding.

Source: Path instructions

@tmshort

tmshort commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

Closing in favor of merged #767

@tmshort tmshort closed this Jul 24, 2026
@tmshort
tmshort deleted the PR-762-new-plus-demo branch July 27, 2026 12:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.