mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-13 08:05:19 +09:00
66acdb80e15d21837fc151f5defd7d65b155da63
7861
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
66acdb80e1 |
ci(e2e): skip final cleanup on disposable PR runners (#5260)
## What this PR does Remove the final sandbox teardown from the two PR E2E workflows. The runners are documented as disposable VMs, so destroying their local containers and zpools after testing delays the result without protecting a later run. Cleanup between preparation attempts and the Makefile targets for reused hosts stay unchanged. The job limit stays at 215 minutes. Suite-length budgeting, including nightly and tag runs, remains separate in #5261. This change relies on the existing disposable-runner contract; it does not change runner provisioning. ### Screenshots Not applicable. ### Downstream repositories - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note NONE ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **CI Workflows** * Removed automatic sandbox and cluster teardown after end-to-end report uploads. * Added checks that cluster cleanup runs before environment preparation is retried. These changes affect automated test workflows and do not alter user-facing product features. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
c6cba19946 |
feat(release): keep a line's backport record and reports across batch pull requests (#5264)
## What this PR does This PR keeps backport batch record of a line across batch pull requests. Before it lived only in body of open batch PR, so once that PR merged or closed it was gone, and a conflict deferred in merged batch showed up as missing in `check` and on cut. Three `check --cut` results also did not match the docs, all three are fixed here. - `check --cut` fails when workflow original is the only thing left waiting. Before it passed as soon as pick next to it got `backport/skip` or landed by hand. - `run`, `check`, `fold` and `notify` read line record from newest trusted batch PR in any state (opened by bot or by someone with write or admin access). If newest record is in doubt (author no longer trusted, bot batch without block, unreadable block, closed record newer than open batch) command stops and doesn't fall back to older one. - Record is written only while its PR is open. Merged and closed batch PRs are never edited or commented, so run that picks nothing with no open batch writes nothing and says so. - Every run makes report: each original merged to `main` since line branched in exactly one category, what the run read (heads, policy, tool commit, Actions run, flags) and each drop with its reason and merge commit. Latest report sits in body next to record and each one also goes to immutable comment. Report ID is hash of classification without PR number, so identical runs post one comment. `backport-batch report --pr N [--id ID]` reads it back, merged batches too, it needs `main` in local clone to check drops. - `run --defer --push` of last pick used to refuse with "close batch pull request instead". Now it writes report and record with reason while PR is open, then closes PR and deletes branch, both only while head is still the same. If close stops halfway next `run --push` finishes it, and it never deletes branch that moved or that new batch uses. - `run --drop N --reason R` keeps original off one line, `--undrop` withdraws it. Drop is stored in line record bound to merge commit and carried to next batches. Original the line already carries can't be dropped, and `backport/include` doesn't lift a drop. - Output names policy rules instead of internal numbers (no more "rule 101"), `--push` prints PR URL. Reasons and file names from record are accepted only in the clean one-line form a run writes them, and everything printed is escaped. Record version 2 reads unversioned blocks that open batches carry today. I ran new tool next to current one without `--push` on today's history for release-1.7 and release-1.6, every original got same category and `check` output is the same. ### Downstream repositories - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note feat(release): backport batch keeps line record and report of every run across batch pull requests, check --cut fails on workflow change left waiting alone, deferred conflict stays deferred after its batch merges, --defer of last pick closes the batch, and new run --drop keeps a fix off one line. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **New Features** * Maintainers can permanently exclude a change from a release line with `--drop`, or undo that decision with `--undrop`. * Added a `report` command to view validated batch reports in JSON or a readable summary. * Deferring every remaining change can close an emptied batch. A later `run --push` can complete an interrupted close. * Batch reports now show change classifications, including deferred and dropped items. * **Bug Fixes** * Checks more clearly distinguish missing, deferred, skipped, and carried changes, with cut checks enforcing outstanding workflow requirements. * Batch operations refuse edited or untrusted records and avoid writing to closed pull requests. * **Documentation** * Updated command and release-process guidance for drops, reports, cut checks, and batch closure. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
9cd51cac2e |
ci(e2e): skip final cleanup on disposable PR runners
Destroying runner-local state after a completed suite can push the job
past its deadline even though the runner is discarded. Keep cleanup
between preparation attempts and for reused hosts instead.
Fixes:
|
||
|
|
c117420f5e |
fix(kubernetes, monitoring): send tenant cluster metrics to the tenant's vminsert (#5024)
<!-- 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 `kind/backport` if it's a bugfix that needs to be backported to a previous version. --> ## What this PR does The vmagent that `packages/apps/kubernetes` deploys into a tenant Kubernetes cluster has not been shipping metrics anywhere, because the app and the `monitoring-agents` chart disagree on two values keys, and Helm drops a key nobody reads without a word. - **Remote write URL.** #697 changed the chart to read `vmagent.remoteWrite.urls` as a list, but the app still passed a single `vmagent.remoteWrite.url` (the cluster domain was later added to that ignored key in #2086). The chart then applied its own defaults, `vminsert-{shortterm,longterm}.cozy-monitoring.svc`, which do not exist inside a tenant cluster. vmagent fails with `no such host` and queues the failed writes on the node disk, up to `-remoteWrite.maxDiskUsagePerURL` (1 GiB) per URL, which is enough to push a small node into DiskPressure. - **Tenant label.** The chart writes `tenant: {{ .Values.global.target }}`, which only the root bundle sets, so every tenant cluster series was labelled `tenant="cozy-monitoring"` and the `vmagent.externalLabels.tenant` the app passes was ignored. The fix: - the app passes `remoteWrite.urls` with the tenant's shortterm vminsert; - the chart uses `vmagent.externalLabels.tenant` when set, and falls back to `global.target`. The label is deliberately not fixed by passing `global.target` from the app, because the tenant label must name the tenant that owns the cluster (`.Release.Namespace`), while the monitoring target can be a parent tenant. The root install sets neither key: `helm template` of `templates/vmagent.yaml` with `global.target=tenant-root` renders the same URLs and label values before and after; the only textual change is that the `tenant` label is now quoted, so a tenant name YAML would read as a boolean or number still renders as a string. Tests: `packages/apps/kubernetes/tests/monitoring_agents_test.yaml` pins the keys the app sends, and `packages/system/monitoring-agents/tests/vmagent_remote_write_test.yaml` pins how the chart reads them, for both the root install and a tenant cluster. Reverting either template change fails its suite. `helm unittest` passes on both packages (358 and 23 tests). Upgrade note for operators: on tenant clusters the `tenant` label of vmagent series moves from `cozy-monitoring` to the owning tenant's namespace, so dashboards or alerts that filtered on `tenant="cozy-monitoring"` for those series need updating. Before this change those series never reached the tenant's Monitoring in the first place. Left out on purpose: the shortterm store stays hardcoded, as it was in the app before; deriving it from the target Monitoring's `metricsStorages`, and bounding vmagent's on-disk buffer, are separate changes. ### 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. --> ### Downstream repositories <!-- Cozystack is upstream for repositories that are NOT kept in sync with it automatically, and nothing in CI compares the two sides, so a change here can break them silently. Which change forces what, and which file to touch, is the trigger map in docs/agents/contributing.md under "Downstream Repositories". Walk it before you tick anything. IF YOU ARE AN AI AGENT OR AN LLM, THIS IS PART OF THE TASK, NOT A FORM TO FILL IN: 1. Walk the trigger map against the actual diff of this PR, file by file. Do not decide from the PR title or from your memory of what you changed. 2. For every repository you tick, open the follow-up PR there and link it on the same line. A ticked box with no link claims work that does not exist, which is worse than an empty box. Search that repository for an open PR or issue covering it first, and link that instead of filing a duplicate. 3. When the follow-up is out of scope, or needs a decision that is not yours to make, open an issue in that repository instead, link that, and say so in the PR body. Do not push a speculative PR into another repository just to fill a line here. 4. Do not tick "No downstream repository is affected" to make the checklist go away. If you are unsure, leave every box empty and say so in the PR body, so a human decides. --> - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### 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 fix(kubernetes, monitoring): the vmagent of tenant Kubernetes clusters now writes to the tenant's vminsert and labels series with the owning tenant instead of `cozy-monitoring`. Previously no tenant cluster metric reached the tenant's Monitoring. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit - **Bug Fixes** - Monitoring agents now configure remote-write endpoints using a URL list. - Tenant labels use explicitly configured values when available, with a fallback to the global target. - Tenant and cluster labels, remote-write URLs, and external labels are applied consistently across root and tenant-cluster deployments. - **Tests** - Added coverage for root and tenant-cluster monitoring configurations, including remote-write settings and metric labels. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
ba0312b35f |
chore(kubernetes): align monitoring fix with current platform base
The previous base differs from the published package configuration, so the image overlay retains release controllers instead of current builds. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
456473dec1 |
fix(mariadb): fail backup and restore jobs whose operator Job failed (#5207)
<!-- 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 `kind/backport` if it's a bugfix that needs to be backported to a previous version. --> ## What this PR does When the Job behind a mariadb-operator `Backup` or `Restore` fails, the operator sets `Complete=True` with reason `JobFailed` (`SetCompleteWithJob` in mariadb-operator 25.10.2). The MariaDB driver read `Complete=True` alone as success, so a backup whose dump or upload failed ended `Succeeded` and produced a `Ready` Cozystack `Backup` pointing at an archive that does not exist, and a failed restore ended `Succeeded` too. A scheduled `Plan` kept producing such backups. The driver now treats `Complete=True` as success only with reason `JobComplete`, and fails the BackupJob or RestoreJob on `JobFailed` whatever the status, without creating a `Backup`. The failure message names the operator object and carries the Job's own `Failed` reason and message, since the operator's condition message is only `Failed` and the Job's pod, with its logs, is already deleted when the Job fails. A Job that is missing or cannot be read is named in the message instead. Any other `Complete` state keeps waiting under the existing deadline, as before; that includes `Complete=False` with reason `Failed`, which the operator sets with its own cause (`Error creating Job`, `Backup not complete`) for a failure outside the Job and then retries, and the deadline failure now carries that message. Regression tests drive the backup and restore reconcilers through every `Complete` status/reason combination, an absent `Complete` condition, and expired deadlines for an absent condition, an unknown reason and reason `Failed`. They assert the job phase and message as persisted in the API rather than on the in-memory object, a requeue while the run is in progress, and, for backups, that no `Backup` is created on failure. Separate tests cover the failure message for a Job that cannot be read and for a Job without a `Failed` condition. Backups that already exist are not touched. A `Ready` MariaDB `Backup` created by a failed run before this fix may have no archive of its own. Restoring from it can fail or select another dump from the shared prefix. ### 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. --> ### Downstream repositories <!-- Cozystack is upstream for repositories that are NOT kept in sync with it automatically, and nothing in CI compares the two sides, so a change here can break them silently. Which change forces what, and which file to touch, is the trigger map in docs/agents/contributing.md under "Downstream Repositories". Walk it before you tick anything. IF YOU ARE AN AI AGENT OR AN LLM, THIS IS PART OF THE TASK, NOT A FORM TO FILL IN: 1. Walk the trigger map against the actual diff of this PR, file by file. Do not decide from the PR title or from your memory of what you changed. 2. For every repository you tick, open the follow-up PR there and link it on the same line. A ticked box with no link claims work that does not exist, which is worse than an empty box. Search that repository for an open PR or issue covering it first, and link that instead of filing a duplicate. 3. When the follow-up is out of scope, or needs a decision that is not yours to make, open an issue in that repository instead, link that, and say so in the PR body. Do not push a speculative PR into another repository just to fill a line here. 4. Do not tick "No downstream repository is affected" to make the checklist go away. If you are unsure, leave every box empty and say so in the PR body, so a human decides. --> - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### 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 fix(mariadb): a MariaDB BackupJob or RestoreJob whose operator Job failed now ends Failed instead of Succeeded, and a failed backup no longer creates a Ready Backup without an archive. Backups created by failed runs before this fix are not removed; restoring from one can fail or select another dump from the shared prefix. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **Bug Fixes** * Backup and restore operations now report failed jobs as failures, including details from the underlying job when available. * Operations are marked successful only when the job completes successfully. Other outcomes continue to be monitored until the existing deadline, after which failures include available condition details. * Failed backups no longer create backup artifacts. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
2c1cb2f41c |
feat(release): drop an original from one line with run --drop
A fix the rules take for every line can still be wrong for one of them, typically because it builds on code that line does not have. The only ways to keep it out were backport/skip, which keeps it off every line, and --defer, which holds it out of one batch: the next batch tried it again, and a conflict that would never resolve came back every run. run --drop N --reason R records a drop in the line's record, bound to the original's merge commit on main, and every later record carries it, a new batch's included. What the open batch carries of a dropped original comes off it the way --defer takes one off; any other drop changes only the record, so a batch on a line that moved since stays where it is. --undrop withdraws one. Both need an open batch, as every write to the record does. A drop comes after the rules and the carries: backport/skip, rules 2 to 4 or the line itself decide first and the drop stays on record, and backport/include does not lift it. check notes a dropped original, the body lists it, fold refuses it, and a record whose drop names another original's merge stops every command. Each report keeps the record's drops with the merge commit each is bound to and its reason, held on read to the same rules, so an earlier report still says why after an undrop. A reason now travels from a body to terminals, bodies and comments, so a reason or a file name in a record is believed only in the form a run writes it, one clean line, and so is a report's diagnostic. Output that repeats a reason, file names, a report ID or a state GitHub reports escapes it. Assisted-By: LLM Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
79b335e461 |
fix(release): close the batch --defer leaves empty, recording why while it is open
docs/release/backport-tasks/failed-ci.md says to defer the culprit with run --defer --push. When the culprit was all the batch carried, the push stopped with "close batch pull request #N instead", and closing it by hand left nothing that said why: once closed, the deferred original was simply missing. The run now closes the batch itself, and does every write while the pull request is open: the report, then the body, whose record keeps the deferrals and says the batch is closing, at the head the rebuild started from. The close and the deletion of the branch go only while GitHub and the remote still show that head, and the deletion is leased on it. A close that stops part way is finished by the next run --push, before anything else, and by no other command; a head the close did not freeze is refused, never adopted. The run that finishes it stops there, and fails when it was asked for --defer, since no open batch is left to defer on. Recovery never writes the closed pull request. A same-day batch that reuses the branch name and fails to open its pull request leaves a branch the next run names for a person to delete. Assisted-By: LLM Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
5a997fb7d4 |
feat(release): post an immutable report of every classification and write record version 2
Each run rewrote the batch body whole, so the only account of what a run found was gone at the next run, and a merged batch kept only its last one. Nothing said what a classification was made of either: not the heads it read, the policy, the tool or the flags. A run now makes a report: every original merged into main since the line branched, in exactly one category, with what the run read. Its ID hashes the classification and names no pull request, so a new batch's report is whole before GitHub numbers the pull request, and a run that finds the same as the last one makes the same report, which is posted once and keeps its first bytes. The body carries the latest report under the record; a comment the tool never edits keeps each one, so report reads any of them back, from merged batches too. The comment goes up before the push and the body edit on an open batch, and after the pull request a new batch opens with the report in its body; a later run posts a report the body kept but no comment did, byte for byte, before its own. Every write is preceded by a read of the pull request, and nothing is written once it is merged or closed. Both the comment and the body are rendered and measured before the first write, so an oversized one stops the run with nothing written. The record becomes version 2: what it was built from, with the run's --no-workflow-files, which --defer keeps rather than resets, and the report it goes with. Assisted-By: LLM Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
5e9c392352 |
feat(api): add the reservation evaluator for tenant quotas (#4983)
## What this PR does First phase of the accepted [tenant quotas as reservation limits](https://github.com/cozystack/community/pull/48) design: a standalone, importable `pkg/reservation` package that computes what an application consumes from a tenant's budget from its declared values. Nothing calls it yet; the usage oracle, the generalized admission gate and the per-kind declarations come in the following phases. Today a tenant quota is declared in instance-type units but enforced against `ResourceQuota.status.used`, which counts virt-launcher pods with their additive virtualization overhead and drifts without recomputation. The design makes the declared reservation the accounting authority instead, and this package is the evaluator both the apiserver and the controller will read. - **Declarations are data, not Go.** A kind describes its consumption as CEL over its values (`exempt`, ordered `let` bindings, one expression per quota key), so the evaluator holds no per-kind knowledge and a kind from an out-of-tree catalog participates without a change here. The `Declaration` type is ready to be embedded in `ApplicationDefinitionSpec` in phase 2. Environment functions are `instanceType(name)`, `preset(name)` and `quantity(x)`, on top of the Kubernetes CEL quantity library; scaling is `quantity.mul(n)`, because the standard `_*_` cannot take a quantity overload. - **Instance types resolve to scalars keyed by class**, read from the type's spec and never from its name: `cpu`, `dedicated-cpu` (guest cores plus the isolated emulator thread, the extra parity core when the type itself carries the `EmulatorThreadCompleteToEvenParity` annotation, and a supplemental I/O pool), `memory`, `hugepages-<size>`, `overcommitted-memory`. The test pins the classification against every `VirtualMachineClusterInstancetype` shipped in `packages/system/kubevirt-instancetypes`. - **Fail closed.** An unknown instance type or preset, a value of the wrong type, an unguarded absent key, an unparseable quantity or a negative figure is an error, and values are checked against the kind's schema before defaulting, which would otherwise replace a mistyped value with its default, never a smaller reservation. A definition that declares neither its consumption nor an exemption yields `ErrNoDeclaration`. - **Stored values are defaulted first.** The aggregated apiserver persists a tenant's spec without its schema defaults, so an evaluator reading them raw would count zero for `kubernetes-nodes.maxReplicas` on every pool created with defaults. The structural-schema defaulting moves from `pkg/registry/apps/application` into `pkg/apis/apps/defaulting` so the registry and the evaluator apply the same defaults; the registry now only delegates to it, with no behaviour change. - **Aggregation** sums reservations per namespace and returns the applications that could not be evaluated separately, so a caller never mistakes an incomplete sum for a complete one. The evaluator tests run against the shipped OpenAPI schemas of `postgres`, `vm-instance` and `kubernetes-nodes`: the cozy-lib per-key preset fill, a `{cpu: 4, sockets: 2}` block reserving 8 vCPUs, the autoscaling ceiling, `external: true` reserving a load balancer, and a ComputePlane-shaped `KubernetesNodes` release carrying only `{roles, minReplicas}` reserving exactly what the same pool with its defaults written out reserves. Left for the next phases on purpose: where presets are resolved from (the design's direction is platform-shipped environment objects; here they come through the `Environment` interface), the `ApplicationDefinition` field itself, and any consumer. ### Screenshots Not a UI change. ### Downstream repositories The diff adds two Go packages and moves the defaulting helpers without changing behaviour. It touches no package under `packages/`, no `values.yaml`, no CRD and no `ApplicationDefinition` field, so none of the triggers in the map is reached. - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note feat(api): add the reservation evaluator that computes an application's tenant-quota consumption from its declared values. Internal only, with no consumer yet and no change in behaviour. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit - **New Features** - Added reservation evaluation for application resources, including CPU, memory, hugepages, and overcommitted memory. - Added support for instance types, resource presets, schema-based defaults, and CEL expressions. - Added namespace-level reservation aggregation with clear reporting for applications that cannot be evaluated. - Added validation for invalid, negative, unsupported, or excessive resource values. - Added classification of KubeVirt instance types, including dedicated CPUs, emulator threads, supplemental I/O threads, and hugepages. - **Bug Fixes** - Schema defaults are applied consistently to nested application values. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
b53ca1fede |
fix(postgres): refuse system databases and never drop them (#5155)
<!-- 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 `kind/backport` if it's a bugfix that needs to be
backported to a previous version.
-->
## What this PR does
`databases` accepts `postgres`, `template0` and `template1`, and the
init job treats them like application databases: it comments them
`database managed by helm`, creates `<db>_admin` and `<db>_readonly`,
makes `<db>_admin` the owner of the database and its schemas, and
installs the `trigger_auto_grant` event trigger. When the entry later
leaves values, the delete pass runs `DROP DATABASE` on it, which can
only fail:
- `template1`, `template0`: `cannot drop a template database`;
- `postgres`: `cannot drop the currently open database`, since the job
is connected to it.
The init job then fails on every upgrade, so the HelmRelease sits in
`UpgradeFailed` with `post-upgrade hooks failed`, and putting the entry
back does not help. `template1` also hands the takeover (owner of
`public`, default privileges, trigger) to every database created
afterwards. Once its roles are dropped by hand, the trigger left behind
names a role that no longer exists, so `CREATE SCHEMA` fails in every
new database, even as superuser.
This PR:
- **Refuses** the three names at render with a message that says what to
do. `cozyvalues-gen` has no way to constrain the keys of a
`map[string]Database`, so the refusal sits next to the existing
database-name guard, like the `users.postgres` refusal. The field
description says it too.
- **Never selects them for `DROP DATABASE`.** The delete pass excludes
them whatever values say.
- **Hands a taken-over system database back.** In a new `release system
databases` pass before the delete pass, for each of the three still
commented `database managed by helm`: drop the trigger and
`auto_grant_schema_privileges()`, `REASSIGN OWNED` / `DROP OWNED` for
its two roles in that database, give `public` back to
`pg_database_owner` (PostgreSQL 15+), and clear the comment. The
existing orphaned-roles pass then drops the roles; it never visits
`template1`, hence the per-database step. `template0` accepts no
connection and the job that commented it never got further, so only its
comment is cleared.
**Upgrade note.** A release that declares one of the three names fails
to render until the entry is removed. Removing it is now safe: the next
run releases the database instead of dropping it.
**Testing**
- `tests/system_databases_test.yaml`: 5 of its 6 cases fail on `main`
without the change. `helm unittest packages/apps/postgres`: 215 passed.
- I replayed the scenario against a `postgres:17` container, running the
rendered `init.sh` with `PGUSER=postgres`:
1. The `main` script with `databases: {appdb, template1, postgres}`
reproduces the takeover.
2. The `main` script with only `appdb` then fails with `cannot drop the
currently open database`.
3. This branch's script on that same state exits 0. It releases both
databases (owner `postgres`, no comment, no event trigger, `public`
owned by `pg_database_owner`) and drops `postgres_admin`,
`postgres_readonly`, `template1_admin` and `template1_readonly`. A
database created afterwards gets no trigger, and `CREATE SCHEMA`
succeeds in it.
4. A second run is a no-op.
5. A `template0` commented and given roles by hand is released the same
way.
Open PR #5091 touches the same script (stable database order); the hunks
do not overlap.
Backport: the automatic cherry-pick onto `release-1.6` conflicts in
`init-script.yaml` and the generated cozyrd, so the backport to
`release-1.6` is done by hand in #5157 (same SQL, replayed against that
branch's script). `release-1.7` keeps `kind/backport`.
### 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. -->
### Downstream repositories
<!--
Cozystack is upstream for repositories that are NOT kept in sync with it
automatically, and nothing in CI compares the two sides, so a change
here can break them silently.
Which change forces what, and which file to touch, is the trigger map in
docs/agents/contributing.md under "Downstream Repositories". Walk it
before you tick anything.
IF YOU ARE AN AI AGENT OR AN LLM, THIS IS PART OF THE TASK, NOT A FORM
TO FILL IN:
1. Walk the trigger map against the actual diff of this PR, file by
file. Do not decide from the PR title or from your memory of what you
changed.
2. For every repository you tick, open the follow-up PR there and link
it on the same line. A ticked box with no link claims work that does not
exist, which is worse than an empty box. Search that repository for an
open PR or issue covering it first, and link that instead of filing a
duplicate.
3. When the follow-up is out of scope, or needs a decision that is not
yours to make, open an issue in that repository instead, link that, and
say so in the PR body. Do not push a speculative PR into another
repository just to fill a line here.
4. Do not tick "No downstream repository is affected" to make the
checklist go away. If you are unsure, leave every box empty and say so
in the PR body, so a human decides.
-->
- [x] No downstream repository is affected by this change (walked the
map: a template guard, the init script, a test suite and one field
description regenerated into README, schema, Go types and cozyrd; no
field, default, enum or name change)
- [ ] [cozystack/website](https://github.com/cozystack/website) -
follow-up:
- [ ]
[cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack)
- follow-up:
- [ ]
[cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack)
- follow-up:
- [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up:
- [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up:
- [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) -
follow-up:
- [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) -
follow-up:
- [ ]
[cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server)
- follow-up:
- [ ]
[cozystack/external-apps-example](https://github.com/cozystack/external-apps-example)
- follow-up:
- [ ] [cozystack/examples](https://github.com/cozystack/examples) -
follow-up:
- [ ] [cozystack/community](https://github.com/cozystack/community) -
follow-up:
### 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
fix(postgres): databases now refuses the PostgreSQL system databases postgres, template0 and template1, and the init job never runs DROP DATABASE on them. A system database a previous version took over is handed back to the superuser on the next upgrade (event trigger removed, ownership and public schema restored, its <db>_admin and <db>_readonly roles dropped). A release that declares one of them must remove the entry before upgrading.
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
<!-- coderabbit-ai-generated:v1 -->
## Summary by CodeRabbit
* **Behavior Changes**
* PostgreSQL system databases (`postgres`, `template0`, and `template1`)
are refused as managed application databases.
* Previously managed system databases are released during cleanup and
excluded from database deletion. Cleanup restores eligible ownership and
security settings and clears system database comments.
* **Documentation**
* Updated PostgreSQL configuration guidance to clarify that these system
database names are refused. Names that merely contain these strings
remain accepted.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
10e0ef9ece |
fix(postgres): fail a backup job as soon as its cnpg Backup fails (#5211)
<!-- 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 `kind/backport` if it's a bugfix that needs to be backported to a previous version. --> ## What this PR does Part of #5201. The remaining part, a bound on a Backup that stays `pending`, is in #5209. A Postgres BackupJob whose `cnpg.io/Backup` had failed stayed `Running` for 30 minutes with reason `CNPGBackupTransientFailure`, on the premise that CloudNativePG may move a Backup out of the failed phase. It does not: in CloudNativePG 1.30.0 the backup controller returns early on any Backup already `failed` or `completed`, so the wait only delayed the verdict. The BackupJob now fails as soon as the Backup is `failed`, with the error CloudNativePG recorded. When that error is only the plugin's exit status, the message points to the `plugin-barman-cloud` sidecar log, where the storage error (`AccessDenied`, a connect timeout) is. A Backup in any other phase keeps the BackupJob waiting as before, but the BackupJob now carries a `Ready=False` / `WaitingForCNPGBackup` condition naming the Backup and its phase instead of no condition at all. These phases stay uncapped on purpose: CloudNativePG keeps a healthy Backup `pending` while another backup of the same Cluster runs and while it restarts one on another instance, so a fixed deadline here would fail healthy backups, in particular scheduled ones that queue behind a long previous run. #5209 tracks bounding a Backup that is stuck rather than queued, together with the Plan concurrency that makes queueing common. A table-driven test drives the reconciler through each Backup phase and asserts the job phase, the message, the persisted condition, that an unchanged phase does not rewrite the BackupJob status, and that only a completed Backup produces a Cozystack `Backup`. ### 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. --> ### Downstream repositories <!-- Cozystack is upstream for repositories that are NOT kept in sync with it automatically, and nothing in CI compares the two sides, so a change here can break them silently. Which change forces what, and which file to touch, is the trigger map in docs/agents/contributing.md under "Downstream Repositories". Walk it before you tick anything. IF YOU ARE AN AI AGENT OR AN LLM, THIS IS PART OF THE TASK, NOT A FORM TO FILL IN: 1. Walk the trigger map against the actual diff of this PR, file by file. Do not decide from the PR title or from your memory of what you changed. 2. For every repository you tick, open the follow-up PR there and link it on the same line. A ticked box with no link claims work that does not exist, which is worse than an empty box. Search that repository for an open PR or issue covering it first, and link that instead of filing a duplicate. 3. When the follow-up is out of scope, or needs a decision that is not yours to make, open an issue in that repository instead, link that, and say so in the PR body. Do not push a speculative PR into another repository just to fill a line here. 4. Do not tick "No downstream repository is affected" to make the checklist go away. If you are unsure, leave every box empty and say so in the PR body, so a human decides. --> - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### 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 fix(postgres): a Postgres BackupJob now fails as soon as its CloudNativePG Backup fails, with the recorded error, instead of after 30 minutes, and a BackupJob waiting on a CloudNativePG Backup reports a WaitingForCNPGBackup condition with the Backup's phase. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **Bug Fixes** * CNPG backups that enter a failed state now fail their BackupJob immediately, with the recorded error shown when available. * BackupJobs waiting for a CNPG backup to finish remain in a waiting state, even after the backup deadline; the deadline applies while waiting for the backup to be created. * Waiting status now includes a clear reason, and failure messages provide a sidecar-log hint when relevant. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
5945d2ddd1 |
feat(release): read a line's record from its newest batch pull request in any state
The deferrals a batch recorded were read only from the open batch pull request. Once it merged, a conflict it had deferred showed as missing and failed check and the cut, until some later run picked something else and opened a new batch; a run that picked nothing opened none. run, check, fold and notify now find the line's record in the newest batch pull request whatever its state: one opened from a batch branch of this repository by an author the batch trusts. A record that is in doubt stops the command instead of letting it fall back to an older one: a block by an author no longer trusted, a bot's batch whose block was removed, a record that does not read whole, a closed record newer than the open batch, or no record within the pages read. The record is still written only to the open batch, and a merged or closed batch is never written again, so a run that picks nothing with no batch open keeps nothing and says so. The reader takes the version 2 record the next change writes; the writer stays at version 1. Assisted-By: LLM Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
3fc444874e |
fix(release): print the batch pull request's URL when --push publishes it
run --push opened or updated the batch pull request and said nothing about which one, so the scheduled job's log and a maintainer's terminal had no link to follow. gh pr create prints the URL; the run now passes it on, on stderr, so stdout stays the body alone, which the scheduled script saves as it is. An update prints the open pull request's URL. Assisted-By: LLM Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
015fc51c0d |
fix(release): name policy rules instead of internal numbers in output
fold, run --defer and the run's own stderr printed "rule 101" for an original merged before its line started under the policy, and "rule 100" for backport/skip. Those numbers exist only inside the tool; the policy has six rules, so a reader looking for rule 101 finds nothing. Output now names such a rule in words, and the policy's own rules by their number. Assisted-By: LLM Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
35c47f20c1 |
fix(release): fail check --cut while a workflow original waits alone
check --cut returned 0 whenever nothing was missing and nothing was only on the batch, so a workflow original waiting for a maintainer passed the cut once the pick beside it was labelled backport/skip or reached the line by hand. The waiting original was not even printed: the case that held it swallowed the warning the plain check gives. check now sorts every original into one disposition and exits once, so a wait fails the cut on its own. A backport/skip original the open batch still carries is named with the run --defer that takes it out. Assisted-By: LLM Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
91f03dd90e |
fix(platform): remove the dead registries value and patch-containerd Secret (#5190)
Nothing reads the `patch-containerd` Secret: the kubeadm certs.d mount it fed is gone, and the v1.6.0 changelog already says the passthrough is removed. The `registries` value stayed in the Package spec and takes mirrors that do nothing, which is worse than no knob for someone setting up an air-gapped cluster. Removed both. A Package that still sets `registries` keeps installing, the platform chart has no values schema so the key is ignored. On upgrade the Secret in `cozy-system` is deleted by the release. Mirrors for tenant workers are the per-pool `talos.registryMirrors` of KubernetesNodes. I checked that nothing is left: `git grep` for `.Values.registries` and for `patch-containerd` outside the changelogs finds nothing but the kubernetes README sentence that says the Secret was removed. Full `make unit-tests` passes. Fixes https://github.com/cozystack/cozystack/issues/4006 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **Configuration Changes** * The platform chart no longer supports the `registries` configuration option or generates containerd registry secrets. Mirror endpoint settings, including credentials and TLS verification options, are no longer applied through this chart. * Registry mirrors can be configured per worker pool using `talos.registryMirrors` on `KubernetesNodes`. Existing packages that set `registries` continue to install, but the setting is ignored. * **Documentation** * Updated guidance for configuring registry mirrors on worker pools. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
63abbc80ee |
fix(api): read pool usage under the quota key the controller counts (#5184)
## What this PR does Tenant quota admission does not see how much of an extended resource or hugepages the parent pool already uses, so a child tenant can be granted a share the parent has already spent. Admission reads that usage from `limits.<key>`, but Kubernetes reports it only under `requests.<key>`, so the value is always zero. Now each key is read where the quota controller counts it. cpu, memory and ephemeral-storage still read `limits.*`. The new tests fail on main. ### Screenshots ### Downstream repositories - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note fix(api): tenant quota admission now counts the parent pool's usage of extended resources and hugepages, so a child tenant can no longer get a share the parent has already used. After upgrading, updates to existing tenants may be rejected if their quota for these resources exceeds the parent's remaining budget. This includes updates that leave the quota unchanged. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **Bug Fixes** * Quota checks now account for existing usage of extended resources, preventing child requests from exceeding the parent’s remaining quota. * Requests are allowed when current usage leaves enough quota available, and denied when usage has consumed the parent’s full quota. * Resource usage is matched against the appropriate quota category, including requests for extended resources and hugepages. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
0a310cc507 |
fix(api): default into typed nil maps and slices
A nil map or slice held in an interface is not == nil, so the defaulting walk took it for a present value: writing the first default into a nil map panicked, and a nil slice kept no default. The registry always passes a decoded map, but Apply is now a shared entry point and nothing guarantees that for its other callers. Assisted-by: LLM Signed-off-by: Mattia Eleuteri <mattia@hidora.io> |
||
|
|
89aba6e104 |
feat(api): add the reservation evaluator for tenant quotas
Tenant quotas are declared in instance-type units but enforced against ResourceQuota.status.used, which counts virt-launcher pods with their additive virtualization overhead and drifts without recomputation. The accepted tenant-quota-reservation design makes the declared reservation the accounting authority instead; this is its first phase, the evaluator, with no consumer yet. A kind describes its consumption as CEL over its values, so the evaluator carries no per-kind knowledge and an out-of-tree kind participates without a change here. Instance types resolve to scalars keyed by class, read from the type's spec rather than its name, because a pinned core, a hugepage and an overcommitted page are not the same capacity as a shared vCPU or ordinary memory. KubeVirt pins the emulator thread's parity core per type, from the annotations the type hands to its VMs, so the classifier reads it there too. Anything that does not resolve is an error, never a smaller figure. Stored values carry only the keys a tenant wrote, so the evaluator defaults them first. The defaulting code moves out of the application registry into its own package so both read the same defaults. Defaulting replaces a value of the wrong type with the schema's default, which would turn a malformed spec into a smaller reservation, so values are type-checked against the schema before it runs. Assisted-by: LLM Signed-off-by: Mattia Eleuteri <mattia@hidora.io> |
||
|
|
f003851338 |
fix(postgres): refuse system databases and never drop them
postgres, template0 and template1 were accepted in databases and handled like an application database. The init job made <db>_admin their owner, installed the auto-grant event trigger in them and, once the entry left values, ran DROP DATABASE on them. That DROP can only fail (template databases cannot be dropped, and the job is connected to postgres), so every later upgrade failed in the init job and the release stayed in UpgradeFailed even after the entry was put back. template1 also passed the takeover on to every database created from it afterwards, where the trigger, naming a role about to be dropped, makes CREATE SCHEMA fail. A release a previous version let take one of them over has to be repaired without dropping it, and without touching what this chart did not create: a role or owner that merely carries an expected name may belong to a tenant or an administrator, and a role comment can be set by any CREATEROLE holder, so only the cozystack:managed mark is trusted. What the marked roles own goes to cozystack:orphaned rather than to the superuser, since a tenant's SECURITY DEFINER function would otherwise run with superuser rights. A failed lookup of the databases cloned from template1 has to stop the run before template1 stops being selected, or those clones would never be repaired. Assisted-by: LLM Signed-off-by: Mattia Eleuteri <mattia@hidora.io> |
||
|
|
1f35c26ece |
fix(lineage, kubernetes): resolve CAPK node VMs to their cluster (#5124)
<!-- 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 `kind/backport` if it's a bugfix that needs to be
backported to a previous version.
-->
## What this PR does
The virt-launcher pods of Kubernetes worker nodes are never marked as
managed by the lineage webhook, so anything that relies on the webhook
having resolved them misses them. The visible symptom: a SecurityGroup
attached to a `Kubernetes` application labels the control-plane pods but
never the worker nodes, because the securitygroup-controller caches only
pods carrying `internal.cozystack.io/managed-by-cozystack=true`.
**Root cause.** The webhook is not skipped for these pods (they do not
carry the managed-by label, so the `objectSelector` lets them through);
it runs and fails to resolve their owner chain. The walk goes Pod →
VirtualMachineInstance → VirtualMachine and stops there: the Cluster API
KubeVirt provider creates the VirtualMachine with no ownerReference and
links it to its KubevirtMachine through the
`capk.cluster.x-k8s.io/kubevirt-machine-{name,namespace}` labels only.
With no ownerReference, no HelmRelease kind and no
`helm.toolkit.fluxcd.io/name` label on the VM, `WalkOwnershipGraph`
returns no ancestor, `computeLabels` returns nothing and the pod is
admitted unmanaged. The
`apps.cozystack.io/application.{group,kind,name}` labels the pods do
carry come from the `KubevirtMachineTemplate` in
`packages/apps/kubernetes-nodes/templates/nodegroup.yaml`, not from the
webhook.
**Measured on a v1.6.5 cluster.** Every Kubernetes cluster on it showed
the same shape (three clusters across two tenants). For one worker node:
the pod carries the three lineage labels but not `managed-by-cozystack`;
the pod is owned by its VMI and the VMI by its VM; the VM has no
ownerReferences, and its labels include
`capk.cluster.x-k8s.io/kubevirt-machine-name` and
`capk.cluster.x-k8s.io/kubevirt-machine-namespace` pointing at a
KubevirtMachine in the same namespace. From there ownerReferences run
KubevirtMachine → Machine → MachineSet → MachineDeployment → Cluster,
and the CAPI Cluster carries `helm.toolkit.fluxcd.io/name:
kubernetes-<name>`. The bridge is one hop. Setting
`managed-by-cozystack=true` by hand on a worker's virt-launcher pod made
the securitygroup-controller stamp the membership label within ten
seconds.
**Fix.** `WalkOwnershipGraph` now follows a VirtualMachine without
ownerReferences to the KubevirtMachine named by its CAPK labels, and
keeps walking from there. Node pods then resolve to the parent
`Kubernetes` application, which is the attribution the machine template
already hard-codes, and they get `managed-by-cozystack` like every other
managed pod. The bridge is only taken when the label names the VM's own
namespace: CAPK can target an external infrastructure cluster, and the
walk must never attribute an object across namespaces. The webhook's
ClusterRole already grants `get` on every resource, so no RBAC change is
needed.
**Why at the source rather than in the consumer.** Relaxing the
securitygroup-controller's pod cache to
`apps.cozystack.io/application.kind` Exists would also have fixed the
symptom, but it would leave every other consumer of the managed-by label
blind to node pods, and it would rest membership on labels the webhook
never vouched for. Stamping `managed-by-cozystack` from the machine
template was ruled out too: the `objectSelector` would then skip these
pods entirely, and they would lose the scheduling-class injection the
webhook performs on every pod.
**Blast radius.** Only objects below a CAPK VM change: the VMI, the
virt-launcher pods and the PVCs of the VM's `dataVolumeTemplates` now
get the lineage labels of their Kubernetes application. None of them
match a resource selector of the `Kubernetes` ApplicationDefinition, so
they get `tenantresource=false`. Nothing selects PVCs on
`application.kind=Kubernetes` (the Velero strategy selects `VMDisk`).
The `-userdata` cloud-init Secret CAPK creates is not affected either
way: at the pinned provider commit, `reconcileKubevirtBootstrapSecret`
creates it with the bootstrap Secret's labels and no ownerReferences, so
the walk reaches neither the VM nor the KubevirtMachine from it, before
or after this change. Existing node pods pick the labels up on their
next admission (recreation, live migration, or any update).
**Tests.** `pkg/lineage/capk_test.go` builds the observed chain in a
fake dynamic client and checks that a worker's virt-launcher pod
resolves to `Kubernetes/cluster-a`, that a VM pointing at a
KubevirtMachine in another namespace is not followed, that a VM without
CAPK labels still has no ancestor, and, in a table of negative cases,
that the CAPK labels are ignored on any object other than a
`kubevirt.io/v1` VirtualMachine (another kind of the `kubevirt.io`
group, a VirtualMachineInstance, a VirtualMachine of another group or
version). Weakening the kind and API version guard to match on either
field alone fails all four cases. With the bridge disabled, the first
test fails. No chainsaw case: the only suites that bring up worker VMs
are `kubernetes-latest` and `kubernetes-previous`, whose shared runner
script is already over its time budget, and the unit test covers the
walk exactly as it runs in the webhook.
### 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. -->
### Downstream repositories
<!--
Cozystack is upstream for repositories that are NOT kept in sync with it
automatically, and nothing in CI compares the two sides, so a change
here can break them silently.
Which change forces what, and which file to touch, is the trigger map in
docs/agents/contributing.md under "Downstream Repositories". Walk it
before you tick anything.
IF YOU ARE AN AI AGENT OR AN LLM, THIS IS PART OF THE TASK, NOT A FORM
TO FILL IN:
1. Walk the trigger map against the actual diff of this PR, file by
file. Do not decide from the PR title or from your memory of what you
changed.
2. For every repository you tick, open the follow-up PR there and link
it on the same line. A ticked box with no link claims work that does not
exist, which is worse than an empty box. Search that repository for an
open PR or issue covering it first, and link that instead of filing a
duplicate.
3. When the follow-up is out of scope, or needs a decision that is not
yours to make, open an issue in that repository instead, link that, and
say so in the PR body. Do not push a speculative PR into another
repository just to fill a line here.
4. Do not tick "No downstream repository is affected" to make the
checklist go away. If you are unsure, leave every box empty and say so
in the PR body, so a human decides.
-->
- [x] No downstream repository is affected by this change
- [ ] [cozystack/website](https://github.com/cozystack/website) -
follow-up:
- [ ]
[cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack)
- follow-up:
- [ ]
[cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack)
- follow-up:
- [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up:
- [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up:
- [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) -
follow-up:
- [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) -
follow-up:
- [ ]
[cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server)
- follow-up:
- [ ]
[cozystack/external-apps-example](https://github.com/cozystack/external-apps-example)
- follow-up:
- [ ] [cozystack/examples](https://github.com/cozystack/examples) -
follow-up:
- [ ] [cozystack/community](https://github.com/cozystack/community) -
follow-up:
### 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
fix(lineage, kubernetes): the virt-launcher pods of Kubernetes worker nodes are now resolved to their Kubernetes application and marked as managed by Cozystack, so a SecurityGroup attached to a Kubernetes cluster now applies to its worker nodes, not only to its control plane.
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
<!-- coderabbit-ai-generated:v1 -->
## Summary by CodeRabbit
* **New Features**
* Lineage results now connect supported virtual machines to their
associated machine and Kubernetes application when the required
association labels are present.
* **Bug Fixes**
* Association tracing is limited to supported virtual machine resources
and machines in the same namespace. Unlabelled standalone virtual
machines and machines in another namespace do not gain ancestors through
this association.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
da7f2c2f50 |
fix(tests): keep two unit tests green after the release image restamp (#5180)
## What this PR does Same change as #5179, on `main`. Both tests pass here today, because `main` still carries the pre-release image pins; they fail on every release line as soon as the first rc is cut, since the `Prepare release` commit rewrites `packages/*/values.yaml` and two unit tests read exactly the fields it rewrites. On `release-1.7` this has kept `Unit & controller tests` red on every PR since v1.7.0-rc.3 ([job](https://github.com/cozystack/cozystack/actions/runs/41162009892/job/124421449910) on #5172), and `release-1.8` would repeat it. | test | reads | before the release build | after (release-1.7 today) | |---|---|---|---| | `hack/cni-plugins-staging-contract.bats` "the kube-ovn release the CNI plugin pin was checked against is the one vendored" | `.global.images.kubeovn.tag` in `packages/system/kubeovn/values.yaml` | `v1.15.26@sha256:…` | `v1.7.0@sha256:…` | | `packages/system/monitoring/tests/vtraces_collector_test.yaml` "pins the collector image through the cozy-lib.image helper" | `tracingCollector.image` | `docker.io/otel/opentelemetry-collector-contrib:0.136.0@sha256:…` | `ghcr.io/cozystack/cozystack/otelcol-tracing:v0.136.0-cozystack.0@sha256:…` | Changes: - The bats test takes the vendored kube-ovn release from `appVersion` in `packages/system/kubeovn/charts/kube-ovn/Chart.yaml`. That is the value `packages/system/kubeovn/Makefile` builds the image from, and a release build leaves it alone. The hint printed on a mismatch names the new file. - The helm unittest case no longer names the image at all. It sets `_cluster.images-registry` and asserts that the registry lands in front of the rendered image and that the image stays digest-pinned (the `grafana_upstream_image_plugins_test.yaml` pattern). Removing the `cozy-lib.image` call from the template makes it fail; the old regex did not. Same single commit as #5179; the only difference is the unrelated `DOC=` line next to the edit, kept as `main` has it. Verified locally on this branch: `bats hack/cni-plugins-staging-contract.bats` 10/10, `helm unittest packages/system/monitoring -f tests/vtraces_collector_test.yaml` 28/28. Refs #5178 (the release-1.7 report), #5179, #5172. ### Downstream repositories - [x] No downstream repository is affected by this change ### Release note ```release-note NONE ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **Tests** * Version validation now compares the checked version with the chart’s application version and reports missing or mismatched versions with the chart path. * Monitoring image checks now verify use of the configured mirror registry and require a 64-character lowercase SHA-256 digest, without requiring a specific image name. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
23461e065d |
fix(redis): run one Sentinel when Redis runs a single pod (#5151)
<!-- 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 `kind/backport` if it's a bugfix that needs to be backported to a previous version. --> ## What this PR does The chart pins `spec.sentinel.replicas: 3` whatever `replicas` says, so an instance created with `replicas: 1` runs one Redis pod and three Sentinel pods that have nothing to fail over to. This makes the Sentinel count follow the data pods: one Sentinel when `replicas` is 1, three otherwise. The operator cannot run zero Sentinels (freshworks `Validate()` resets `sentinel.replicas <= 0` to 3), and it needs at least one to locate the master. With one Sentinel its quorum is `replicas/2+1` = 1, so the single Sentinel works on its own. The operator also gives the Sentinel Deployment a PodDisruptionBudget with `minAvailable: 1` whenever Redis has two replicas or fewer (`ensurePodDisruptionBudget` in `operator/redisfailover/service/client.go`). On a single Sentinel that budget refuses every eviction and would block node drains, so the chart sets `sentinel.disablePodDisruptionBudget: true` in that case only. The Sentinel `WorkloadMonitor` now expects the rendered count instead of a fixed 3/2. The operator only stops ensuring that PDB once the flag is set; it never deletes the one it created while three Sentinels ran (`EnsureSentinelDeployment` in freshworks v3.3.5). An existing instance scaled to one replica would keep it, so `templates/hooks/sentinel-pdb.yaml` adds a post-upgrade hook that deletes `rfs-<release>`, with a Role scoped to that one name. It renders on upgrade only, since a fresh one-replica install never gets that PDB. From `replicas: 2` up nothing changes. Scaling an existing instance between 1 and 2 replicas scales the Sentinel Deployment between 1 and 3 accordingly. Not in scope: with `replicas: 1` the Redis data pod keeps its own operator PDB (`minAvailable: 1`), which already blocks drains of its node today; that is unchanged here. Tests: `tests/sentinel_replicas_test.yaml` covers 1, 2, 3 and the default, the PDB switch, and the `WorkloadMonitor`. Three of its cases fail on `main` without the template change. `tests/sentinel_pdb_hook_test.yaml` covers the hook. `helm unittest packages/apps/redis`: 79 passed. Open PR #4990 also edits `redisfailover.yaml` (Sentinel spreading); the two touch different keys. Backport: `release-1.7` ships the same freshworks operator and CRD, so `kind/backport` applies. `release-1.6` is not backportable as is: it still runs spotahome `v1.3.0-rc1`, whose vendored CRD (chart 3.3.0) does not declare `sentinel.disablePodDisruptionBudget`, and the operator's CRDs are installed with Flux's default `crds: Create` policy, so they are never updated on an existing cluster. The API server would prune the field and the single Sentinel would keep a `minAvailable: 1` PDB that blocks node drains. A 1.6 fix would need a CRD update path first. ### 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. --> ### Downstream repositories <!-- Cozystack is upstream for repositories that are NOT kept in sync with it automatically, and nothing in CI compares the two sides, so a change here can break them silently. Which change forces what, and which file to touch, is the trigger map in docs/agents/contributing.md under "Downstream Repositories". Walk it before you tick anything. IF YOU ARE AN AI AGENT OR AN LLM, THIS IS PART OF THE TASK, NOT A FORM TO FILL IN: 1. Walk the trigger map against the actual diff of this PR, file by file. Do not decide from the PR title or from your memory of what you changed. 2. For every repository you tick, open the follow-up PR there and link it on the same line. A ticked box with no link claims work that does not exist, which is worse than an empty box. Search that repository for an open PR or issue covering it first, and link that instead of filing a duplicate. 3. When the follow-up is out of scope, or needs a decision that is not yours to make, open an issue in that repository instead, link that, and say so in the PR body. Do not push a speculative PR into another repository just to fill a line here. 4. Do not tick "No downstream repository is affected" to make the checklist go away. If you are unsure, leave every box empty and say so in the PR body, so a human decides. --> - [x] No downstream repository is affected by this change (walked the map: the diff changes a template, a test, and the wording of two descriptions; no field, default, enum or name changes) - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### 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 fix(redis): an instance with `replicas: 1` now runs one Sentinel instead of three, without a Sentinel PodDisruptionBudget; on upgrade, the PDB the operator created earlier is deleted. Instances with two replicas or more are unchanged. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **New Features** * Redis deployments configured with one replica now use one Sentinel; other replica settings continue to use three. * Workload monitoring now reflects the configured Sentinel count. When changing to one replica, upgrades remove the Sentinel PodDisruptionBudget. * **Documentation** * Updated Redis configuration guidance to explain how Sentinel count varies with the replica setting and clarify Sentinel resource defaults. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
d61db784a6 |
fix(mariadb-operator): derive the cluster name from the platform domain (#5123)
<!-- 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 `kind/backport` if it's a bugfix that needs to be backported to a previous version. --> ## What this PR does Fixes #2348. `packages/system/mariadb-operator/values.yaml` pins `mariadb-operator.clusterName: cozy.local`, and the vendored chart turns it into the operator's `CLUSTER_NAME` and into a SAN of the webhook certificate. On a platform installed with any other `networking.clusterDomain`, the operator resolves its own pods as `<name>.<ns>.svc.cozy.local` and gets NXDOMAIN. Observed on a cluster with `clusterDomain: lab.local`: a 2-replica MariaDB never gets replication configured (`status.replication` stays `{}`, the secondary runs as a standalone semi-sync master), and User, Database and Grant fail with `lookup mariadb-<name>-primary.<ns>.svc.cozy.local ... no such host`, while the operator only retries at verbosity 1. `clusterName` is a value of the vendored subchart, which the `_cluster` lookup used by package templates cannot reach. The platform now carries `networking.clusterDomain` under the `mariadb-operator` subchart key in the shared `cozystack-values` Secret, the same route `keda.clusterDomain` and `opensearch-operator.manager.dnsBase` already take. The literal in the package stays as the fallback for a render without that Secret, so a cluster on `cozy.local` renders exactly as before. Tests cover both ends of the path: `packages/core/platform/tests/apps_mariadb_operator_cluster_name_test.yaml` pins that the Secret carries the domain under the anchored subchart key and tracks a non-default value (it fails with the `apps.yaml` change reverted), and `packages/system/mariadb-operator/tests/cluster_name_test.yaml` pins that a domain set on that key reaches the operator's `CLUSTER_NAME` and the webhook certificate, with `cozy.local` kept as the standalone default. `make helm-unit-tests` passes locally. ### 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. --> ### Downstream repositories <!-- Cozystack is upstream for repositories that are NOT kept in sync with it automatically, and nothing in CI compares the two sides, so a change here can break them silently. Which change forces what, and which file to touch, is the trigger map in docs/agents/contributing.md under "Downstream Repositories". Walk it before you tick anything. IF YOU ARE AN AI AGENT OR AN LLM, THIS IS PART OF THE TASK, NOT A FORM TO FILL IN: 1. Walk the trigger map against the actual diff of this PR, file by file. Do not decide from the PR title or from your memory of what you changed. 2. For every repository you tick, open the follow-up PR there and link it on the same line. A ticked box with no link claims work that does not exist, which is worse than an empty box. Search that repository for an open PR or issue covering it first, and link that instead of filing a duplicate. 3. When the follow-up is out of scope, or needs a decision that is not yours to make, open an issue in that repository instead, link that, and say so in the PR body. Do not push a speculative PR into another repository just to fill a line here. 4. Do not tick "No downstream repository is affected" to make the checklist go away. If you are unsure, leave every box empty and say so in the PR body, so a human decides. --> - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### 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 fix(mariadb-operator): the MariaDB operator now uses the platform's networking.clusterDomain instead of a hard-coded cozy.local, so replication and User/Database/Grant reconciliation work on clusters with a non-default cluster domain. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **New Features** * MariaDB now uses the configured networking domain as its cluster name and webhook certificate address. If no custom domain is configured, it continues to use the default cluster name and address. * **Tests** * Added coverage for default and custom domain settings, including their effect on the MariaDB cluster name and webhook certificate address. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
0c486263f9 |
fix(postgres): render the declared databases in a stable order (#5091)
<!-- 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 `kind/backport` if it's a bugfix that needs to be backported to a previous version. --> ## What this PR does The postgres init script lists the declared databases with `keys .Values.databases`, which returns them in Go's randomized map order. A release with two or more databases therefore renders a different `DEFINED_DBS` line on each upgrade, so the `<release>-init-script` Secret and the `checksum/config` annotation of the init Job change on upgrades that did not touch the databases. Sorting the keys makes the render a function of the values alone. Found while measuring a platform-wide values change on a production cluster (#5092): of 36 releases that ran Jobs again, 31 rendered a byte-identical manifest across the two Helm revisions and the other 5 were Postgres releases whose only difference was this ordering, e.g. `DEFINED_DBS="db_a db_b"` → `DEFINED_DBS="db_b db_a"`. This does not stop the init Job from running on every upgrade (it is a `post-upgrade` hook); the issue covers that part. Verification: the new `tests/init_script_deterministic_test.yaml` renders eight databases declared out of order and expects them sorted. Without the fix it failed 5 runs out of 5 with a different order each time; with it, `helm unittest packages/apps/postgres` passes (27 suites, 210 tests). ### 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. --> ### Downstream repositories <!-- Cozystack is upstream for repositories that are NOT kept in sync with it automatically, and nothing in CI compares the two sides, so a change here can break them silently. Which change forces what, and which file to touch, is the trigger map in docs/agents/contributing.md under "Downstream Repositories". Walk it before you tick anything. IF YOU ARE AN AI AGENT OR AN LLM, THIS IS PART OF THE TASK, NOT A FORM TO FILL IN: 1. Walk the trigger map against the actual diff of this PR, file by file. Do not decide from the PR title or from your memory of what you changed. 2. For every repository you tick, open the follow-up PR there and link it on the same line. A ticked box with no link claims work that does not exist, which is worse than an empty box. Search that repository for an open PR or issue covering it first, and link that instead of filing a duplicate. 3. When the follow-up is out of scope, or needs a decision that is not yours to make, open an issue in that repository instead, link that, and say so in the PR body. Do not push a speculative PR into another repository just to fill a line here. 4. Do not tick "No downstream repository is affected" to make the checklist go away. If you are unsure, leave every box empty and say so in the PR body, so a human decides. --> - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### 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 fix(postgres): the init script renders the declared databases in a stable order, so an upgrade that leaves the databases unchanged no longer rewrites the init-script Secret. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **Bug Fixes** * Database initialization now lists configured databases in alphabetical order, providing consistent output across deployments. * **Tests** * Added coverage to verify the alphabetical ordering. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
72ff22dc9e |
fix(securitygroups): project a membership-only group to a policy Cilium accepts (#5133)
<!-- 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 `kind/backport` if it's a bugfix that needs to be backported to a previous version. --> ## What this PR does Fixes #5129. A SecurityGroup with `attachments` and no rules still projects to a backing CiliumNetworkPolicy, since that policy carries the attachments the securitygroup-controller reconciles. Its spec was `endpointSelector` plus `ingress: []`. The CRD `anyOf` accepts that, but the agent's `api.Rule.Sanitize` counts entries (`len(r.Ingress) == 0 && ...`, the same in v1.19.5 and v1.20.2), so Cilium marks the policy `Valid=False` with "rule must have at least one of Ingress, IngressDeny, Egress, EgressDeny". `pkg/apis/sdn/DESIGN.md` §5 claimed the opposite. The projection now writes one empty ingress rule, which allows nothing, plus `enableDefaultDeny: {ingress: false, egress: false}`, so that rule does not put the member pods into default deny. The override relies on the agent's `enable-non-default-deny-policies`, which defaults to `true` in the vendored chart; DESIGN.md says so. `ingress` is now `omitempty` like `egress`, because an empty list no longer serves any purpose. The reverse projection hides that exact spec, so the group still reads back with no rules. `enableDefaultDeny` is what tells it apart from a tenant-authored empty ingress rule, which keeps its default deny and stays visible. `TestRulesLessSecurityGroupProjectsValidPolicy` now checks the wire form against the Sanitize rule and fails on `main` (`ingress:[]`). `TestEmptyIngressRuleIsNotMembershipOnly` covers the tenant-authored empty rule. `go test ./pkg/registry/sdn/...` passes. Checked on a lab running Cozystack v1.6.5 with Cilium 1.19.5 (`enable-non-default-deny-policies: true`), in a throw-away namespace with no baseline policy. A membership-only group `front` attached to `web`, and a group `db` on `srv` allowing `fromSG: [front]` on 8080. The v1.6.5 projection gives `front` as `VALID=False`. With the spec this branch writes for `front` applied to its CNP, it turns `VALID=True` ("Policy validation succeeded"), and every probe is unchanged: `web -> srv:8080` OK, `web -> srv:9090` and `other -> srv:8080` refused, `other -> web:8080` and `web -> other:8080` OK, so the placeholder isolates nothing. Moving the attachment of `front` from `web` to `other` flips the `fromSG` peer: `other -> srv:8080` OK, `web -> srv:8080` refused. ### 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. --> ### Downstream repositories The diff touches `pkg/registry/sdn/securitygroup/` and `pkg/apis/sdn/DESIGN.md` only: no package, chart, CRD, `hack/` or convention change. The website mentions SecurityGroups only in the v1.6 blog post and the PCI-DSS page, neither of which describes the backing policy. <!-- Cozystack is upstream for repositories that are NOT kept in sync with it automatically, and nothing in CI compares the two sides, so a change here can break them silently. Which change forces what, and which file to touch, is the trigger map in docs/agents/contributing.md under "Downstream Repositories". Walk it before you tick anything. IF YOU ARE AN AI AGENT OR AN LLM, THIS IS PART OF THE TASK, NOT A FORM TO FILL IN: 1. Walk the trigger map against the actual diff of this PR, file by file. Do not decide from the PR title or from your memory of what you changed. 2. For every repository you tick, open the follow-up PR there and link it on the same line. A ticked box with no link claims work that does not exist, which is worse than an empty box. Search that repository for an open PR or issue covering it first, and link that instead of filing a duplicate. 3. When the follow-up is out of scope, or needs a decision that is not yours to make, open an issue in that repository instead, link that, and say so in the PR body. Do not push a speculative PR into another repository just to fill a line here. 4. Do not tick "No downstream repository is affected" to make the checklist go away. If you are unsure, leave every box empty and say so in the PR body, so a human decides. --> - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### 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 fix(securitygroups): a SecurityGroup with attachments and no rules no longer leaves an invalid CiliumNetworkPolicy behind; its backing policy is now accepted by Cilium and still allows or denies nothing. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **Bug Fixes** * Membership-only SecurityGroups now round-trip without displaying ingress or egress rules, while remaining usable without triggering default-deny behavior. * SecurityGroups with an explicitly configured empty ingress rule continue to retain that rule when read back. * This behavior depends on Cilium’s `enable-non-default-deny-policies` option being enabled; when disabled, Cilium applies default deny to every policy. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
9e8e10c307 |
fix(backups): re-render the default backup objects when the S3 endpoint changes (#5230)
## What this PR does Refs #5205. The S3 endpoint the platform backups use is copied twice, and neither copy is refreshed after `publishing.host` changes. The COSI sidecar writes `BucketInfo` once per `BucketAccess`, so the credentials Secret `bucket-cozy-backups-system-credentials` rendered from it keeps the old endpoint. The Velero BSL and the default Strategy CRs keep whatever endpoint the last render of `backupstrategy-controller` saw. The default objects gate only acted on missing objects, so backups kept going to the old host and nothing reported it. The gate now also forces a render when a copy is stale: - the bucket's `<bucket>-system` release, when the credentials Secret's endpoint differs from the COSI Secret it is rendered from; - `backupstrategy-controller`, when the endpoint an object was rendered with differs from the credentials Secret's. The chart stamps the rendered endpoint on the BSL and on every default Strategy as `backups.cozystack.io/endpoint`, because the endpoint itself sits at a different path in every kind. Objects without the annotation count as stale until a render stamps it; `MinForceInterval` bounds the forces. Stale credentials are forced before the BackupClass and the routed objects are read, so an absent BackupClass or an unreadable Strategy still fails the check but does not keep the old endpoint in the credentials Secret. A `BucketInfo` without an endpoint is not compared, since rendering from it would write an empty endpoint or fail the bucket release. Repairing missing objects keeps working while the credentials comparison is stale or fails, and a `systemSecretName` that is not derived from a COSI Secret (no `-credentials` suffix, or the raw COSI Secret itself) is not compared at all. RBAC is unchanged: the controller already holds cluster-wide `get` on Secrets. No new metric: nothing would consume it. What this does not do: the COSI Secret still holds the endpoint the `BucketAccess` was granted with, so after a host change the endpoint follows only once an operator deletes the `BucketAccess` and forces `bucket-cozy-backups` to recreate it (this issues new S3 keys). From there the gate replaces the remaining manual steps of the recovery described in the issue. Automatic re-grant is left for a separate issue, and the operator runbook goes to the website, hence `Refs` rather than `Fixes`. Known limitation: the credentials comparison runs only when `backupStorage.systemSecretName` is `bucket-<bucketName>-system-credentials`, the Secret the forced `bucket-<bucketName>-system` release renders. If an operator sets `bucketName` and `systemSecretName` inconsistently, the comparison is switched off rather than forcing a release that never rewrites the compared Secret, so a stale endpoint in that Secret is not repaired. Repairing a missing credentials Secret still forces the release derived from `bucketName`, as before this PR. Tested with unit tests for the gate (including the comparison normalisation shared with the chart helpers), helm-unittest for the annotation and the wiring, and a bats guard that every rendered Strategy CR and the BSL carry the annotation. On a live cluster, a server-side render of the chart produced exactly the annotation the gate derives from the real credentials Secret, so the steady state does not force anything. ### Screenshots Not a UI change. ### Downstream repositories - [ ] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: an operator runbook for changing `publishing.host` with platform backups enabled (re-grant the `BucketAccess`, then let the gate converge; restart ClickHouse pods that read the credentials from environment variables). Not filed yet, pending approval of the text. - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note fix(backups): the backup controller now re-renders the Velero BSL, the default backup strategies and the platform bucket's credentials Secret when their S3 endpoint is stale, so after the platform bucket's BucketAccess is re-granted for a new publishing.host, backups move to the new endpoint without forcing releases by hand. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **New Features** * Backup strategies and storage locations now record their storage endpoint, enabling detection and repair of outdated endpoint settings after bucket access changes. * Bucket credentials and backup objects are refreshed independently when their endpoints are missing or out of date. * **Documentation** * Clarified when endpoint changes trigger updates and how suspended releases are handled. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
7097cc5cda |
feat(release): make backports automatic with backport-batch (#5106)
## What this PR does Backports become automatic. Fix merged to `main` with `fix` title, or `security` for fix that comes through security advisory, reaches release lines through batch that runs on Monday and Thursday, newest line first, nobody requests, labels or opens backports by hand. Batch runs for two newest lines with stable release (`released-lines` in policy block) and every line branched after them that has no stable release yet: with 1.6 and 1.7 released, `release-1.8` created at `v1.8.0-rc.1` joins them, and `v1.8.0` drops 1.6. Line counts as released once `vX.Y.Z` tag without pre-release suffix exists on origin. Rules are in `docs/release/backports.md`, `cmd/backport-batch` applies them, `.github/workflows/backport-batch.yaml` runs it. Design is in cozystack/community#114, merge shape of each original in cozystack/community#119. - `backport-batch run --line release-X.Y` takes PRs merged to `main` since line branched (title and body read from merge commit) and skips what rules exclude: other types and `deps`, breaking changes, platform migrations, `targetVersion`, changed CRD documents, API changes that API review gate calls sizeable (batch runs `internal/apigate` itself whenever PR changes a file the gate parses: `pkg/apiserver/apiserver.go`, an ApplicationDefinition, or YAML under `packages/` or `internal/` naming `CustomResourceDefinition` or `APIService`), and on older line what next newer line doesn't carry yet. The rest goes onto `backport-batch/<line>-<date>` in merge order. PR merged to `main` with merge commit goes as its own commits picked with `cherry-pick -x --signoff`, so each keeps its author, message and sign-offs and gets sign-off of whoever runs the batch (with `-m 1` author was whoever merged on `main`), merges of `main` into PR branch are left out, and merge commit joins them to the batch with original's merge message and `Backported-from:` trailer. Squash-merged PR goes as one pick. Conflict on any commit takes branch back to where it was before that original, it's listed with the commit that failed, run goes on. `--push` opens or updates draft PR, `--continue` carries on open batch PR as fast-forward only, PR body it didn't write is never rewritten. Same-day run over batch branch whose PR never got opened refuses and names `run --line <line> --onto <head> --push`, which continues it. Run or `--defer` that resets local batch branch over commits only it has prints `git branch` command that restores them. - `run --defer <N> --reason <why>` takes original out of open batch (usually the one failing CI is pinned on). It rebuilds branch replaying batch unit by unit without it, so merges and pushed conflict resolutions keep their shape, and only this rebuild pushes with `--force-with-lease`. Deferred original comes back in next batch. - Line carries something only if its own history shows it: picks whose `-x` line, the one git appends, names PR's merge commit or every commit of its own, or pick that changes nothing. Picked commits keep their messages and batch merge carries PR body, so text in them (`-x` lines, `Backported-from:`, `Backport of #N`) counts only on commits from before `batch-only` day in policy block, where it records old hand backports and batches. Otherwise text in a merged fix could mark another fix as already backported, and it would never reach the line. PR against line never counts. Open batch PR counts only from this repo and from author with write access or the batch's own bot (`BACKPORT_BATCH_BOT`, exact login, `cozystack-ci[bot]` when unset, so maintainer's run by hand continues scheduled batch instead of opening second one), and is read the same way. Actions bot isn't trusted anymore, any workflow token writes as it. - Any failed GitHub API or git call stops the run with message naming the call, no retries. Failed permission lookup used to count batch PR out as look-alike, so `--continue` opened second batch PR and `notify` posted second comment; now `run`, `check`, `verify` and `notify` exit 2 and write nothing. - Policy applies fully from `release-1.7`. `release-1.6` takes only fixes merged from 2026-10-26, older ones need `backport/include`. Start days are in `backport-policy` block on the policy page, test keeps page and code in sync. - `backport-batch check --cut` replaces `backport-audit` as gate before patch cut and before every rc after the first, it also fails while a fix is only on open batch PR. Plain `check`, which scheduled run uses, lets those through. `backport-batch fold` checks conflict resolution in the same shape: merge on batch head whose second parent is straight line of picks of PR's own commits in order, each with its `-x`, only PR's files (one pick for squash). `backport-batch verify` holds every original on batch to that shape, clean picks included, and `pr-labeler.yaml` runs it on every push to batch PR: `pull_request_target` so it reaches `release-*`, tool built from `main`, batch head fetched as data, read-only token. Batch PR body says per original how many commits it brought and which picks differ from their commits. `backport-batch notify` reports batch that is still open from previous run and deferred conflicts in one comment on batch PR, edited in place, with `BACKPORT_ALERT_TEAM` mention. - `hack/backport-batch-scheduled.sh` is what the workflow runs and maintainer can run by hand (`--dry-run` changes nothing on GitHub): for each line newest first `run --continue --push`, `check`, `notify`. It pushes with `BACKPORT_BATCH_TOKEN` only and fails without it, never `GITHUB_TOKEN`, because its pushes don't start CI. Workflow runs it as cozystack-ci App: it mints token for this repo only with Contents and Pull requests write, passes it as `BACKPORT_BATCH_TOKEN`, commits as `cozystack-ci[bot]`, and sets `BACKPORT_BATCH_BOT` so the tool trusts that bot's batch PR and comment. Job timeout is 30 minutes, under the token's hour. - App has no workflows permission, so workflow runs the script with `--no-workflow-files`: original that changes `.github/workflows/` isn't picked and waits on batch PR for maintainer, listed with its workflow files in body and in notify comment. It's never a conflict. `check` warns about it while it waits and `check --cut` fails on it. Maintainer brings it over with own token by `run --continue --push` without the flag, or takes it out with `--defer`. - Deferred conflicts and failed batch CI wait for maintainer. `notify` keeps one comment on batch PR listing stalled batch, conflicts and workflow changes, mentioning `BACKPORT_ALERT_TEAM` (team or login) when it's set. Failed batch CI isn't in the comment, it shows on batch PR checks, and `check --cut` fails while batch is unmerged. - Two steps that need judgement (resolve conflict, pin failed CI on original and defer it) are written as runbooks in `docs/release/backport-tasks/`: inputs, the only allowed output, check it must pass before push, what never to do. - `backport/include` and `backport/skip` let maintainer override rules for single PR, they are new `backport/` category in `labels.yml`. Skip wins over include, if open batch already picked it `--defer` takes it out. - Text written by other people (titles, release notes, reasons, file names) goes to batch PR body only inside code spans or release-note block, control, bidi and zero-width characters are dropped, file names in deferred block included, git args go after `--end-of-options`, no shell. - Removed: `cmd/backport-audit`, `backport.yaml`, `kind/backport` and `kind/backport-previous` labels with aliases and stale exemption, trailer-check exemption for bot branches. `Commit trailers` job exempts only `backport-batch/*` branches of this repo, changelog instructions read originals from batch commits. Exemption lives in main's `pre-commit.yml`, and batch PR runs its line's copy: `release-1.7` has its own copy that exempts only old `backport-<pr>-to-<branch>` branches, `release-1.6` has no such job. So on `release-1.7` picked commit with bad trailer fails batch CI until line gets main's copy. - `hack/close-manual-backport.sh` runs from `pr-labeler.yaml` on `opened` and closes PR against `release-*` from outside contributor (association contributor, first-time contributor or none, permission read or none). Owners, members, collaborators, anyone with triage or more and bots are left alone. When GitHub's answer on author's permission can't be read, it closes nothing and fails the job naming the failed read. Maintainer keeps release-only fix by reopening it. Release-only PRs are occasional and opened by maintainers, for fix with no counterpart on `main`, or one that on `main` came inside another PR or was written for `main`; if its counterpart on `main` is a fix the batch would take, the batch skips it once picking it changes nothing on the line, otherwise maintainer labels it `backport/skip`. - `docs/release.md` is split into pages under `docs/release/`, PR template doesn't ask for `kind/backport` anymore. `security` type is added to commit format in `docs/agents/contributing.md`, PR template, Gemini review guide and labeler's list (labeler maps no `kind/*` to it, `labels.yml` has no fitting one). - `SECURITY.md`, `docs/security/incident-response.md` and `GENERAL_TECHNICAL_REVIEW.md` now say two latest minor releases are supported, same window the batch runs for, and link the backport policy for which fixes go there. Dry runs without push, on 2026-11-06, with `--no-workflow-files` as the workflow runs it: `lines` gives `release-1.7` and `release-1.6`. On `release-1.7` batch picks 12 fixes, defers 3 conflicts (#4756, #4867, #5082), leaves #4888 and #4971 to a maintainer because they change workflows, and skips 49. On `release-1.6` it picks #5088, defers 3 conflicts (#5071, #5086, #5087), leaves #5142 to a maintainer, and skips 590. `verify` passes both batches. Setup after merge: no new secret. Batch runs as cozystack-ci App from existing `COZYSTACK_CI_APP_ID` and `COZYSTACK_CI_PRIVATE_KEY`, job fails when either is missing. App's installation already has Contents and Pull requests write on all org repos, and no Workflows is needed: PRs that change `.github/workflows/` wait for maintainer, who brings them over with own token as "Changes to workflows" in `docs/release/backports.md` says. Today that's #4888 and #4971 on `release-1.7` and #5142 on `release-1.6`. Set `BACKPORT_ALERT_TEAM` to a team or a login (for example `cozystack/maintainers`): unset, batch comment mentions nobody and nobody is notified. Once this PR is merged, `Backport batch shape` can be required check in the release lines ruleset (`release-*` excluding `release-*.*.*`), with "Do not require status checks on creation" on, because `cut-prerelease.yaml` creates `release-X.Y` by push. `PR Auto-Label` with both new jobs runs on `pull_request_target`, so it needs #5135 sorted before 2026-12-02. `kind/backport*` labels have to be deleted by hand, label sync doesn't delete. ### Screenshots Not a UI change. ### Downstream repositories cozystack/community `contributors/README.md` lists commit types, so it needs `security` too, it has no backport label text. Website has no backport label instructions, and its links to `docs/release.md` carry no anchor, the page stays as index. Trigger map lists commit convention change for cozystack/ccp: this adds `security` type, but not message format or trailer, and `package-bump` writes only `chore(...)` commits and restates the trailer, so nothing changes there. - [ ] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: add `security` to commit types in `contributors/README.md` ### Release note ```release-note feat(release): backports are automatic. Fixes merged to main with fix or security title reach release lines through a batch built by cmd/backport-batch every Monday and Thursday, by the rules in docs/release/backports.md. The batch runs for the two newest lines with a stable release and for a line in its rc window: the release-X.Y branch the first rc creates joins at once, and its vX.Y.0 drops the oldest line. Features, chores, docs, dependency bumps, breaking changes, migrations, CRDs and API changes that the API review gate calls sizeable wait for the next minor. The policy applies fully from release-1.7, release-1.6 takes only fixes merged from 2026-10-26. Each original reaches the line as its own commits under a merge commit, keeping their authors and sign-offs. Maintainers override the rules for single PR with backport/include and backport/skip labels and take an original out of a batch with backport-batch run --defer. backport-batch check replaces backport-audit as the gate before a patch release and before a later rc. The label-driven backport workflow and kind/backport labels are removed. Backport PR opened by hand against a release branch by author with read access or less is closed automatically. The scheduled batch runs as the cozystack-ci App and needs no secret of its own; a fix that changes .github/workflows waits on the batch pull request for a maintainer, since the App may not push workflow changes. Release documentation now lives in one page per topic under docs/release/. ``` |
||
|
|
9fba8af69c |
test(redis): pin the release name in the Sentinel PDB hook for the longest release
The long-name case checked only that the Job name fits in 63 characters and that the Job targets the right PDB. A Job name that dropped the release, letting two releases' hooks replace each other, or a Role granting a different PDB would both have passed. Assisted-by: LLM Signed-off-by: Mattia Eleuteri <mattia@hidora.io> |
||
|
|
e92bc8664b |
fix(tests): keep two unit tests green after the release image restamp
The release build rewrites packages/*/values.yaml: the kube-ovn image tag becomes the Cozystack version and the traces collector becomes the first-party otelcol-tracing build. Two unit tests read exactly those fields, so every PR against release-1.7 has failed Unit & controller tests since the first rc, and release-1.8 would repeat it. Same change as #5179 on release-1.7. Assisted-by: LLM Signed-off-by: Marian Koreniuk <moriarti@cp.if.ua> |
||
|
|
a7f84242d1 |
fix(redis): keep three Sentinels for a zero or negative replica count
The operator runs three Redis pods when the count is zero or negative, but the chart treated any count up to 1 as the single-pod case. Such a cluster got one Sentinel and no Sentinel PDB, while three Redis pods ran under it. Assisted-by: LLM Signed-off-by: Mattia Eleuteri <mattia@hidora.io> |
||
|
|
fd9245f008 |
test(lineage): reject CAPK labels on objects that are not KubeVirt VMs
The bridge from a VirtualMachine to its KubevirtMachine is guarded by the object's API version and kind, but no test exercised that guard: weakening it to match on either field alone still passed, and let a labelled kubevirt.io Cluster or a VirtualMachine of another group resolve to the Kubernetes application. Assisted-by: LLM Signed-off-by: Mattia Eleuteri <mattia@hidora.io> |
||
|
|
55d6c52fab |
fix(kubernetes, monitoring): send tenant cluster metrics to the tenant's vminsert
The monitoring-agents chart reads vmagent.remoteWrite.urls as a list and takes the tenant label from global.target, while the kubernetes app still passed a single remoteWrite.url and vmagent.externalLabels.tenant. Both keys were dropped in silence, so the vmagent of every tenant cluster fell back to the chart defaults: it wrote to vminsert services in cozy-monitoring that do not exist inside the tenant cluster, queued the failed writes on the node disk, and labelled every series tenant="cozy-monitoring". No tenant cluster metric reached the tenant's Monitoring. The tenant label has to name the tenant that owns the cluster, which is not always the tenant whose Monitoring receives the data: a tenant without its own Monitoring inherits a parent's. Assisted-by: LLM Signed-off-by: Mattia Eleuteri <mattia@hidora.io> |
||
|
|
5f0da5a09a |
docs(mariadb): list the operator's Failed reason on the Complete condition
The reason list read as everything the operator writes on Complete, yet mariadb-operator also sets Complete=False with reason Failed when a run fails before or outside its Job. A reader taking the list as exhaustive would treat Failed as an unknown reason, or make it terminal, while the operator retries those failures. A table row pins that the driver keeps waiting on it. Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
c6c107fd08 |
docs(backups): state when the gate compares endpoints in the values reference
The values reference read as if the credentials endpoint were always compared and an object without the endpoint annotation never forced a render. Operators sizing the force counter or choosing a custom systemSecretName need both conditions spelled out. Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
69cea9ccbd |
fix(mariadb): keep the operator's message in deadline failures
The operator sets Complete=False with reason Failed and its own cause
in the message ("Error creating Job", "Backup not complete") when a
run fails before or outside its Job. Such a run waits out the
deadline, and the deadline failure kept only the status and reason,
so the BackupJob or RestoreJob ended without the one line that says
why.
Assisted-by: LLM
Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io>
|
||
|
|
ee5e51ee6c |
fix(backups): keep forcing objects that still lack the endpoint annotation
An object without backups.cozystack.io/endpoint stopped counting as stale as soon as one forced render had been requested, whether or not that render succeeded. A failed upgrade left the objects unannotated and the gate silent until the controller restarted, which also hid the climbing force counter meant to report exactly that failure. Such an object now stays stale until a render stamps it; MinForceInterval already bounds the cost. Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
9f51b9db04 |
fix(mariadb): report the operator Job's own failure on JobFailed
The operator's JobFailed condition message is only "Failed", and with the operator's default restartPolicy OnFailure the Job controller deletes the pod once the backoff limit is spent, before the operator sets JobFailed. Pointing the reader at the Job's logs therefore sent them to logs that no longer exist. The Job, which the operator names after the Backup or Restore, keeps its Failed condition with the reason and message, so the BackupJob or RestoreJob now carries those instead; a Job that cannot be read is named in the message rather than dropped. Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
dc909c778c |
fix(backups): compare the credentials endpoint only for the forced bucket's Secret
The gate forces bucket-<bucketName>-system, which renders the credentials Secret of that bucket's system user and nothing else. The COSI Secret name was derived from systemSecretName instead, so a value naming another bucket's Secret made a lagging endpoint there force the platform bucket release every throttle window without ever refreshing the Secret that was compared. Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
7e1fc7173c |
test(mariadb): cover the absent Complete condition and expired deadlines
Every first reconcile after the operator Backup or Restore is created sees no Complete condition, and the guards that keep that case from dereferencing nil could be dropped with the outcome tables staying green. The tables now also cover the deadline failure for a run that never reports a known reason, and read the job status back from the API, so a lost status write fails them instead of passing on the in-memory object. Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
bd2b6c4b49 |
fix(backups): leave the credentials Secret alone when BucketInfo has no endpoint
A BucketInfo without an endpoint differs from every credentials Secret that has one, so the gate forced the bucket release on every throttle window. That render cannot converge: an empty endpoint would be written into the Secret every driver reads, and with the key absent the template's trimPrefix fails and parks the release in Failed. Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
ccac0e17e9 |
fix(mariadb): fail backup and restore jobs whose operator Job failed
mariadb-operator reports a failed backing Job as Complete=True with reason JobFailed, and Complete=True alone was read as success. A backup whose dump or upload failed therefore ended Succeeded and left a Ready Backup pointing at an archive that does not exist, and a scheduled Plan kept producing such Backups; a failed restore ended Succeeded too. Success now requires reason JobComplete, and JobFailed fails the job whatever the status. Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> Assisted-by: LLM |
||
|
|
399ccd3f4a |
fix(backups): refresh stale credentials even when the routed objects are unreadable
The credentials endpoint comparison needs only the credentials Secret and the COSI Secret it is rendered from, yet its forced render was issued only after the BackupClass and every routed object had been read. A missing BackupClass or one unreadable Strategy therefore kept the old endpoint in the credentials Secret, which the projector hands to every driver, not just the one whose object failed. Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
ef7626a951 |
fix(backups): keep repairing missing default objects while credentials lag
The credentials comparison returned early when the credentials Secret was stale or the COSI Secret could not be read, so a missing default Strategy or BSL was no longer created on that tick, nor on any later one while the bucket release stayed suspended, kept failing, or the COSI Secret stayed unreadable. Repairing missing objects is what the gate did before the comparison existed, and it does not depend on the answer. Run the object check on every tick and force each release for what it renders, reporting a comparison error alongside instead of in place of the repair. Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
d0f47f7dd5 |
fix(backups): compare the credentials endpoint only for a Secret derived from COSI
backupStorage.systemSecretName may name a Secret the bucket chart does not render from a COSI Secret: the raw COSI Secret itself, which the projector accepts, or any Secret without the -credentials suffix. The COSI Secret name was then the source name unchanged, so the gate compared a Secret with itself and either reported it stale on every tick or failed the check, and stopped repairing missing default objects as well. Skip the comparison when there is no distinct COSI Secret or no endpoint key to compare. The gate compares the annotation with what the chart's endpoint helper renders, and the helper renders a present but blank endpoint as a bare https:// instead of falling back, so the gate has to compute the same value or its expectation and the chart disagree for that Secret. The gate's docs, metric help and log lines named only missing objects, so they did not cover a stale endpoint they now report. Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
cb3fcd3357 |
feat(operator): let the platform source trust a private registry CA (#5237)
## What this PR does The operator creates the `cozystack-platform` OCIRepository from its own command-line arguments and rewrites the whole object on every start; `cozystack-packages` copies that spec. When the platform source is a registry whose certificate is issued by a private CA (an internal pull-through cache in an air-gapped install, for example), there is no durable way to make Flux trust it: a `certSecretRef` patched onto the live object is dropped on the next operator restart, source-controller then fails TLS, and platform updates silently stop arriving. This adds `--platform-source-cert-secret` to the operator and `cozystackOperator.platformSourceCertSecret` to the installer chart. The named Secret in `cozy-system` is set as `spec.certSecretRef` on the generated OCIRepository, so it holds `ca.crt` for a private CA and/or `tls.crt`+`tls.key` for client certificate auth, with the Flux key layout. `cozystack-packages` inherits it through the existing spec copy. The flag is OCI only. `GitRepository` has no `certSecretRef` (Flux reads a Git CA from the `ca.crt` key of the `secretRef` Secret), so a Git platform source with the flag set is refused at startup instead of having its CA silently ignored. Tests: unit tests for the generated spec, a regression test that the CA survives the operator's update of an existing OCIRepository, a test that a Git source with the flag writes nothing, and a helm-unittest suite for the new chart value. ### 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. --> ### Downstream repositories <!-- Cozystack is upstream for repositories that are NOT kept in sync with it automatically, and nothing in CI compares the two sides, so a change here can break them silently. Which change forces what, and which file to touch, is the trigger map in docs/agents/contributing.md under "Downstream Repositories". Walk it before you tick anything. IF YOU ARE AN AI AGENT OR AN LLM, THIS IS PART OF THE TASK, NOT A FORM TO FILL IN: 1. Walk the trigger map against the actual diff of this PR, file by file. Do not decide from the PR title or from your memory of what you changed. 2. For every repository you tick, open the follow-up PR there and link it on the same line. A ticked box with no link claims work that does not exist, which is worse than an empty box. Search that repository for an open PR or issue covering it first, and link that instead of filing a duplicate. 3. When the follow-up is out of scope, or needs a decision that is not yours to make, open an issue in that repository instead, link that, and say so in the PR body. Do not push a speculative PR into another repository just to fill a line here. 4. Do not tick "No downstream repository is affected" to make the checklist go away. If you are unsure, leave every box empty and say so in the PR body, so a human decides. --> - [ ] No downstream repository is affected by this change - [x] [cozystack/website](https://github.com/cozystack/website) - follow-up: https://github.com/cozystack/website/pull/791 - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: The new installer value is optional, so `ansible-cozystack` is not reached. The website's air-gapped guide (`content/en/docs/next/install/kubernetes/air-gapped.md`) added the private CA to the nodes only, while Flux fetches the platform source itself; cozystack/website#791 adds a step for `platformSourceUrl`, `platformSourceSecret` and `platformSourceCertSecret`. ### Release note ```release-note feat(operator): the platform source can be served from a registry behind a private CA. Set `cozystackOperator.platformSourceCertSecret` in the installer to a Secret in `cozy-system` with `ca.crt` (and optionally `tls.crt`/`tls.key`); the operator sets it as `certSecretRef` on the `cozystack-platform` OCIRepository, so it survives operator restarts. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **New Features** * Added the `platformSourceCertSecret` setting for OCI platform sources. It allows a Secret containing certificates for private CA trust or client authentication to be configured separately from registry credentials. * The configured certificate Secret is applied to the OCI source and inherited by its package source. * **Configuration** * The setting is empty by default. Git platform sources do not support a separate certificate Secret; use the existing platform source Secret for Git TLS certificates. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
41507e36aa |
docs(kubernetes): say where worker registry mirrors are configured
The air-gapped note said in-guest image pulls honour no per-tenant mirror until a Phase 2 that has landed, so an operator setting up an air-gapped cluster would read that mirroring is unavailable and file an issue. It now says the Secret and the platform registries value are removed, that a Package still setting the value keeps installing, and that worker mirrors are set per pool through talos.registryMirrors of the KubernetesNodes resource. Assisted-by: LLM Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
0a448963e3 |
docs(installer): say a CA-only cert secret must be Opaque
kubernetes.io/tls requires both tls.crt and tls.key, so a Secret that carries only ca.crt is rejected under that type. Assisted-by: LLM Signed-off-by: Kirill Ilin <stitch14@yandex.ru> |
||
|
|
fbfc270c71 |
test(installer): tie each platform source flag to its own value
Both secrets were only ever set together, so a cert flag keyed on platformSourceSecret stayed green. A pull-through cache behind a private CA usually needs the CA without credentials, which is exactly the case such a slip breaks. The absence checks match the flag by prefix, since a whole-element comparison misses the flag rendered with any value. Assisted-by: LLM Signed-off-by: Kirill Ilin <stitch14@yandex.ru> |