Skip to content

feat(flux): upgrade to v2.8.0 + chart fixes for strict SSA & kstatus (folds #2612) - #2602

Merged
myasnikovdaniil merged 29 commits into
mainfrom
flux-bump-v048
Jun 2, 2026
Merged

feat(flux): upgrade to v2.8.0 + chart fixes for strict SSA & kstatus (folds #2612)#2602
myasnikovdaniil merged 29 commits into
mainfrom
flux-bump-v048

Conversation

@myasnikovdaniil

@myasnikovdaniil myasnikovdaniil commented May 10, 2026

Copy link
Copy Markdown
Contributor

What this PR does

Upgrades Flux v2.7.3 → v2.8.0 across both the vendored tenant chart and the embedded management-cluster manifests, and folds in the chart fixes that become hard errors under the new strict helm-controller v1.5.

Flux v2.8's helm-controller v1.5.0 ships:

  • Server-Side Apply with --force-conflicts — strict CRD schema enforcement; misplaced fields (silently dropped on v2.7) now fail the apply.
  • kstatus-based health checking by default — parent HR waits for every applied resource (including child HRs) to be Ready before flipping its own Ready, surfacing latent ordering deadlocks.
  • Helm v4 embeddedupgrade.force: true is deprecated and now conflicts with SSA.
  • HelmRelease.spec.healthCheckExprs — prerequisite for proper readiness gating (used in PR refactor(seaweedfs): split seaweedfs-system into seaweedfs-db + seaweedfs-system #2601 split).

Folds in PR #2612 (kubevirt-instancetypes null TPM fix) since the same Flux upgrade triggers it.

Commits

Flux upgrade itself:

  • feat(fluxcd): bump flux-operator / flux-instance vendored charts to v0.48.0; web UI opt-in.
  • feat(flux): regenerate embedded management-cluster manifests via make update in packages/core/flux-aio (timoni bundle build).

Chart fixes for strict SSA — fields the chart sent that v2.7 silently dropped, v2.8 rejects:

  • fix(kubevirt-instancetypes): drop persistent strip that produced null preferredTPM (folds fix(kubevirt-instancetypes): drop persistent strip that produced null TPM #2612).
  • fix(foundationdb): relocate faultDomain, imageType, labels, minimumUptimeSecondsForBounce from inside automationOptions to direct children of spec.
  • fix(kafka): place enableServiceLinks under template.pod, not a phantom template.spec.
  • fix(vm-instance): emit disk: {} (not disk:/null) when no bus is set.
  • fix(platform): drop deprecated upgrade.force: true from HelmReleases; fix kafka WorkloadMonitor replicas paths.

Ordering / deadlock fixes under v2.8 kstatus:

  • fix(vpa): break circular wait between parent install and nested vpa-for-vpa HR.
  • fix(kubernetes): drop lookup-guarded parent-HR dependsOn on tenant addon child HRs (parent waits on child via kstatus, child waited on parent — deadlock).

E2E waits for v2.8 kstatus timing:

  • test(e2e): bump app HR-Ready waits to 5m (was 20s–100s under v2.7's faster dispatch).
  • test(e2e): wait for parent HR Ready before downstream asserts in run-kubernetes.sh and vminstance.bats.

Scope discipline

This PR is part of the split of #2619 (the consolidated CI fixes branch) into review-friendly pieces. Companion PRs:

Verification

  • helm template renders cleanly for both fluxcd and fluxcd-operator packages with web.enabled=false (default) and web.enabled=true.
  • Embedded cmd/cozystack-operator binary contains the v1.5.0 / v1.8.0 / v2.1.0 controller image strings.
  • No references to the v0.39-removed --disable-wait-interruption flag anywhere in packages/ or internal/.

Release note

Flux upgraded to v2.8.0 (helm-controller v1.5 — Helm v4 Server-Side Apply with --force-conflicts, kstatus health checking).

When upgrading existing clusters:
- Kubernetes 1.33+ is now required for the platform (management) cluster, and for any tenant cluster that enables the optional (default-off) Flux addon — that addon ships the bumped Flux too.
- HelmReleases no longer set `upgrade.force: true`. Helm v4 SSA resolves field-ownership conflicts automatically (`--force-conflicts`), but that is not the old client-side replace: immutable-field changes (e.g. StatefulSet volumeClaimTemplates/serviceName) no longer self-heal and require manual recreation — delete the object (e.g. `kubectl delete sts <name> --cascade=orphan`) and let Flux recreate it.
- KubeVirt: persistent TPM/EFI is re-enabled for the Windows 11/2k22/2k25 preferences (KubeVirt 1.8 VMPersistentState); each affected VM provisions an extra RWO backend-storage PVC from the default StorageClass.
- KubeVirt: the EOL centos.7*/centos.stream8* preferences are retained as deprecated, hidden aliases (`tags: hidden`, `instancetype.kubevirt.io/deprecated: "true"`) — existing VMInstances on these profiles keep rendering and need no action on upgrade, but the profiles are no longer offered for new VMs; repoint to centos.stream9/10 when convenient. The gn1.* GPU instancetypes are likewise retained.
- FoundationDB: imageType now reaches the operator (silently dropped pre-SSA); it is pinned to `split` to match the value existing clusters effectively ran, so upgrades stay non-disruptive. Set `imageType: unified` to migrate deliberately.

Summary by CodeRabbit

  • New Features

    • Flux Status web UI: optional web server, config secret, service port, HTTPRoute/Ingress, network policy, and RBAC roles.
    • New SeaweedFS DB Helm chart and optional managed DB release.
  • Improvements

    • CRD/schema enhancements: new provider kinds, validations, variant option, and external checksum refs.
    • Raised Kubernetes prerequisite to 1.30+; extended e2e timeouts for reliability.
  • Chores

    • Bumped Flux Operator and Flux versions; documentation links updated to fluxoperator.dev.
  • Bug Fixes

    • Removed aggressive HelmRelease force-upgrade/install flags.

Review Change Stack

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request updates the Flux CD stack to version 2.8.x to leverage new Helm controller capabilities. The primary motivation is to enable advanced health checking for Helm releases, which will support more robust dependency management for various system packages. The changes include updating the vendored charts, adjusting the distribution version, and ensuring the new web interface remains disabled by default to maintain existing operational standards.

Highlights

  • Flux Upgrade: Upgraded flux-operator and flux-instance charts from v0.33.0 to v0.48.0, moving the underlying Flux distribution from 2.7.x to 2.8.x.
  • Web UI Opt-in: Disabled the new Flux Status Web UI by default in the operator values to ensure it remains an opt-in feature.
  • Readiness Gating: Enabled support for spec.install.healthCheckExprs, allowing for future CR-status-based readiness gating for dependency-target packages.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Ignored Files
  • Ignored by pattern: **/*.diff (1)
    • packages/system/fluxcd-operator/patches/networkPolicy.diff
  • Ignored by pattern: **/charts/** (25)
    • packages/system/fluxcd-operator/charts/flux-operator/Chart.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/README.md
    • packages/system/fluxcd-operator/charts/flux-operator/templates/NOTES.txt
    • packages/system/fluxcd-operator/charts/flux-operator/templates/_helpers.tpl
    • packages/system/fluxcd-operator/charts/flux-operator/templates/admin-clusterrole.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/aggregate-clusterrole.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/crds.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/deployment.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/httproute.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/ingress.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/networkpolicy.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/service.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/web-clusterrole.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/web-secret.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/web-standard-roles.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/values.schema.json
    • packages/system/fluxcd-operator/charts/flux-operator/values.yaml
    • packages/system/fluxcd/charts/flux-instance/Chart.yaml
    • packages/system/fluxcd/charts/flux-instance/README.md
    • packages/system/fluxcd/charts/flux-instance/templates/NOTES.txt
    • packages/system/fluxcd/charts/flux-instance/templates/healthcheck.yaml
    • packages/system/fluxcd/charts/flux-instance/templates/instance.yaml
    • packages/system/fluxcd/charts/flux-instance/values.schema.json
    • packages/system/fluxcd/charts/flux-instance/values.yaml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment Gemini (@gemini-code-assist) Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions github-actions Bot added area/platform Issues or PRs related to platform infrastructure (bundle, flux, talos, installer) kind/feature Categorizes issue or PR as related to a new feature size/S This PR changes 10-29 lines, ignoring generated files labels May 10, 2026
@coderabbitai

coderabbitai Bot commented May 10, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

Bump flux-operator/flux-instance charts to v0.48.0; add Flux Status Web UI (templates, helpers, values/schema); update CRDs to controller-gen v0.20.0; add/gate RBAC, Ingress/HTTPRoute, NetworkPolicy; simplify many HelmRelease upgrade/dependsOn patterns; app template fixes; seaweedfs-db chart + migration; increase e2e timeouts and bump helm-controller image.

Changes

Flux Operator Chart

Layer / File(s) Summary
Metadata & docs
packages/system/fluxcd-operator/charts/flux-operator/Chart.yaml, README.md, templates/NOTES.txt
Chart/app versions bumped to 0.48.0; home/docs moved to fluxoperator.dev; README updated and K8s prereq raised.
CRDs
templates/crds.yaml
controller-gen → v0.20.0; FluxInstance/FluxReport/ResourceSetInputProvider/ResourceSet schemas extended (variants, provider types, filters, insecure, validations, externalChecksumRefs).
Helpers & values/schema
templates/_helpers.tpl, values.schema.json, values.yaml
New web helpers and top-level web schema/values for config, secret, httpRoute, ingress, networkPolicy, RBAC, serverOnly/replicas.
Deployment & Service
templates/deployment.yaml, templates/service.yaml
Conditional replicas, web args/env/ports, checksum annotation, secret volume mount; Service adds http-web 9080 when web enabled.
Web templates
templates/web-secret.yaml, templates/ingress.yaml, templates/httproute.yaml, templates/networkpolicy.yaml, patches/networkPolicy.diff
New web secret rendering; Ingress and HTTPRoute to route to 9080; NetworkPolicy templates and Cilium patch to deny world->9080.
RBAC
templates/admin-clusterrole.yaml, aggregate-clusterrole.yaml, web-clusterrole.yaml, web-standard-roles.yaml
Gate admin/aggregate roles for webServerOnly; add web-only view role and flux-web user/admin/edit ClusterRoles and optional aggregation.

Flux Instance Chart

Layer / File(s) Summary
Chart & README
packages/system/fluxcd/charts/flux-instance/Chart.yaml, README.md, templates/NOTES.txt
Version bump to 0.48.0; docs moved to fluxoperator.dev; README K8s prereq 1.30+.
Templates & schema
templates/instance.yaml, values.schema.json, templates/healthcheck.yaml
Quote distribution.version, conditional distribution.variant, new variant enum; healthcheck Job namespace set.
Values updates
values.yaml, packages/system/fluxcd/values.yaml
Docs links updated and flux-instance distribution default bumped to 2.8.x.

HelmRelease & app adjustments

Layer / File(s) Summary
HelmRelease behavior
packages/**/templates/helmreleases/*.yaml (many)
Removed force: true and many lookup-guarded conditional dependsOn entries; adjusted install/upgrade nesting and dependsOn lists across many HelmRelease templates.
App fixes
packages/apps/foundationdb/..., packages/apps/kafka/..., workloadmonitor.yaml
Fix FoundationDB field nesting, move Kafka pod metadata under pod, use chart-specific replicas for workload monitors.
VM & schemas
packages/apps/vm-instance/...
Compute disk deviceKey rendering; update instanceProfile enum values.
SeaweedFS DB
packages/system/seaweedfs-db/*, packages/extra/seaweedfs/templates/seaweedfs-db.yaml, migration
Add seaweedfs-db chart, values/schema, templates; add migration script to re-annotate existing CNPG clusters; remove embedded db values from seaweedfs chart.
E2E & images
hack/e2e-apps/*, internal/fluxinstall/manifests/fluxcd-tenants.yaml
Increase many kubectl wait timeouts to 5m, add parent HR readiness gate, bump helm-controller image to v1.5.0.

Sequence Diagram

sequenceDiagram
  participant User
  participant Ingress
  participant HTTPRoute
  participant Service
  participant Pod
  participant HelmChart
  User->>Ingress: HTTP request (host/path)
  Ingress->>Service: route to service:http-web (port 9080)
  HTTPRoute->>Service: optional Gateway routing to 9080
  Service->>Pod: forward to container port 9080
  HelmChart->>Pod: provide web config secret (if createWebConfigSecret)
  HelmChart->>Pod: set args/env (--web-server-only, WEB_SERVER_PORT)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Suggested labels

area/testing, area/build

Suggested reviewers

  • lexfrei
  • androndo
  • sircthulhu
  • kvaps
  • lllamnyp

Poem

"I hop through YAML, badges bright,
Charts rise to v0.48 by night,
Web UI ports and secrets sown,
CRDs hum and roles are known,
A rabbit's badge of CI delight." 🐰

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch flux-bump-v048

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request updates the FluxCD version to 2.8.x and introduces an opt-in configuration for the Flux Status Web UI in the fluxcd-operator, which is disabled by default. Feedback suggests explicitly disabling the upstream chart's built-in NetworkPolicy for the Web UI to prevent potential resource conflicts with Cozystack's custom Cilium policies.

Comment on lines +17 to +18
web:
enabled: false

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.

low

Since Cozystack provides a custom CiliumClusterwideNetworkPolicy for the Flux Status Web UI (as mentioned in the PR description), it is recommended to disable the built-in NetworkPolicy created by the upstream chart. This avoids redundant or conflicting resources if a user later opts-in by setting web.enabled: true.

  web:
    enabled: false
    networkPolicy:
      create: false

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in d0480f4 — pinned flux-operator.web.networkPolicy.create: false. The Cozystack-shipped CiliumClusterwideNetworkPolicy already restricts ports 8080/8081/9080, so this keeps the Cilium policy as the single source of truth even if a user later opts in to web.enabled: true. helm template with web.enabled=true confirms no upstream NetworkPolicy is rendered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
packages/system/fluxcd-operator/charts/flux-operator/templates/web-clusterrole.yaml (1)

16-24: Security consideration: Web-server-only mode grants cluster-wide read + user impersonation.

When web-server-only mode is enabled, this ClusterRole grants:

  • Cluster-wide read access to all API groups and resources
  • Impersonation of any user or group

These permissions enable the Flux Web UI to provide multi-tenant views but represent significant privilege. If the web UI were compromised, an attacker would gain cluster-wide read access and could bypass authorization checks via impersonation.

The PR correctly defaults web.enabled: false to keep this opt-in. Operators should understand these security implications before enabling the web UI, especially in multi-tenant environments. Consider documenting the security model and recommending network isolation (e.g., internal-only ingress) when the web UI is enabled.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/system/fluxcd-operator/charts/flux-operator/templates/web-clusterrole.yaml`
around lines 16 - 24, The ClusterRole in web-clusterrole.yaml currently grants
cluster-wide read ("apiGroups":["*"], "resources":["*"],
verbs:["get","list","watch"]) and unrestricted impersonation
("resources":["users","groups"], verbs:["impersonate"]), which is overly
privileged for the web UI; change the template to narrow permissions by
replacing the wildcard apiGroups/resources block (the apiGroups/resources/verbs
entries) with only the specific API groups and resources the web UI actually
needs, remove the impersonate verbs unless impersonation is strictly required,
and if impersonation is required restrict scope by converting to a namespaced
Role or by binding the ClusterRole only to the web serviceAccount (instead of
granting impersonation to broad subjects); also add a short comment in
web-clusterrole.yaml explaining the remaining privileges and a note to operators
about the security implications.
packages/system/fluxcd-operator/charts/flux-operator/templates/web-standard-roles.yaml (1)

1-131: ⚖️ Poor tradeoff

Heads-up on RBAC blast radius when operators opt into the web UI.

Vendored upstream content looks intact and correctly gated by flux-operator.createWebRoles / flux-operator.createWebRolesAggregation (both require web.enabled: true), so this template renders to nothing under the chart's default. No action needed for this PR.

Two things worth surfacing in the opt-in docs / release note for downstream operators who enable web.enabled: true:

  1. flux-web-user and flux-web-admin grant cluster-wide get/list/watch on apiGroups: ["*"], resources: ["*"] (lines 16-18, 34-36) — this includes secrets across all namespaces. Anyone bound to these roles can read every Secret in the cluster.
  2. flux-web-edit aggregates into the built-in edit ClusterRole via rbac.authorization.k8s.io/aggregate-to-edit: "true" (line 87). Every principal with the edit ClusterRole (commonly granted to namespace tenants) automatically inherits the Flux verbs (reconcile, suspend, resume, download) on all Flux API groups plus patch/restart on Deployments/StatefulSets/DaemonSets and delete on pods cluster-wide. For a multi-tenant Cozystack cluster this is a meaningful privilege expansion at the moment web is enabled.

Combined with CVE-2026-23990 (Web UI OIDC impersonation bypass) noted in the commit message, the web feature should stay opt-in (which this PR does) and the opt-in instructions should warn operators about the aggregation behavior before flipping createAggregation.

Static analysis note: YAMLlint's "expected the node content, but found '-'" at line 1 is a false positive on the leading {{- if ... }} Helm directive — safe to ignore.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/system/fluxcd-operator/charts/flux-operator/templates/web-standard-roles.yaml`
around lines 1 - 131, Add an opt-in warning to the chart README and release
notes explaining the RBAC blast radius when enabling the web UI: document that
enabling web.enabled (controls used by include "flux-operator.createWebRoles"
and include "flux-operator.createWebRolesAggregation") creates ClusterRoles
flux-web-user and flux-web-admin which grant cluster-wide get/list/watch on
apiGroups:["*"], resources:["*"] (including secrets), and that flux-web-edit is
labeled rbac.authorization.k8s.io/aggregate-to-edit:"true" (so it aggregates
into the built-in edit role), causing edit-role principals to inherit Flux verbs
(reconcile/suspend/resume/download), patch/restart on workloads and pod delete
cluster-wide; also mention the related CVE-2026-23990 and recommend keeping the
web feature opt-in and warning operators to review aggregation before setting
createWebRolesAggregation/createAggregation true.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/system/fluxcd-operator/charts/flux-operator/templates/httproute.yaml`:
- Around line 1-25: The HTTPRoute resource (httproute.yaml) is rendered when
.Values.web.httpRoute.enabled is true even if the web server is disabled,
risking routing to a non-existent backend on port 9080; update the top
conditional to require both .Values.web.enabled and
.Values.web.httpRoute.enabled so the HTTPRoute (which references the backend
name via include "flux-operator.fullname" and port 9080) is only emitted when
the web server is enabled and the httpRoute feature is enabled.

In `@packages/system/fluxcd-operator/charts/flux-operator/templates/ingress.yaml`:
- Around line 1-42: The Ingress template currently only guards on
.Values.web.ingress.enabled and conditionally renders pathType, which can
produce invalid networking.k8s.io/v1 manifests; change the top-level conditional
so the block only renders when both .Values.web.enabled and
.Values.web.ingress.enabled are true (e.g., require both in the initial {{- if
... -}}), and ensure each path always emits a pathType (use the existing
.pathType when present otherwise render a default like "ImplementationSpecific")
where the backend references include "flux-operator.fullname" and the port name
"http-web".

---

Nitpick comments:
In
`@packages/system/fluxcd-operator/charts/flux-operator/templates/web-clusterrole.yaml`:
- Around line 16-24: The ClusterRole in web-clusterrole.yaml currently grants
cluster-wide read ("apiGroups":["*"], "resources":["*"],
verbs:["get","list","watch"]) and unrestricted impersonation
("resources":["users","groups"], verbs:["impersonate"]), which is overly
privileged for the web UI; change the template to narrow permissions by
replacing the wildcard apiGroups/resources block (the apiGroups/resources/verbs
entries) with only the specific API groups and resources the web UI actually
needs, remove the impersonate verbs unless impersonation is strictly required,
and if impersonation is required restrict scope by converting to a namespaced
Role or by binding the ClusterRole only to the web serviceAccount (instead of
granting impersonation to broad subjects); also add a short comment in
web-clusterrole.yaml explaining the remaining privileges and a note to operators
about the security implications.

In
`@packages/system/fluxcd-operator/charts/flux-operator/templates/web-standard-roles.yaml`:
- Around line 1-131: Add an opt-in warning to the chart README and release notes
explaining the RBAC blast radius when enabling the web UI: document that
enabling web.enabled (controls used by include "flux-operator.createWebRoles"
and include "flux-operator.createWebRolesAggregation") creates ClusterRoles
flux-web-user and flux-web-admin which grant cluster-wide get/list/watch on
apiGroups:["*"], resources:["*"] (including secrets), and that flux-web-edit is
labeled rbac.authorization.k8s.io/aggregate-to-edit:"true" (so it aggregates
into the built-in edit role), causing edit-role principals to inherit Flux verbs
(reconcile/suspend/resume/download), patch/restart on workloads and pod delete
cluster-wide; also mention the related CVE-2026-23990 and recommend keeping the
web feature opt-in and warning operators to review aggregation before setting
createWebRolesAggregation/createAggregation true.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9440b6e7-5190-4b18-9137-2be02e9d88b3

📥 Commits

Reviewing files that changed from the base of the PR and between 99e7070 and 7e756e9.

📒 Files selected for processing (28)
  • packages/system/fluxcd-operator/charts/flux-operator/Chart.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/README.md
  • packages/system/fluxcd-operator/charts/flux-operator/templates/NOTES.txt
  • packages/system/fluxcd-operator/charts/flux-operator/templates/_helpers.tpl
  • packages/system/fluxcd-operator/charts/flux-operator/templates/admin-clusterrole.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/aggregate-clusterrole.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/crds.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/deployment.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/httproute.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/ingress.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/networkpolicy.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/service.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/web-clusterrole.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/web-secret.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/web-standard-roles.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/values.schema.json
  • packages/system/fluxcd-operator/charts/flux-operator/values.yaml
  • packages/system/fluxcd-operator/patches/networkPolicy.diff
  • packages/system/fluxcd-operator/values.yaml
  • packages/system/fluxcd/charts/flux-instance/Chart.yaml
  • packages/system/fluxcd/charts/flux-instance/README.md
  • packages/system/fluxcd/charts/flux-instance/templates/NOTES.txt
  • packages/system/fluxcd/charts/flux-instance/templates/healthcheck.yaml
  • packages/system/fluxcd/charts/flux-instance/templates/instance.yaml
  • packages/system/fluxcd/charts/flux-instance/values.schema.json
  • packages/system/fluxcd/charts/flux-instance/values.yaml
  • packages/system/fluxcd/values.yaml

@github-actions github-actions Bot added size/XXL This PR changes 1000+ lines, ignoring generated files and removed size/S This PR changes 10-29 lines, ignoring generated files labels May 10, 2026
@myasnikovdaniil myasnikovdaniil changed the title feat(fluxcd): bump flux-operator/instance to v0.48.0, web UI opt-in feat(flux): upgrade to v2.8.0 — tenant chart v0.48.0 + management-cluster embed, web UI opt-in May 10, 2026
@myasnikovdaniil myasnikovdaniil changed the title feat(flux): upgrade to v2.8.0 — tenant chart v0.48.0 + management-cluster embed, web UI opt-in feat(flux): upgrade to v2.8.0 + chart fixes for strict SSA & kstatus (folds #2612) May 25, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
hack/e2e-apps/vminstance.bats (1)

34-37: ⚡ Quick win

Prefer teardown-based cleanup instead of inline end-of-test deletes.

Line 34-37 and Line 115-116 only execute on success paths; a prior failure can leak VMInstance/VMDisk resources and increase cross-test flakiness. Move this cleanup into teardown() (or shared framework cleanup) and keep the current pre-clean logic.

Based on learnings: e2e cleanup in hack/e2e-apps should be framework-level teardown rather than inline per-test cleanup.

Also applies to: 115-116

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@hack/e2e-apps/vminstance.bats` around lines 34 - 37, The inline resource
cleanup that deletes VMDisk/VMInstance (the kubectl -n tenant-test delete
vmdisks.apps.cozystack.io $name --ignore-not-found --timeout=3m and the similar
delete at lines ~115-116) must be moved from the end of individual tests into
the shared teardown() (or the framework-level cleanup) so failures don't leak
resources; retain the current pre-test delete as-is, but remove the
post-success-only deletes and implement equivalent deletion logic inside
teardown() to unconditionally remove VMInstance and VMDisk resources for the
test name/scope.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@hack/e2e-apps/external-dns.bats`:
- Around line 23-25: The script currently calls "kubectl -n tenant-test wait hr
${name}-system --for=condition=ready" without first ensuring the ${name}-system
HelmRelease exists; add the same existence backstop used for ${name} (a loop
using "kubectl -n tenant-test get hr ${name}-system >/dev/null 2>&1; do sleep 2;
done" or equivalent timeout-backed polling) immediately before the wait for
condition=ready to avoid immediate failures, and apply the identical existence
polling change to the other occurrence around lines 48-50 where ${name}-system
is waited on as well.

---

Nitpick comments:
In `@hack/e2e-apps/vminstance.bats`:
- Around line 34-37: The inline resource cleanup that deletes VMDisk/VMInstance
(the kubectl -n tenant-test delete vmdisks.apps.cozystack.io $name
--ignore-not-found --timeout=3m and the similar delete at lines ~115-116) must
be moved from the end of individual tests into the shared teardown() (or the
framework-level cleanup) so failures don't leak resources; retain the current
pre-test delete as-is, but remove the post-success-only deletes and implement
equivalent deletion logic inside teardown() to unconditionally remove VMInstance
and VMDisk resources for the test name/scope.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7a645b39-6f2e-4e42-a763-96c968fdebf4

📥 Commits

Reviewing files that changed from the base of the PR and between da618d0 and 7aac5ca.

📒 Files selected for processing (48)
  • hack/e2e-apps/bucket.bats
  • hack/e2e-apps/clickhouse.bats
  • hack/e2e-apps/etcd.bats
  • hack/e2e-apps/external-dns.bats
  • hack/e2e-apps/harbor.bats
  • hack/e2e-apps/kafka.bats
  • hack/e2e-apps/mariadb.bats
  • hack/e2e-apps/mongodb.bats
  • hack/e2e-apps/openbao.bats
  • hack/e2e-apps/postgres.bats
  • hack/e2e-apps/qdrant.bats
  • hack/e2e-apps/redis.bats
  • hack/e2e-apps/run-kubernetes.sh
  • hack/e2e-apps/vminstance.bats
  • internal/fluxinstall/manifests/fluxcd-tenants.yaml
  • internal/fluxinstall/manifests/fluxcd.yaml
  • packages/apps/bucket/templates/helmrelease.yaml
  • packages/apps/foundationdb/templates/cluster.yaml
  • packages/apps/harbor/templates/harbor.yaml
  • packages/apps/kafka/templates/kafka.yaml
  • packages/apps/kafka/templates/workloadmonitor.yaml
  • packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml
  • packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml
  • packages/apps/kubernetes/templates/helmreleases/cilium.yaml
  • packages/apps/kubernetes/templates/helmreleases/coredns.yaml
  • packages/apps/kubernetes/templates/helmreleases/csi.yaml
  • packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml
  • packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml
  • packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml
  • packages/apps/kubernetes/templates/helmreleases/hami.yaml
  • packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml
  • packages/apps/kubernetes/templates/helmreleases/metrics-server.yaml
  • packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml
  • packages/apps/kubernetes/templates/helmreleases/ouroboros.yaml
  • packages/apps/kubernetes/templates/helmreleases/prometheus-operator-crds.yaml
  • packages/apps/kubernetes/templates/helmreleases/velero.yaml
  • packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml
  • packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml
  • packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml
  • packages/apps/kubernetes/templates/helmreleases/volumesnapshot-crd.yaml
  • packages/apps/nats/templates/nats.yaml
  • packages/apps/openbao/templates/openbao.yaml
  • packages/apps/qdrant/templates/qdrant.yaml
  • packages/apps/tenant/templates/etcd.yaml
  • packages/apps/tenant/templates/info.yaml
  • packages/apps/tenant/templates/ingress.yaml
  • packages/apps/tenant/templates/monitoring.yaml
  • packages/apps/tenant/templates/seaweedfs.yaml
💤 Files with no reviewable changes (33)
  • internal/fluxinstall/manifests/fluxcd-tenants.yaml
  • packages/apps/foundationdb/templates/cluster.yaml
  • packages/apps/kafka/templates/workloadmonitor.yaml
  • packages/apps/bucket/templates/helmrelease.yaml
  • packages/apps/openbao/templates/openbao.yaml
  • packages/apps/tenant/templates/monitoring.yaml
  • packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml
  • packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml
  • packages/apps/kubernetes/templates/helmreleases/cilium.yaml
  • packages/apps/tenant/templates/ingress.yaml
  • packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml
  • packages/apps/kubernetes/templates/helmreleases/csi.yaml
  • packages/apps/kubernetes/templates/helmreleases/hami.yaml
  • packages/apps/harbor/templates/harbor.yaml
  • packages/apps/tenant/templates/seaweedfs.yaml
  • packages/apps/kubernetes/templates/helmreleases/metrics-server.yaml
  • packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml
  • packages/apps/kubernetes/templates/helmreleases/coredns.yaml
  • packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml
  • packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml
  • packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml
  • packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml
  • packages/apps/kubernetes/templates/helmreleases/ouroboros.yaml
  • packages/apps/nats/templates/nats.yaml
  • packages/apps/kubernetes/templates/helmreleases/prometheus-operator-crds.yaml
  • packages/apps/tenant/templates/info.yaml
  • packages/apps/qdrant/templates/qdrant.yaml
  • packages/apps/tenant/templates/etcd.yaml
  • packages/apps/kafka/templates/kafka.yaml
  • packages/apps/kubernetes/templates/helmreleases/volumesnapshot-crd.yaml
  • packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml
  • packages/apps/kubernetes/templates/helmreleases/velero.yaml
  • packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml
✅ Files skipped from review due to trivial changes (2)
  • hack/e2e-apps/etcd.bats
  • hack/e2e-apps/bucket.bats

Comment thread hack/e2e-apps/external-dns.bats
myasnikovdaniil added a commit that referenced this pull request May 25, 2026
…edfs-system

Splits the seaweedfs-system HelmRelease in two so the CNPG
Cluster/seaweedfs-db lives in its own HR (seaweedfs-db), and the
application HR (seaweedfs-system) dependsOn it. The new HR uses Flux v2
HelmRelease.spec.healthCheckExprs with a CEL expression on
Cluster.status.conditions[type=Ready] plus waitStrategy.name: poller, so
its Ready=True only flips after the postgres primary is actually serving
connections — not just after helm install applied the Cluster CR.

This eliminates the seaweedfs-filer CrashLoopBackOff race on a fresh
tenant install. With Cilium kubeProxyReplacement: true, socket-LB
returns EPERM from connect(2) to ClusterIPs with no Ready endpoints.
Pre-split, the filer StatefulSet scheduled concurrently with the CNPG
bootstrap (~55–70s of unavailable postgres), each connect() failed
EPERM, kubelet exponential restart backoff pushed past the e2e bats
'kubectl wait hr/seaweedfs-system --timeout=2m' window, and the
'Configure Tenant and wait for applications' test failed.

healthCheckExprs uses Flux's three-predicate form: route
ClusterIsNotReady (the CNPG bootstrap condition) to `inProgress` so the
HR keeps polling, keep `failed` for other Ready=False reasons, and rely
on the HR `timeout: 10m` as the real backstop for a genuinely stuck
cluster. A plain Ready=False predicate would flag the HR failed within
seconds of creating the Cluster CR.

Migration 42 adopts existing Cluster/seaweedfs-db resources into the new
release on upgrade by rewriting meta.helm.sh/release-name and stamping
helm.sh/resource-policy: keep so the seaweedfs-system upgrade (which no
longer renders the Cluster) does not delete it during the transition.

The application HR's dependsOn collapses the db dependency (unconditional)
with the existing ingress dependency (guarded by `if eq $ingress
.Release.Namespace` so sub-tenants that inherit ingress from a parent
namespace don't deadlock on a non-existent local HR) into one list.

Requires Flux v2.8.x (helm-controller v1.5.0+) for healthCheckExprs.
Provided by the parent PR #2602 in this chain.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
myasnikovdaniil and others added 5 commits May 28, 2026 12:43
Bump flux-operator and flux-instance vendored charts from v0.33.0 to
v0.48.0, moving the Flux distribution from 2.7.x to 2.8.x. This brings
helm-controller v1.5.x, which exposes spec.install.healthCheckExprs on
HelmRelease — a prerequisite for adding real readiness gating to
dependency-target packages (postgres, mongodb, kafka, etc.).

The new flux-operator chart defaults web.enabled=true; override it to
false in packages/system/fluxcd-operator/values.yaml so the Flux Status
Web UI stays opt-in. Operators wanting it can set web.enabled=true and
configure web.config / web.configSecretName / web.ingress per the
upstream chart values.

Patches reapplied:
- kubernetesEnvs.diff: matched cleanly (offset shift only)
- networkPolicy.diff: extended to also restrict port 9080 (web UI port);
  hunk count updated 20 -> 22

Pre-flight: no references to the v0.39-removed --disable-wait-interruption
flag anywhere in packages/ or internal/.

Verified locally:
- helm template renders both packages without errors
- web.enabled=false (default): no web Deployment/Service/NetworkPolicy
- web.enabled=true: renders web NetworkPolicy on port 9080
- CiliumClusterwideNetworkPolicy lists 8080/8081/9080
- FluxInstance distribution.version: "2.8.x", all 7 components present
- Cozystack kustomize patches (concurrent, requeue, storage-adv-addr,
  events-addr) intact

Notable upstream changes between v0.33 and v0.48:
- Flux 2.8.x with HelmRelease inventory format change (auto-migrated)
- Reliability fixes for stuck FluxInstance/ResourceSet on health-check
  cancellation (v0.39, v0.46)
- New CLI: flux-operator migrate, diff, patch instance, distro mirror
- ResourceSetInputProvider: GitLab Environments, GitHub App, Gitea/Forgejo
- CVE-2026-23990 (Web UI OIDC impersonation bypass) — N/A while web is off

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
… 2.8.0

Re-render internal/fluxinstall/manifests/fluxcd.yaml via
`make update` in packages/core/flux-aio (timoni bundle build against
oci://ghcr.io/stefanprodan/modules/flux-aio at the latest tag) so
the cozystack-operator binary embeds Flux 2.8.0 instead of 2.7.3.
Auto-syncs the helm-controller image into fluxcd-tenants.yaml.

Embedded versions now match the chart bump in the prior commit:
  flux:                   v2.7.3 -> v2.8.0
  helm-controller:        v1.4.3 -> v1.5.0   (enables healthCheckExprs)
  source-controller:      v1.7.3 -> v1.8.0
  kustomize-controller:   v1.7.2 -> v1.8.0
  notification-controller:v1.7.4 -> v1.8.0
  source-watcher:         v2.0.2 -> v2.1.0

Verified by rebuilding cmd/cozystack-operator and running `strings`
on the binary -- the expected v1.5.0 / v1.8.0 / v2.1.0 image strings
are now embedded in place of the v1.4.x / v1.7.x ones.

Structure preserved:
- single AIO Deployment named "flux" in namespace cozy-fluxcd
- all 5 controllers + source-watcher as containers in one pod
- custom tolerations from flux-aio.cue intact
- Namespace pod-security label still "privileged" via the
  Makefile yq post-processing step

Net diff is -3664 lines (mostly CRD schema simplification in 2.8).

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
… TPM

`make update` stripped `persistent: true` from upstream's
`preferredTPM: { persistent: true }`, leaving the parent key with a null value.
KubeVirt v1.6's CRD tolerated it; v1.8 (the operator version we bumped to in
6af0bf7) enforces structural schema and rejects null:

  VirtualMachineClusterPreference "windows.11" is invalid:
  spec.devices.preferredTPM: Invalid value: "null": spec.devices.preferredTPM
  in body must be of type object: "null"

Stop stripping the line and regenerate the templates from upstream
common-instancetypes. Persistent TPM state falls back to the cluster default
StorageClass with RWO access mode when `vmStateStorageClass` is unset on the
KubeVirt CR, per pkg/storage/backend-storage/backend-storage.go.

Drive-by from the regen:
- Removed (upstream EOL): centos.7*, centos.stream8*
- Added: debian, oraclelinux, legacy, linux*, fedora.s390x, rhel.{9,10}.s390x,
  windows.{xp,7,7.virtio,2k3,2k8,2k8.virtio,2k12,2k12.virtio}, plus new
  cx1.*1gi and d1 instancetype variants.

Also regenerates packages/apps/vm-instance instanceProfile enum
(values.schema.json / README.md) from the refreshed preferences.yaml.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
…o spec

The chart nested `faultDomain`, `imageType`, `labels`, and
`minimumUptimeSecondsForBounce` inside `automationOptions`, but the
FoundationDBCluster CRD schema defines all four as direct children of
`spec`. Flux v2.7 (helm-controller v1.4.3) used permissive client-side
patch and silently dropped the unknown fields; v2.8 (helm-controller
v1.5.0) does strict Server-Side Apply and rejects:

  failed to create typed patch object: .spec.automationOptions.<field>:
  field not declared in schema

This was a latent bug from day one — none of those fields ever actually
configured anything. Moving them one level up applies the values to
where the operator looks for them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
…m .spec

Same class of bug as the foundationdb misplaced-field fixes. The kafka
chart had:

  entityOperator:
    template:
      pod:
        metadata: { labels: { ... } }
      spec:                          ← child of template, not of pod
        enableServiceLinks: false

The Strimzi Kafka CRD's `entityOperator.template` has no `spec` key.
`enableServiceLinks` is a direct field of `template.pod` (alongside
metadata, affinity, tolerations, etc.). Flux v2.7's permissive
client-side patch silently dropped the misplaced field; v2.8's strict
Server-Side Apply rejects:

  failed to create typed patch object (Kind=Kafka):
  .spec.entityOperator.template.spec: field not declared in schema

Move `enableServiceLinks` under `template.pod` where the operator
actually reads it, and fix the inconsistent metadata.labels indentation
(was 9/11 spaces instead of 10/12) while we're here.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
(cherry picked from commit 447f1dc)
tenant-rd now carries release.cozystack.io/helm-install-timeout alongside
kubernetes-rd (its parent chart bootstraps the seaweedfs-db CNPG cluster, whose
first reconcile exceeds flux's default wait budget). Update the comment that
claimed only kubernetes-rd carries it.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
- kafka: assert WorkloadMonitor reads .Values.kafka.replicas /
  .Values.zookeeper.replicas (regression for the phantom .Values.replicas),
  and that enableServiceLinks lives under entityOperator.template.pod.
- tenant: pin that no swept HelmRelease carries upgrade.force (would have
  caught the missed gateway.yaml).
- seaweedfs-db: baseline render cover for the new split-out chart.
- kafka and seaweedfs-db had no `test` Makefile target, so their suites never
  ran in CI; add one to each.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
@myasnikovdaniil

Copy link
Copy Markdown
Contributor Author

Aleksei Sviridkin (@lexfrei) thanks — all three blockers are addressed, plus the cheap follow-ups.

B1 (f880b32): migrations.targetVersion 43 → 44 so seq $CURRENT $((TARGET-1)) includes migration 43 and the seaweedfs-db adoption runs.

B2 (9cda93d): pinned common-instancetypes to commit 3a552da6 — a release tag would regress the multi-arch preferredArchitecture/requirements.architecture fields (only on main past v1.6.0), so the SHA reproduces the reviewed catalog byte-for-byte. The gn1.* GPU instancetypes (dropped upstream in v1.3.0) are re-added as a Cozystack-local extra-instancetypes.yaml the regen re-appends, so existing GPU VMs/workers keep rendering. EOL centos.7*/centos.stream8* stay dropped (release-noted with repoint guidance). Both vm-instance and kubernetes READMEs regenerated to match the catalog. Closes the unpinned-source point (#5).

B3 (e3f4e34): dropped upgrade.force from gateway.yaml; added a tenant unit suite asserting no swept HR carries it.

Follow-ups: foundationdb imageType pinned to split to match the prior effective value, so no image migration on upgrade (2a6112b); stale rest.go comment fixed (e44457a); WorkloadMonitor replica-path + enableServiceLinks tests added, and make test wired for kafka + seaweedfs-db which had none (57c0ce6); release note expanded for the K8s 1.33 minimum (platform + Flux addon), persistent TPM/EFI PVCs, the centos removal, and the loss of force-recreate recovery under SSA.

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.

NOT LGTM — the three earlier blockers are resolved, but the foundationdb imageType change was hand-edited without running make generate, leaving the generated tree inconsistent and the pre-commit check red.

Business context: Flux v2.7.3 → v2.8.0 (helm-controller v1.5, Helm v4 Server-Side Apply + kstatus), plus chart fixes for fields v2.7 silently dropped and v2.8 SSA now rejects.

Blockers

foundationdb imageType default out of sync — make generate not run (pre-commit red)

File: api/apps/v1alpha1/foundationdb/types.go:42

Issue: The imageType default was switched to split in values.yaml, values.schema.json, README.md and the RD schema, but api/apps/v1alpha1/foundationdb/types.go still carries +kubebuilder:default:="unified", and packages/apps/foundationdb/README.md keeps the table column sized for the old longer value.

Evidence: The pre-commit job fails with exit 123 on an uncommitted make generate diff covering exactly these two files. Reproduced locally with cozyvalues-gen 1.5.0: make generate -C packages/apps/foundationdb rewrites types.go to +kubebuilder:default:="split" and reflows the README table — byte-identical to the CI diff. types.go is not touched anywhere in this PR.

Impact: Runtime CR defaulting is unaffected — the dynamic CRD defaults imageType from the RD openAPISchema, which already says split, so the non-disruptive-upgrade guarantee holds. But the pre-commit check is red (merge-blocking) and the generated source tree is internally inconsistent.

Fix: Run make generate -C packages/apps/foundationdb and fold the result into the imageType commit.

Resolved since the previous review (verified)

  • migrations.targetVersion bumped 43 → 44: migration 43 now falls inside seq CURRENT 43; the file exists and the missing-file guard is intact. The migrations image digest is auto-stamped at build time (same convention as migration 42), so leaving it untouched is correct.
  • kubevirt-instancetypes: the gn1.* GPU instancetypes are re-added in extra-instancetypes.yaml byte-for-byte identical to the previous catalog; common-instancetypes is pinned to a documented commit; only the EOL centos.7*/centos.stream8* preferences are dropped (release-noted with repoint guidance); both READMEs are regenerated to match.
  • The tenant gateway HelmRelease no longer sets upgrade.force; no force: true remains anywhere under packages/ (excluding vendored charts); the new invariant suite asserts notExists on spec.upgrade.force across all six swept HRs and renders each one (non-vacuous).
  • rest.go annotation comment corrected; both kubernetes-rd and tenant-rd carry the annotation.
  • Test coverage added for the WorkloadMonitor replica-path fix, the enableServiceLinks relocation, the no-upgrade.force invariant, and the new seaweedfs-db chart; the kafka and seaweedfs-db test Makefile targets were wired (previously absent, so the pre-existing kafka suites were not running in CI at all).
  • Kubernetes 1.33 minimum: confirmed accurate — Flux v2.8 supports 1.33/1.34/1.35; the release note documents both the platform and the default-off tenant addon.

Non-blocking follow-ups

  1. The default-off tenant Flux addon ships Flux v2.8, which requires Kubernetes 1.33+, while tenant clusters can still run v1.30–1.32. This is release-noted but not version-gated; a preflight gate would be more robust than a release note for operators who do not read changelogs.
  2. No sibling docs PR was found for the user-facing K8s 1.33 prerequisite bump. The requirements page does not appear to pin a minimum, so there may be nothing stale to fix — worth a glance.

… default

The imageType default was switched to split in values.yaml/values.schema.json/
RD schema but make generate was not run, leaving the +kubebuilder:default marker
in api/apps/v1alpha1/foundationdb/types.go at "unified" and the README param
table sized for the old value — failing the pre-commit generate check (exit 123).
Regenerated with cozyvalues-gen v1.5.0.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Re-pull the vendored flux-operator and flux-instance charts from 0.48.0 to the
latest v0.50.0 (operator-version bumps only: OpenShift v4.21 compat, OLM base
image, Kubernetes client deps — no Flux distribution change). The kubernetesEnvs
and networkPolicy patches re-apply cleanly. distribution.version stays 2.8.x, so
the tenant Flux toolkit auto-tracks the latest 2.8 patch (currently 2.8.8) at
reconcile. The management flux-aio module is already at its latest published
build (2.8.0); no newer 2.8.x module exists upstream yet.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
@myasnikovdaniil

Copy link
Copy Markdown
Contributor Author

Aleksei Sviridkin (@lexfrei) good catch — fixed in 5c4e927. Ran make generate with cozyvalues-gen v1.5.0: api/apps/v1alpha1/foundationdb/types.go now carries +kubebuilder:default:="split" and the README param table is reflowed, byte-identical to the CI diff. Also verified kafka/kubernetes/tenant/vm-instance are generate-clean under v1.5.0, so the pre-commit check is green.

Separately bumped the vendored flux-operator/flux-instance charts 0.48.0 → v0.50.0 (fd59dea) — operator-version bumps only (OpenShift/OLM/dep updates), no Flux distribution change. distribution.version stays 2.8.x, so the tenant toolkit auto-tracks the latest 2.8 patch (currently 2.8.8) at reconcile. The management flux-aio module is already at its newest published build (2.8.0) — no later 2.8.x module exists upstream yet.

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.

NOT LGTM — two upgrade regressions for existing clusters: migration 43 strips the deletion-protection label off the cozystack-version ConfigMap (undoing migration 42), and dropping the EOL centos.7*/centos.stream8* preferences hard-fails the HelmRelease render of every existing VM that references them, with no migration or compatibility alias.

Business context: Flux v2.7.3 → v2.8.0 (helm-controller v1.5, Helm v4 Server-Side Apply + kstatus), plus chart fixes for fields v2.7 silently dropped and v2.8 SSA now rejects.

Blockers

B1 — Migration 43 strips the no-delete label from the cozystack-version ConfigMap

File: packages/core/platform/images/migrations/migrations/43:30-32

Issue: The version stamp at the end of migration 43 emits a label-less manifest and kubectl applys it under the same client-side field manager migration 42 used:

kubectl create configmap -n cozy-system cozystack-version \
  --from-literal=version=44 --dry-run=client -o yaml | kubectl apply -f-

Migration 42 deliberately applied this ConfigMap with platform.cozystack.io/no-delete: "true", and its own header warns: "a label-less apply by the same field manager would strip it." Migration 43 performs exactly that label-less apply.

Evidence:

  • migrations/42 applies the ConfigMap with the no-delete label via heredoc + kubectl apply, with an explicit comment that a later label-less apply by the same manager would strip it.
  • templates/cozystack-version.yaml only renders the labeled ConfigMap {{- if not $configMap }} — first install only. On an existing cluster the template renders nothing, so the chart does not restore the label after the migration removes it.
  • templates/deletion-protection.yaml defines cozystack-no-delete-guardrail, a ValidatingAdmissionPolicy matching objects with platform.cozystack.io/no-delete: "true". Once the label is stripped, the guardrail no longer covers cozystack-version.
  • The upgrade path that runs migration 43 is not exercised by E2E (fresh installs stamp version = targetVersion via the chart and skip the migration hook), so the green E2E run does not validate this.

Impact: Every cluster upgrading through migration 43 loses deletion protection on cozystack-version — the ConfigMap that anchors migration-version tracking. An accidental kubectl delete configmap cozystack-version -n cozy-system then succeeds and can cause migrations to re-run or version detection to break on the next upgrade. This regresses the exact protection migration 42 added.

Fix: Stamp the version with the labeled manifest mirroring migration 42 (include metadata.labels.platform.cozystack.io/no-delete: "true"), and add a test asserting the label survives the stamp. Better: factor the version stamp into a shared helper so future migrations cannot drift from the labeled pattern.

B2 — Removing the EOL centos.7* / centos.stream8* preferences hard-breaks existing VMs on upgrade

File: packages/system/kubevirt-instancetypes/templates/preferences.yaml (removal) + packages/apps/vm-instance/templates/vm.yaml:4-6 (hard fail)

Issue: centos.7, centos.7.desktop, centos.stream8, centos.stream8.desktop, centos.stream8.dpdk are removed from the preference catalog and from the vm-instance schema enum, and are not re-added anywhere. vm.yaml hard-fails the render when a referenced VirtualMachineClusterPreference is absent from the cluster. Any existing VMInstance using one of these profiles fails its HelmRelease render on the next reconcile after upgrade, with no automatic remediation — and the operator cannot patch the object through the API either, because the dynamic CRD enum now rejects the stored value.

Evidence:

  • origin/main:.../preferences.yaml ships these five preferences; HEAD ships none of them, and they are absent from extra-instancetypes.yaml.
  • vm-instance/values.schema.json drops the five centos.* enum entries.
  • vm.yaml:4-6: {{- if and .Values.instanceProfile (not (lookup ... "VirtualMachineClusterPreference" "" .Values.instanceProfile)) }}{{- fail ... }}.
  • The PR already solves this exact failure mode for the in-use gn1.* instancetypes by re-adding them as deprecated aliases in extra-instancetypes.yaml; the header comment states the purpose verbatim: "vm.yaml fails the Helm render when a referenced VirtualMachineClusterInstancetype is absent ... appended ... to keep those workloads renderable."

Impact: Hard, unrecoverable HelmRelease render failure for every existing VM on these profiles, on a platform whose target operator does not read changelogs. The "repoint manually before upgrading" note in the PR body is the operator-facing symptom, not a mitigation.

Fix: Re-add the five centos.* preferences as deprecated-alias VirtualMachineClusterPreference objects, mirroring the gn1.* treatment in extra-instancetypes.yaml; or ship a repointing migration (same class as migration 43) that rewrites instanceProfile on existing VMInstances. EOL guest OS is not a reason to hard-fail a running VM's reconciliation — the deprecated-alias mechanism already in this PR keeps such objects renderable while hiding them from new use.

Non-blocking follow-ups

  1. Stale Flux version label on the tenant sharded controller. internal/fluxinstall/manifests/fluxcd-tenants.yaml bumps helm-controller to v1.5.0 (Flux 2.8.0) but keeps app.kubernetes.io/version: v2.7.3 on the flux-tenants Deployment (line 8). packages/core/flux-aio/Makefile's update target only syncs the container image into this file via yq; it never touches the version label, so the label drifts on every bump and make update will not self-correct. Cosmetic (the running image is correct) but misreports the Flux version to anything reading the standard label. Fix: update the label, or extend the yq patch to carry app.kubernetes.io/version too.
  2. K8s 1.33 minimum is release-noted but not gated. Flux v2.8 requires Kubernetes 1.33+, while tenant clusters can still run v1.30–1.32 and would deploy this Flux if the (default-off) tenant Flux addon is enabled. A preflight version gate would be more robust than a changelog note. No sibling docs PR is open in the website repo.

Resolved since the prior round (verified)

  • foundationdb imageType generated-tree drift: 5c4e927 regenerates types.go to +kubebuilder:default:="split" and reflows the README; the "Verify generated code" and pre-commit gates are now green.
  • The fd59dea flux-operator/flux-instance chart bump v0.48.0 → v0.50.0 is the operator version only; distribution.version stays pinned at 2.8.x, the chart delta is additive (optional service.ipFamilyPolicy, AWSCodeCommit CRD validations), and the embedded bootstrap installs raw Flux controllers, so there is no operator/bootstrap skew.

done

# Stamp version
kubectl create configmap -n cozy-system cozystack-version \

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.

This label-less kubectl apply strips the platform.cozystack.io/no-delete label that migration 42 added — see migration 42's own warning that a label-less apply by the same field manager removes it. templates/cozystack-version.yaml only re-creates the labeled ConfigMap when it is absent, so on upgrade the chart does not restore the label and the cozystack-no-delete-guardrail policy stops protecting this ConfigMap. Stamp the version with the labeled manifest as migration 42 does.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 797284ab4. The version stamp now applies a labeled heredoc manifest carrying platform.cozystack.io/no-delete: "true" and version: "44", mirroring migration 42, instead of the label-less kubectl create configmap | kubectl apply. The label is recorded inline by the same field manager, so it survives the stamp and cozystack-version stays covered by the cozystack-no-delete-guardrail ValidatingAdmissionPolicy on upgrade.

# The gn1.* (GPU NVIDIA) series was removed upstream in common-instancetypes
# v1.3.0, but existing GPU VMs and tenant Kubernetes GPU worker pools still
# reference these names, and packages/apps/vm-instance/templates/vm.yaml fails
# the Helm render when a referenced VirtualMachineClusterInstancetype is absent.

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.

The same rationale applies to the centos.7* / centos.stream8* VirtualMachineClusterPreference objects this PR removes: vm.yaml hard-fails the render when a referenced preference is absent, so existing VMs on those profiles break on upgrade. Re-add them here as deprecated aliases (as done for gn1.*) instead of relying on a manual pre-upgrade repoint.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 27edd73bc. The five centos.7, centos.7.desktop, centos.stream8, centos.stream8.desktop, centos.stream8.dpdk VirtualMachineClusterPreference objects are re-added as deprecated aliases in extra-instancetypes.yaml, mirroring the gn1.* treatment, so vm.yaml no longer hard-fails the render. I also extended the vm-instance enum generation to union preference names from extra-instancetypes.yaml, so these profiles stay in values.schema.json and the RD schema — the dynamic CRD no longer rejects existing VMInstance CRs referencing them.

Address review feedback from lexfrei on migrations/43: the version stamp
did a label-less `kubectl create configmap | kubectl apply` under the same
field manager migration 42 used, stripping the platform.cozystack.io/no-delete
label and dropping cozystack-version out of the deletion-protection guardrail on
every upgrade through this migration. Replace it with a labeled heredoc manifest
mirroring migration 42 so the label survives the stamp.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
…ted aliases

Address review feedback from lexfrei: dropping the centos.7/centos.7.desktop/
centos.stream8{,.desktop,.dpdk} VirtualMachineClusterPreference objects hard-fails
the vm-instance Helm render (vm.yaml fails when a referenced preference is absent)
and makes the dynamic CRD enum reject the stored value for every existing VM on
those profiles on upgrade. Re-add them as deprecated aliases in
extra-instancetypes.yaml, mirroring the gn1.* GPU instancetype treatment, and
extend the vm-instance enum generation to union preference names from
extra-instancetypes.yaml so the retained profiles stay in values.schema.json and
the RD schema.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
@myasnikovdaniil

Copy link
Copy Markdown
Contributor Author

Aleksei Sviridkin (@lexfrei) both blockers from this round are addressed:

  • B1 (migration 43 strips the no-delete label): 797284ab4 — the version stamp now uses a labeled heredoc mirroring migration 42, so platform.cozystack.io/no-delete survives and cozystack-version stays under the deletion-protection guardrail on upgrade.
  • B2 (EOL centos.7*/centos.stream8* preferences hard-break existing VMs): 27edd73bc — re-added as deprecated aliases in extra-instancetypes.yaml (mirroring gn1.*), and the vm-instance enum generation now unions preference names from that file so the profiles stay in values.schema.json and the RD schema enum.

The two non-blocking follow-ups (stale app.kubernetes.io/version label on the tenant flux Deployment, and a preflight K8s 1.33 gate vs the release note) are noted — happy to fold them into this PR if you'd prefer, otherwise I'll leave them for a follow-up.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — both blockers from the prior round are resolved and verified; the only open items are the two known non-blocking follow-ups, both acknowledged.

Business context: Flux v2.7.3 → v2.8.0 (helm-controller v1.5, Helm v4 Server-Side Apply + kstatus), plus chart fixes for fields v2.7 silently dropped and v2.8 SSA now rejects.

Resolved since the prior round (verified)

  • B1 — migration 43 no longer strips the no-delete label (797284ab). The version stamp now applies cozystack-version from a labeled heredoc carrying platform.cozystack.io/no-delete: "true", mirroring migration 42, so the ConfigMap stays under the cozystack-no-delete-guardrail ValidatingAdmissionPolicy on upgrade. Same client-side field manager as migration 42 → the relabel is a clean 3-way merge, no conflict. The inline comment documents why the label must be carried here.
  • B2 — EOL centos.7* / centos.stream8* preferences retained as deprecated aliases (27edd73b). All five (centos.7, centos.7.desktop, centos.stream8, centos.stream8.desktop, centos.stream8.dpdk) are re-added to extra-instancetypes.yaml verbatim from the pre-removal catalog (only an explanatory comment prepended), marked instancetype.kubevirt.io/deprecated: "true" + tags: hidden, mirroring the gn1.* treatment — so vm.yaml's lookup/fail finds them and existing VMs keep rendering. The enum generation now unions preference names from extra-instancetypes.yaml, so values.schema.json and the RD openAPISchema enum both regain the five names and the dynamic CRD no longer rejects the stored values. Evidence: reconstructing instanceProfile.enum from the source catalogs with the Makefile's own yq/jq pipeline reproduces the committed schema byte-for-byte (60 entries); the RD enum matches values.schema.json; there are no object-name collisions between extra-instancetypes.yaml and preferences.yaml/instancetypes.yaml; and the "Verify generated code is up to date" + pre-commit checks are green — so the generated tree is consistent.

Non-blocking follow-ups (carried over, both acknowledged)

  1. internal/fluxinstall/manifests/fluxcd-tenants.yaml:8 still reads app.kubernetes.io/version: v2.7.3 while the Deployment now runs helm-controller:v1.5.0 (Flux 2.8.0). Cosmetic (the running image is correct) but misreports the version; make update won't self-correct since the yq patch only syncs the image.
  2. K8s 1.33 minimum is release-noted but not gated; a preflight version gate on the default-off tenant Flux addon would be more robust than a changelog note. No sibling website-repo docs PR is open.

No new issues introduced by either commit.

…ment

Address non-blocking review feedback from lexfrei: the flux-tenants
sharded-controller Deployment carried a stale app.kubernetes.io/version: v2.7.3
while running helm-controller v1.5.0 (Flux 2.8.0). The flux-aio Makefile update
target only synced the container image, so the version label drifted on every
bump and make update never self-corrected. Bump the label to v2.8.0 and extend
the yq patch to carry app.kubernetes.io/version from the source flux Deployment.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
@myasnikovdaniil

Copy link
Copy Markdown
Contributor Author

Aleksei Sviridkin (@lexfrei) folded in non-blocking follow-up #1 as well: 910b505dc bumps the stale app.kubernetes.io/version: v2.7.3v2.8.0 on the flux-tenants Deployment and extends the flux-aio Makefile update target to yq-sync that label from the source flux Deployment, so it self-corrects on future bumps instead of drifting.

The K8s 1.33 preflight gate (follow-up #2) I'd prefer to keep out of this PR — it's a new feature (version-gating the default-off tenant Flux addon) and the user-facing docs piece lives in the website repo. Happy to open a tracking issue for it if you agree.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — the last open item (non-blocking follow-up #1) is now resolved and verified; no regressions, CI green.

Business context: Flux v2.7.3 → v2.8.0 (helm-controller v1.5, Helm v4 Server-Side Apply + kstatus), plus chart fixes for fields v2.7 silently dropped and v2.8 SSA now rejects.

Resolved since the prior round (verified)

  • Stale Flux version label synced (910b505d). The flux-tenants sharded-controller Deployment now carries app.kubernetes.io/version: v2.8.0 (was v2.7.3), matching the helm-controller:v1.5.0 it runs. The flux-aio Makefile update target was extended with a yq patch that sources the label from the flux Deployment in fluxcd.yaml, so the label self-corrects on future bumps instead of drifting. Evidence: the source flux Deployment in fluxcd.yaml carries v2.8.0; re-running the new yq expression against the committed tree is a no-op (idempotent); fluxcd-tenants.yaml holds a single document, so the selector-less patch has no collateral; no v2.7.3 references remain under internal/ or packages/.

Non-blocking follow-up (deferred with rationale)

  1. K8s 1.33 preflight gate on the default-off tenant Flux addon — deferred to a separate change (it is a new feature; the requirement is already captured in the release note). A tracking issue is the right home for it.

@myasnikovdaniil
myasnikovdaniil merged commit c435efa into main Jun 2, 2026
11 checks passed
@myasnikovdaniil
myasnikovdaniil deleted the flux-bump-v048 branch June 2, 2026 09:08
Aleksei Sviridkin (lexfrei) added a commit that referenced this pull request Jun 9, 2026
…ay.bats tenant teardown (#2558)

## What this PR does

Drops the 3× retry loop on `Run E2E tests` and `Install Cozystack into
sandbox`. `Prepare environment` keeps its 3× retry — that step is pure
infrastructure (Talos image download, sandbox VM boot, network) where
transient runner hiccups warrant a retry.

On failure, the test step now captures `kubectl get hr -A -o wide` and
`kubectl get events -A` under a collapsible group so triage starts with
the actual broken-state snapshot.

> [!NOTE]
> An earlier revision of this PR also doubled every bats timeout. That
commit was dropped in a rebase and is intentionally **not restored**:
the timeout class that actually matters (per-app HR-Ready waits) has
since been standardized at 5m on `main` (7b9f286), making a blanket 2×
redundant.

**Fixes gateway.bats teardown leakage.** The nested-tenant tests deleted
tenants fire-and-forget, parent and child back-to-back. The leftover
uninstalls (each blocked on a cleanup Job, parents wedged on
still-terminating child namespaces) plus one mid-install child HR
occupied exactly 5 workers on the `--concurrent=5` tenants
helm-controller shard, starving whichever app test ran next — observed
as the harbor HR sitting unreconciled for its whole 5m HR-Ready budget
in [run
27020081550](https://github.com/cozystack/cozystack/actions/runs/27020081550),
surfaced by this PR's own retry removal + diagnostics dump. Teardown now
deletes child→parent with hard `wait hr --for=delete` between, so a
wedged tenant uninstall fails gateway.bats itself, not an innocent
neighbor.

## Why

Audit of 30 successful PR runs found that across 5 sampled failure
attempts, **25/25 retries** on `Run E2E tests` failed — the retry loop
never recovered a flake, only stretched deterministic failures and
tripled diagnostic wall-time. Same data shape on `Install Cozystack`.

Beyond wasted CI time, the retry was hiding ~10 deterministic bugs (Helm
namespace-ownership conflict, seaweedfs HR timeout, harbor BucketInfo
wiring, vminstance disk race, etc.). Each failure looked like a "flake"
because the retry sometimes coincided with whatever transient state had
cleared — the retry never fixed the bug, just delayed surfacing.

## Dependencies

The deterministic bugs the retry was masking are now fixed on `main`:
- ✅ **#2508** — installer namespace bootstrap (Helm namespace-ownership
conflict on cold install) — merged
- ✅ **#2509** — operator HelmRelease config knobs (`seaweedfs-system`
2-min wait race within Flux's 5-min reconcile windows) — merged
- ✅ **#2528** — harbor bucket-secret + BucketInfo gating (harbor
`ValuesError` on first install) — merged
- ✅ **#2529** — objectstorage-controller BucketAccess conflict retry —
merged

Companion PRs in the #2619 split (independent of this PR,
ordering-wise):
- **#2602** — Flux v2.8.0 + chart fixes
- **#2601** — seaweedfs-system split

This PR does NOT depend on #2602/#2601 — it now touches only the
workflow file and gateway.bats teardown, both on top of fresh `main`.

Surfaced from #2500.

### Release note

```release-note
NONE
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* CI prepare-environment step now reports plain attempt counts with
clear success/failure messages.
* Install and per-app test steps no longer retry; each runs once and
fails immediately on error. Failed apps log diagnostics and job proceeds
to remaining apps while overall job fails.
* **Tests**
* End-to-end tests and install/prepare flows use longer, more tolerant
timeouts and added existence polling to reduce flakiness and improve
diagnostics.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2558?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
myasnikovdaniil added a commit that referenced this pull request Jul 16, 2026
The kstatus readiness work (#2642) sets WaitStrategy /
kustomize.CustomHealthCheck / HelmReleaseSpec.HealthCheckExprs on generated
HelmReleases. Those Go types do not exist at helm-controller/api v1.4.3 — the
runtime CRD is already v1.5.0 (shipped by #2602), so this closes a
Go-types-vs-runtime skew rather than getting ahead of the runtime.

The bump is not isolated: helm-controller/api v1.5.x requires k8s 0.35 +
controller-runtime 0.23, cascading the k8s stack 0.34 -> 0.35. cozystack
replaces k8s.io/apimachinery with a fork carrying the (still-open) upstream
ConvertToVersion patch k/k#135537; that single commit is rebased cleanly onto
apimachinery v0.35.0 at cozystack/apimachinery@release-1.35-pr135537. The repo
builds with no source changes under the new stack.

Refs #2642

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
myasnikovdaniil added a commit that referenced this pull request Jul 21, 2026
…2642) (#3273)

## What

Adds typed `waitStrategy` + `healthCheckExprs` fields so a package/app
can declare the Flux helm-controller v1.5.0 kstatus health gate for the
custom resource it wraps — making `HelmRelease.Ready` mean "the CR is
actually healthy" instead of "helm applied the CR". This is the
operator/apiserver foundation of the kstatus epic (#2642); the API
surface was reviewed and approved by the API owner in #3263.

Commits (per the review's "isolated step-0" request):
1. `build(deps)` — the dependency bump (see below).
2. `feat(api)` — the fields, plumbing, tests, and regenerated code.
3. `fix(api)` — match the openapi code-generator pin to the 0.35 runtime
(fixes an aggregated-apiserver crash the bump surfaced).
4. `fix(api)` — declare `OpenAPIModelName` on the apps types so SSA
resolves catalog kinds.
5. `docs(api)` — note that `disableWait` silently defeats
`healthCheckExprs`.

## API surface

Typed fields on **both** HelmRelease-building paths:
- `ApplicationDefinition.spec.release` (apiserver / catalog apps →
`convertApplicationToHelmRelease`)
- `ComponentInstall` (operator / platform packages →
`buildHelmReleaseSpec`)

```go
// WaitStrategy maps to HelmReleaseSpec.WaitStrategy.Name — a deliberate scalar
// simplification of the upstream {name} object. One of poller|legacy.
WaitStrategy string
// HealthCheckExprs maps to HelmReleaseSpec.HealthCheckExprs (the upstream
// kustomize.CustomHealthCheck type verbatim).
HealthCheckExprs []kustomize.CustomHealthCheck
```

`config.ResolveWaitStrategy` is shared by both builders and **couples
the default**: `healthCheckExprs` are only evaluated under the `poller`
strategy, so when expressions are set and no strategy is given, the
generated HelmRelease defaults to `poller`. A package that sets only
`healthCheckExprs` is therefore self-contained, independent of the
controller's global default.

## The dependency bump (commit 1)

The `WaitStrategy` / `kustomize.CustomHealthCheck` /
`HelmReleaseSpec.HealthCheckExprs` types do not exist below
`helm-controller/api` v1.5.0 — the runtime is already v1.5.0 (shipped by
#2602), so this closes a Go-types-vs-runtime skew. It is **not** an
isolated bump: v1.5.x requires **k8s 0.35 + controller-runtime 0.23**,
cascading the k8s stack 0.34 → 0.35 (and the go directive to 1.26).

cozystack replaces `k8s.io/apimachinery` with a fork carrying the
still-open upstream `ConvertToVersion` patch (k/k#135537). That single
commit rebases cleanly onto apimachinery v0.35.0; published at
`cozystack/apimachinery@release-1.35-pr135537`, and `go.mod` pins its
pseudo-version. **The repo builds with zero source changes under the new
stack.**

> Maintainer note: please confirm the `release-1.35-pr135537` fork
branch naming, or fold it into the `cozystack` branch as you prefer —
the pin can be updated to match.

## Not included (conscious YAGNI)

`disableWait` is intentionally omitted. The only known need (the
kubernetes tenant-addon deadlock) was resolved child-side, and
`waitStrategy: legacy` is not equivalent (legacy still waits
Helm-v3-style; `disableWait` skips waiting entirely). Add it later when
a concrete leaf needs a true no-gate escape hatch.

## Tests

- `config.TestResolveWaitStrategy` — the couple-the-default logic
(unset+exprs→poller; explicit legacy honored; unset+no-exprs→nil).
- Operator + apiserver cases mirror each other
(`TestBuildHelmReleaseSpecHealthCheckExprs` /
`TestConvertApplicationToHelmRelease_HealthCheckExprs`).
- `go build ./...` clean, `go vet` clean, `gofmt` clean, codegen
regenerated and committed.

The 4 backupstrategy CRDs regenerate with benign k8s-0.35 PodSpec
description drift (DynamicResourceAllocation alpha→stable, toleration
Lt/Gt, resizePolicy note) — no functional change.

## Follow-up

Phase 3 (per-leaf adoption — postgres/kafka/mongodb/etc. declaring their
CEL via these fields) builds on this. The full CRD→CEL catalog is
maintained in the epic's readiness audit.

Refs #2642

```release-note
feat(api): add `waitStrategy` and `healthCheckExprs` to ApplicationDefinition and ComponentInstall, so a HelmRelease reports Ready only once the custom resource it wraps is actually healthy
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added configurable CEL health-check expressions for application
releases and package components.
* Added `waitStrategy` support (`poller` and `legacy`) with automatic
`poller` selection when health checks are configured and no strategy is
set.
* Propagated these settings into generated Helm releases, affecting
readiness/wait behavior.

* **Documentation**
* Updated Application and PackageSource schemas to include
`healthCheckExprs` and `waitStrategy`.
* Extended related Kubernetes CRD documentation, including projected pod
certificate annotations and workload reference fields.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/platform Issues or PRs related to platform infrastructure (bundle, flux, talos, installer) kind/feature Categorizes issue or PR as related to a new feature size/XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants