Skip to content

🌱 Fix SA1019: server-side apply required, needs generated apply configurations#2511

Open
camilamacedo86 wants to merge 1 commit intooperator-framework:mainfrom
camilamacedo86:fix
Open

🌱 Fix SA1019: server-side apply required, needs generated apply configurations#2511
camilamacedo86 wants to merge 1 commit intooperator-framework:mainfrom
camilamacedo86:fix

Conversation

@camilamacedo86
Copy link
Contributor

@camilamacedo86 camilamacedo86 commented Feb 16, 2026

No description provided.

Copilot AI review requested due to automatic review settings February 16, 2026 17:39
@openshift-ci openshift-ci bot requested review from bentito and pedjak February 16, 2026 17:39
@netlify
Copy link

netlify bot commented Feb 16, 2026

Deploy Preview for olmv1 ready!

Name Link
🔨 Latest commit 30e7965
🔍 Latest deploy log https://app.netlify.com/projects/olmv1/deploys/69957190e813800008d2e9b1
😎 Deploy Preview https://deploy-preview-2511--olmv1.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

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

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses the SA1019 deprecation warning by replacing the deprecated client.Apply variable with a custom serverSideApplyPatch implementation. The change maintains server-side apply semantics with field ownership management while avoiding the need to generate ApplyConfiguration types.

Changes:

  • Implemented custom serverSideApplyPatch type that satisfies the client.Patch interface
  • Replaced deprecated client.Apply usage with serverSideApplyPatch{}
  • Removed extensive deprecation comment and nolint directive
  • Added two new imports: k8s.io/apimachinery/pkg/types and k8s.io/apimachinery/pkg/util/json

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

@codecov
Copy link

codecov bot commented Feb 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.40%. Comparing base (23dd207) to head (30e7965).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2511      +/-   ##
==========================================
+ Coverage   73.21%   73.40%   +0.18%     
==========================================
  Files         102      102              
  Lines        8504     8564      +60     
==========================================
+ Hits         6226     6286      +60     
  Misses       1799     1799              
  Partials      479      479              
Flag Coverage Δ
e2e 45.55% <0.00%> (-0.29%) ⬇️
experimental-e2e 53.95% <100.00%> (+0.45%) ⬆️
unit 58.09% <86.44%> (+0.20%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

// nolint:staticcheck // SA1019: server-side apply required, needs generated apply configurations
return bc.Client.Patch(ctx, rev, client.Apply, client.FieldOwner(bc.FieldOwner), client.ForceOwnership)
// Use Server-Side Apply to manage field ownership and handle conflicts during OLM upgrades.
return bc.Client.Patch(ctx, rev, serverSideApplyPatch{}, client.FieldOwner(bc.FieldOwner), client.ForceOwnership)
Copy link
Contributor

Choose a reason for hiding this comment

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

IMHO, the right fix here would be to use Client.Apply(..) and generate apply configuration from unstructured, see https://github.com/kubernetes-sigs/controller-runtime/blob/main/pkg/client/applyconfigurations.go#L38

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Amazing idea. Done !!!

Copy link
Contributor

Copilot AI left a comment

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 2 out of 2 changed files in this pull request and generated 1 comment.


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

@camilamacedo86 camilamacedo86 force-pushed the fix branch 2 times, most recently from 767a688 to 83002f3 Compare February 17, 2026 14:19
Copilot AI review requested due to automatic review settings February 17, 2026 14:19
Copy link
Contributor

Copilot AI left a comment

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 2 out of 2 changed files in this pull request and generated 2 comments.


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

Copy link
Member

@joelanford joelanford left a comment

Choose a reason for hiding this comment

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

This kind of conversion is not safe:

  • (typed struct) -> (unstructured) -> (apply configuration)

In this type of conversion it is impossible to tell the difference between:

  • Intentionally use the default value of a type for a field, AND
  • I don't care about that field

return bc.Client.Patch(ctx, rev, client.Apply, client.FieldOwner(bc.FieldOwner), client.ForceOwnership)
// Convert the revision to an unstructured object to create an apply configuration.
// This allows us to use Server-Side Apply without needing generated apply types.
unstructuredRev, err := runtime.DefaultUnstructuredConverter.ToUnstructured(rev)
Copy link
Member

Choose a reason for hiding this comment

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

If there is any field in rev without omitzero and omitempty, those fields will be serialized and applied with our field owner, despite rev not having an opinion on them. To use SSA properly there are basically only two options:

  1. Build unstructured from scratch
  2. Use an apply configuration type.

Copy link
Member

Choose a reason for hiding this comment

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

I think the solution here is to generate the apply configurations for our types (which I think is now possible using controller-gen?)

Copy link
Contributor

Choose a reason for hiding this comment

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

I think the solution here is to generate the apply configurations for our types (which I think is now possible using controller-gen?)

IMHO, this is a bigger change, perhaps we should merge this first and explore it in another PR?

Copy link
Member

Choose a reason for hiding this comment

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

I'm reading the comments that are removed and it seems like they all still apply though? So at a minimum, I think we should restore the comments that talk about needing to use generated applyconfigurations.

Otherwise, what is the functional change here?

Does the switch from this:

bc.Client.Patch(ctx, rev, client.Apply, client.FieldOwner(bc.FieldOwner), client.ForceOwnership)

to this (with the rev -> unstructured -> applyConfig traversal):

bc.Client.Apply(ctx, applyConfig, client.FieldOwner(bc.FieldOwner), client.ForceOwnership)

have any actual change other than removing our use of a deprecated function?

Copy link
Contributor Author

@camilamacedo86 camilamacedo86 Feb 18, 2026

Choose a reason for hiding this comment

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

Joe I checked this one and accordingly to Claude

Your Current Implementation is Already Correct! ✓

Implements the recommended approach for using Server-Side Apply with controller-runtime v0.23+:

  • Manual construction of unstructured objects with only managed fields
  • client.ApplyConfigurationFromUnstructured() to create apply configurations
  • client.Apply() instead of the deprecated client.Patch() with client.Apply type

For custom CRDs, the manual ApplyConfigurationFromUnstructured approach is the recommended pattern because:

  • It gives you fine-grained control over which fields to manage
  • Avoids ownership conflicts from zero-value fields
  • No code generation required
  • Works perfectly with Server-Side Apply semantics

However, I think we should invest some times, maybe create a tech-debt task for deeper analyse the possibility to use controller-tools with serversideapply markers to generate the manifests. Looking for better maintainability in long term.

Copy link
Contributor

@pedjak pedjak left a comment

Choose a reason for hiding this comment

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

/lgtm

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Feb 17, 2026
@camilamacedo86 camilamacedo86 changed the title 🌱 Fix SA1019: server-side apply required, needs generated apply configurations WIP 🌱 Fix SA1019: server-side apply required, needs generated apply configurations Feb 17, 2026
@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 Feb 17, 2026
@camilamacedo86
Copy link
Contributor Author

I will hold based on the @joelanford feedback #2511 (comment) and solve it in another way

/hold

@openshift-ci openshift-ci bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Feb 17, 2026
@openshift-ci openshift-ci bot removed the lgtm Indicates that a PR is ready to be merged. label Feb 18, 2026
@openshift-ci
Copy link

openshift-ci bot commented Feb 18, 2026

New changes are detected. LGTM label has been removed.

@openshift-ci
Copy link

openshift-ci bot commented Feb 18, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please ask for approval from joelanford. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found 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

Copy link
Contributor

Copilot AI left a comment

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 2 out of 2 changed files in this pull request and generated 1 comment.


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

@camilamacedo86 camilamacedo86 changed the title WIP 🌱 Fix SA1019: server-side apply required, needs generated apply configurations 🌱 Fix SA1019: server-side apply required, needs generated apply configurations Feb 18, 2026
@openshift-ci openshift-ci bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Feb 18, 2026
@camilamacedo86
Copy link
Contributor Author

Hi @joelanford and @pedjak

The comments raised were all addressed.
I added the review done by claude and the info generated from there as well.

So, I think it is good to fly 🚀 now.

@camilamacedo86
Copy link
Contributor Author

/hold cancel

All addressed

@openshift-ci openshift-ci bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Feb 18, 2026
Comment on lines +444 to +447
// We cannot safely convert the typed ClusterExtensionRevision struct directly to unstructured
// because that would serialize all fields, including zero values for fields without omitempty tags.
// This would incorrectly claim field ownership for fields we don't manage, violating Server-Side
// Apply semantics.
Copy link
Contributor

Choose a reason for hiding this comment

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

Just checked ClusterExtensionRevisionSpec and we do not have fields without omitempty tag. Hence, it is safe to use the previous approach with DefaultUnstructuredConverter:

func (bc *Boxcutter) createOrUpdate(ctx context.Context, user user.Info, rev *ocv1.ClusterExtensionRevision) error {

	// Run auth preflight checks
	if err := bc.runPreAuthorizationChecks(ctx, user, rev); err != nil {
		return err
	}

	data, err := runtime.DefaultUnstructuredConverter.ToUnstructured(rev)
	if err != nil {
		return err
	}
	u := &unstructured.Unstructured{Object: data}
	gvk, err := apiutil.GVKForObject(rev, bc.Scheme)
	if err != nil {
		return err
	}
	u.GetObjectKind().SetGroupVersionKind(gvk)
    applyConfig := client.ApplyConfigurationFromUnstructured(u)

	// Use Server-Side Apply with field ownership to manage the revision.
	return bc.Client.Apply(ctx, applyConfig, client.FieldOwner(bc.FieldOwner), client.ForceOwnership)
}

why this works?

  • rev argument contains desired resource, created by bc.RevisionGenerator.GenerateRevision - that object contains only the fields we are interested in, it is not pulled from the cache.
  • even if we had a field to zero value, we should own it, actually we should own the whole .spec, because we are creating and reconciling CERs - no other controller should be able to change the spec.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think is safe we keep as it is
WHY?
If something change there all still working

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

Comments