Skip to content

refactor: extract shared reconciliation logic into pkg/reconcile#1572

Merged
istio-testing merged 3 commits intoistio-ecosystem:mainfrom
aslakknutsen:controller_reorg
Feb 6, 2026
Merged

refactor: extract shared reconciliation logic into pkg/reconcile#1572
istio-testing merged 3 commits intoistio-ecosystem:mainfrom
aslakknutsen:controller_reorg

Conversation

@aslakknutsen
Copy link
Copy Markdown
Contributor

@aslakknutsen aslakknutsen commented Feb 5, 2026

What type of PR is this?

  • Refactor

What this PR does / why we need it:

Move validation, Helm installation, and image digest logic from individual controllers into a shared pkg/reconcile package. This enables code reuse between operator controllers and (future) the install library, ensuring the same code path is used regardless of deployment mode.

Changes:

  • Add pkg/reconcile with IstiodReconciler, CNIReconciler, ZTunnelReconciler
  • Each reconciler provides ValidateSpec(), Validate(), Install(), Uninstall()
  • Export ApplyCNIImageDigests() and ApplyZTunnelImageDigests() for reuse
  • Refactor IstioRevision, IstioCNI, ZTunnel controllers to delegate to shared reconcilers
  • Update controller tests to use shared reconcilers

Design decisions:

  • Two-tier validation: ValidateSpec() for basic checks, Validate() for K8s API checks (supports library usage without K8s client)
  • Controller-agnostic error messages (e.g., "version not set" instead of "spec.version not set")

Which issue(s) this PR fixes:

Additional information:

Co-authored-by: Cursor noreply@cursor.com

@istio-testing
Copy link
Copy Markdown
Collaborator

Hi @aslakknutsen. Thanks for your PR.

I'm waiting for a istio-ecosystem or istio member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

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.

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 5, 2026

Codecov Report

❌ Patch coverage is 84.67742% with 38 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.70%. Comparing base (fe94427) to head (c51614a).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
pkg/reconcile/cni.go 77.77% 7 Missing and 7 partials ⚠️
pkg/reconcile/ztunnel.go 78.46% 7 Missing and 7 partials ⚠️
pkg/reconcile/istiod.go 85.45% 4 Missing and 4 partials ⚠️
...trollers/istiorevision/istiorevision_controller.go 97.14% 0 Missing and 1 partial ⚠️
controllers/ztunnel/ztunnel_controller.go 92.85% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1572      +/-   ##
==========================================
+ Coverage   71.09%   80.70%   +9.61%     
==========================================
  Files          40       50      +10     
  Lines        2072     2441     +369     
==========================================
+ Hits         1473     1970     +497     
+ Misses        430      347      -83     
+ Partials      169      124      -45     

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

@nrfox
Copy link
Copy Markdown
Contributor

nrfox commented Feb 5, 2026

/ok-to-test

Move validation, Helm installation, and image digest logic from
individual controllers into a shared pkg/reconcile package. This
enables code reuse between operator controllers and (future) the
install library, ensuring the same code path is used regardless
of deployment mode.

Changes:
- Add pkg/reconcile with IstiodReconciler, CNIReconciler, ZTunnelReconciler
- Each reconciler provides ValidateSpec(), Validate(), Install(), Uninstall()
- Export ApplyCNIImageDigests() and ApplyZTunnelImageDigests() for reuse
- Refactor IstioRevision, IstioCNI, ZTunnel controllers to delegate to
  shared reconcilers
- Update controller tests to use shared reconcilers

Design decisions:
- Two-tier validation: ValidateSpec() for basic checks, Validate() for
  K8s API checks (supports library usage without K8s client)
- Controller-agnostic error messages (e.g., "version not set" instead
  of "spec.version not set")

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>
…ecks to controller

The validation was awkwardly split between ValidateSpec (no client) and
Validate (with client), but both paths actually need a client. This
refactoring creates a cleaner separation:

- General validations (version/namespace/values checks, target namespace
  exists) remain in pkg/reconcile
- CRD-specific validations (revision name consistency, IstioRevisionTag
  conflict) move to the controller level

Changes:
- Remove ValidateSpec from IstiodReconciler, CNIReconciler, ZTunnelReconciler
- Collapse validation into single Validate function that always requires client
- Add validateRevisionConsistency and validateNoTagConflict to controller
- Update tests to reflect new validation structure

This enables library consumers to use pkg/reconcile without needing to
implement operator-specific validation logic.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Comment on lines +136 to +144
// GetReleaseName returns the Helm release name for a given revision and chart.
func GetReleaseName(revisionName, chartName string) string {
return fmt.Sprintf("%s-%s", revisionName, chartName)
}

// GetChartPath returns the path to a chart for a given version.
func GetChartPath(version, chartName string) string {
return path.Join(version, "charts", chartName)
}
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.

Do these need to be exported? I don't see them currently used outside this package but maybe it's intended for users of the library to consume these?

Copy link
Copy Markdown
Contributor Author

@aslakknutsen aslakknutsen Feb 6, 2026

Choose a reason for hiding this comment

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

GetChartPath is used across all reconcilers and from the Library install package(downstream), so moved to common.go(types.go).
GetReleaseName is only used in istiod so unexported.

10cdd85

Replace inline path.Join(version, "charts", ...) calls with the existing
GetChartPath helper across all three reconcilers. Unexport getReleaseName
since it's only used within istiod.go. Move GetChartPath and its test to
common.go/common_test.go (renamed from types.go) since it's shared across
packages.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
@istio-testing istio-testing merged commit 3001001 into istio-ecosystem:main Feb 6, 2026
17 checks passed
@aslakknutsen aslakknutsen deleted the controller_reorg branch February 6, 2026 14:25
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 6, 2026
* upstream/main: (30 commits)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  docs: Add comprehensive Istio Ambient Mode update and waypoint proxy procedures (istio-ecosystem#1279)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1549)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1546)
  fixing the step numbers in our docs (istio-ecosystem#1545)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1543)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 6, 2026
* upstream/main: (31 commits)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  docs: Add comprehensive Istio Ambient Mode update and waypoint proxy procedures (istio-ecosystem#1279)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1549)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1546)
  fixing the step numbers in our docs (istio-ecosystem#1545)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 6, 2026
* upstream/main: (31 commits)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  docs: Add comprehensive Istio Ambient Mode update and waypoint proxy procedures (istio-ecosystem#1279)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1549)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1546)
  fixing the step numbers in our docs (istio-ecosystem#1545)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 9, 2026
* upstream/main: (33 commits)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  docs: Add comprehensive Istio Ambient Mode update and waypoint proxy procedures (istio-ecosystem#1279)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1549)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 9, 2026
* upstream/main: (33 commits)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  docs: Add comprehensive Istio Ambient Mode update and waypoint proxy procedures (istio-ecosystem#1279)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1549)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 9, 2026
* upstream/main: (33 commits)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  docs: Add comprehensive Istio Ambient Mode update and waypoint proxy procedures (istio-ecosystem#1279)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1549)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 9, 2026
* upstream/main: (33 commits)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  docs: Add comprehensive Istio Ambient Mode update and waypoint proxy procedures (istio-ecosystem#1279)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1549)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 9, 2026
* upstream/main: (33 commits)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  docs: Add comprehensive Istio Ambient Mode update and waypoint proxy procedures (istio-ecosystem#1279)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1549)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 9, 2026
* upstream/main: (33 commits)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  docs: Add comprehensive Istio Ambient Mode update and waypoint proxy procedures (istio-ecosystem#1279)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1549)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 9, 2026
* upstream/main: (33 commits)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  docs: Add comprehensive Istio Ambient Mode update and waypoint proxy procedures (istio-ecosystem#1279)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1549)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 9, 2026
* upstream/main: (33 commits)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  docs: Add comprehensive Istio Ambient Mode update and waypoint proxy procedures (istio-ecosystem#1279)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1549)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 10, 2026
* upstream/main: (33 commits)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  docs: Add comprehensive Istio Ambient Mode update and waypoint proxy procedures (istio-ecosystem#1279)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1549)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 10, 2026
* upstream/main: (33 commits)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  docs: Add comprehensive Istio Ambient Mode update and waypoint proxy procedures (istio-ecosystem#1279)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1549)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 10, 2026
* upstream/main: (34 commits)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1579)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  docs: Add comprehensive Istio Ambient Mode update and waypoint proxy procedures (istio-ecosystem#1279)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 10, 2026
* upstream/main: (35 commits)
  Expose "peerCaCrl" Ztunnel param added in Helm (istio-ecosystem#1578)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1579)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 10, 2026
* upstream/main: (35 commits)
  Expose "peerCaCrl" Ztunnel param added in Helm (istio-ecosystem#1578)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1579)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1551)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 10, 2026
* upstream/main: (36 commits)
  Adding TARGET_ARCH to tag definition when run on CI true (istio-ecosystem#1583)
  Expose "peerCaCrl" Ztunnel param added in Helm (istio-ecosystem#1578)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1579)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 10, 2026
* upstream/main: (36 commits)
  Adding TARGET_ARCH to tag definition when run on CI true (istio-ecosystem#1583)
  Expose "peerCaCrl" Ztunnel param added in Helm (istio-ecosystem#1578)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1579)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 10, 2026
* upstream/main: (36 commits)
  Adding TARGET_ARCH to tag definition when run on CI true (istio-ecosystem#1583)
  Expose "peerCaCrl" Ztunnel param added in Helm (istio-ecosystem#1578)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1579)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 11, 2026
* upstream/main: (36 commits)
  Adding TARGET_ARCH to tag definition when run on CI true (istio-ecosystem#1583)
  Expose "peerCaCrl" Ztunnel param added in Helm (istio-ecosystem#1578)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1579)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  Fix profile column status (istio-ecosystem#1553)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 11, 2026
* upstream/main: (37 commits)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1587)
  Adding TARGET_ARCH to tag definition when run on CI true (istio-ecosystem#1583)
  Expose "peerCaCrl" Ztunnel param added in Helm (istio-ecosystem#1578)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1579)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 11, 2026
* upstream/main: (37 commits)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1587)
  Adding TARGET_ARCH to tag definition when run on CI true (istio-ecosystem#1583)
  Expose "peerCaCrl" Ztunnel param added in Helm (istio-ecosystem#1578)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1579)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1557)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 11, 2026
* upstream/main: (38 commits)
  Improve scorecard test to avoid running on kind cluster inside OCP cl… (istio-ecosystem#1589)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1587)
  Adding TARGET_ARCH to tag definition when run on CI true (istio-ecosystem#1583)
  Expose "peerCaCrl" Ztunnel param added in Helm (istio-ecosystem#1578)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1579)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 11, 2026
* upstream/main: (38 commits)
  Improve scorecard test to avoid running on kind cluster inside OCP cl… (istio-ecosystem#1589)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1587)
  Adding TARGET_ARCH to tag definition when run on CI true (istio-ecosystem#1583)
  Expose "peerCaCrl" Ztunnel param added in Helm (istio-ecosystem#1578)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1579)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1558)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 11, 2026
* upstream/main: (39 commits)
  Add Claude /refactor command for code improvements (istio-ecosystem#1489)
  Improve scorecard test to avoid running on kind cluster inside OCP cl… (istio-ecosystem#1589)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1587)
  Adding TARGET_ARCH to tag definition when run on CI true (istio-ecosystem#1583)
  Expose "peerCaCrl" Ztunnel param added in Helm (istio-ecosystem#1578)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1579)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 11, 2026
* upstream/main: (39 commits)
  Add Claude /refactor command for code improvements (istio-ecosystem#1489)
  Improve scorecard test to avoid running on kind cluster inside OCP cl… (istio-ecosystem#1589)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1587)
  Adding TARGET_ARCH to tag definition when run on CI true (istio-ecosystem#1583)
  Expose "peerCaCrl" Ztunnel param added in Helm (istio-ecosystem#1578)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1579)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 12, 2026
* upstream/main: (39 commits)
  Add Claude /refactor command for code improvements (istio-ecosystem#1489)
  Improve scorecard test to avoid running on kind cluster inside OCP cl… (istio-ecosystem#1589)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1587)
  Adding TARGET_ARCH to tag definition when run on CI true (istio-ecosystem#1583)
  Expose "peerCaCrl" Ztunnel param added in Helm (istio-ecosystem#1578)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1579)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  ...
openshift-service-mesh-bot pushed a commit to openshift-service-mesh-bot/sail-operator that referenced this pull request Feb 12, 2026
* upstream/main: (39 commits)
  Add Claude /refactor command for code improvements (istio-ecosystem#1489)
  Improve scorecard test to avoid running on kind cluster inside OCP cl… (istio-ecosystem#1589)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1587)
  Adding TARGET_ARCH to tag definition when run on CI true (istio-ecosystem#1583)
  Expose "peerCaCrl" Ztunnel param added in Helm (istio-ecosystem#1578)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1579)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1577)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1576)
  feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)
  refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1573)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1571)
  Add automation for updating EOL Istio versions (istio-ecosystem#1562)
  Fix e2e midstream CI mode (istio-ecosystem#1564)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1565)
  Migrate to fs.FS as the sole resource loading interface (istio-ecosystem#1561)
  Adding documentation for zero downtime ztunnel upgrade (istio-ecosystem#1552)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1563)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1560)
  Automator: Update dependencies in istio-ecosystem/sail-operator@main (istio-ecosystem#1559)
  ...
dgn pushed a commit to dgn/sail-operator that referenced this pull request Mar 17, 2026
…io-ecosystem#1572)

* refactor: extract shared reconciliation logic into pkg/reconcile

Move validation, Helm installation, and image digest logic from
individual controllers into a shared pkg/reconcile package. This
enables code reuse between operator controllers and (future) the
install library, ensuring the same code path is used regardless
of deployment mode.

Changes:
- Add pkg/reconcile with IstiodReconciler, CNIReconciler, ZTunnelReconciler
- Each reconciler provides ValidateSpec(), Validate(), Install(), Uninstall()
- Export ApplyCNIImageDigests() and ApplyZTunnelImageDigests() for reuse
- Refactor IstioRevision, IstioCNI, ZTunnel controllers to delegate to
  shared reconcilers
- Update controller tests to use shared reconcilers

Design decisions:
- Two-tier validation: ValidateSpec() for basic checks, Validate() for
  K8s API checks (supports library usage without K8s client)
- Controller-agnostic error messages (e.g., "version not set" instead
  of "spec.version not set")

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(validation): consolidate validation and move CRD-specific checks to controller

The validation was awkwardly split between ValidateSpec (no client) and
Validate (with client), but both paths actually need a client. This
refactoring creates a cleaner separation:

- General validations (version/namespace/values checks, target namespace
  exists) remain in pkg/reconcile
- CRD-specific validations (revision name consistency, IstioRevisionTag
  conflict) move to the controller level

Changes:
- Remove ValidateSpec from IstiodReconciler, CNIReconciler, ZTunnelReconciler
- Collapse validation into single Validate function that always requires client
- Add validateRevisionConsistency and validateNoTagConflict to controller
- Update tests to reflect new validation structure

This enables library consumers to use pkg/reconcile without needing to
implement operator-specific validation logic.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(reconcile): use GetChartPath helper and tidy up exports

Replace inline path.Join(version, "charts", ...) calls with the existing
GetChartPath helper across all three reconcilers. Unexport getReleaseName
since it's only used within istiod.go. Move GetChartPath and its test to
common.go/common_test.go (renamed from types.go) since it's shared across
packages.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

---------

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Signed-off-by: Daniel Grimm <dgrimm@redhat.com>
aslakknutsen added a commit to aslakknutsen/sail-operator that referenced this pull request Mar 25, 2026
…io-ecosystem#1572)

* refactor: extract shared reconciliation logic into pkg/reconcile

Move validation, Helm installation, and image digest logic from
individual controllers into a shared pkg/reconcile package. This
enables code reuse between operator controllers and (future) the
install library, ensuring the same code path is used regardless
of deployment mode.

Changes:
- Add pkg/reconcile with IstiodReconciler, CNIReconciler, ZTunnelReconciler
- Each reconciler provides ValidateSpec(), Validate(), Install(), Uninstall()
- Export ApplyCNIImageDigests() and ApplyZTunnelImageDigests() for reuse
- Refactor IstioRevision, IstioCNI, ZTunnel controllers to delegate to
  shared reconcilers
- Update controller tests to use shared reconcilers

Design decisions:
- Two-tier validation: ValidateSpec() for basic checks, Validate() for
  K8s API checks (supports library usage without K8s client)
- Controller-agnostic error messages (e.g., "version not set" instead
  of "spec.version not set")

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(validation): consolidate validation and move CRD-specific checks to controller

The validation was awkwardly split between ValidateSpec (no client) and
Validate (with client), but both paths actually need a client. This
refactoring creates a cleaner separation:

- General validations (version/namespace/values checks, target namespace
  exists) remain in pkg/reconcile
- CRD-specific validations (revision name consistency, IstioRevisionTag
  conflict) move to the controller level

Changes:
- Remove ValidateSpec from IstiodReconciler, CNIReconciler, ZTunnelReconciler
- Collapse validation into single Validate function that always requires client
- Add validateRevisionConsistency and validateNoTagConflict to controller
- Update tests to reflect new validation structure

This enables library consumers to use pkg/reconcile without needing to
implement operator-specific validation logic.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(reconcile): use GetChartPath helper and tidy up exports

Replace inline path.Join(version, "charts", ...) calls with the existing
GetChartPath helper across all three reconcilers. Unexport getReleaseName
since it's only used within istiod.go. Move GetChartPath and its test to
common.go/common_test.go (renamed from types.go) since it's shared across
packages.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

---------

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

(cherry picked from commit 3001001)

Backport-Change: Apply ApplyZTunnelFipsValues in pkg/reconcile ZTunnel ComputeValues (was only in controller on release-3.3)
Backport-Reason: Upstream commit series omitted FIPS merge; preserve OSSM behavior after refactor.
aslakknutsen added a commit to aslakknutsen/sail-operator that referenced this pull request Mar 25, 2026
…io-ecosystem#1572)

* refactor: extract shared reconciliation logic into pkg/reconcile

Move validation, Helm installation, and image digest logic from
individual controllers into a shared pkg/reconcile package. This
enables code reuse between operator controllers and (future) the
install library, ensuring the same code path is used regardless
of deployment mode.

Changes:
- Add pkg/reconcile with IstiodReconciler, CNIReconciler, ZTunnelReconciler
- Each reconciler provides ValidateSpec(), Validate(), Install(), Uninstall()
- Export ApplyCNIImageDigests() and ApplyZTunnelImageDigests() for reuse
- Refactor IstioRevision, IstioCNI, ZTunnel controllers to delegate to
  shared reconcilers
- Update controller tests to use shared reconcilers

Design decisions:
- Two-tier validation: ValidateSpec() for basic checks, Validate() for
  K8s API checks (supports library usage without K8s client)
- Controller-agnostic error messages (e.g., "version not set" instead
  of "spec.version not set")

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(validation): consolidate validation and move CRD-specific checks to controller

The validation was awkwardly split between ValidateSpec (no client) and
Validate (with client), but both paths actually need a client. This
refactoring creates a cleaner separation:

- General validations (version/namespace/values checks, target namespace
  exists) remain in pkg/reconcile
- CRD-specific validations (revision name consistency, IstioRevisionTag
  conflict) move to the controller level

Changes:
- Remove ValidateSpec from IstiodReconciler, CNIReconciler, ZTunnelReconciler
- Collapse validation into single Validate function that always requires client
- Add validateRevisionConsistency and validateNoTagConflict to controller
- Update tests to reflect new validation structure

This enables library consumers to use pkg/reconcile without needing to
implement operator-specific validation logic.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(reconcile): use GetChartPath helper and tidy up exports

Replace inline path.Join(version, "charts", ...) calls with the existing
GetChartPath helper across all three reconcilers. Unexport getReleaseName
since it's only used within istiod.go. Move GetChartPath and its test to
common.go/common_test.go (renamed from types.go) since it's shared across
packages.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

---------

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

(cherry picked from commit 3001001)

Backport-Change: Apply ApplyZTunnelFipsValues in pkg/reconcile ZTunnel ComputeValues (was only in controller on release-3.3)
Backport-Reason: Upstream commit series omitted FIPS merge; preserve OSSM behavior after refactor.
openshift-merge-bot bot pushed a commit to openshift-service-mesh/sail-operator that referenced this pull request Mar 26, 2026
* refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)

* refactor: extract shared reconciliation logic into pkg/reconcile

Move validation, Helm installation, and image digest logic from
individual controllers into a shared pkg/reconcile package. This
enables code reuse between operator controllers and (future) the
install library, ensuring the same code path is used regardless
of deployment mode.

Changes:
- Add pkg/reconcile with IstiodReconciler, CNIReconciler, ZTunnelReconciler
- Each reconciler provides ValidateSpec(), Validate(), Install(), Uninstall()
- Export ApplyCNIImageDigests() and ApplyZTunnelImageDigests() for reuse
- Refactor IstioRevision, IstioCNI, ZTunnel controllers to delegate to
  shared reconcilers
- Update controller tests to use shared reconcilers

Design decisions:
- Two-tier validation: ValidateSpec() for basic checks, Validate() for
  K8s API checks (supports library usage without K8s client)
- Controller-agnostic error messages (e.g., "version not set" instead
  of "spec.version not set")

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(validation): consolidate validation and move CRD-specific checks to controller

The validation was awkwardly split between ValidateSpec (no client) and
Validate (with client), but both paths actually need a client. This
refactoring creates a cleaner separation:

- General validations (version/namespace/values checks, target namespace
  exists) remain in pkg/reconcile
- CRD-specific validations (revision name consistency, IstioRevisionTag
  conflict) move to the controller level

Changes:
- Remove ValidateSpec from IstiodReconciler, CNIReconciler, ZTunnelReconciler
- Collapse validation into single Validate function that always requires client
- Add validateRevisionConsistency and validateNoTagConflict to controller
- Update tests to reflect new validation structure

This enables library consumers to use pkg/reconcile without needing to
implement operator-specific validation logic.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(reconcile): use GetChartPath helper and tidy up exports

Replace inline path.Join(version, "charts", ...) calls with the existing
GetChartPath helper across all three reconcilers. Unexport getReleaseName
since it's only used within istiod.go. Move GetChartPath and its test to
common.go/common_test.go (renamed from types.go) since it's shared across
packages.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

---------

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

(cherry picked from commit 3001001)

Backport-Change: Apply ApplyZTunnelFipsValues in pkg/reconcile ZTunnel ComputeValues (was only in controller on release-3.3)
Backport-Reason: Upstream commit series omitted FIPS merge; preserve OSSM behavior after refactor.

* feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)

Adds RenderChart() and RenderLoadedChart() to render Helm chart
templates without cluster access. This enables extracting resource
types from charts for watch setup in the install library.

Co-authored-by: Cursor noreply@cursor.com

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

(cherry picked from commit 360205e)

* feat(helm): make managed-by label value configurable via ChartManagerOption (istio-ecosystem#1630)

Allow callers to override the "managed-by" label value set on all
Helm-managed resources by passing WithManagedByValue() to NewChartManager.
The default remains "sail-operator" so existing operator behavior is
unchanged. The value is threaded from ChartManager through
HelmPostRenderer, replacing the previously hardcoded constant.

BREAKING CHANGE: NewHelmPostRenderer now requires a managedByValue parameter

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

(cherry picked from commit cb42ccb)

* feat(library): Add `pkg/install` library for embedding Istio installation in external operators (#721)

* feat(install): add GetWatchSpecs for drift detection

Adds WatchSpec types and GetWatchSpecs() method that dynamically
extracts GVKs by rendering Helm charts. This allows library consumers
to set up watches for owned resources to detect configuration drift.

The extraction happens at runtime to ensure watch specs always match
what the charts actually create for the given options.

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): add Gateway API value helpers

Adds GatewayAPIDefaults() and MergeValues() as exported helper
functions for consumers to configure istiod for Gateway API mode.

This approach keeps YAML profiles (like "openshift") for Helm chart
processing, while providing programmatic defaults as composable
helpers that consumers can modify directly:

  values := install.GatewayAPIDefaults()
  values.Pilot.Env["CONTROLLER_NAME"] = "my-controller"
  installer.Install(ctx, Options{Values: values})

The Gateway API defaults include:
- Disabled PDB and CNI (not needed for Gateway API only)
- Gateway API env vars for deployment controller mode
- Disabled sidecar injection by default
- Proxy header configuration for gateway traffic

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(crds): embed CRD YAML files for programmatic access

Adds an embed.FS in chart/crds/ that exposes all CRD YAML files.
This enables downstream libraries to install CRDs programmatically
without requiring filesystem access to the chart directory.

CRD files follow the naming convention: {group}_{plural}.yaml
(e.g., extensions.istio.io_wasmplugins.yaml)

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): add CRD management for Gateway API mode

Adds automatic CRD installation based on PILOT_IGNORE_RESOURCES and
PILOT_INCLUDE_RESOURCES filters. For Gateway API mode, only 3 Istio
CRDs are installed: WASMPlugin, EnvoyFilter, and DestinationRule.

Changes:
- Add resource filtering constants (X_ prefixed until Istio feature ready)
- Add GatewayAPIIgnoreResources and GatewayAPIIncludeResources values
- Include resource filtering env vars in GatewayAPIDefaults()
- Add ManageCRDs option (defaults to true) to control CRD installation
- Add ensureCRDs() that derives CRD filenames dynamically from resource names
- Add matchesPattern() using filepath.Match for glob wildcards (*.istio.io)
- Add shouldManageResource() with correct filter precedence: INCLUDE > IGNORE

The X_ prefix on env var names prevents Istio from processing them
until the upstream feature is available. The library uses these values
internally to determine which CRDs to install.

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(install): use shared value computation pipeline

Replace local prepareValues() with revision.ComputeValues() to ensure
the library uses the same value processing as the operator:
- image digest application
- vendor default values
- profile and platform defaults
- FIPS configuration
- namespace and revision overrides

This aligns the library code path with the operator, ensuring bug fixes
and enhancements in value computation apply to both.

Note: Image digests currently require config.Config to be populated,
which is a known limitation being tracked separately.

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): add DriftReconciler for automatic drift detection

Add a DriftReconciler that watches resources created by Install() and
automatically restores them when drift is detected. This enables library
consumers to maintain installation consistency without implementing their
own watch logic.

Key changes:
- Install() now returns (*DriftReconciler, error) instead of just error,
  ensuring opts consistency between installation and drift detection
- DriftReconciler uses dynamic informers to watch namespaced and
  cluster-scoped resources separately
- Ignores Add events entirely (avoids reconciliation on initial cache sync)
- Predicates filter Update/Delete events to avoid unnecessary reconciliation
  (e.g., status-only changes, ServiceAccount token updates)
- Support for owner reference filtering when OwnerRef is configured
- Rate-limited workqueue coalesces rapid events into single reconciliation

Usage:
  reconciler, _ := installer.Install(ctx, opts)
  reconciler.Start(ctx)  // blocks until stopped

BREAKING CHANGE: Install() signature changed from returning `error` to
returning `(*DriftReconciler, error)`. Callers that don't need drift
detection can ignore the first return value with `_, err := Install(...)`.

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): add LibraryRBACRules for consumer RBAC aggregation

Expose the RBAC PolicyRules required by library consumers as a Go API.
Rules are derived from chart/templates/rbac/role.yaml with sailoperator.io
CRs filtered out, since library consumers don't manage Sail CRDs.

This allows operators using the install library (e.g., OpenShift Ingress)
to aggregate the required permissions into their own ClusterRole at build
time rather than discovering them at runtime.

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): auto-populate downstream image refs from embedded FS

The library path has no OLM config file to provide production image
refs. SetImageDefaults scans the embedded resource FS for version
directories and constructs full image refs from a registry and naming
convention. NewInstaller calls SetImageDefaults with the same resourceFS
used for chart loading, ensuring consistency. The operator path
(config.Read) takes precedence if already populated.

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): derive version from resource FS instead of versions.yaml

The library path doesn't use the operator's versions.yaml, so relying
on istioversion.Default and istioversion.Resolve was wrong for
downstream. DefaultVersion scans the resource FS for the highest stable
semver directory, and ValidateVersion checks a version directory exists
directly. This removes the istioversion dependency from pkg/install
entirely, making version resolution consistent with the FS used for
charts and images.

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(install): replace manual MergeValues with generic map merge

The previous MergeValues implementation manually copied each supported
field from overlay to base, requiring updates whenever new fields were
added to v1.Values. This was brittle and would silently ignore new
fields until explicitly handled.

The new implementation:
- Converts Values to map[string]any via helm.FromValues()
- Uses recursive mergeOverwrite (copied from istiovalues package)
- Converts back via helm.ToValues()

This matches Helm's merge semantics: maps merge recursively, lists
replace entirely. Added explicit test coverage for list replacement
behavior to document this semantic.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): add batch CRD ownership management and Status type

The per-CRD create-if-not-exists approach didn't account for ownership
conflicts between CIO, OSSM/OLM, and third-party CRD installations.
This rewrites CRD management to classify all target CRDs as a batch
before acting, preventing mixed ownership scenarios.

Key changes:
- Add Status type covering both CRD state and Helm install result
- Add CRDManagementState enum (ManagedByCIO, ManagedByOLM,
  UnknownManagement, MixedOwnership, NoneExist)
- Batch CRD classification: check all targets, aggregate ownership,
  act atomically (install all or touch none)
- CIO-owned CRDs get ingress.operator.openshift.io/owned label and
  helm.sh/resource-policy:keep annotation
- CIO-owned CRDs are updated on each reconcile (not just created)
- Add IncludeAllCRDs option (default false: only PILOT_INCLUDE_RESOURCES)
- Extract doInstall() so DriftReconciler avoids creating nested reconcilers
- Install() returns (*DriftReconciler, Status) instead of error

BREAKING CHANGE: Install() signature changed from returning
`(*DriftReconciler, error)` to `(*DriftReconciler, Status)`.
Check `status.Error` instead of the error return.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(install)!: replace Installer+DriftReconciler with Library actor

The Installer+DriftReconciler pair forced the consumer to manage two
separate types and couldn't propagate status from internal drift
reconciliations back to the controller. Replace with a single Library
type that runs as an independent actor:

- New() creates the Library with kube and dynamic clients
- Start(ctx) returns a <-chan struct{} notification channel, launches
  the internal worker goroutine, and sits idle until first Apply()
- Apply(opts) sets desired state; no-op if options unchanged (deep
  compare via optionsEqual)
- Status() returns the latest reconciliation result (thread-safe)

The Library owns its own workqueue, informers, and lifecycle. The
consumer just sends desired state and watches the notification channel,
which fits the controller-runtime source.Channel pattern for the CIO.

BREAKING CHANGE: `NewInstaller`, `Installer`, `DriftReconciler`, and
`Install()` are removed. Use `New()`, `Library.Start()`, `Library.Apply()`,
and `Library.Status()` instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): watch CRDs for ownership changes and lifecycle events

The Library needs to detect when Istio CRDs are created, deleted, or
have their ownership labels changed (e.g. OSSM takes over via OLM, or
CRDs are removed). Without this, the Library would only re-classify
CRD ownership on explicit Apply() calls or Helm resource drift.

Add WatchTypeCRD with a dedicated event handler that filters by target
CRD names and triggers on label/annotation/generation changes, plus
create and delete events. The CRD informer is set up alongside Helm
resource informers when ManageCRDs is enabled.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* ix(install): resolve default version in getWatchSpecs

getWatchSpecs called applyDefaults() which fills in namespace and
revision but not version. When version was empty, ValidateVersion
failed silently and no Helm resource informers were created — only
CRD informers. Drift detection for Deployments, ConfigMaps, etc.
was completely disabled without any visible error.

Add the same DefaultVersion(resourceFS) fallback that reconcile()
uses, and add logging so silent informer setup failures are visible.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(install): add Status.String() for human-readable status output

Include all fields in the output: installed state, version, CRD
aggregate state, per-CRD name:state pairs, and error if present.
Useful for logging and debugging from consumer operators.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(install): add structured logging to Library internals

The Library had no logging at all — errors from getWatchSpecs were
silently swallowed, informer setup failures were invisible, and
drift events left no trace. Add ctrllog-based logging to run loop,
setupInformers, and event handlers so operators can diagnose issues
without attaching a debugger.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(install): reclaim CRDs with lost labels and reinstall deleted ones

Three related fixes to CRD drift recovery:

1. aggregateCRDState treated CIO+unknown as UnknownManagement, blocking
   all action. Now treats it as ManagedByCIO — if no OLM is involved,
   unknown labels are drift, not foreign ownership.

2. updateCRDs only did Get+Update, failing on deleted CRDs. Now falls
   back to Create when the CRD is NotFound.

3. manageCRDs CIO branch now re-labels unknowns and reinstalls missing
   CRDs, reporting what it did in the status message.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(install): remove error retry loop from workqueue

AddRateLimited on permanent errors (CRD classification, bad config)
caused infinite reconcile loops. The library is event-driven —
informers trigger on state changes and Apply() enqueues explicitly.
No need for automatic retries.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor(install): extract CRDManager type and split filtering utilities

CRD logic in crds.go was a mix of free functions, Library methods, and
filtering utilities with no clear entry point. This extracts a CRDManager
type that owns the client and provides Reconcile() as the single entry
point for CRD classification/install/update. Pure filtering functions
(pattern matching, filename conversion, target resolution) move to
crds_filter.go. Tests split accordingly.

- Add CRDResult type to replace the 4-tuple return from manageCRDs
- Introduce CRDManager with Reconcile(), WatchTargets(), and private
  classifyCRD/installCRDs/updateCRDs methods
- Simplify Library.buildCRDWatchSpec to delegate to CRDManager.WatchTargets
- Add classifyCRD unit tests using fake client
- Add unlabeledCRDNames tests

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(install): strip "v" prefix from image tags and normalize version input

Image tags in container registries use bare semver (e.g. 1.28.0), but
SetImageDefaults was using the directory name directly (v1.28.0).
Also adds NormalizeVersion to accept version input with or without the
"v" prefix, called from applyDefaults so it's caught at a single point.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(install): deep-copy Values to prevent infinite reconcile loop

Apply() and reconcile() shared the same *v1.Values pointer. When
ComputeValues (via ApplyDigests) mutated the Values in place during
reconcile, the stored desiredOpts diverged from freshly built Options,
causing optionsEqual to fail and re-enqueue on every Apply() call.

Fix by deep-copying at two boundaries:
- Apply(): DeepCopy Values on store, isolating from the caller's pointer
- reconcile(): DeepCopy Values at entry, isolating from all downstream
  mutations (ApplyDigests, future code, etc.)

Also adds TestCIOReconcileLoopConverges which simulates the full
Library-controller interaction to verify the loop converges after
exactly one reconcile, and adds caller tracing to enqueue() for
debugging.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(install)!: remove OwnerRef and support Apply/Uninstall lifecycle

Multiple GatewayClasses can share one istiod, so OwnerRef-based GC is
wrong. Replace with explicit lifecycle management: the consumer calls
Uninstall() when no GatewayClasses remain, using labels for drift
filtering instead.

Rework the run() loop to support multiple idle/active cycles so the
Library can be reused after Uninstall. Add a lifecycle mutex so Apply
blocks while Uninstall is in progress, preventing the drift-repair
loop from fighting Helm teardown.

BREAKING CHANGE: `Options.OwnerRef` field removed; `Uninstall` signature
changed from `Uninstall(ctx, namespace, revision)` to `Uninstall(ctx)`.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(install): restructure package for clarity and fix race condition

Split the monolithic install.go into focused files by responsibility:
- library.go: public API surface (Library, Options, Status, New)
- lifecycle.go: run loop, workqueue, Apply/Uninstall/Start
- installer.go: core reconcile/uninstall logic and watch-spec computation
- informers.go: informer setup and event handler constructors
- values.go: GatewayAPIDefaults, MergeValues (renamed from profiles.go)

Extract installer struct from Library so reconcile, uninstall, and
watch-spec logic can be tested without concurrency machinery. Make
predicates and event handlers take explicit dependencies instead of
closing over Library state.

Unexport internal symbols (CRDManager, WatchType, WatchSpec, label/env
constants) to shrink the API surface. Replace 100ms polling in
waitForDesiredState with a signal channel. Replace custom combineErrors
with stdlib errors.Join. Move env/pattern constants to crds_filter.go
where they are consumed.

Fix a race in processWorkQueue where Uninstall could nil desiredOpts
between a nil-check and dereference done under separate locks. Fix
repeated regex compilation in shouldReconcileValidatingWebhook by
hoisting to a package-level MustCompile. Hoist isClusterScoped map
to a package-level var. Normalize function naming to consistent
patterns (apiVersionKindToGVK, shouldFilterStatusChanges).

Add unit tests for installer.reconcile status paths and event handler
constructor predicate matrix.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* test(install): add fake-client tests for crdManager

Cover Reconcile, classifyCRDs, WatchTargets, loadCRD, and
applyCIOLabels using a fake Kubernetes client. Tests exercise
fresh install, CIO-owned updates, reinstall of missing CRDs,
reclaiming unlabeled CRDs, OLM-owned passthrough, mixed
ownership error, and no-targets short circuit.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(install): use configurable managed-by label for Library resources

Set the managed-by label to "sail-library" on all Helm resources created
by the Library, distinguishing them from operator-managed resources.
Thread the value into informer predicates so drift detection filters on
the correct label. Also fix isOwnedResource to check the actual
managed-by key set by the post-renderer instead of stale
app.kubernetes.io/managed-by == "sail-operator" match.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(install)!: accept namespace/revision params in Uninstall for crash recovery

After a crash, the Library has no in-memory desiredOpts, so Uninstall
silently returned nil while the Helm release remained on the cluster.
By taking explicit namespace and revision parameters, callers can
uninstall without needing a prior Apply() call.

BREAKING CHANGE: Uninstall signature changed from (ctx) to (ctx, namespace, revision).

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(install): allow consumer to adopt orphaned OLM-managed CRDs

When OLM manages Istio CRDs via a subscription, deleting that
subscription leaves the CRDs with olm.managed=true but no actual
owner. Add OverwriteOLMManagedCRDFunc callback to Options so the
consumer can inspect the CRD's OLM annotations and decide whether
to take ownership. The callback is invoked during classification;
returning true reclassifies the CRD as CIO-managed so the existing
update path replaces OLM labels with CIO labels.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(install): add Enqueue() to force reconciliation on external state changes

Apply() skips reconciliation when Options are unchanged, which prevents
consumers from triggering CRD re-classification when external cluster
state changes (e.g. OLM Subscription deleted) but Options stay the same.

Enqueue() bypasses the optionsEqual check and directly adds a work item,
letting the consumer signal "something outside my Options changed, please
re-evaluate." This avoids removing the idempotency guard in Apply(),
which would create an infinite notify-Apply-reconcile feedback loop.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(install): prevent panic on double Uninstall by niling closed channels

Uninstall() captured informerStop and processingDone from the Library
struct but never cleared them. A second Uninstall() would attempt to
close the already-closed channels, causing a panic. Nil out both fields
after capturing the locals so subsequent calls see nil and skip the
close/wait via the existing guards.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Made-with: Cursor

* fix(install): add exponential backoff on failed reconciliations

When Helm install fails, its partial-create/rollback cycle fires
informer events that immediately re-enqueue work. Because enqueue()
used Add() (bypassing the rate limiter) and processWorkQueue always
called Forget() (resetting the backoff counter), the library spun
at full speed retrying permanent errors every ~3 seconds.

Switch enqueue() to AddRateLimited() so informer-driven re-enqueues
respect the backoff counter. Only call Forget() on success so the
counter accumulates on failure. Apply() uses Add() directly to
ensure explicit user intent is never delayed by prior failures.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Made-with: Cursor

* fix(install): fix Uninstall deadlock caused by niled processingDone channel

Commit 909ab26 nils l.processingDone in Uninstall to prevent
double-close panics, but processWorkQueue's defer re-read the struct
field — which is now nil — and skipped closing the channel. Uninstall
then blocks forever on <-processingDone.

Fix by capturing both channels as locals under the lock in run() and
passing them to callees. processWorkQueue now receives the done channel
as a parameter, so Uninstall niling the struct field doesn't affect it.

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* docs(install): add README and fix source.Channel usage in USAGE.md

The USAGE.md example used source.Channel with a <-chan struct{}, which
doesn't compile against controller-runtime v0.23.1 (expects
TypedGenericEvent). Replace with source.Func and remove the now-unnecessary
custom event handler section.

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): load image digests from embedded CSV annotations

The library previously constructed image refs from hardcoded downstream
registry/name/tag values. This reads the canonical image references
directly from the ClusterServiceVersion pod template annotations, which
are already maintained by the build pipeline. This means the library
gets the correct upstream images (or digest-pinned images when built
with USE_IMAGE_DIGESTS=true) without requiring manual synchronization.

Signed-off-by: Aslak Knutsen <aslak@redhat.com>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Made-with: Cursor

* fix(install): clear status after successful Uninstall

Uninstall never updated the stored Status, so Status() returned stale
data with Installed:true after the Helm release was removed. Reset to
zero-value Status on the success path so consumers see Installed:false.
The old status is preserved if the uninstall fails, since the release
may still exist.

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* fix(embed): update embed csv ref to match downstream

* fix: remove unused default values and deprecated api refs

* refactor(bundle): move CSV embed out of bundle/manifests to avoid operator-sdk validation errors

operator-sdk bundle validation rejects non-YAML files in bundle/manifests/.
Move the embed to bundle/bundle.go as []byte, simplify LoadImageDigestsFromCSV
to accept raw bytes instead of fs.FS, and add a test against the real embedded CSV.

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* fix: lint stuff

* fix: lint stuff

* fix: make gen go.mod updates

* fix(install): align clearIgnoredFields with upstream webhook predicate

Clear caBundle from clientConfig for both ValidatingWebhookConfiguration
and MutatingWebhookConfiguration, and only clear failurePolicy for
validating webhooks. Uses a kind-based switch to avoid affecting
unrelated resource types.

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

---------

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Signed-off-by: Aslak Knutsen <aslak@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

(cherry picked from commit 665c0b8)
openshift-merge-bot bot pushed a commit to openshift-service-mesh/sail-operator that referenced this pull request Mar 26, 2026
* refactor: extract shared reconciliation logic into pkg/reconcile (istio-ecosystem#1572)

* refactor: extract shared reconciliation logic into pkg/reconcile

Move validation, Helm installation, and image digest logic from
individual controllers into a shared pkg/reconcile package. This
enables code reuse between operator controllers and (future) the
install library, ensuring the same code path is used regardless
of deployment mode.

Changes:
- Add pkg/reconcile with IstiodReconciler, CNIReconciler, ZTunnelReconciler
- Each reconciler provides ValidateSpec(), Validate(), Install(), Uninstall()
- Export ApplyCNIImageDigests() and ApplyZTunnelImageDigests() for reuse
- Refactor IstioRevision, IstioCNI, ZTunnel controllers to delegate to
  shared reconcilers
- Update controller tests to use shared reconcilers

Design decisions:
- Two-tier validation: ValidateSpec() for basic checks, Validate() for
  K8s API checks (supports library usage without K8s client)
- Controller-agnostic error messages (e.g., "version not set" instead
  of "spec.version not set")

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(validation): consolidate validation and move CRD-specific checks to controller

The validation was awkwardly split between ValidateSpec (no client) and
Validate (with client), but both paths actually need a client. This
refactoring creates a cleaner separation:

- General validations (version/namespace/values checks, target namespace
  exists) remain in pkg/reconcile
- CRD-specific validations (revision name consistency, IstioRevisionTag
  conflict) move to the controller level

Changes:
- Remove ValidateSpec from IstiodReconciler, CNIReconciler, ZTunnelReconciler
- Collapse validation into single Validate function that always requires client
- Add validateRevisionConsistency and validateNoTagConflict to controller
- Update tests to reflect new validation structure

This enables library consumers to use pkg/reconcile without needing to
implement operator-specific validation logic.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(reconcile): use GetChartPath helper and tidy up exports

Replace inline path.Join(version, "charts", ...) calls with the existing
GetChartPath helper across all three reconcilers. Unexport getReleaseName
since it's only used within istiod.go. Move GetChartPath and its test to
common.go/common_test.go (renamed from types.go) since it's shared across
packages.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

---------

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

(cherry picked from commit 3001001)

Backport-Change: Apply ApplyZTunnelFipsValues in pkg/reconcile ZTunnel ComputeValues (was only in controller on release-3.3)
Backport-Reason: Upstream commit series omitted FIPS merge; preserve OSSM behavior after refactor.

* feat(helm): add RenderChart functions for template rendering (istio-ecosystem#1575)

Adds RenderChart() and RenderLoadedChart() to render Helm chart
templates without cluster access. This enables extracting resource
types from charts for watch setup in the install library.

Co-authored-by: Cursor noreply@cursor.com

Signed-off-by: Aslak Knutsen <aslak@4fs.no>

(cherry picked from commit 360205e)

* feat(helm): make managed-by label value configurable via ChartManagerOption (istio-ecosystem#1630)

Allow callers to override the "managed-by" label value set on all
Helm-managed resources by passing WithManagedByValue() to NewChartManager.
The default remains "sail-operator" so existing operator behavior is
unchanged. The value is threaded from ChartManager through
HelmPostRenderer, replacing the previously hardcoded constant.

BREAKING CHANGE: NewHelmPostRenderer now requires a managedByValue parameter

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

(cherry picked from commit cb42ccb)

* feat(library): Add `pkg/install` library for embedding Istio installation in external operators (#721)

* feat(install): add GetWatchSpecs for drift detection

Adds WatchSpec types and GetWatchSpecs() method that dynamically
extracts GVKs by rendering Helm charts. This allows library consumers
to set up watches for owned resources to detect configuration drift.

The extraction happens at runtime to ensure watch specs always match
what the charts actually create for the given options.

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): add Gateway API value helpers

Adds GatewayAPIDefaults() and MergeValues() as exported helper
functions for consumers to configure istiod for Gateway API mode.

This approach keeps YAML profiles (like "openshift") for Helm chart
processing, while providing programmatic defaults as composable
helpers that consumers can modify directly:

  values := install.GatewayAPIDefaults()
  values.Pilot.Env["CONTROLLER_NAME"] = "my-controller"
  installer.Install(ctx, Options{Values: values})

The Gateway API defaults include:
- Disabled PDB and CNI (not needed for Gateway API only)
- Gateway API env vars for deployment controller mode
- Disabled sidecar injection by default
- Proxy header configuration for gateway traffic

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(crds): embed CRD YAML files for programmatic access

Adds an embed.FS in chart/crds/ that exposes all CRD YAML files.
This enables downstream libraries to install CRDs programmatically
without requiring filesystem access to the chart directory.

CRD files follow the naming convention: {group}_{plural}.yaml
(e.g., extensions.istio.io_wasmplugins.yaml)

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): add CRD management for Gateway API mode

Adds automatic CRD installation based on PILOT_IGNORE_RESOURCES and
PILOT_INCLUDE_RESOURCES filters. For Gateway API mode, only 3 Istio
CRDs are installed: WASMPlugin, EnvoyFilter, and DestinationRule.

Changes:
- Add resource filtering constants (X_ prefixed until Istio feature ready)
- Add GatewayAPIIgnoreResources and GatewayAPIIncludeResources values
- Include resource filtering env vars in GatewayAPIDefaults()
- Add ManageCRDs option (defaults to true) to control CRD installation
- Add ensureCRDs() that derives CRD filenames dynamically from resource names
- Add matchesPattern() using filepath.Match for glob wildcards (*.istio.io)
- Add shouldManageResource() with correct filter precedence: INCLUDE > IGNORE

The X_ prefix on env var names prevents Istio from processing them
until the upstream feature is available. The library uses these values
internally to determine which CRDs to install.

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(install): use shared value computation pipeline

Replace local prepareValues() with revision.ComputeValues() to ensure
the library uses the same value processing as the operator:
- image digest application
- vendor default values
- profile and platform defaults
- FIPS configuration
- namespace and revision overrides

This aligns the library code path with the operator, ensuring bug fixes
and enhancements in value computation apply to both.

Note: Image digests currently require config.Config to be populated,
which is a known limitation being tracked separately.

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): add DriftReconciler for automatic drift detection

Add a DriftReconciler that watches resources created by Install() and
automatically restores them when drift is detected. This enables library
consumers to maintain installation consistency without implementing their
own watch logic.

Key changes:
- Install() now returns (*DriftReconciler, error) instead of just error,
  ensuring opts consistency between installation and drift detection
- DriftReconciler uses dynamic informers to watch namespaced and
  cluster-scoped resources separately
- Ignores Add events entirely (avoids reconciliation on initial cache sync)
- Predicates filter Update/Delete events to avoid unnecessary reconciliation
  (e.g., status-only changes, ServiceAccount token updates)
- Support for owner reference filtering when OwnerRef is configured
- Rate-limited workqueue coalesces rapid events into single reconciliation

Usage:
  reconciler, _ := installer.Install(ctx, opts)
  reconciler.Start(ctx)  // blocks until stopped

BREAKING CHANGE: Install() signature changed from returning `error` to
returning `(*DriftReconciler, error)`. Callers that don't need drift
detection can ignore the first return value with `_, err := Install(...)`.

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): add LibraryRBACRules for consumer RBAC aggregation

Expose the RBAC PolicyRules required by library consumers as a Go API.
Rules are derived from chart/templates/rbac/role.yaml with sailoperator.io
CRs filtered out, since library consumers don't manage Sail CRDs.

This allows operators using the install library (e.g., OpenShift Ingress)
to aggregate the required permissions into their own ClusterRole at build
time rather than discovering them at runtime.

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): auto-populate downstream image refs from embedded FS

The library path has no OLM config file to provide production image
refs. SetImageDefaults scans the embedded resource FS for version
directories and constructs full image refs from a registry and naming
convention. NewInstaller calls SetImageDefaults with the same resourceFS
used for chart loading, ensuring consistency. The operator path
(config.Read) takes precedence if already populated.

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): derive version from resource FS instead of versions.yaml

The library path doesn't use the operator's versions.yaml, so relying
on istioversion.Default and istioversion.Resolve was wrong for
downstream. DefaultVersion scans the resource FS for the highest stable
semver directory, and ValidateVersion checks a version directory exists
directly. This removes the istioversion dependency from pkg/install
entirely, making version resolution consistent with the FS used for
charts and images.

Co-authored-by: Cursor noreply@cursor.com
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(install): replace manual MergeValues with generic map merge

The previous MergeValues implementation manually copied each supported
field from overlay to base, requiring updates whenever new fields were
added to v1.Values. This was brittle and would silently ignore new
fields until explicitly handled.

The new implementation:
- Converts Values to map[string]any via helm.FromValues()
- Uses recursive mergeOverwrite (copied from istiovalues package)
- Converts back via helm.ToValues()

This matches Helm's merge semantics: maps merge recursively, lists
replace entirely. Added explicit test coverage for list replacement
behavior to document this semantic.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): add batch CRD ownership management and Status type

The per-CRD create-if-not-exists approach didn't account for ownership
conflicts between CIO, OSSM/OLM, and third-party CRD installations.
This rewrites CRD management to classify all target CRDs as a batch
before acting, preventing mixed ownership scenarios.

Key changes:
- Add Status type covering both CRD state and Helm install result
- Add CRDManagementState enum (ManagedByCIO, ManagedByOLM,
  UnknownManagement, MixedOwnership, NoneExist)
- Batch CRD classification: check all targets, aggregate ownership,
  act atomically (install all or touch none)
- CIO-owned CRDs get ingress.operator.openshift.io/owned label and
  helm.sh/resource-policy:keep annotation
- CIO-owned CRDs are updated on each reconcile (not just created)
- Add IncludeAllCRDs option (default false: only PILOT_INCLUDE_RESOURCES)
- Extract doInstall() so DriftReconciler avoids creating nested reconcilers
- Install() returns (*DriftReconciler, Status) instead of error

BREAKING CHANGE: Install() signature changed from returning
`(*DriftReconciler, error)` to `(*DriftReconciler, Status)`.
Check `status.Error` instead of the error return.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(install)!: replace Installer+DriftReconciler with Library actor

The Installer+DriftReconciler pair forced the consumer to manage two
separate types and couldn't propagate status from internal drift
reconciliations back to the controller. Replace with a single Library
type that runs as an independent actor:

- New() creates the Library with kube and dynamic clients
- Start(ctx) returns a <-chan struct{} notification channel, launches
  the internal worker goroutine, and sits idle until first Apply()
- Apply(opts) sets desired state; no-op if options unchanged (deep
  compare via optionsEqual)
- Status() returns the latest reconciliation result (thread-safe)

The Library owns its own workqueue, informers, and lifecycle. The
consumer just sends desired state and watches the notification channel,
which fits the controller-runtime source.Channel pattern for the CIO.

BREAKING CHANGE: `NewInstaller`, `Installer`, `DriftReconciler`, and
`Install()` are removed. Use `New()`, `Library.Start()`, `Library.Apply()`,
and `Library.Status()` instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): watch CRDs for ownership changes and lifecycle events

The Library needs to detect when Istio CRDs are created, deleted, or
have their ownership labels changed (e.g. OSSM takes over via OLM, or
CRDs are removed). Without this, the Library would only re-classify
CRD ownership on explicit Apply() calls or Helm resource drift.

Add WatchTypeCRD with a dedicated event handler that filters by target
CRD names and triggers on label/annotation/generation changes, plus
create and delete events. The CRD informer is set up alongside Helm
resource informers when ManageCRDs is enabled.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* ix(install): resolve default version in getWatchSpecs

getWatchSpecs called applyDefaults() which fills in namespace and
revision but not version. When version was empty, ValidateVersion
failed silently and no Helm resource informers were created — only
CRD informers. Drift detection for Deployments, ConfigMaps, etc.
was completely disabled without any visible error.

Add the same DefaultVersion(resourceFS) fallback that reconcile()
uses, and add logging so silent informer setup failures are visible.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(install): add Status.String() for human-readable status output

Include all fields in the output: installed state, version, CRD
aggregate state, per-CRD name:state pairs, and error if present.
Useful for logging and debugging from consumer operators.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(install): add structured logging to Library internals

The Library had no logging at all — errors from getWatchSpecs were
silently swallowed, informer setup failures were invisible, and
drift events left no trace. Add ctrllog-based logging to run loop,
setupInformers, and event handlers so operators can diagnose issues
without attaching a debugger.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(install): reclaim CRDs with lost labels and reinstall deleted ones

Three related fixes to CRD drift recovery:

1. aggregateCRDState treated CIO+unknown as UnknownManagement, blocking
   all action. Now treats it as ManagedByCIO — if no OLM is involved,
   unknown labels are drift, not foreign ownership.

2. updateCRDs only did Get+Update, failing on deleted CRDs. Now falls
   back to Create when the CRD is NotFound.

3. manageCRDs CIO branch now re-labels unknowns and reinstalls missing
   CRDs, reporting what it did in the status message.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(install): remove error retry loop from workqueue

AddRateLimited on permanent errors (CRD classification, bad config)
caused infinite reconcile loops. The library is event-driven —
informers trigger on state changes and Apply() enqueues explicitly.
No need for automatic retries.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor(install): extract CRDManager type and split filtering utilities

CRD logic in crds.go was a mix of free functions, Library methods, and
filtering utilities with no clear entry point. This extracts a CRDManager
type that owns the client and provides Reconcile() as the single entry
point for CRD classification/install/update. Pure filtering functions
(pattern matching, filename conversion, target resolution) move to
crds_filter.go. Tests split accordingly.

- Add CRDResult type to replace the 4-tuple return from manageCRDs
- Introduce CRDManager with Reconcile(), WatchTargets(), and private
  classifyCRD/installCRDs/updateCRDs methods
- Simplify Library.buildCRDWatchSpec to delegate to CRDManager.WatchTargets
- Add classifyCRD unit tests using fake client
- Add unlabeledCRDNames tests

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(install): strip "v" prefix from image tags and normalize version input

Image tags in container registries use bare semver (e.g. 1.28.0), but
SetImageDefaults was using the directory name directly (v1.28.0).
Also adds NormalizeVersion to accept version input with or without the
"v" prefix, called from applyDefaults so it's caught at a single point.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(install): deep-copy Values to prevent infinite reconcile loop

Apply() and reconcile() shared the same *v1.Values pointer. When
ComputeValues (via ApplyDigests) mutated the Values in place during
reconcile, the stored desiredOpts diverged from freshly built Options,
causing optionsEqual to fail and re-enqueue on every Apply() call.

Fix by deep-copying at two boundaries:
- Apply(): DeepCopy Values on store, isolating from the caller's pointer
- reconcile(): DeepCopy Values at entry, isolating from all downstream
  mutations (ApplyDigests, future code, etc.)

Also adds TestCIOReconcileLoopConverges which simulates the full
Library-controller interaction to verify the loop converges after
exactly one reconcile, and adds caller tracing to enqueue() for
debugging.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(install)!: remove OwnerRef and support Apply/Uninstall lifecycle

Multiple GatewayClasses can share one istiod, so OwnerRef-based GC is
wrong. Replace with explicit lifecycle management: the consumer calls
Uninstall() when no GatewayClasses remain, using labels for drift
filtering instead.

Rework the run() loop to support multiple idle/active cycles so the
Library can be reused after Uninstall. Add a lifecycle mutex so Apply
blocks while Uninstall is in progress, preventing the drift-repair
loop from fighting Helm teardown.

BREAKING CHANGE: `Options.OwnerRef` field removed; `Uninstall` signature
changed from `Uninstall(ctx, namespace, revision)` to `Uninstall(ctx)`.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* refactor(install): restructure package for clarity and fix race condition

Split the monolithic install.go into focused files by responsibility:
- library.go: public API surface (Library, Options, Status, New)
- lifecycle.go: run loop, workqueue, Apply/Uninstall/Start
- installer.go: core reconcile/uninstall logic and watch-spec computation
- informers.go: informer setup and event handler constructors
- values.go: GatewayAPIDefaults, MergeValues (renamed from profiles.go)

Extract installer struct from Library so reconcile, uninstall, and
watch-spec logic can be tested without concurrency machinery. Make
predicates and event handlers take explicit dependencies instead of
closing over Library state.

Unexport internal symbols (CRDManager, WatchType, WatchSpec, label/env
constants) to shrink the API surface. Replace 100ms polling in
waitForDesiredState with a signal channel. Replace custom combineErrors
with stdlib errors.Join. Move env/pattern constants to crds_filter.go
where they are consumed.

Fix a race in processWorkQueue where Uninstall could nil desiredOpts
between a nil-check and dereference done under separate locks. Fix
repeated regex compilation in shouldReconcileValidatingWebhook by
hoisting to a package-level MustCompile. Hoist isClusterScoped map
to a package-level var. Normalize function naming to consistent
patterns (apiVersionKindToGVK, shouldFilterStatusChanges).

Add unit tests for installer.reconcile status paths and event handler
constructor predicate matrix.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* test(install): add fake-client tests for crdManager

Cover Reconcile, classifyCRDs, WatchTargets, loadCRD, and
applyCIOLabels using a fake Kubernetes client. Tests exercise
fresh install, CIO-owned updates, reinstall of missing CRDs,
reclaiming unlabeled CRDs, OLM-owned passthrough, mixed
ownership error, and no-targets short circuit.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(install): use configurable managed-by label for Library resources

Set the managed-by label to "sail-library" on all Helm resources created
by the Library, distinguishing them from operator-managed resources.
Thread the value into informer predicates so drift detection filters on
the correct label. Also fix isOwnedResource to check the actual
managed-by key set by the post-renderer instead of stale
app.kubernetes.io/managed-by == "sail-operator" match.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(install)!: accept namespace/revision params in Uninstall for crash recovery

After a crash, the Library has no in-memory desiredOpts, so Uninstall
silently returned nil while the Helm release remained on the cluster.
By taking explicit namespace and revision parameters, callers can
uninstall without needing a prior Apply() call.

BREAKING CHANGE: Uninstall signature changed from (ctx) to (ctx, namespace, revision).

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(install): allow consumer to adopt orphaned OLM-managed CRDs

When OLM manages Istio CRDs via a subscription, deleting that
subscription leaves the CRDs with olm.managed=true but no actual
owner. Add OverwriteOLMManagedCRDFunc callback to Options so the
consumer can inspect the CRD's OLM annotations and decide whether
to take ownership. The callback is invoked during classification;
returning true reclassifies the CRD as CIO-managed so the existing
update path replaces OLM labels with CIO labels.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(install): add Enqueue() to force reconciliation on external state changes

Apply() skips reconciliation when Options are unchanged, which prevents
consumers from triggering CRD re-classification when external cluster
state changes (e.g. OLM Subscription deleted) but Options stay the same.

Enqueue() bypasses the optionsEqual check and directly adds a work item,
letting the consumer signal "something outside my Options changed, please
re-evaluate." This avoids removing the idempotency guard in Apply(),
which would create an infinite notify-Apply-reconcile feedback loop.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(install): prevent panic on double Uninstall by niling closed channels

Uninstall() captured informerStop and processingDone from the Library
struct but never cleared them. A second Uninstall() would attempt to
close the already-closed channels, causing a panic. Nil out both fields
after capturing the locals so subsequent calls see nil and skip the
close/wait via the existing guards.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Made-with: Cursor

* fix(install): add exponential backoff on failed reconciliations

When Helm install fails, its partial-create/rollback cycle fires
informer events that immediately re-enqueue work. Because enqueue()
used Add() (bypassing the rate limiter) and processWorkQueue always
called Forget() (resetting the backoff counter), the library spun
at full speed retrying permanent errors every ~3 seconds.

Switch enqueue() to AddRateLimited() so informer-driven re-enqueues
respect the backoff counter. Only call Forget() on success so the
counter accumulates on failure. Apply() uses Add() directly to
ensure explicit user intent is never delayed by prior failures.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Made-with: Cursor

* fix(install): fix Uninstall deadlock caused by niled processingDone channel

Commit 909ab26 nils l.processingDone in Uninstall to prevent
double-close panics, but processWorkQueue's defer re-read the struct
field — which is now nil — and skipped closing the channel. Uninstall
then blocks forever on <-processingDone.

Fix by capturing both channels as locals under the lock in run() and
passing them to callees. processWorkQueue now receives the done channel
as a parameter, so Uninstall niling the struct field doesn't affect it.

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* docs(install): add README and fix source.Channel usage in USAGE.md

The USAGE.md example used source.Channel with a <-chan struct{}, which
doesn't compile against controller-runtime v0.23.1 (expects
TypedGenericEvent). Replace with source.Func and remove the now-unnecessary
custom event handler section.

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* feat(install): load image digests from embedded CSV annotations

The library previously constructed image refs from hardcoded downstream
registry/name/tag values. This reads the canonical image references
directly from the ClusterServiceVersion pod template annotations, which
are already maintained by the build pipeline. This means the library
gets the correct upstream images (or digest-pinned images when built
with USE_IMAGE_DIGESTS=true) without requiring manual synchronization.

Signed-off-by: Aslak Knutsen <aslak@redhat.com>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Made-with: Cursor

* fix(install): clear status after successful Uninstall

Uninstall never updated the stored Status, so Status() returned stale
data with Installed:true after the Helm release was removed. Reset to
zero-value Status on the success path so consumers see Installed:false.
The old status is preserved if the uninstall fails, since the release
may still exist.

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* fix(embed): update embed csv ref to match downstream

* fix: remove unused default values and deprecated api refs

* refactor(bundle): move CSV embed out of bundle/manifests to avoid operator-sdk validation errors

operator-sdk bundle validation rejects non-YAML files in bundle/manifests/.
Move the embed to bundle/bundle.go as []byte, simplify LoadImageDigestsFromCSV
to accept raw bytes instead of fs.FS, and add a test against the real embedded CSV.

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

* fix: lint stuff

* fix: lint stuff

* fix: make gen go.mod updates

* fix(install): align clearIgnoredFields with upstream webhook predicate

Clear caBundle from clientConfig for both ValidatingWebhookConfiguration
and MutatingWebhookConfiguration, and only clear failurePolicy for
validating webhooks. Uses a kind-based switch to avoid affecting
unrelated resource types.

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>

---------

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Signed-off-by: Aslak Knutsen <aslak@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

(cherry picked from commit 665c0b8)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants