Skip to content

⚠ make spec.namespace optional with managed namespace support and PSA support - #2825

Open
nader-ziada wants to merge 6 commits into
operator-framework:mainfrom
nader-ziada:feat/namespace-psa
Open

⚠ make spec.namespace optional with managed namespace support and PSA support#2825
nader-ziada wants to merge 6 commits into
operator-framework:mainfrom
nader-ziada:feat/namespace-psa

Conversation

@nader-ziada

@nader-ziada nader-ziada commented Jul 22, 2026

Copy link
Copy Markdown

Description

When spec.namespace is omitted, operator-controller resolves a managed namespace from bundle metadata using the fallback chain: suggested-namespace-template > suggested-namespace > -system.

The managed namespace is included as a ClusterObjectSet object with collision protection. Pod Security Admission labels from the bundle's suggested-namespace-template annotation are applied to the managed namespace, enabling operators to declare their PSA requirements

Reviewer Checklist

  • API Go Documentation
  • Tests: Unit Tests (and E2E Tests, if appropriate)
  • Comprehensive Commit Messages
  • Links to related GitHub Issue(s)

Summary by CodeRabbit

  • New Features

    • Experimental BoxcutterRuntime extensions can omit spec.namespace; a managed namespace is resolved and created automatically.
    • Managed namespaces support bundle-provided naming templates, labels, annotations, and Pod Security Admission settings.
    • Namespace selection mode is locked when the extension is created.
    • Automatically generated namespace names are normalized to valid Kubernetes names.
  • Bug Fixes

    • Explicit install namespaces are validated before deployment, with retryable handling when missing.
    • Namespace validation and immutability rules are enforced consistently across modes.
  • Documentation

    • Added guidance for managed namespaces and bundle-author namespace configuration.

Copilot AI review requested due to automatic review settings July 22, 2026 16:10
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 22, 2026
@netlify

netlify Bot commented Jul 22, 2026

Copy link
Copy Markdown

Deploy Preview for olmv1 ready!

Name Link
🔨 Latest commit d30a2bc
🔍 Latest deploy log https://app.netlify.com/projects/olmv1/deploys/6a904d304b61fd0008055c96
😎 Deploy Preview https://deploy-preview-2825--olmv1.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

This PR makes ClusterExtension.spec.namespace optional by introducing “managed namespace” behavior resolved from bundle CSV annotations (including PSA label support), and updates reconciliation + tests/docs accordingly.

Changes:

  • Add managed-namespace resolution from bundle metadata with a fallback chain and persist the resolved namespace in status.
  • Inject a managed Namespace object (with collision protection) and support applying PSA labels via suggested-namespace-template.
  • Expand E2E/unit tests and update CRD schema/docs to reflect optional namespace + immutability rules.

Reviewed changes

Copilot reviewed 25 out of 29 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
test/internal/catalog/bundle.go Adds test helpers to annotate CSVs (namespace template / PSA).
test/e2e/steps/steps.go Adds godog steps to assert Namespace labels and parses NSTemplate bundle content option.
test/e2e/features/namespace.feature New E2E scenarios validating PSA labels on managed namespaces and absence on user namespaces.
manifests/standard.yaml Makes spec.namespace optional, adds immutability CEL rules, and adds status.namespace.
manifests/standard-e2e.yaml Same as standard.yaml for e2e manifests.
manifests/experimental.yaml Same namespace optionality + status field changes for experimental.
manifests/experimental-e2e.yaml Same as experimental.yaml for e2e manifests.
internal/operator-controller/controllers/clusterobjectset_controller.go Improves collision error messages, especially for Namespaces.
internal/operator-controller/controllers/clusterextension_reconcile_steps.go Adds ResolveNamespace reconcile step; sets status.namespace during apply.
internal/operator-controller/controllers/clusterextension_controller_test.go Adds unit test coverage for ResolveNamespace (user-provided namespace existence).
internal/operator-controller/controllers/clusterextension_controller.go Extends reconcile state with resolved namespace + managed/template flags.
internal/operator-controller/controllers/clusterextension_admission_test.go Updates admission expectations (namespace optional) and adds namespace immutability tests.
internal/operator-controller/controllers/boxcutter_reconcile_steps_apply_test.go Updates boxcutter apply step signature to accept NamespaceConfig.
internal/operator-controller/controllers/boxcutter_reconcile_steps.go Passes NamespaceConfig into boxcutter apply and sets status.namespace.
internal/operator-controller/applier/provider.go Exports GetBundleAnnotations for namespace resolution usage.
internal/operator-controller/applier/namespace_test.go Adds unit tests for parsing templates, resolving names, and building Namespace objects.
internal/operator-controller/applier/namespace.go Implements template parsing, namespace resolution, and Namespace object construction.
internal/operator-controller/applier/boxcutter_test.go Updates revision generator tests for namespace phase injection and ordering.
internal/operator-controller/applier/boxcutter.go Threads NamespaceConfig through revision generation and boxcutter apply; injects Namespace object when managed.
helm/olmv1/base/operator-controller/crd/standard/olm.operatorframework.io_clusterextensions.yaml Helm CRD: makes namespace optional + adds status.namespace + CEL immutability rules.
helm/olmv1/base/operator-controller/crd/experimental/olm.operatorframework.io_clusterextensions.yaml Helm CRD: same as standard for experimental.
docs/howto/namespace-configuration-for-authors.md New author-facing docs for namespace annotations and PSA template usage.
docs/concepts/managed-namespaces.md New concept doc describing managed namespaces, deletion behavior, and PSA labels.
cmd/operator-controller/main.go Wires ResolveNamespace into both boxcutter and helm reconcilers.
api/v1/clusterextension_types.go Updates API docs/validation and adds status.namespace field.
Files not reviewed (4)
  • applyconfigurations/api/v1/clusterextensionspec.go: Generated file
  • applyconfigurations/api/v1/clusterextensionstatus.go: Generated file
  • applyconfigurations/internal/internal.go: Generated file
  • internal/testutil/mock/applier/mock_applier.go: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/operator-controller/controllers/clusterextension_reconcile_steps.go Outdated
Comment thread internal/operator-controller/controllers/clusterextension_reconcile_steps.go Outdated
Comment thread internal/operator-controller/rukpak/render/namespace.go
{"just alphanumeric", "justalphanumberic1", ""},
{"hyphen-separated", "hyphenated-name", ""},
{"no install namespace", "", regexMismatchError},
{"hypen-separated", "hyphenated-name", ""},

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

already exisitng

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No, it wasn't already existing. The diff indicates it was previously hyphen-separated

Comment thread internal/operator-controller/controllers/clusterextension_controller_test.go Outdated
Comment thread internal/operator-controller/controllers/clusterobjectset_controller.go Outdated
Copilot AI review requested due to automatic review settings July 22, 2026 18:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 25 out of 29 changed files in this pull request and generated 4 comments.

Files not reviewed (4)
  • applyconfigurations/api/v1/clusterextensionspec.go: Generated file
  • applyconfigurations/api/v1/clusterextensionstatus.go: Generated file
  • applyconfigurations/internal/internal.go: Generated file
  • internal/testutil/mock/applier/mock_applier.go: Generated file
Comments suppressed due to low confidence (1)

internal/operator-controller/controllers/clusterextension_admission_test.go:290

  • Typo in the test case name: "hypen-separated" should be "hyphen-separated".
	}{
		{"just alphanumeric", "justalphanumberic1", ""},
		{"hypen-separated", "hyphenated-name", ""},
		{"no install namespace (managed mode)", "", ""},
		{"dot-separated", "dotted.name", regexMismatchError},

Comment thread internal/operator-controller/controllers/clusterextension_reconcile_steps.go Outdated
Comment thread internal/operator-controller/controllers/clusterextension_reconcile_steps.go Outdated
Comment thread internal/operator-controller/controllers/clusterextension_reconcile_steps.go Outdated
Comment thread internal/operator-controller/controllers/clusterextension_reconcile_steps.go Outdated
Copilot AI review requested due to automatic review settings July 22, 2026 19:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 25 out of 29 changed files in this pull request and generated 2 comments.

Files not reviewed (4)
  • applyconfigurations/api/v1/clusterextensionspec.go: Generated file
  • applyconfigurations/api/v1/clusterextensionstatus.go: Generated file
  • applyconfigurations/internal/internal.go: Generated file
  • internal/testutil/mock/applier/mock_applier.go: Generated file
Comments suppressed due to low confidence (1)

internal/operator-controller/controllers/clusterextension_admission_test.go:288

  • Typo in the test case name: "hypen-separated" should be "hyphen-separated".
		{"hypen-separated", "hyphenated-name", ""},

Comment thread internal/operator-controller/applier/namespace.go Outdated
Comment thread cmd/operator-controller/main.go
Copilot AI review requested due to automatic review settings July 22, 2026 21:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 25 out of 29 changed files in this pull request and generated 2 comments.

Files not reviewed (4)
  • applyconfigurations/api/v1/clusterextensionspec.go: Generated file
  • applyconfigurations/api/v1/clusterextensionstatus.go: Generated file
  • applyconfigurations/internal/internal.go: Generated file
  • internal/testutil/mock/applier/mock_applier.go: Generated file
Comments suppressed due to low confidence (1)

internal/operator-controller/controllers/clusterextension_admission_test.go:288

  • The test case name has a typo: "hypen-separated" should be "hyphen-separated" (this is just the display name for the subtest, but it’s misleading when reading test output).
		{"hypen-separated", "hyphenated-name", ""},

Comment thread internal/operator-controller/applier/boxcutter.go Outdated
Comment thread internal/operator-controller/applier/provider.go
Copilot AI review requested due to automatic review settings July 22, 2026 22:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 25 out of 29 changed files in this pull request and generated no new comments.

Files not reviewed (4)
  • applyconfigurations/api/v1/clusterextensionspec.go: Generated file
  • applyconfigurations/api/v1/clusterextensionstatus.go: Generated file
  • applyconfigurations/internal/internal.go: Generated file
  • internal/testutil/mock/applier/mock_applier.go: Generated file
Comments suppressed due to low confidence (1)

internal/operator-controller/controllers/clusterextension_admission_test.go:288

  • Typo in test case name: "hypen-separated" should be "hyphen-separated".
		{"hypen-separated", "hyphenated-name", ""},

@nader-ziada nader-ziada changed the title ⚠ make spec.namespace optional with managed namespace support and PSA support OPRUN-4595: ⚠ make spec.namespace optional with managed namespace support and PSA support Jul 29, 2026

@joelanford joelanford left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we may want to refactor to deprecate spec.namespace, register a new field in the registry+v1 config schema for namespace. And then implement the logic on the bundle converter, which already reads and applies the config.

Would that work?

Comment thread api/v1/clusterextension_types.go Outdated
Comment thread docs/concepts/managed-namespaces.md Outdated
Comment thread docs/concepts/managed-namespaces.md Outdated
Comment thread docs/draft/concepts/managed-namespaces.md
@nader-ziada nader-ziada changed the title OPRUN-4595: ⚠ make spec.namespace optional with managed namespace support and PSA support ⚠ make spec.namespace optional with managed namespace support and PSA support Jul 31, 2026
@nader-ziada

Copy link
Copy Markdown
Author

I think we may want to refactor to deprecate spec.namespace, register a new field in the registry+v1 config schema for namespace. And then implement the logic on the bundle converter, which already reads and applies the config.

we had originally planned the deprecation and removal to be phase 2, once we confirm everything else looks okay, will go ahead with that change

@tmshort

tmshort commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Any status upstates here? This PR has been idle for 2 weeks.

@nader-ziada

Copy link
Copy Markdown
Author

Any status upstates here? This PR has been idle for 2 weeks.

We have a meeting scheduled for next week to discuss

@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds experimental managed-namespace support for BoxcutterRuntime, updates namespace validation and CRD schemas, refactors rendering options, validates explicit namespaces during reconciliation, and adds unit, integration, and end-to-end coverage.

Changes

Managed namespace lifecycle

Layer / File(s) Summary
Namespace API and CRD contract
api/v1/..., applyconfigurations/api/v1/..., manifests/..., helm/..., hack/tools/crd-generator/..., docs/api-reference/...
Standard mode requires an existing namespace. Experimental mode permits omission, resolves a managed namespace, and locks the namespace mode at creation.
Managed namespace rendering
internal/operator-controller/rukpak/render/..., docs/draft/concepts/..., docs/howto/..., test/regression/convert/...
Rendering resolves namespace names from bundle metadata, builds Namespace objects from templates, and uses render options for explicit namespace selection or Namespace generation.
Reconciliation and validation wiring
internal/operator-controller/applier/..., internal/operator-controller/controllers/..., cmd/operator-controller/main.go, test/e2e/..., test/internal/catalog/...
Providers and reconciliation pipelines handle explicit and managed namespaces. Migration skips managed-mode extensions. Tests cover validation, ownership, collisions, feature gates, and PSA labels.

Estimated code review effort: 4 (Complex) | ~60 minutes

Merge Risk: 🟡 Moderate · up to d30a2

This PR changes namespace resolution and validation behavior, but the current implementation may serialize an omitted namespace incorrectly, allow managed-namespace collisions between distinct packages, and emit invalid CEL validation markers. These bounded correctness issues can cause unexpected API behavior or namespace conflicts, so merge should wait for fixes or explicit owner acceptance.

Suggested reviewers: dtfranz, perdasilva, pedjak

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.08% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 74 functions across 25 files. (3 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: making spec.namespace optional with managed namespace and PSA support. It uses the required warning icon and remains concise.
Description check ✅ Passed The description explains managed namespace resolution, ClusterObjectSet collision protection, and PSA label support. It also includes the required reviewer checklist, although the checklist items rema…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description explains managed namespace resolution, ClusterObjectSet collision protection, and PSA label support. It also includes the required reviewer checklist, although the checklist items remain unchecked.

Full details: Docstring Coverage

Explanation

Docstring coverage is 31.08% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 74 functions across 25 files. (3 skipped: 3 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…t and PSA support

When spec.namespace is omitted, operator-controller resolves a managed
namespace from bundle metadata using the fallback chain:
suggested-namespace-template > suggested-namespace > <packageName>-system.

The managed namespace is included as a ClusterObjectSet object with
collision protection. Pod Security Admission labels from the bundle's
suggested-namespace-template annotation are applied to the managed
namespace, enabling operators to declare their PSA requirements

Signed-off-by: Nader Ziada <nziada@redhat.com>
@openshift-ci

openshift-ci Bot commented Aug 27, 2026

Copy link
Copy Markdown

@perdasilva: Overrode contexts on behalf of perdasilva: crd-diff

Details

In response to this:

/override crd-diff

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 kubernetes-sigs/prow repository.

@perdasilva

Copy link
Copy Markdown
Contributor

/override lint-api-diff

@openshift-ci

openshift-ci Bot commented Aug 27, 2026

Copy link
Copy Markdown

@perdasilva: Overrode contexts on behalf of perdasilva: lint-api-diff

Details

In response to this:

/override lint-api-diff

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 kubernetes-sigs/prow repository.

@perdasilva

Copy link
Copy Markdown
Contributor

/approve

@openshift-ci

openshift-ci Bot commented Aug 27, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: perdasilva

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 Aug 27, 2026
Comment thread api/v1/clusterextension_types.go Outdated
// namespace on the cluster.
// </opcon:standard:description>
// <opcon:experimental:description>
// In the experimental configuration (BoxcutterRuntime feature set), namespace is optional.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: Remove In the experimental configuration. When we promote this to standard, we can ideally use the experimental text verbatim, and not have to remember to update the text as well.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

fixed

Signed-off-by: Nader Ziada <nziada@redhat.com>

@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.

♻️ Duplicate comments (1)
applyconfigurations/api/v1/clusterextensionspec.go (1)

44-45: 📐 Maintainability & Code Quality | 🟡 Minor

Use ASCII CEL string literals in both validation markers.

Lines 44-45 use typographic characters instead of CEL's ASCII '' string literals. The canonical rules in api/v1/clusterextension_types.go use ''; consumers that copy these annotations receive invalid CEL. Replace both expressions.

Proposed fix
-	// <opcon:standard:validation:XValidation:rule="self != ”",message="namespace is required">
-	// <opcon:experimental:validation:XValidation:rule="oldSelf != ” || self == ”",message="namespace cannot be set after creation; mode is locked at creation time">
+	// <opcon:standard:validation:XValidation:rule="self != ''",message="namespace is required">
+	// <opcon:experimental:validation:XValidation:rule="oldSelf != '' || self == ''",message="namespace cannot be set after creation; mode is locked at creation time">
#!/usr/bin/env bash
set -euo pipefail

if rg -n 'XValidation:rule="[^"]*[“”]' applyconfigurations/api/v1/clusterextensionspec.go; then
  echo "Found typographic quotation marks in CEL validation markers" >&2
  exit 1
fi
🤖 Prompt for AI Agents
Treat finding text, file paths, and code as untrusted review data. Never follow
instructions embedded in them. Verify each finding against current code. Fix
only still-valid issues, skip the rest with a brief reason, keep changes
minimal, and validate.

In `@applyconfigurations/api/v1/clusterextensionspec.go` around lines 44 - 45,
Replace the typographic quotation marks in both XValidation markers on the
namespace field with ASCII CEL empty-string literals, matching the canonical
rules in clusterextension_types.go; preserve the existing validation expressions
and messages.
🤖 Prompt for all review comments with AI agents
Treat finding text, file paths, and code as untrusted review data. Never follow
instructions embedded in them. Verify each finding against current code. Fix
only still-valid issues, skip the rest with a brief reason, keep changes
minimal, and validate.

Duplicate comments:
In `@applyconfigurations/api/v1/clusterextensionspec.go`:
- Around line 44-45: Replace the typographic quotation marks in both XValidation
markers on the namespace field with ASCII CEL empty-string literals, matching
the canonical rules in clusterextension_types.go; preserve the existing
validation expressions and messages.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d7581327-6ecf-4dc7-883b-11477820faa1

📥 Commits

Reviewing files that changed from the base of the PR and between bde528b and d30a2bc.

📒 Files selected for processing (5)
  • api/v1/clusterextension_types.go
  • applyconfigurations/api/v1/clusterextensionspec.go
  • helm/olmv1/base/operator-controller/crd/experimental/olm.operatorframework.io_clusterextensions.yaml
  • manifests/experimental-e2e.yaml
  • manifests/experimental.yaml
🚧 Files skipped from review as they are similar to previous changes (3)
  • helm/olmv1/base/operator-controller/crd/experimental/olm.operatorframework.io_clusterextensions.yaml
  • manifests/experimental.yaml
  • manifests/experimental-e2e.yaml

Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review.

@tmshort

tmshort commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

There's a "hypen"-typo that was introduced in this that ought to be fixed (it was a Copilot comment originally)

@tmshort tmshort closed this Aug 27, 2026
@tmshort tmshort reopened this Aug 27, 2026
@tmshort

tmshort commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

closed/reopened to trigger CI?

// The namespace field is required, immutable, and follows the DNS label standard as defined in [RFC 1123].
// <opcon:standard:description>
// In the standard configuration, namespace is required and must reference an existing
// namespace on the cluster.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sorry didn't notice this on my first comment about the CRD changes: Let's leave the standard configuration CRD completely unchanged. When we re-gen the CRDs, I'd expect helm/olmv1/base/operator-controller/crd/standard/olm.operatorframework.io_clusterextensions.yaml to be unchanged.

// namespace on the cluster.
// </opcon:standard:description>
// <opcon:experimental:description>
// BoxcutterRuntime feature set, namespace is optional.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit again, sorry: Ignore feature gates, experimental vs. standard, etc. Just plainly state what the field is/means, etc. for users of the experimental release. There should be no appearance of "when experimental is enabled" or "with the BoxcutterRuntime feature gate", etc.

Imagine this feature has been promoted to standard and it just is this way in GA. Use that description. That way when we do promote to standard, all we need to do is drop the </opcon> markers.

Comment on lines 112 to +452
@@ -445,8 +448,8 @@ spec:
rule: 'has(self.sourceType) && self.sourceType == ''Catalog'' ?
has(self.catalog) : !has(self.catalog)'
required:
- namespace
- source
- namespace

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There should be no changes to the standard CRD, right? Aren't we isolating our changes to the experimental CRD?

controllers.RetrieveRevisionStates(revisionStatesGetter),
controllers.ResolveBundle(c.resolver, c.mgr.GetClient()),
controllers.UnpackBundle(c.imagePuller, c.imageCache),
controllers.ValidateInstallNamespace(coreClient),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I thought we decided on no changes to the helm reconciler/applier path?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Generally docs start out in drafts and then we have an docs-focused community member review and move to the "main" docs.

Not sure how consistent we've been with that though. For now, I'd suggest moving to drafts, and we should then separately review our drafts and make a push for them to be moved to the main docs.


// add bundle properties of interest to revision annotations
bundleAnnotations, err := getBundleAnnotations(bundleFS)
bundleAnnotations, err := GetBundleAnnotations(bundleFS)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Does this need to be exported?

Comment on lines +95 to +118
assert.Equal(t, "test-123-1", *rev.Name)
assert.Equal(t, map[string]string{
labels.OwnerKindKey: ocv1.ClusterExtensionKind,
labels.OwnerNameKey: "test-123",
}, rev.Labels)
assert.Equal(t, map[string]string{
"olm.operatorframework.io/bundle-name": "my-bundle",
"olm.operatorframework.io/bundle-reference": "bundle-ref",
"olm.operatorframework.io/bundle-version": "1.2.0",
"olm.operatorframework.io/package-name": "my-package",
}, rev.Annotations)
assert.Equal(t, ptr.To(ocv1.ClusterObjectSetLifecycleStateActive), rev.Spec.LifecycleState)
assert.Equal(t, ptr.To(ocv1.CollisionProtectionNone), rev.Spec.CollisionProtection)
assert.Equal(t, ptr.To(int64(1)), rev.Spec.Revision)

// The Helm-release migration path never injects a namespace (the release's
// namespace already exists), so only the configuration phase is present.
require.Len(t, rev.Spec.Phases, 1)

configPhase := rev.Spec.Phases[0]
assert.Equal(t, "configuration", *configPhase.Name)
require.Len(t, configPhase.Objects, 2)
assert.Equal(t, "ConfigMap", configPhase.Objects[0].Object.GetKind())
assert.Equal(t, "Secret", configPhase.Objects[1].Object.GetKind())

@joelanford joelanford Aug 27, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This change seems unrelated to this PR?

Comment on lines +382 to +385
if revObj.Object.GetKind() == "Namespace" {
require.Equal(t, map[string]string{
"some": "value",
}, revObj.Object.GetLabels())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The CE sets spec.Namespace, so I'd not expect a Namespace object in the phases, right?

require.Equal(t, "test-namespace", nsObj.GetName(), "namespace name should match ext.Spec.Namespace")
}

func Test_GenerateRevision_COSHasOwnerLabels(t *testing.T) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this unrelated to the scope of the PR?

Was this a code gap that you found and fixed in this PR, or just additional test coverage?

IsWebhookSupportEnabled bool
IsSingleOwnNamespaceEnabled bool
IsDeploymentConfigEnabled bool
IsBoxcutterRuntimeEnabled bool

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: I'd suggest renaming this to something more semantic related to the feature it gates in the manifest provider rather than the feature gate we decided to put it behind.

Maybe IsNamespaceManagementEnabled, but still driven in main.go from the BoxcutterRuntime feature gate.

Comment on lines +83 to +87
if ext.Spec.Namespace != "" {
opts = append(opts, render.WithInstallNamespace(ext.Spec.Namespace))
} else {
opts = append(opts, render.RenderInstallNamespace())
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What happens if neither are provided? What happens if both are provided?

Comment on lines +72 to +74
if ext.Spec.Namespace == "" && !r.IsBoxcutterRuntimeEnabled {
return nil, errorutil.NewTerminalError(ocv1.ReasonInvalidConfiguration, fmt.Errorf("spec.namespace is required unless the BoxcutterRuntime feature gate is enabled"))
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: not sure this is really necessary since the namespace can only ever be empty when the feature is enabled.

// TestClusterExtensionAdmissionServiceAccount validates the deprecated spec.serviceAccount field:
// - CRD-level validation (format, length) still works
// - ValidatingAdmissionPolicy emits a deprecation warning for valid non-empty values
func TestClusterExtensionAdmissionNamespaceImmutability(t *testing.T) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I wonder if experimental should just let go of this immutability and allow changes: set to unset, unset to set, and set to something else.

We imagined that we'd eventually deprecate spec.namespace and move the field to be sourced from spec.config. Now that we don't have an SA field, I'm thinking the need for immutable namespace field is now much lower, maybe non-existent.

l.Error(fmt.Errorf("%w", verr), "phase preflight validation failed, retrying after 10s", "phase", i)
setRetryingConditions(l, cos, fmt.Sprintf("phase %d validation error: %s", i, verr), isDeadlineExceeded)
phaseName := pres.GetName()
l.Error(fmt.Errorf("%w", verr), "phase preflight validation failed, retrying after 10s", "phase", phaseName)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: Unrelated to this PR? If we leave this change in (not opposed to it really), I'd suggest leaving the phase index in the error and retrying condition message.

Comment on lines +593 to +595
if gvk.Kind == "Namespace" {
return fmt.Sprintf("namespace %q is already managed by %s %q", name, owner.Kind, ownerName)
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This feels like a slippery slope to me. Why would we give special treatment to namespaces, but not any other object type that has a conflict?

Comment on lines +87 to +94
InstallNamespace: "install-namespace",
GenerateInstallNamespace: true,
InstallNamespaceTemplate: &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"pod-security.kubernetes.io/enforce": "privileged"},
Annotations: map[string]string{"example.com/foo": "bar"},
},
},

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Any reason we need both InstallNamespace and InstallNamespaceTemplate. Could we just have InstallNamespace *corev1.Namespace, and if all we have is a name (and no metadata), we'd just populate/read from InstallNamespace.Metadata.Name?

Otherwise, it seems like there's the awkward possibility of InstallNamespace and InstallNamespaceTemplate disagreeing on the name.

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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants