Introduces a new opt-in system package that provisions an admin-facing
GitOps surface: a Flux GitRepository + Kustomization in cozy-system
reconciling an admin-owned git repo of cluster customizations via a
curated ServiceAccount.
The admin uses this to manage Package CR patches (e.g. OIDC enable,
MetalLB option overrides) and bring their own HelmReleases / Keycloak
realm imports / NetworkPolicies as code in a repo they own, rather
than via in-cluster kubectl patch.
Wired into the platform chart via a single `customizer.enabled` flag
in values; off by default. When enabled, emits the cozystack.customizer
Package CR through the existing bundles/system.yaml path and respects
bundles.disabledPackages.
Curated ClusterRole grants patch (not delete) on packages.cozystack.io,
read-only on platform HelmReleases, full ownership of PackageSources +
admin-owned namespaces (default: cozy-customizer), and Keycloak realm
CRs. Explicitly does NOT grant delete on Packages, anything on CRDs,
the cozystack-controller Deployment, or kube-system.
NOTE: this MVP ships the GitOps surface only. The field-ownership
contract documented in the package values is currently advisory; a
validating admission webhook on packages.cozystack.io is the planned
enforcement (kustomize-controller hardcodes client.ForceOwnership on
Apply, so SSA conflict detection cannot block silent ownership
transfer at the Flux layer). Risk callout is inline in the values
block.
Includes helm-unittest coverage for the bundle wiring (off, on with
values, disabledPackages override).
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
## What this PR does
Fixes the OpenSSF Scorecard workflow added in #2720.
The initial workflow used floating major-version tags (`@v2`, `@v4`,
`@v3`). `ossf/scorecard-action` does not publish a floating `v2` tag —
only specific patch releases — so the first scheduled run failed:
> Unable to resolve action `ossf/scorecard-action@v2`, unable to find
version `v2`
This PR pins every action by its full commit SHA with a trailing comment
showing the human-readable version. This also satisfies the
**Pinned-Dependencies** Scorecard check itself.
- `actions/checkout@de0fac2` (v6.0.2)
- `ossf/scorecard-action@4eaacf0` (v2.4.3)
- `actions/upload-artifact@043fb46` (v7.0.1)
- `github/codeql-action/upload-sarif@03e4368` (v3)
### Release note
```release-note
NONE
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated CI/CD infrastructure dependency versions to maintain security
and stability.
**Note:** This release contains no user-facing changes.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2721?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 -->
The initial Scorecard workflow used floating major-version tags
(@v2, @v4, @v3). ossf/scorecard-action does not publish a floating
v2 tag — only specific patch releases — so the first scheduled run
failed with `Unable to resolve action ossf/scorecard-action@v2`.
Pin every action by its full commit SHA with a trailing comment
showing the human-readable version. This also satisfies the
`Pinned-Dependencies` Scorecard check itself.
- actions/checkout@de0fac2 (v6.0.2)
- ossf/scorecard-action@4eaacf0 (v2.4.3)
- actions/upload-artifact@043fb46 (v7.0.1)
- github/codeql-action/upload-sarif@03e4368 (v3)
Signed-off-by: Timur Tukaev <timur.tukaev@aenix.io>
## What this PR does
Adds a GitHub Actions workflow that runs the [OpenSSF
Scorecard](https://github.com/ossf/scorecard) on this repository.
### Schedule
- Weekly on Mondays at 06:00 UTC
- On branch protection rule changes
- On pushes to `main`
- Manual dispatch
### Where results go
- **Public**
[`scorecard.dev`](https://scorecard.dev/viewer/?uri=github.com/cozystack/cozystack)
— transparency for adopters and reviewers (CNCF DD).
- **Code-scanning dashboard** (Security tab) — for in-team triage of
individual findings.
- SARIF artifact retained for 5 days for local inspection.
### Token permissions
Default `read-all`, with the minimum required scopes elevated only
inside the analysis job:
- `security-events: write` — upload to code scanning
- `id-token: write` — publish to `scorecard.dev` via OIDC, no long-lived
secret
- `contents: read`, `actions: read`
### Why no README badge yet
This PR enables the workflow but **does not add a badge to the README**.
Once the first scans have completed and quick-win improvements (token
permissions across other workflows, dependency pinning in workflows,
etc.) have landed, a follow-up PR will add the badge.
### Context
- Tracked under the project's CNCF Incubation readiness work and the
in-progress security self-assessment.
- Companion to the OpenSSF Best Practices passing badge
(https://www.bestpractices.dev/en/projects/10177) — Scorecard adds
machine-verifiable, continuously-updated evidence; Best Practices
captures self-attested controls.
### Release note
\`\`\`release-note
NONE
\`\`\`
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Added automated security scanning to the development process to
continuously monitor codebase health and security posture.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2720?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 -->
Runs the OpenSSF Scorecard action on:
- weekly schedule (Mon 06:00 UTC)
- branch protection rule changes
- pushes to main
- manual dispatch
Publishes results to:
- the public OpenSSF Scorecard API (scorecard.dev) for transparency
- the GitHub code-scanning dashboard (Security tab) for triage
No README badge is added yet — the badge will be introduced in a
follow-up PR once the first scans have run and any quick-win
improvements (token permissions, dependency pinning) have landed.
Aligns with the project's CNCF Incubation readiness work and the
security self-assessment in progress.
Signed-off-by: Timur Tukaev <timur.tukaev@aenix.io>
## What this PR does
Updates @lllamnyp's responsibility in `MAINTAINERS.md` from
`Etcd-operator Lead` to `Core Maintainer`.
The etcd-operator is hosted in the separate
[aenix-io/etcd-operator](https://github.com/aenix-io/etcd-operator)
repository — its leadership scope is tracked there. In
`cozystack/cozystack`, @lllamnyp's role is a project-level Core
Maintainer, which this change reflects.
### Release note
```release-note
NONE
```
## What this PR does
Expands the **Stepping Down / Emeritus Process** section in
`CONTRIBUTOR_LADDER.md`:
- Adds an explicit PR-based mechanism for moving a maintainer's row from
`Active` to `Emeritus` in `MAINTAINERS.md`.
- Adds a five-business-day technical offboarding checklist: GitHub team
membership, org role, direct collaborator entries, `CODEOWNERS`, Actions
secret rotation, internal channels.
- Defines a path for an Emeritus maintainer to return to active status.
This codifies the offboarding flow actually exercised in #2717 and
removes ambiguity for future maintainer lifecycle events. Useful
evidence for the CNCF Incubation Due Diligence review (Governance
section, maintainer-lifecycle criteria).
### Release note
```release-note
NONE
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Updated contributor documentation with details on the Emeritus
transition process, including offboarding procedures and reactivation
guidelines.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2718?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 -->
The etcd-operator lives in the aenix-io/etcd-operator repository, not
cozystack/cozystack. Listing it as a responsibility in this project's
MAINTAINERS.md was a leftover from the earlier sub-project layout.
Replace with the project-level "Core Maintainer" role, which reflects
the actual scope of @lllamnyp's work on this repository.
Signed-off-by: Timur Tukaev <timur.tukaev@aenix.io>
Expands the Stepping Down / Emeritus Process section with:
- An explicit PR-based mechanism for recording an Emeritus transition.
- A five-business-day technical offboarding checklist (team membership,
org role, direct collaborator entries, CODEOWNERS, secret rotation,
internal channels).
- A defined path for an Emeritus maintainer to return to active status.
Reflects the actual offboarding flow exercised in #2717 and removes
ambiguity for future maintainer lifecycle events.
Signed-off-by: Timur Tukaev <timur.tukaev@aenix.io>
## What this PR does
- Add `Active Maintainers` and `Emeritus Maintainers` sub-sections.
- Update @gecube affiliation to Independent (was Ænix).
- Update @lllamnyp affiliation to Ænix (was 3commas).
- Mark @nbykov0 as Independent (was Ænix).
- Move @aobort to Emeritus Maintainers.
- Move @klinch0 to Emeritus Maintainers.
### Release note
```release-note
NONE
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Updated project maintainers information in the maintainers list.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2717?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 -->
<!-- Thank you for making a contribution! Here are some tips for you:
- Use Conventional Commits for the PR title: `type(scope): description`
- Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore
- Scopes are not an exhaustive list — pick the most specific scope for
the change and extend the list when a genuinely new area appears.
Examples:
- System components: dashboard, platform, operator, cilium, kube-ovn,
linstor, fluxcd, cluster-api
- Managed apps: postgres, mariadb, redis, kafka, clickhouse,
virtual-machine, kubernetes
- Development and maintenance: api, hack, tests, ci, docs, maintenance
- Breaking changes: append `!` after type/scope (`feat(api)!: ...`) or
add a `BREAKING CHANGE:` footer
- If it's a work in progress, consider creating this PR as a draft.
- Don't hesistate to ask for opinion and review in the community chats,
even if it's still a draft.
- Add the label `backport` if it's a bugfix that needs to be backported
to a previous version.
-->
## What this PR does
### Screenshots
<!-- REQUIRED for UI changes: attach screenshots or screen recordings
demonstrating
the visual impact of your changes. PRs with UI changes without
screenshots will not be merged. -->
### Release note
<!-- Write a release note:
- Explain what has changed internally and for users.
- Start with the same `type(scope):` prefix as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->
```release-note
add implementation of backup-strategy controller for etcd
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Cluster-scoped Etcd backup strategy CRD (S3-only) plus controller
support for BackupJob (snapshot → Backup) and destructive in-place
RestoreJob flows; snapshot metadata persisted and destination validation
enforced.
* **Documentation**
* Complete etcd backup/restore README and admin/tenant scenario guides.
* **Examples & Tests**
* End-to-end demo scripts (helpers, stepper, cleanup, runner), Bats e2e,
and extensive unit tests.
* **Chores**
* RBAC updates for etcd access, chart version bumped, demo env files
added to .gitignore.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2641?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 -->
## What this PR does
PostgreSQL server parameters like `max_connections` are natural
integers,
but the chart's schema declared them as `{type: string}` only. When
users
supply bare integers (e.g. `max_connections: 100`) — either directly in
Application CR specs or via the UI — Helm rejects the values at schema
validation time before template rendering, causing HelmRelease failures.
The Helm template already handles both types via `{{ $value | toString |
quote }}`,
so the fix is to teach the schema to accept both.
### Approach
The schema files (`values.schema.json` and the embedded `openAPISchema`
in `postgres-rd/cozyrds/postgres.yaml`) are generated from `values.yaml`
annotations via `cozyvalues-gen`. Hand-editing them does not survive
`make generate` — same regeneration trap that caught #2466 (issue
#2597).
`cozyvalues-gen` v1.4.0 (cozystack/cozyvalues-gen#25) adds an
`intOrString` type alias for map values that emits
`additionalProperties.anyOf: [integer, string]` plus the Kubernetes
`x-kubernetes-int-or-string: true` marker.
### Changes
- `packages/apps/postgres/values.yaml`: annotation flipped from
`@field {map[string]string}` to `@field {map[string]intOrString}`,
description updated to note integer values are accepted.
- Regenerated artifacts: `values.schema.json`, embedded `openAPISchema`
in `packages/system/postgres-rd/cozyrds/postgres.yaml`,
`packages/apps/postgres/README.md`, and
`api/apps/v1alpha1/postgresql/types.go`
(Parameters is now `map[string]intstr.IntOrString`).
- `packages/apps/postgres/templates/db.yaml`: `$dangerousParams` list
extended with `archive_cleanup_command` and `recovery_end_command`
(same RCE surface as `archive_command` / `restore_command`).
### Verification
- `helm template` with `max_connections: 200` (int) and
`max_connections: "200"`
(string) produce identical render output.
- Dangerous-param block list rejects `archive_cleanup_command` and
`recovery_end_command` with the expected `SECURITY:` error.
- `make test` in `packages/apps/postgres/`: 13/13 pass.
- `make generate` is idempotent — schema files don't drift on regen.
### Release note
```release-note
fix(postgres): accept integer values for postgresql.parameters to prevent HelmRelease failures when parameters are supplied as unquoted integers; also block archive_cleanup_command and recovery_end_command (RCE surface).
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* PostgreSQL parameters now accept integer or string values; integers
are automatically coerced to strings.
* **Security**
* Enhanced parameter filtering blocks additional dangerous settings:
archive_cleanup_command and recovery_end_command.
* **Documentation**
* Updated docs and charts to describe int-or-string parameter support
and revised blocked-parameter guidance.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2687?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 -->
## Problem
PR #2454 renamed `nodeGroups[*].ephemeralStorage` →
`nodeGroups[*].diskSize` with
a hard `{{ fail }}` guard. Any cluster whose HelmRelease still carries
the legacy
field cannot be reconciled by Flux at all — unrelated control-plane
changes and
MachineHealthCheck remediations are also blocked.
## Solution
Add platform migration 41 that runs as a pre-upgrade hook before any
chart
resources are applied. The migration walks every
`kuberneteses.apps.cozystack.io`
Application CR cluster-wide and renames `nodeGroups[*].ephemeralStorage`
to
`nodeGroups[*].diskSize`, preserving the user's value.
- Idempotent: a second run is a no-op (field is already absent)
- Best-effort: a failed patch is logged; the version stamp stays at 41
so the
migration retries on the next platform upgrade
- Bumps `migrations.targetVersion` 41 → 42
The chart-side guard remains in place with an updated error message that
directs
operators to the migration job logs if the field somehow reappears
post-upgrade.
## Testing
Verified on dev cluster: migration correctly renames `ephemeralStorage`
values
in existing Application CRs. All 123 helm unit tests pass.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Release Notes
* **Documentation**
* Platform migration 41 now automatically handles the `ephemeralStorage`
to `diskSize` field rename for Kubernetes node groups
* Migration is transparent during upgrade with no manual configuration
changes required
* Error messages updated with clearer troubleshooting guidance
* **Tests**
* Updated test assertions for migration error messages
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2688?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 -->
Companion regen for the type change in the previous commit. The
deepcopy generator emits a fresh import for intstr and updates the
inner make() call to match the new map value type. Caught by the
codegen-drift check on CI.
Generated by `make generate` at repo root (hack/update-codegen.sh).
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
v1.4.0 adds the `intOrString` type alias used by the postgres package's
`postgresql.parameters` schema in this PR. CI must install v1.4.0 so the
"Verify generated code is up to date" check regenerates the same schema
shape (anyOf + x-kubernetes-int-or-string: true) rather than reverting
to {type: string}.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Ivan's original schema edits were correct in intent but lived in the
generated artifacts (values.schema.json and the embedded openAPISchema
in postgres-rd/cozyrds/postgres.yaml). `make generate` reverts them
because values.yaml's `@field {map[string]string}` annotation is the
source of truth -- same regeneration trap that caught #2466 (issue #2597).
cozyvalues-gen v1.4.0 (cozystack/cozyvalues-gen#25, merged 2026-05-21)
adds an `intOrString` type alias for map values that emits
`additionalProperties.anyOf: [integer, string]` plus
`x-kubernetes-int-or-string: true`. Move the change to source by
flipping the annotation, then regenerate:
- packages/apps/postgres/values.yaml: `@field {map[string]intOrString}`
with updated description noting integer values are accepted.
- packages/apps/postgres/values.schema.json: regenerated -- now carries
anyOf + x-kubernetes-int-or-string: true.
- packages/system/postgres-rd/cozyrds/postgres.yaml: embedded
openAPISchema regenerated to match.
- packages/apps/postgres/README.md: regenerated type column.
- api/apps/v1alpha1/postgresql/types.go: Parameters is now
`map[string]intstr.IntOrString`.
The result survives future regenerations. The template's
`{{ \$value | toString | quote }}` already coerces both inputs to
quoted strings, verified end-to-end with helm template against both
`max_connections: 100` (int) and `max_connections: "100"` (string) --
identical render output. Dangerous-param block list still rejects
archive_cleanup_command and recovery_end_command additions from the
prior commit.
Co-Authored-By: IvanHunters <xorokhotnikov@gmail.com>
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Add archive_cleanup_command and recovery_end_command to the dangerous
parameters blocklist in db.yaml. Both are PostgreSQL shell-exec hooks
identical in threat model to archive_command/restore_command and must
not be settable by tenants.
Also update the BLOCKED list in values.schema.json, values.yaml, and
the embedded openAPISchema in cozyrds/postgres.yaml to reflect the
two new blocked parameters.
Additionally update the embedded openAPISchema in cozyrds/postgres.yaml
to allow integer values for postgresql.parameters (anyOf string|integer),
matching the fix already applied to values.schema.json.
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
The template already coerces all parameter values to strings via
'toString | quote', but the JSON schema had 'additionalProperties: {type: string}'
which caused Helm schema validation to fail before the template ran
when users passed integer values (e.g. max_connections: 100).
Accept both string and integer types in additionalProperties so that
existing configurations with unquoted numbers continue to work.
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
## What this PR does
Fixes resource specs on CAPI provider pods in `cozy-cluster-api`.
**Kamaji control-plane-provider — fix OOMKilled crashloop.**
The override in
`packages/system/capi-providers-cpprovider/templates/providers.yaml`
targeted `containers[name=manager]`, but the upstream container in
`docker.io/clastix/cluster-api-control-plane-provider-kamaji` is named
`controller`. The CAPI operator merges container overrides by container
name, so the intended `cpu: 1 / memory: 1024Mi` limits were silently
dropped and the upstream default of `memory: 128Mi` was used. The kamaji
controller pod therefore restarts repeatedly with `exit code 137`
(OOMKilled), even at idle.
**Core / bootstrap / kubevirt providers — add limits.**
Upstream `*-components.yaml` for these three providers ships with no
`resources:` block, and cozystack added no override. The pods run
BestEffort and are first to evict under memory pressure. Set modest
limits (`500m / 256Mi`) and requests (`10m / 64Mi`) matching typical
CAPI controller-manager footprint.
### Release note
```release-note
fix(cluster-api): fix the resource override for the kamaji control-plane-provider (was silently ignored due to a wrong container name, causing OOMKilled restarts) and set requests/limits for the core, kubeadm-bootstrap, and kubevirt-infrastructure providers (were running BestEffort).
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated provider deployment configurations to establish resource
management parameters (CPU/memory requests and limits) for container
deployments across multiple provider types, improving scheduling
optimization and resource predictability
* Standardized container naming conventions in provider templates for
consistency
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2708?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 -->
## What this PR does
The `update-website-docs` job in `tags.yaml` runs `make release-next`
(on new minor/major releases) and `make update-all` against
`cozystack/website`. Both paths can create a new
`data/versions/<DOC_VERSION>.yaml`:
- `release_next.sh` snapshots `data/versions/next.yaml →
data/versions/vX.Y.yaml` at release time so the released docs freeze on
the pins that were true at the cut.
- `init_version.sh` (invoked by `update-all → init-version`) seeds the
same file from the source version when a target version directory
doesn't yet exist.
The job's commit step staged only `content hugo.yaml`, so the new
versions file was silently dropped from the website PR — leaving `{{<
version-pin >}}` shortcodes in the released docs without a data file to
resolve against.
This adds `data/versions` to `git add` so the snapshot lands in the same
commit as the rest of the release-time docs update.
### Release note
```release-note
NONE
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated documentation versioning management in the build process.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2707?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 -->
## What this PR does
Trims the `Install Cozystack into sandbox` CI step from ~40k log lines
back down to a normal size.
The `Pre-pull platform images` bats test was capturing each rendered
chart into a shell variable so a render failure would trip `set -e`:
```sh
kubeovn_manifests=$(helm template packages/system/kubeovn)
linstor_manifests=$(helm template packages/system/linstor)
printf '%s\n%s\n' "$kubeovn_manifests" "$linstor_manifests" | yq ... | hack/e2e-prepull-images.sh
```
`hack/cozytest.sh` runs every bats test under `set -x`, and bash expands
captured command output into the trace as `+ var=<entire stdout>`. The
kubeovn and linstor renders are several thousand lines each, and the
`printf` line re-expands both variables, so the same YAML was being
dumped to the log three times.
This PR stages each render to a tmp file instead:
```sh
helm template packages/system/kubeovn > "$kubeovn_yaml"
helm template packages/system/linstor > "$linstor_yaml"
cat "$kubeovn_yaml" "$linstor_yaml" | yq ... | hack/e2e-prepull-images.sh
```
The original safety property is preserved — `helm template ... > file`
is a simple command whose exit code still triggers `set -e` on failure,
exactly like `var=$(helm template ...)` did. The trace now shows the
command line, not its rendered output.
### Release note
```release-note
NONE
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Tests**
* Improved image pre-pull test to render charts into temporary files,
consolidate results, and feed them deterministically into the image
pre-pull check.
* Made failure handling more reliable so rendering or parsing errors now
cause the test to fail predictably.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2615?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 -->
The kamaji control-plane-provider override in templates/providers.yaml
targeted containers[name=manager], but the upstream container is named
"controller". The CAPI operator merges container overrides by name, so
the intended cpu: 1 / memory: 1024Mi limits were silently dropped and
the upstream default of memory: 128Mi was used, producing repeated
OOMKilled restarts of the kamaji controller (exit code 137).
The other three providers (core, bootstrap, infraprovider/kubevirt)
ship upstream with no resources block and have no cozystack override,
so they run BestEffort and are first to evict under memory pressure.
Set modest limits (500m / 256Mi) and requests (10m / 64Mi) matching
typical CAPI controller-manager footprint.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
`release_next.sh` and `init_version.sh` (via `update-all → init-version`)
create `data/versions/<DOC_VERSION>.yaml` for new versions, but the
`update-website-docs` job only staged `content` and `hugo.yaml`. The new
file was silently dropped from the website PR, breaking
`{{< version-pin >}}` lookups for the released minor.
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Add pre-upgrade migration 41 that walks all kuberneteses.apps.cozystack.io
Application CRs and renames nodeGroups[*].ephemeralStorage to diskSize,
preserving the user's value.
Without this migration, clusters upgraded after PR #2454 either fail to
reconcile (hard fail blocks all Flux operations) or silently lose the user's
disk size setting (default 20Gi replaces whatever was configured).
The migration is idempotent and best-effort: a failed patch is logged and
leaves the version stamp at 41 for retry on next upgrade.
Update the chart-side guard error message to direct operators to the
migration job logs when the field appears post-upgrade (regression detector).
Bump migrations.targetVersion 41 -> 42.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
## What this PR does
Aligns ZooKeeper storage cleanup with the existing Kafka broker behavior
so deleting a Kafka release reclaims all of its persistent storage. The
Strimzi `Kafka` CR template already set `deleteClaim: true` on the
broker JBOD volume, but the ZooKeeper persistent-claim was left at
`deleteClaim: false`. As a result, removing a Kafka application freed
the broker PVCs while orphaning the ZooKeeper PVCs in the tenant
namespace, requiring manual cleanup before the same release name could
be reused.
The change is a single field flip in
`packages/apps/kafka/templates/kafka.yaml` on the
`spec.zookeeper.storage` block.
### Behavior change
Users who previously relied on orphaned ZooKeeper PVCs as an implicit
"soft delete" for ZooKeeper state recovery should be aware that
uninstalling a Kafka release now also removes the underlying ZooKeeper
storage. Take a backup before deletion if ZooKeeper data retention is
required.
### Screenshots
Not applicable — no UI changes.
### Release note
```release-note
fix(kafka): ZooKeeper PVCs are now reclaimed when a Kafka release is deleted, matching the existing Kafka broker storage behavior.
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Kafka storage behavior updated so persistent volumes are automatically
removed when claims are deleted, changing storage lifecycle for
deployments.
* **Tests**
* End-to-end cleanup adjusted to remove the Kafka resource and verify
volumes are reclaimed automatically, adding waits to confirm PVC binding
and removal.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2679?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 -->
## What this PR does
Removes the dashboard controller and its API surface. cozystack-ui now
consumes `ApplicationDefinition` resources directly, so the controller
that projected them into a set of `dashboard.cozystack.io` CRDs
(Sidebar, Factory, Navigation, Breadcrumb, CustomFormsOverride,
CustomFormsPrefill, CustomColumnsOverride, MarketplacePanel,
TableUriMapping, CFOMapping, BreadcrumbInside) is dead code.
Removed:
- `internal/controller/dashboard/` Go package
- `api/dashboard/v1alpha1/` API types
-
`packages/system/cozystack-controller/definitions/dashboard.cozystack.io_*.yaml`
CRDs
- `dashboard.cozystack.io` wiring in `cmd/cozystack-controller/main.go`
- `dashboard.cozystack.io` RBAC rules in the `cozystack-controller` and
`cozy-dashboard` charts
- `./api/dashboard/...` codegen path in `hack/update-codegen.sh`
The `spec.dashboard` field on `ApplicationDefinition` is intentionally
kept — it is populated by `hack/update-crd.sh` and read directly by
cozystack-ui.
### Release note
```release-note
chore(controller): remove the dashboard controller and dashboard.cozystack.io CRDs; cozystack-ui now reads ApplicationDefinitions directly.
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Removed dashboard-related APIs, controllers, and UI integrations,
disabling dashboard custom resources and related runtime behavior.
* Removed dashboard CRDs from deployments and added a migration to clean
up obsolete dashboard CRDs.
* Updated RBAC to remove dashboard API group access and bumped platform
migration target version.
* **Documentation**
* Removed dashboard integration and configuration guides.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2694?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 -->
## What this PR does
Adds a `namespacelabs/breakpoint-action` step at the end of the E2E job
that opens an SSH endpoint to the failing sandbox so maintainers can
inspect Talos and Cozystack state before teardown.
The step runs whenever an earlier step in the E2E job fails. Idle
breakpoints time out after 30 minutes; maintainers can release the
sandbox sooner by running `breakpoint resume` from the SSH session.
The breakpoint connects to the project's self-hosted rendezvous server
at `158.101.126.45:5000`. Authorized users are the maintainers listed
in `MAINTAINERS.md`; SSH public keys are pulled from each maintainer's
GitHub profile by the action.
Inspired by [squat/kilo's CI
setup](https://github.com/squat/kilo/blob/main/.github/workflows/ci.yml).
### Screenshots
<img width="713" height="55" alt="Screenshot 2026-05-14 at 20 57 43"
src="https://github.com/user-attachments/assets/fc1b76b1-1eb0-4f52-976f-f469e71222b4"
/>
<img width="1404" height="956" alt="Screenshot 2026-05-14 at 20 58 27"
src="https://github.com/user-attachments/assets/87194312-57c3-40ec-af58-262c9bba990f"
/>
### Release note
```release-note
ci(workflows): open SSH breakpoint to the runner on E2E failure
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* CI now selects runner conditionally for PRs with specific labels
(self-hosted vs cloud).
* CI job permissions expanded to allow creating/updating check runs.
* Added a conditional "Breakpoint on E2E failure" step that can open an
SSH-accessible breakpoint and publishes a "Breakpoint Open" check with
endpoint and attach/resume instructions.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2535?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 -->
Existing clusters still have the legacy dashboard.cozystack.io CRDs
installed even after the dashboard controller has been removed.
Add a platform migration that deletes them and bump targetVersion
to 41.
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
The dashboard controller used to project ApplicationDefinitions
into a set of dashboard.cozystack.io CRDs (Sidebar, Factory,
Navigation, Breadcrumb, CustomFormsOverride, CustomFormsPrefill,
CustomColumnsOverride, MarketplacePanel, TableUriMapping,
CFOMapping, BreadcrumbInside) consumed by the legacy UI.
cozystack-ui now reads ApplicationDefinitions directly, so the
controller, its API types, the generated CRDs and the related
RBAC rules are no longer used.
Removes:
- internal/controller/dashboard
- api/dashboard/v1alpha1
- packages/system/cozystack-controller/definitions/dashboard.cozystack.io_*.yaml
- dashboard.cozystack.io wiring from cmd/cozystack-controller/main.go
- dashboard.cozystack.io RBAC rules from cozystack-controller and cozy-dashboard charts
- ./api/dashboard/... codegen path from hack/update-codegen.sh
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
Replace MAINTAINERS.md snapshot with a list derived from actual recent
activity on main (commits, merged PRs and reviews over the last three
months). MAINTAINERS.md had drifted in both directions — listing people
no longer active on the project while missing several current
maintainers — so copying it verbatim was both handing SSH access to
inactive accounts and locking out people who would actually use this
debug feature.
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
When the e2e job fails on a PR carrying the `debug` or `release` label
(release PRs are bot-created, so the label implies maintainer authorship),
hold the runner and open an SSH breakpoint via cozystack/breakpoint-action
(a fork of namespacelabs/breakpoint-action pinned by SHA) so a maintainer
can attach, inspect Talos/Cozystack state, and resume.
The fork adds three things on top of upstream:
* `mode: pause-idle` — waits 20m for the first SSH connection, then keeps
the workflow paused while sessions are active, exiting 10m after the
last session disconnects. Saves runner-minutes vs a fixed timeout.
* `endpoint` step output + `::notice::` annotation — surfaces the SSH
endpoint while the step is still paused (step logs are buffered until
step completion, so the endpoint would otherwise be invisible).
* A dedicated Check Run "Breakpoint Open" with conclusion=failure
carrying the SSH endpoint and sandbox-entry hint in output.summary
(Markdown, rendered in the UI). Surfaces as a standard ✗ in
`gh pr checks` so any CI watcher sees the open breakpoint without
bespoke marker parsing. Updated to conclusion=success when the
breakpoint exits.
The step is configured via the `BREAKPOINT_ENDPOINT` repo variable. In
fork PRs, repo variables are not exposed, so the step is naturally
skipped and forks cannot reach the self-hosted rendezvous server. The
`authorized-users` list is kept as a second defense layer at the
breakpoint level.
Permissions on the e2e job: `checks: write` (for Check Run create+update).
Upstream PR: namespacelabs/breakpoint-action#16
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
## What this PR does
Replaces the broken `gcr.io/kubebuilder/kube-rbac-proxy:v0.15.0` image
in the opensearch-operator chart with
`quay.io/brancz/kube-rbac-proxy:v0.15.0`
(the same image already used elsewhere in cozystack, e.g.
etcd-operator).
The kubebuilder GCR registry was sunset and the image no longer pulls.
The fix is a local patch in `patches/fix-kube-rbac-proxy-image.patch`,
wired into the `update` target so it survives future chart re-pulls.
Upstream chart 2.8.1+ removes `kubeRbacProxy` entirely, but it also
bumps
CRDs to controller-gen v0.19.0 with significant schema changes — too
much
surface area for a focused image fix.
Follows the precedent set in #2181 for etcd-operator.
### Release note
```release-note
fix(opensearch-operator): replace deprecated `gcr.io/kubebuilder/kube-rbac-proxy` image with `quay.io/brancz/kube-rbac-proxy`
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated the container image repository used by the OpenSearch
operator's kube-rbac-proxy component to the current upstream source.
This ensures continued availability of security proxy updates and avoids
service disruption from deprecated image locations.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2689?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 -->
The prior commit added `set -o pipefail` to catch yq failures in the
prepull pipeline. CI failed at runtime: hack/cozytest.sh has a
`#!/bin/sh` shebang, /bin/sh is dash on Ubuntu CI, and dash rejects
`set -o pipefail` ("Illegal option").
Drop the pipe entirely. Each step is now its own command with stdin/
stdout redirection — set -e catches failures at the helm-template, yq,
or prepull stage without needing pipefail and without `var=$(...)`
captures that would balloon the `set -x` trace with rendered YAML.
Verified under dash in Ubuntu 24.04 by running cozytest.sh against the
test.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
The previous form staged each helm-template render to a tmp file so a
render failure would trip `set -e` outside the pipe. That avoided the
`var=$(...)` trace-bloat trap, but yq still ran inside a pipe with
pipefail off, so a yq failure (bad expression, schema drift) would be
masked by the prepull script's exit code and the test would pass while
silently pre-pulling nothing.
Replace the tmp-file dance with a brace group + `set -o pipefail`:
helm-template output flows through the pipe, never expanded into the
`set -x` trace (verified under `hack/cozytest.sh`: 5 command lines, no
YAML), and pipefail now surfaces a failure at any stage. Drops the
mktemp/rm scaffolding and the `cat` subprocess.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Address review feedback from coderabbitai on hack/e2e-apps/kafka.bats:58:
The post-delete `while kubectl get pvc data-kafka-$name-zookeeper-1` loop
exits immediately when the PVC has never been created, so a regression
that prevents Strimzi from provisioning the second ZooKeeper PVC would
silently pass the reclamation check. Mirror the PVC-0 readiness guard
(existence + Bound) for PVC-1 before deleting the Kafka CR so the test
only proceeds once both PVCs are observed.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
## What this PR does
Follow-up to #2675. Fixes four broken references in
`docs/changelogs/v1.4.0.md` that were caught by re-verifying every link
in the merged changelog:
| Where | Was | Now |
|---|---|---|
| Resource Presets doc link (Feature Highlights) |
`cozystack.io/docs/operations/resource-presets/` (404) |
`cozystack.io/docs/v1.4/guides/resource-management/` |
| HAMi doc link (Feature Highlights) |
`cozystack.io/docs/operations/kubernetes/hami/` (404) |
`cozystack.io/docs/v1.4/kubernetes/gpu-sharing/` |
| Upgrade notes — resource presets PR ref | `#2426` (`feat(monitoring):
upgrade victoria-metrics-operator`) | `#2607` (`feat(apps):
instance-type resource presets`) |
| Upgrade notes — postgres parameters PR ref | `#2475` (unrelated open
issue about bundle YAML) | `#2466` (`feat(postgres)!: support all
PostgreSQL configuration parameters`) |
The Feature Highlights / Major Features sections already cited #2607 and
#2466 correctly; only the Upgrade Notes section pointed at the wrong PR
numbers.
### Release note
```release-note
NONE
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Updated changelog documentation links to reflect new resource
management guides location.
* Refreshed HAMi compatibility references to point to current
GPU-sharing documentation.
* Updated related PR references in upgrade notes for accuracy.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2693?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 -->
Move the kube-rbac-proxy image override from a patch + vendored-chart
edit to a values.yaml override under kubeRbacProxy.image.repository.
This matches the project convention documented in docs/agents/overview.md
("Override configuration in root values.yaml") and the pattern used by
sibling packages such as kamaji.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
The gcr.io/kubebuilder/kube-rbac-proxy image is no longer available
since GCR was deprecated. Replace it with quay.io/brancz/kube-rbac-proxy
from the original upstream author.
Applied as a local patch in patches/ because upstream chart 2.8.1+ drops
kubeRbacProxy entirely but also bumps CRDs to controller-gen v0.19.0 with
significant schema changes — out of scope for this fix.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Address review feedback from gemini-code-assist on
hack/e2e-apps/kafka.bats:53-55:
Replace the manual kubectl delete of the two ZooKeeper PVCs with a poll
that waits for the Strimzi operator to reclaim them. With deleteClaim:
true on the ZooKeeper persistent-claim storage, the operator removes
the PVCs as part of Kafka CR deletion; manual deletion would either
race the operator, fail with NotFound, or silently mask a regression
in the reclamation path.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
Set deleteClaim: true on the ZooKeeper persistent-claim storage so the
Strimzi operator removes the PVCs together with the rest of the cluster
when the Kafka CR is deleted. Previously the Kafka broker PVCs were
reclaimed (deleteClaim: true) but the ZooKeeper PVCs were orphaned,
forcing manual cleanup before the same release name could be reused.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
## Summary
- `RUN curl … mc` in
`packages/core/testing/images/e2e-sandbox/Dockerfile` ran without `-L`,
so when `dl.min.io` returned a 302, the HTML redirect body (`<a
href=...>Found</a>`) was written to `/usr/local/bin/mc` and chmod'd
executable.
- When the bucket E2E test then ran `mc alias set …`, the shell tried to
interpret the HTML as a script and errored with `/usr/local/bin/mc: 1:
cannot open a: No such file` (dash reading `<a` as an input redirect).
- Switching to `curl -fsSL` follows the redirect and fails fast on HTTP
errors. The textual change to the `RUN` instruction also busts the
cached layer so the next build pulls a real ELF binary.
## Test plan
- [x] CI Build job rebuilds `e2e-sandbox` image with the new layer
- [x] E2E `bucket` bats test runs `mc alias set` without the `cannot
open a` error
- [x] `file /usr/local/bin/mc` inside the rebuilt image reports an ELF
binary, not ASCII text
### Release note
```release-note
fix(e2e-sandbox): download `mc` with `curl -fsSL` so the image ships a real binary
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Improved Docker sandbox test environment build reliability by
enhancing MinIO client installation with robust error handling and
corrected configuration paths to ensure consistent container image
creation.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2690?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 -->
The minio client was downloaded without -L, so when dl.min.io served
a 302 redirect, curl wrote the HTML body ("<a href=...>Found</a>") to
/usr/local/bin/mc, chmod +x'd it, and shipped that as the binary. When
the bucket E2E test ran "mc alias set ...", the shell tried to interpret
the HTML as a script and errored with:
/usr/local/bin/mc: 1: cannot open a: No such file
(dash reading "<a" as an input redirect from a file named "a").
The image is rebuilt per CI run from cached layers; the broken mc layer
was cached and reused. Adding -fsSL fixes the download and the textual
change busts the cache so the next build pulls a real ELF binary.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
This PR adds the changelog for release `v1.3.4`.
✅ Changelog has been automatically generated in
`docs/changelogs/v1.3.4.md`.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* OpenSearch is now integrated into the 1.3 PaaS bundle so operator and
dashboard components deploy when PaaS is enabled.
* Storage class input now renders as a dropdown including OpenSearch as
an option.
* **Bug Fixes**
* Fixed Harbor reconciliation regression related to bucket secret
handling and render-path coverage.
* **Documentation**
* v1.3.4 release notes published, expanded docs, summary of related
project changes, contributor list and compare link.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2676?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 -->