Skip to content

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

Closed
camilamacedo86 wants to merge 1 commit into
operator-framework:mainfrom
camilamacedo86:fix
Closed

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

Conversation

@camilamacedo86

@camilamacedo86camilamacedo86 commented Feb 16, 2026

Copy link
Copy Markdown
Contributor

No description provided.

CopilotAI review requested due to automatic review settings February 16, 2026 17:39
@netlify

netlifyBot commented Feb 16, 2026

Copy link
Copy Markdown

Deploy Preview for olmv1 ready!

NameLink
🔨 Latest commit30e7965
🔍 Latest deploy loghttps://app.netlify.com/projects/olmv1/deploys/69957190e813800008d2e9b1
😎 Deploy Previewhttps://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.

CopilotAI 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

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

codecovBot commented Feb 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.40%. Comparing base (23dd207) to head (30e7965).
⚠️ Report is 21 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 
FlagCoverage Δ
e2e45.55% <0.00%> (-0.29%)⬇️
experimental-e2e53.95% <100.00%> (+0.45%)⬆️
unit58.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.

Comment threadinternal/operator-controller/applier/boxcutter.go Outdated
// 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
Copy Markdown
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
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Amazing idea. Done !!!

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

Comment threadinternal/operator-controller/applier/boxcutter_test.go Outdated
@camilamacedo86
camilamacedo86force-pushed the fix branch 2 times, most recently from 767a688 to 83002f3CompareFebruary 17, 2026 14:19
CopilotAI review requested due to automatic review settings February 17, 2026 14:19

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

Comment threadinternal/operator-controller/applier/boxcutter_test.go
Comment threadinternal/operator-controller/applier/boxcutter.go Outdated

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

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
Copy Markdown
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
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 the solution here is to generate the apply configurations for our types (which I think is now possible using controller-gen?)

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.

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
Copy Markdown
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?

@camilamacedo86camilamacedo86Feb 18, 2026

Copy link
Copy Markdown
ContributorAuthor

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.

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

/lgtm

@openshift-ciopenshift-ciBot added the lgtm Indicates that a PR is ready to be merged. label Feb 17, 2026
@camilamacedo86camilamacedo86 changed the title 🌱 Fix SA1019: server-side apply required, needs generated apply configurationsWIP 🌱 Fix SA1019: server-side apply required, needs generated apply configurationsFeb 17, 2026
@openshift-ciopenshift-ciBot 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
Copy Markdown
ContributorAuthor

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

/hold

@openshift-ciopenshift-ciBot 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-ciopenshift-ciBot removed the lgtm Indicates that a PR is ready to be merged. label Feb 18, 2026
@openshift-ci

Copy link
Copy Markdown

New changes are detected. LGTM label has been removed.

@openshift-ci

Copy link
Copy Markdown

[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

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

Comment threadinternal/operator-controller/applier/boxcutter.go Outdated
@camilamacedo86camilamacedo86 changed the title WIP 🌱 Fix SA1019: server-side apply required, needs generated apply configurations🌱 Fix SA1019: server-side apply required, needs generated apply configurationsFeb 18, 2026
@openshift-ciopenshift-ciBot 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
Copy Markdown
ContributorAuthor

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
Copy Markdown
ContributorAuthor

/hold cancel

All addressed

@openshift-ciopenshift-ciBot 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
Copy Markdown
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 checksiferr:=bc.runPreAuthorizationChecks(ctx, user, rev); err!=nil {
returnerr
}
data, err:=runtime.DefaultUnstructuredConverter.ToUnstructured(rev)
iferr!=nil {
returnerr
}
u:=&unstructured.Unstructured{Object: data}
gvk, err:=apiutil.GVKForObject(rev, bc.Scheme)
iferr!=nil {
returnerr
}
u.GetObjectKind().SetGroupVersionKind(gvk)
applyConfig:=client.ApplyConfigurationFromUnstructured(u)
// Use Server-Side Apply with field ownership to manage the revision.returnbc.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
Copy Markdown
ContributorAuthor

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

@joelanford

Copy link
Copy Markdown
Member

Addressed by #2515

Sign up for freeto 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.

5 participants

@camilamacedo86@joelanford@pedjak@tmshort