Add helm-unittest suite asserting KC_HOSTNAME_ADMIN env, the extra
Ingress rule/TLS entry, and the appended HTTPRoute hostname are emitted
only when ingress.adminHost is set. Wire up the chart 'test' target.
Assisted-By: Claude AI
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
Add ingress.adminHost option to serve the Keycloak admin console and
admin REST API on a dedicated hostname, separate from the login/realm
hostname. When set, KC_HOSTNAME_ADMIN is configured and an additional
Ingress rule / HTTPRoute hostname routes the admin domain to the same
Keycloak service. Empty by default, keeping current behavior.
Assisted-By: Claude AI
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
## What this PR does
Raises OpenSSF Scorecard **Pinned-Dependencies** (currently **1/10**) by
having Renovate manage and pin container base images and GitHub Actions
to immutable digests.
[PR #2849](https://github.com/cozystack/cozystack/pull/2849) SHA-pinned
actions in 13 workflows, but the Scorecard check also scores **container
base images** — 58 unpinned `FROM` lines across **27 distinct images** —
which dominate the score and keep it at 1/10. #2849 also left
`build-main.yaml` and `release-e2e.yaml` actions unpinned, and nothing
in the Renovate config kept the newly-added action SHAs updated (they
were set to rot).
### Changes
- **`.github/renovate.json`**
- Add `dockerfile` and `github-actions` to `enabledManagers` (was
`gomod`-only).
- `pinDigests: true` for both managers — Renovate opens the initial "pin
to `@sha256:`" PR (including the two workflows #2849 missed) and keeps
digests fresh thereafter.
- Batch the initial pin + all digest-only refreshes into a **single
weekly PR** (`matchUpdateTypes: ["digest", "pinDigest"]`, scheduled
Monday). Frequently-rebuilt bases (alpine, debian, golang, distroless)
would otherwise trickle in one rebuild-triggering PR each and load the
shared CI runner. Real tag bumps (major/minor/patch) are intentionally
excluded from the group so they get individual review.
- Existing `do-not-merge/hold` label + `automerge: false` are unchanged,
so every PR still requires a manual merge.
- **`packages/system/bucket/images/s3manager/Dockerfile`** — pin
floating tags to concrete versions so digest tracking doesn't churn
endlessly: `golang:1` → `golang:1.26`, `alpine:latest` → `alpine:3.24`.
### Notes
- The bulk digest pin of the 27 images is left to Renovate's first run
(one grouped PR) rather than hand-edited here, keeping this PR to the
config + tag-hygiene prerequisites.
- Expected effect once the follow-up pin PR merges: Pinned-Dependencies
**1 → ~7–8**. The remaining `downloadThenRun` / pip / npm items cap it
below 10.
### Release note
```release-note
ci(renovate): enable Renovate digest pinning for Dockerfile base images and GitHub Actions to improve the OpenSSF Scorecard Pinned-Dependencies score
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Improved automated dependency management for container images and
GitHub Actions, including clearer update grouping and digest pinning.
* Updated container base images to newer, fixed versions for more
predictable builds and deployments.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What this PR does
The TenantNamespace registry helpers (`filterAccessible`,
`hasAccessToNamespace`, `hasAccessToNamespaceForUser`) returned plain
`fmt.Errorf` values, which the API server coerces into a generic `500
InternalError` regardless of the actual failure. This PR types the error
paths so clients get accurate status codes: a request without user
identity in context now returns `401 Unauthorized`, and a RoleBinding
list failure returns `500 InternalError` with a properly structured
`Status` body that preserves the underlying cause.
Additionally, `Get` now repackages a NotFound from the backing Namespace
lookup under the `tenantnamespaces` GroupResource, so the `Status`
details no longer leak the backing `namespaces` resource identity.
The `Watch` goroutine error path was audited as part of this change:
access-check failures there are logged and the event is skipped, so no
untyped error escapes to the client from that path. No changes were
needed.
All changed error paths are covered by new tests (helper-level plus
end-to-end through `Get` and `List`), using an interceptor-based fake
client that fails List only for RoleBindings.
Closes#2521
### Screenshots
No UI changes.
### Release note
```release-note
refactor(api): TenantNamespace API now returns 401 Unauthorized for requests without user identity and a structured 500 InternalError for RBAC lookup failures, instead of a generic 500
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved REST error handling to return standard Kubernetes API error
types, including proper scoping for missing tenant-namespace resources,
unauthorized requests when no user identity is present, and internal
failures when RoleBindings can’t be listed.
* **Tests**
* Expanded typed-error test coverage for access checks and listing
paths, including scenarios for missing user context, RoleBinding list
failures, and NotFound responses that surface the expected resource
details.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What this PR does
Two fixes to the tenant chart's `pre-delete` cleanup hook (the Job that
deletes a tenant's HelmReleases when the tenant is removed).
**1. Grant the `watch` verb so the hook stops hanging.** The hook runs
`kubectl delete helmreleases ... --wait=true`. Since Kubernetes 1.25
that flag opens a watch on the target resources to block until
finalization. The hook's Role granted only `get`, `list`, `delete`, so
the watch was rejected with HTTP 403, `kubectl delete` hung
indefinitely, the Job never finished, and tenant deletion stalled on the
pre-delete hook. Adding `watch` brings the Role in line with the
`kubernetes` app chart's cleanup Role, which already grants it for the
same `--wait` deletes.
**2. Replace the unmaintained image.** The Job ran kubectl from
`bitnami/kubectl:latest`. The bitnami Docker Hub catalog has moved to a
legacy/sunset state, so that pull is at risk of breaking — which would
stop the hook from starting at all — and `:latest` leaves the kubectl
version unpinned. It now uses `docker.io/clastix/kubectl:v1.32`, the
version-pinned image already used by every other first-party
cleanup/delete hook in the repo (kubernetes, keycloak-configure,
dashboard, mariadb). That image is Alpine-based and ships only
`/bin/sh`, so the hook script (pure POSIX) now invokes `/bin/sh` instead
of `/bin/bash`.
A helm-unittest suite pins all three invariants (watch verb, image,
shell) so none can regress.
### Screenshots
N/A — no UI impact.
### Release note
```release-note
fix(tenant): grant the watch verb to the cleanup Role and move it to a maintained kubectl image so tenant deletion no longer hangs on the pre-delete hook
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Improvements**
* Expanded pre-delete cleanup RBAC permissions to include watching
HelmRelease resources.
* Hardened the cleanup Job runtime security settings for stronger
container confinement.
* Pinned the cleanup Job to a specific kubectl image version and
switched the command interpreter for safer execution.
* **Tests**
* Added/extended automated validation for the pre-delete cleanup hook,
covering RBAC rules, kubectl image pinning, command usage, and
securityContext hardening.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What this PR does
Updates kubevirt-operator from v1.8.2 to v1.8.4. This backports the VMI
checksum status-field validation fix (uint32 range) that Kubernetes 1.36
requires — without it, strict CRD numeric-format validation leaves VMIs
stuck in `Scheduled`. The release also carries assorted bug fixes and
CVE remediations. The v1.7.x line is skipped (live-migration regression,
kubevirt/kubevirt#16386).
The KubeVirt custom resource is unchanged — upstream ships a
byte-identical CR across these versions.
Verified on a dev cluster: all virt-* components roll out to v1.8.4 and
become ready.
Closes#2769
### Screenshots
Not applicable — no UI changes.
### Release note
```release-note
fix(kubevirt): update KubeVirt to v1.8.4; fixes VMIs stuck in Scheduled on Kubernetes 1.36 (strict CRD numeric-format validation of VMI checksum status fields)
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated the KubeVirt operator version from v1.8.2 to v1.8.4, including
the corresponding deployment configuration and operator
image/environment version bumps.
* Adjusted the operator update process to download the manifest using
v1.8.4 while skipping v1.7.x.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What this PR does
Completes the Go-toolchain modernization for first-party images — the
build-time counterpart to #2852, which raised the root and `api/`
modules to Go 1.26.4.
1. **First-party image Go modules → go 1.26.4** (`token-proxy`,
`kube-ovn-webhook`, `kubevirt-csi-driver`): raise the `go` directive and
refresh dependencies. `kube-ovn-webhook` moves `k8s.io/*` 0.26 → 0.36.2
(only long-stable admission/core API is used); `kubevirt-csi-driver`
keeps its existing replace-based k8s alignment at 0.36.0 (main's
refactor owns that module's pin) and raises the `go` directive, with the
`golang.org/x/net` 0.56.0 security bump — which clears the reachable
GO-2026-5026 — reapplied. Adds two `.gitignore` files so the
locally-built binaries can't be committed.
2. **Go builder images → `golang:1.26`** across 8 images still on
EOL/behind toolchains (golang 1.20, 1.20.6, 1.23.4, 1.24, 1.25):
`cluster-autoscaler`, `kubevirt-cloud-provider`, `redis-operator`,
`multus-cni`, `keycloak-operator`, `objectstorage`, `kilo`,
`linstor-csi`. The builder image tag — not the go.mod minimum — sets the
standard-library version baked into the binary, so these still shipped
unpatched stdlib on a plain rebuild.
Verified: `GOOS=linux go build`/`go vet` pass for all three modules and
`go mod tidy` is a no-op; the three biggest builder jumps
(redis-operator, kubevirt-cloud-provider, cluster-autoscaler — all
formerly Go 1.20.x/1.23.x) were verified with a local `docker build`;
the remaining five (1.24/1.25 → 1.26) are covered by CI image builds.
### Release note
```release-note
chore(platform): raise the Go toolchain to 1.26 across first-party images to clear standard-library security advisories
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated several container build environments to a newer Go release for
consistency across Kubernetes-related components.
* Refreshed module and dependency versions in a few services to keep
builds current.
* Expanded ignore rules for generated image artifacts so build outputs
aren’t tracked.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What this PR does
Every migration that stamps the `cozystack-version` ConfigMap must carry
the `platform.cozystack.io/no-delete=true` label so the
`cozystack-no-delete-guardrail` ValidatingAdmissionPolicy guards it. The
chart template renders the labeled ConfigMap only on first install, so
each upgrade-time stamp has to re-emit the label by hand — migration 43
had to inline-copy migration 42's heredoc to avoid a label-less apply by
the same field manager stripping it. The bug class was patched
per-migration, not eliminated.
This extracts the stamp into a shared, sourced helper
(`render_cozystack_version_manifest` + `stamp_cozystack_version`) under
`images/migrations/migrations/lib/`, and routes migrations 42, 43, 44
and the `run-migrations.sh` bootstrap path through it. The labeled
manifest now has a single definition, so future migrations cannot drift
back to a label-less apply.
The upgrade path is behavior-preserving: the rendered manifest is
byte-identical to the previous heredocs (pinned by a golden unit test).
The bootstrap path in `run-migrations.sh` previously created the
ConfigMap without the label — it now carries it like every
migration-driven stamp.
Adds `hack/cozystack-version-stamp.bats` (8 tests) covering the helper:
label presence, ConfigMap name, quoted-string version type, namespace
default and override, required-argument guard, and the byte-exact golden
manifest.
Closes#2781
### Release note
```release-note
fix(platform): always stamp the platform.cozystack.io/no-delete label on the cozystack-version ConfigMap, including the migration bootstrap path, so deletion protection cannot be silently dropped
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Release Notes
* **Tests**
* Expanded validation to confirm the version-stamp manifest is parseable
YAML, includes the required no-delete label, targets the correct
`cozystack-version` ConfigMap, and quotes the version value correctly.
* Added coverage for default and overridden namespaces, argument
validation failures, and a golden “byte-for-byte” render check.
* Added a guardrail test to prevent bypassing the shared stamping logic
by direct `kubectl` ConfigMap stamping.
* **Refactor**
* Centralized `cozystack-version` rendering and stamping into a shared
helper and updated migrations and the migrations runner to use it
consistently.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What
Rebuild the kamaji image and force the fixed versions of three Go
modules whose advisories are compiled into the manager binary. Two build
changes:
- Advance the build source from `26.3.5-edge` to `26.3.6-edge`,
recompiling on the current `golang:1.26` toolchain (1.26.4) to close the
Go stdlib advisories.
- After applying the source patches and before `go build`, run `go get
golang.org/x/net@v0.55.0 golang.org/x/crypto@v0.52.0
go.opentelemetry.io/otel/sdk@v1.43.0 && go mod tidy` to pull the patched
module versions into the build.
## Why
The pinned image is flagged for a set of CVEs that fall into three
groups:
- 16 OS-package findings (libpython, libexpat, gnutls, krb5, sqlite,
curl, libgcrypt, libcap, nghttp2). The base is
`gcr.io/distroless/static:nonroot`, which ships no OS packages, so these
do not apply to the image — false positives.
- 1 `stdlib` finding: the binary was compiled with a go1.26 patch older
than 1.26.4. The `26.3.6-edge` rebuild on the current toolchain closes
it (crypto/x509 CVE-2026-27145, mime CVE-2026-42504, net/textproto
CVE-2026-42507).
- Go-module advisories that, unlike the OS-package noise, are genuinely
present in the compiled binary. `26.3.6-edge` pins `golang.org/x/net
v0.51.0`, `golang.org/x/crypto v0.49.0` and
`go.opentelemetry.io/otel/sdk v1.41.0`, all carrying published
advisories:
- `golang.org/x/net` < 0.55.0: CVE-2026-42506, CVE-2026-42502,
CVE-2026-39821, CVE-2026-25680, CVE-2026-25681, CVE-2026-27136 (plus
CVE-2026-33814, fixed at 0.53.0). Target 0.55.0.
- `golang.org/x/crypto` < 0.52.0: 13 advisories in
`golang.org/x/crypto/ssh` (e.g. CVE-2026-39827, CVE-2026-46595,
CVE-2026-46598). Target 0.52.0.
- `go.opentelemetry.io/otel/sdk` < 1.43.0: CVE-2026-39883
(GHSA-hfvc-g4fc-pqhx), a PATH-hijack on BSD/Solaris only; the affected
code path does not run on the Linux distroless target, but the bump
clears the finding at no runtime cost. Target 1.43.0.
A source-version bump cannot close the module advisories: no kamaji edge
tag up to `26.6.4-edge` ships the fixed module versions (it still pins
x/net 0.53.0, x/crypto 0.51.0, otel/sdk 1.41.0), and the tags that
advance the k8s line to 1.36 regress tenant control-plane RBAC. Forcing
the modules during the build is the minimal correct lever, and the
overlay already triggers a fresh compile, so it subsumes the stdlib
rebuild.
## Verification
Built the image source end to end: extracted `26.3.6-edge`, applied the
patch, ran the overlay (`go get` + `go mod tidy`, clean), and compiled
with `CGO_ENABLED=0 go build -a -o kamaji main.go`. The build succeeds
and `go version -m` on the binary embeds `golang.org/x/net v0.55.0`,
`golang.org/x/crypto v0.52.0` and the `go.opentelemetry.io/otel` set at
v1.43.0. The source has no `vendor/` directory, so `go get` + `go mod
tidy` is sufficient. Advisory IDs and fixed boundaries verified against
the OSV database.
After this change the shipped binary carries no Go advisory with an
available fix; the only residual scanner entries are in
`k8s.io/kubernetes` with no upstream fix, which no version bump can
close.
Closes#2885
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated the Kamaji image version to a newer patch release.
* Refreshed several bundled Go dependencies to newer pinned versions
before building.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What this PR does
Fixes two failure modes in the COSI control plane built from upstream
container-object-storage-interface v0.2.2, both carried as image
patches.
**BucketClaim never converges to ready (#3032).** The controller does
not watch Bucket objects, and the generic controller drops no-op resync
deltas, so a BucketClaim whose backend Bucket flips to ready *after* the
first reconcile stayed `bucketReady=false` indefinitely — BucketAccess
was never granted and the consuming app (bucket, harbor) got no
credentials. The existing re-read of the live Bucket only ran during a
reconcile that nothing re-triggered. The controller now returns an error
while the Bucket is not ready, forcing a rate-limited requeue that
re-reads the Bucket until its readiness propagates, so the claim
converges deterministically instead of racing the async sidecar.
**Slow provisioner failover on pod recreate (part of #2429).** The
controller and the per-driver sidecar run single-replica, so leader
election adds no availability — only failover latency. The upstream 150s
lease made a recreated provisioner pod stall reconciliation for up to
~150s. The lease is lowered to the standard Kubernetes values
(15s/10s/2s), so a recreated pod resumes in ~15s. The stale unix-socket
CrashLoop in #2429 was already resolved by the seaweedfs-cosi-driver
v0.3.1 self-heal; the silent "Bucket ready with no backend bucket"
finding on that issue is a separate driver bug and is left tracked
there.
Coverage: a unit test in the patched controller pins the
requeue/propagation contract (fails without the requeue), and the
bucket/harbor e2e suites now assert `bucketReady=true` on a tight bound
instead of tolerating the lag, with scoped diagnostics on the failure
path.
Closes#3032
Refs #2429
### Screenshots
N/A — no UI changes.
### Release note
```release-note
fix(objectstorage-controller): converge BucketClaim readiness to the backend Bucket and speed up single-replica COSI provisioner failover
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved object storage bucket readiness propagation so bucket claims
now track the backend bucket’s actual `bucketReady` status and requeue
when readiness isn’t yet observed.
* Reduced and made readiness waits more reliable in end-to-end checks,
with explicit match conditions and clearer debug output (including claim
YAML, backend bucket list, and controller pod status).
* Shortened leader-election timing to speed up recovery after pod
restarts.
* **Chores**
* Updated automated PR labeling to map the object storage controller
scope to the storage area label.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What
Make it unambiguous where each kind of contribution lands:
| Contribution | Destination |
|---|---|
| Bug | issue here (`kind/bug`) |
| Concrete, scoped feature | issue here (`kind/feature`) |
| Question / early idea | GitHub Discussions |
| Cross-cutting / architectural change | design proposal in
cozystack/community |
| Governance / process / community | cozystack/community |
## Changes
- Add `.github/ISSUE_TEMPLATE/config.yml` — a chooser
(`blank_issues_enabled: false`) linking to Discussions, the community
design-proposal process, community governance issues, and chat.
- Add `.github/ISSUE_TEMPLATE/feature_request.md` (`kind/feature`) with
an up-front gate (question → Discussion; cross-cutting → design
proposal) and a scope checklist.
- `CONTRIBUTING.md`: add a "Where do I file?" routing table.
- `README.md`: feature requests now point at issues instead of a
Discussions category, reconciling a contradiction with the actively-used
issue tracker.
## Notes
- `blank_issues_enabled: false` removes the blank-issue escape hatch to
keep triage clean — easy to flip if you'd rather keep it.
- Pairs with a companion PR in cozystack/community (routing table +
dead-link fix).
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Added “Where do I file?” guidance to help route bugs, scoped feature
requests, questions/early ideas, cross-cutting design proposals, and
community/process topics.
* Updated the README “Contributions” section with clearer links and
pointers to the right place for each request type.
* **New Features**
* Added a structured “Feature request” issue template to collect
consistent, scoped details.
* Disabled blank issue submissions and provided curated entry points for
common support and discussion paths.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What this PR does
`packages/apps/kafka` rendered the Strimzi `Kafka` CR with
`entityOperator.topicOperator: {}` / `userOperator: {}` and no
`resources`. Tenant namespaces ship a `LimitRange` that defaults
containers to `memory: 128Mi`, so the topic-operator and user-operator
JVM containers (Kafka 3.9.1 + fabric8/vertx) are **OOMKilled (exit
137)** on startup. The `<cluster>-entity-operator` Deployment never
becomes Ready (CrashLoopBackOff), so:
- `KafkaTopic` / `KafkaUser` CRs never reconcile — topic creation
effectively fails;
- the cluster-operator logs `Exceeded timeout of 300000ms while waiting
for Deployment ...-entity-operator ... to be ready`;
- on teardown, `KafkaTopic`s get stuck permanently with the
`strimzi.io/topic-operator` finalizer (no operator left to clear them),
blocking namespace deletion.
The Kafka broker + ZooKeeper come up fine — only the entity-operator
dies. The `apps.cozystack.io/Kafka` schema exposes no field for
entity-operator resources, so there is no user-side workaround.
## Fix
Set explicit `resources` (requests `256Mi`/`100m`, limit `512Mi` memory)
on `entityOperator.topicOperator` and `userOperator` so they no longer
inherit the 128Mi namespace default. Adds a `helm-unittest` assertion
for the rendered limits.
## Testing
Reproduced on a clean cluster (Cozystack v1.4.3 and v1.5.0-rc.2; Strimzi
0.45.1, Kafka 3.9.1): both entity-operator containers `OOMKilled` at
128Mi → CrashLoopBackOff → `KafkaTopic` never `READY`. After bumping to
512Mi the entity-operator rolls cleanly (both containers Ready, 0
restarts) and the `KafkaTopic` reconciles to `READY=True`.
### Release note
```release-note
fix(kafka): give entity-operator (topic/user-operator) explicit resources so they no longer inherit the 128Mi tenant LimitRange default and OOMKill, which left KafkaTopics/KafkaUsers unreconciled.
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Kafka topic and user operators now use explicit CPU and memory
requests and limits, avoiding reliance on namespace-level defaults.
* **Tests**
* Added regression coverage to verify the Kafka entity operator’s topic
and user operator memory limits are explicitly set (512Mi).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What this PR does
Removes the `Release E2E` workflow
(`.github/workflows/release-e2e.yaml`), which ran the full bats suite on
every release tag.
**Why it's redundant.** `release-e2e.yaml` was a non-blocking alarm —
its own header states *"a failure here is an alarm, not a release
blocker."* The coverage it provided is already delivered by the
release-cut PR: the "Prepare release" commit bakes image digests into
`packages/core/` (installer, platform, testing) and other packages, and
`select-e2e.sh`'s full-suite pattern escalates any `packages/core/`
change to the **full** suite. So the release PR already runs the whole
suite against the commit the tag will point at.
**Why now.** The workflow has never been green since it was added
(2026-05-02) — every tag run (`v1.5.0-rc.2`, `-rc.3`, `v1.5.0`) failed
at the build step. Even after #2973 fixed the registry login earlier
today, the next run still failed at *Build Talos image*. A
perpetually-red, non-gating duplicate is pure noise.
**Changes**
- Delete `.github/workflows/release-e2e.yaml`.
- Drop `release-e2e` from the full-suite pattern in
`hack/select-e2e.sh`.
- Repoint the workflow-trigger unit test in `hack/select-e2e_test.bats`
to `pull-requests.yaml` (the remaining E2E workflow), preserving
"workflow edit → full suite" coverage. All 11 `select-e2e_test.bats`
cases pass.
- Update `docs/agents/e2e-testing.md` to describe the release-cut PR as
where the full suite runs.
Refs #2397.
### Release note
```release-note
ci(tests): remove the redundant Release E2E workflow; the full E2E suite already runs on the release-cut PR
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Removed automated release end-to-end testing workflow
* Updated E2E test selection logic to reflect testing infrastructure
changes
* **Documentation**
* Updated E2E testing procedures documentation to reflect current
testing approach
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
While the backend Bucket is not ready the controller returns an error to
force a requeue, but that error is only logged at klog.V(3) and is
suppressed at default verbosity, so an operator cannot see why the claim
is stuck. Record a WaitingForBucket Warning event on the BucketClaim on
each requeue (event aggregation folds the repetition) and still return
the error so the requeue happens as before. Pin the requeue contract in
the test by asserting the error carries the stable "not ready yet"
substring, not merely that it is non-nil.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The two bucketaccesses waits used the bare jsonpath form, which also
matches the literal "false"; require =true so a never-granted access
fails the wait instead of passing against an ungranted object. Also
print the objectstorage-controller pod status in the bucketReady
failure block so controller-side issues are visible from the test log.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The kamaji source up to the 26.6.4-edge tag pins Go modules that carry
known advisories compiled into the manager binary: golang.org/x/net
below 0.55.0, golang.org/x/crypto below 0.52.0 and
go.opentelemetry.io/otel/sdk below 1.43.0. Unlike the distroless
OS-package findings, these advisories ship inside the Go binary and are
reported against the deployed image.
Force the fixed module versions during the build, after applying the
source patches and before compiling, so the binary embeds them. No edge
tag ships the fixes, and the tags that advance these modules also bring
the k8s 1.36 kubeadm change that regresses tenant control-plane RBAC, so
a source version bump is not a viable alternative.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The objectstorage-controller package ships the COSI control plane; its commits
use the objectstorage-controller scope, which had no area mapping and fell back
to area/uncategorized. Map it to area/storage alongside the other COSI/storage
scopes.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The bucket suite waited on '{.status.bucketReady}' without an expected value;
a bare jsonpath match is satisfied by the literal "false", so the wait passed
against an unready claim. Both suites also allowed 300s/600s, long enough to
tolerate the propagation race rather than catch it, so they stayed green
whether or not the BucketClaim ever converged.
Assert bucketReady=true on a 120s bound. Convergence is now controller-driven
(the controller requeues the claim until the backend Bucket's readiness
propagates) and completes within tens of seconds; a claim frozen by the
propagation race never converges and now fails the wait fast instead of being
masked.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The shipped kamaji binary was compiled with go1.26.3, which trivy flags
for the standard-library CVEs fixed in go1.26.4: crypto/x509
CVE-2026-27145, mime CVE-2026-42504, and net/textproto CVE-2026-42507.
The image base is distroless/static, so the remaining OS-package CVEs
from the scan do not apply to it.
Advance the build source from 26.3.5-edge to 26.3.6-edge, the next
patch on the same edge line (identical k8s.io/api v0.35.0 and
controller-runtime v0.22.4, staying clear of the k8s 1.36 line that
regresses tenant control-plane RBAC). The version change busts the
build-layer cache so the release rebuild compiles against the current
golang:1.26 toolchain, which resolves to 1.26.4 and closes the stdlib
CVEs.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The controller and the per-driver sidecar both run single-replica, so leader
election provides no high availability -- it only governs how quickly a freshly
recreated pod takes over. With the upstream 150s lease duration a recreated
provisioner pod stalls reconciliation for up to 150s while it waits out the
stale lease still held by the previous, now-deleted pod. Lower the lease timings
to the standard Kubernetes values (15s/10s/2s) so a recreated pod resumes
reconciliation in roughly 15s.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The dynamic-provisioning path re-reads the live Bucket after create and copies
its readiness onto the BucketClaim, but only during a reconcile. Nothing
re-drives that reconcile afterwards: the controller does not watch Buckets, and
the generic controller drops no-op resync deltas (reflect.DeepEqual), so once
the BucketClaim stops changing the listener is never re-invoked. The Bucket's
false->true transition, performed asynchronously by the sidecar on a different
object, is therefore reflected onto the claim only if the Bucket happened to be
ready during that single reconcile -- a race the sidecar usually loses, leaving
bucketReady frozen at false and BucketAccess never granted.
Return an error while the backend Bucket is not ready so the work queue
requeues the claim with exponential backoff; each retry re-reads the live
Bucket until its readiness has been propagated, converging deterministically
instead of depending on a resync that never fires.
Add a unit test pinning the contract (requeue while not ready, propagate true
once ready) and adjust the existing status-update conflict-retry test, which
pinned the old never-requeue behavior.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Refresh the vendored virt-operator manifest from v1.8.2 to v1.8.4. The
release backports validation of the VMI checksum status fields as a
uint32 range, required on Kubernetes 1.36 where strict CRD numeric
format validation otherwise leaves VMIs stuck in Scheduled. Remaining
changes are bug fixes and CVE remediations; the embedded CRDs and RBAC
are unchanged, so only the operator image tag moves.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Clear the reachable GO-2026-5026 advisory: idna.ToASCII is reached
through the KubeVirt client path, and the fix landed in x/net v0.55.0.
Bump to v0.56.0, pulling x/sys, x/term and x/text forward as required;
govulncheck then reports the module clean.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
A local `go build` emits the module-named binary (kube-ovn-webhook),
while the Dockerfile builds `-o webhook`. Ignore both names so neither
local binary is accidentally committed.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Several first-party images still built their Go binaries with EOL or
behind-latest toolchains (golang 1.20, 1.20.6, 1.23.4, 1.24, 1.25), so a
plain rebuild kept shipping standard-library versions that the current
1.26 toolchain fixes. Raise every Go builder image (FROM and the
builder_image ARG defaults) to golang:1.26 across cluster-autoscaler,
kubevirt-cloud-provider, redis-operator, multus-cni, keycloak-operator,
objectstorage, kilo and linstor-csi.
This is the build-time counterpart to raising the go directive in the
first-party Go modules: the toolchain that compiles the binary, not the
go.mod minimum, determines the standard-library version baked into the
image.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The token-proxy, kube-ovn-webhook and kubevirt-csi-driver image modules
still pinned go 1.26.2, so their binaries shipped standard-library
versions that the 1.26.4 toolchain fixes. Raise the go directive and
refresh module dependencies to current releases.
token-proxy and kube-ovn-webhook take a full dependency refresh;
kube-ovn-webhook also moves k8s.io/* from 0.26.0 to 0.36.2 (only
long-stable admission/core API is used, so no code change is needed).
kubevirt-csi-driver keeps its existing replace-based k8s.io/* alignment
at 0.36.0 and only raises the go directive; a blanket go get -u is
avoided there because it pulls transitive bumps that break compilation
of the pinned vendored upstream csi-driver source.
Also ignore the locally-built binaries under the two image directories so
they cannot be committed by accident.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The pre-delete cleanup Job ran kubectl as root with no securityContext.
Add a pod-level runAsNonRoot + runAsUser 65534 + seccompProfile
RuntimeDefault and a container-level allowPrivilegeEscalation: false plus
capabilities drop ALL, mirroring the dashboard adopt hook that runs the
same clastix/kubectl image non-root. Pin the securityContext in
helm-unittest.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The pre-delete cleanup Job ran kubectl from `bitnami/kubectl:latest`. The
bitnami Docker Hub catalog has moved to a legacy/sunset state, so that pull is
at risk of breaking — which would stop the cleanup hook from starting at all —
and the `:latest` tag leaves the kubectl version unpinned and non-reproducible.
Switch to `docker.io/clastix/kubectl:v1.32`, the version-pinned image already
used by every other first-party cleanup/delete hook in the repo (kubernetes,
keycloak-configure, dashboard, mariadb). That image is Alpine-based and ships
only `/bin/sh`, so the hook script (pure POSIX) now invokes `/bin/sh` instead
of `/bin/bash` — matching those sibling hooks.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The pre-delete cleanup hook deletes the tenant's HelmReleases with
`kubectl delete --wait=true`, which opens a watch on helmreleases to block
until finalization. The hook Role granted only get/list/delete, so the watch
was rejected with 403, the delete call hung, the Job never finished, and
tenant deletion stalled on the hook.
Add the watch verb, matching the kubernetes app chart's cleanup Role which
already includes it for the same --wait deletes.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The access-check helpers returned plain fmt.Errorf values, which the
apiserver coerces to 500 InternalError regardless of the actual failure.
A request without user identity now surfaces as 401 Unauthorized, and a
RoleBinding list failure as 500 InternalError with a typed Status body.
Get also repackages a NotFound from the backing Namespace lookup so the
Status body reports the tenantnamespaces resource instead of namespaces.
The Watch goroutine already logs access-check failures and skips the
event, so no untyped error escapes to the client from that path.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The helper header and run-migrations.sh claimed every migration-driven
stamp routes through the helper, but migrations 1-41 still stamp the
cozystack-version ConfigMap label-less and are backfilled by migration 42.
Scope the comments to go-forward stamps (migration 42 onward and the
bootstrap path), and add a unittest asserting no migration numbered >= 42
nor run-migrations.sh stamps cozystack-version without the helper, so the
no-drift invariant is enforced rather than aspirational.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Mirror render_cozystack_version_manifest's argument guard in
stamp_cozystack_version so a missing version aborts before the kubectl
pipe. Without it, a render failure in a shell without pipefail would
leave the pipeline exit status to kubectl, which would apply empty input.
Add a unittest covering the guard.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The bootstrap path that creates cozystack-version when the ConfigMap is
absent applied it without the platform.cozystack.io/no-delete label,
leaving it unguarded by the cozystack-no-delete-guardrail
ValidatingAdmissionPolicy. Route it through the shared helper so the
bootstrap ConfigMap carries the label like every migration-driven stamp.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Migrations 42, 43 and 44 each carried a copy-pasted heredoc that applied
the labeled cozystack-version ConfigMap. Source the shared helper and call
it instead, so the labeled manifest has a single definition and future
migrations cannot reintroduce a label-less apply.
Behavior-preserving: the rendered manifest is byte-identical to the
previous heredocs. Migration 42 keeps its MIGRATION_DRY_RUN path, now
building its manifest from the helper's pure renderer.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Extract the labeled cozystack-version ConfigMap stamp into a sourced
shell helper so migrations cannot drift back to a label-less apply that
strips the platform.cozystack.io/no-delete label.
render_cozystack_version_manifest emits the manifest on stdout (pure,
unit-testable); stamp_cozystack_version renders and applies it. The
namespace defaults to cozy-system and honors $NAMESPACE.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
## What this PR does
Bumps three of the small components listed in #2900, each picking up
published security fixes:
- **opencost** chart `1.41.0 → 2.5.23` (app `1.111.0 → 1.120.3`). The
1.x→2.x chart-major bump's values schema is additive, so the cozystack
overrides (external prometheus vmselect endpoint, customPricing) stay
valid. The Makefile now pins `--version 2.5.23` and drops the upstream
snapshot test suite (it can't resolve in the cozystack render context);
cozystack ships its own helm-unittest.
- **multus-cni** `v4.2.3 → v4.3.0`, rebuilt multi-arch (builder
`golang:1.24 → 1.26` for the Go-stdlib CVEs). This also **folds the
`multusMasterCNI: 05-cilium.conflist` CNI-ordering fix into
`customize-deployment.patch`** — it was previously a raw daemonset
hand-edit that the next `make update` would have wiped, re-introducing
the kube-ovn-before-cilium startup race. A new helm-unittest pins it.
- **clickhouse-backup tool** `altinity/clickhouse-backup 2.6.32 →
2.7.2`, rebuilt multi-arch. The separate `clickhouse-backup` image
(clickhouse-server base) and the managed clickhouse-server version are
intentionally left as-is (multi-major server upgrade, out of scope).
Each package gains helm-unittest coverage (none shipped before).
**Deferred from #2900 (this PR does NOT close the issue):**
- **bootbox** — already at the latest upstream tag (no-op).
- **kubeovn-plunger** — first-party cozystack component, no upstream
release to bump.
- **etcd-operator** — held at 0.4.5: the 0.5.x Helm chart is not
published on the `ghcr.io/aenix-io/charts` OCI registry yet (only GitHub
releases exist), so `helm pull` can't fetch it. Needs an aenix-io chart
publish first.
- **ingress-nginx** — deliberately pinned to 4.11.2 (revert `5c900a746`
after the CVE-2025-1974 mitigation attempt); bumping needs a separate
investigation, not a routine sweep.
### Release note
```release-note
chore(images): bump opencost to 2.5.23, multus-cni to v4.3.0, and clickhouse-backup to 2.7.2
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Enhanced OpenCost Helm support for plugin installation/config
validation, cloud integration (secret or JSON), MCP server, and
`extraObjects` rendering
* Added admin token secret creation and Pod Disruption Budget options
* Expanded UI/API/MCP exposure via Ingress, OpenShift Route, and Gateway
API HTTPRoute
* Improved internal Prometheus/Thanos endpoint handling and optional CA
trust update
* **Updates**
* Updated ClickHouse backup and Multus images; adjusted Multus “thick”
deployment behavior/resources and namespace usage
* Refreshed OpenCost chart values/docs and bumped chart/app versions
* **Tests**
* Added/extended Helm unittest suites and rendering invariants for
backup, Multus, and OpenCost
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What this PR does
Bumps cilium from 1.19.3 to 1.19.5 (latest 1.19 patch), picking up the
published security fixes the issue enumerates (incl. the
`moby/spdystream` and `golang.org/x/net` updates carried by 1.19.4) plus
upstream bug fixes: CiliumEgressGatewayPolicy NamespaceSelector
corruption, BGP PeerConfig status cleanup, and a reused-endpoint BPF
state race.
The change is a single self-contained commit:
- Re-vendors the chart via `make update` (helm pull cilium 1.19.5). The
two cozystack vendoring patches re-apply cleanly — the
SYS_MODULE/iptables capability lines and the k8s<1.30 AppArmor
annotation block are stripped (the Makefile guard confirms the AppArmor
block is gone, so there is no duplicate-mapping-key risk on the agent
DaemonSet).
- Points `images/cilium/Dockerfile` at `quay.io/cilium/cilium:v1.19.5`.
- Rebuilds the cozystack agent image multi-arch (linux/amd64 +
linux/arm64) and pins it in `values.yaml` (`1.19.5@sha256:8f0e898…`),
mirroring the rebuild-and-pin step done for the 1.19.3 bump — so the
deployed agent carries the fixes immediately, not just on the next
release rebuild.
Upstream dropped the dev-only `values.yaml.tmpl` / `README.md.gotmpl`
from the 1.19.5 release tarball (hence the large deletion). The defunct
`l2podAnnouncements.interface` and `loadBalancer.standalone` removals
don't affect cozystack, which uses neither.
Verified: `helm template` renders the agent at `1.19.5@sha256:8f0e898…`
across the talos/kilo/kubeovn/apparmor overlays; `helm lint` passes
aside from the expected wrapper-chart dependency artifact.
Closes#2893
### Release note
```release-note
chore(cilium): bump cilium to 1.19.5
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Upgraded the Cilium Helm chart to **1.19.5** and refreshed default
container images/digests across components.
* Adjusted Helm packaging to exclude `*.tmpl`/`*.gotmpl` artifacts.
* **New Features**
* Expanded RBAC to include **BGP peering policy** resources.
* Updated **L2 pod announcements** configuration to use
`interfacePattern`.
* **Bug Fixes**
* Improved ingress EndpointSlice readiness/labels for more consistent
endpoint behavior.
* Enabled IPv6 traffic to fall back to the kernel stack when the IPv6
datapath is disabled.
* **Refactor**
* Made the operator health `hostPort` configurable based on host
networking.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What this PR does
Rebuilds the first-party `kilo` image to clear the published
`libpng16-16` / `libpng` advisories carried by the stale pinned layers,
and refreshes it onto current upstream.
- `images/kilo/Dockerfile`: `ARG VERSION` `fbce60d8` → `944dff57`
(current `squat/kilo` `main` HEAD); the rebuild also refreshes the
`golang:1.25` stdlib compiled into the `kg` / `kgctl` binaries. The
builder tag stays `golang:1.25` (upstream `go.mod` is `go 1.25.0`).
- runtime and `cni` base: `alpine:3.23` → `alpine:3.24`, which clears
the `libpng` advisories pulled in through the `graphviz` / `font-noto`
dependency chain.
- CNI plugins: `v1.9.0` → `v1.9.1`.
- `values.yaml`: re-pinned to the rebuilt multi-arch digest
(`linux/amd64` + `linux/arm64`); the human-readable tag handle moves
from `latest` to `v<version>` to match the sibling first-party images.
The in-repo cross-mesh-granularity feature patch still applies cleanly
on the new HEAD and is verified present in the built binary (`kg
--mesh-granularity` lists `cross`). Adds the package's first
helm-unittest coverage, pinning the image ref and the default mesh-arg
wiring.
### Release note
```release-note
chore(kilo): rebuild kilo image on current upstream and alpine 3.24 to clear the libpng advisories
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Upgraded Kilo to **v1.5.0**.
* Updated bundled CNI plugins to **v1.9.1**.
* Updated Kilo build/runtime base to **Alpine 3.24**.
* **Tests**
* Added Helm/unit coverage to validate Kilo DaemonSet image pinning and
default/overridden argument behavior (including compatibility options).
* Added a `test` make target to run Helm unit tests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Enable Renovate's dockerfile and github-actions managers with
pinDigests so OpenSSF Scorecard Pinned-Dependencies (currently 1/10)
can pass and supply-chain refs stay reproducible.
PR #2849 SHA-pinned actions in 13 workflows, but the check also scores
container base images -- 58 unpinned FROM lines across 27 distinct
images -- and left build-main.yaml / release-e2e.yaml unpinned.
Nothing kept the new action SHAs updated either, so they would
silently stop receiving security patches.
Enabling the managers lets Renovate open the initial pin PR (and pin
the two missed workflows) and keep digests fresh thereafter.
Digest-only refreshes and the initial pin are batched into a single
weekly PR to avoid a trickle of rebuild-triggering PRs on the shared
CI runner; real tag bumps stay individual for review.
Also pin s3manager's floating tags (golang:1, alpine:latest) to
concrete versions first, otherwise digest tracking churns endlessly.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
## What this PR does
Restores the OpenSSF Scorecard **Vulnerabilities** check to green. It
regressed to **0/10** after #2852: in the weeks since,
`golang.org/x/crypto v0.51.0` accrued **13 new advisories**
(`GO-2026-5005`, `5006`, `5013`–`5021`, `5023`, `5033`). An
`osv-scanner` pass over `main` confirmed all 13 trace to that single
package.
### Change
- **`golang.org/x/crypto 0.51.0 → 0.52.0`** (the fixed version for all
13). No transitive cascade — `go mod tidy` changed only this line plus
its two `go.sum` hashes.
Bumped with `go get` / `go mod tidy`, not by hand-editing the generated
`go.mod`.
### Verification
- `osv-scanner` after the bump: **No issues found** (0 advisories across
both modules).
- `go build ./...` passes.
- `make generate` produces **no drift** — `codegen-drift` stays green.
> Scorecard's report mentioned advisory IDs as low as `GO-2025-3512`
(kubevirt-csi, CVE-2024-1725). That package is **not** in `go.mod` or
`go.sum` — it isn't a cozystack dependency, so nothing to bump there.
The real cluster is the 13 x/crypto advisories this PR closes.
### Why this keeps happening (and the durable fix)
`x/crypto` is an **indirect** dependency, and the Renovate app isn't
actually opening PRs on this repo yet (no `renovate[bot]` PRs, no
Dependency Dashboard) — the org Renovate install needs
`cozystack/cozystack` added to its repo list. Until then, indirect-dep
and Go-toolchain advisories will keep knocking this check back to 0 and
need manual bumps like this one. Recommended follow-ups: enable Renovate
on the repo, and allow it to bump indirect deps (and optionally the Go
patch version).
### Release note
```release-note
fix(deps): bump golang.org/x/crypto to v0.52.0, closing 13 known OSV advisories (GO-2026-5005…5033)
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated cryptographic dependency to the latest patch version for
enhanced security and stability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What this PR does
Hardens GitHub Actions security posture to raise two OpenSSF Scorecard
checks that currently score **0/10**, as part of the push to ≥7.5 ahead
of CNCF Incubation due diligence. No workflow triggers, job graphs, or
step logic change — only `GITHUB_TOKEN` scopes and action pin refs.
### Token-Permissions (was 0/10)
The check failed because several workflows (`codegen-drift.yml`,
`pre-commit.yml`, `retest.yaml`, `tags.yaml`, …) declared **no
`permissions:` block at all**, so their jobs inherited the repository
default token — typically read/write across all scopes.
This PR applies the OpenSSF-recommended pattern to **every** workflow:
- A **top-level read-only default**: `permissions: { contents: read }`.
- An **explicit per-job `permissions:` block** granting only the writes
that job needs. Workflows that previously held write scopes at the
*workflow* level (`backport`, `pr-labeler`, `pr-size`, `stale`) now hold
them at *job* level, so the read-only default applies everywhere else.
Per-job scopes were derived from what each job actually calls:
| Workflow | Job | Scopes granted |
|---|---|---|
| auto-release | auto-release | `contents: write, pull-requests: read`
*(unchanged)* |
| backport | prepare | `contents: read` |
| backport | backport | `contents: write, pull-requests: write` |
| codegen-drift | codegen-drift | `contents: read` |
| labels | validate | `contents: read` |
| labels | sync | `contents: read, issues: write, pull-requests: write`
|
| pre-commit | pre-commit | `contents: read` |
| pr-labeler | label | `pull-requests: write` |
| pr-size | size | `pull-requests: write` |
| retest | retest | `actions: write, pull-requests: read` *(unchanged)*
|
| stale | stale | `issues: write, pull-requests: write` |
| update-releasenotes | update-releasenotes | `contents: write`
*(unchanged)* |
| pull-requests | detect-changes | `contents: read, pull-requests: read`
|
| pull-requests | build | `contents: read, packages: write`
*(unchanged)* |
| pull-requests | resolve_assets | `contents: read` |
| pull-requests | e2e | `contents: read, packages: read, checks: write`
*(unchanged)* |
| pull-requests-release | finalize | `contents: write` *(unchanged)* |
| tags | prepare-release | `contents/packages/pull-requests/actions:
write` *(unchanged)* |
| tags | generate-changelog | `contents: write, pull-requests: write`
*(unchanged)* |
| tags | update-website-docs | `contents: read` *(unchanged)* |
Self-hosted release jobs that push tags/branches/releases authenticate
via the `cozystack-ci` GitHub App token, so reducing the workflow
`GITHUB_TOKEN` does not affect them; the job-level write scopes they
already declared are preserved verbatim.
### Pinned-Dependencies (was 0/10)
Every GitHub-owned and third-party action is now pinned to a **full
commit SHA** with a human-readable version comment, e.g.
`actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4`.
`scorecard.yml` was already SHA-pinned in #2721; `breakpoint-action` was
already pinned. SHAs were resolved from each tag's current commit at
authoring time, so behavior is identical to the previously-referenced
tag.
> **Scope note:** this PR pins **GitHub Actions** only. Dockerfile
`FROM` digest pinning (≈40 images) is deliberately out of scope here —
it touches image builds and is higher blast-radius; tracked separately.
### Verification
- `actionlint` over all workflows: **exit 0**.
- All 14 workflow files parse as valid YAML.
- Diff is mechanical: only `permissions:` blocks and action `@ref`s
changed.
### Release note
```release-note
ci: declare least-privilege per-job GITHUB_TOKEN permissions and pin all GitHub Actions by commit SHA across CI workflows (OpenSSF Scorecard hardening)
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Tightened CI/CD security with least-privilege workflow token
permissions: workflows now default to read-only access (`contents:
read`), with select jobs requesting write or additional scopes only when
needed.
* Improved supply-chain safety and consistency by pinning GitHub Actions
(and related third-party actions) to specific commit SHAs across
multiple workflows, reducing reliance on floating version tags.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Add an issue-template chooser and a feature-request template, and document
in CONTRIBUTING and the README where each kind of contribution belongs:
- bugs and concrete features -> issues in this repo
- questions and early ideas -> GitHub Discussions
- cross-cutting / architectural changes -> design proposals in cozystack/community
Also reconciles the README, which routed feature requests to a Discussions
category while the issue tracker is actually used for kind/feature issues.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Restores the OpenSSF Scorecard Vulnerabilities check to green. It
regressed to 0/10 after #2852 because golang.org/x/crypto v0.51.0 accrued
13 new advisories (GO-2026-5005, 5006, 5013-5021, 5023, 5033). osv-scanner
confirms all 13 trace to that one indirect package; v0.52.0 is the fixed
version. go mod tidy changed only this line and its two go.sum hashes.
After the bump osv-scanner reports no issues, both modules build, and
'make generate' produces no drift. Versions were changed with go get /
go mod tidy, not by hand-editing the generated go.mod.
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Assisted-By: Claude <noreply@anthropic.com>
Re-vendors the cilium chart from 1.19.3 to 1.19.5 (latest 1.19 patch) and
points the agent image build at v1.19.5. Picks up the published security
fixes plus upstream bug fixes (CiliumEgressGatewayPolicy NamespaceSelector
corruption, BGP PeerConfig status cleanup, reused-endpoint BPF state race).
The make-update vendoring patches re-apply cleanly: the SYS_MODULE/iptables
capability lines and the k8s<1.30 AppArmor annotation block are stripped (the
guard confirms the AppArmor block is gone, and the rendered agent DaemonSet
carries the annotation exactly once via cozystack podAnnotations). Upstream
dropped the dev-only values.yaml.tmpl / README.md.gotmpl from the 1.19.5
release tarball. The defunct l2podAnnouncements.interface removal does not
affect cozystack, which uses interfacePattern.
The BPF host patch (pass-ipv6-to-stack-when-ipv6-datapath-disabled.diff) is
refreshed against v1.19.5 bpf_host.c: identical logic, only context lines
re-synced.
The deployed agent image pin in values.yaml is intentionally left on the
current release-line digest; the multi-arch cilium agent is rebuilt and
re-pinned during release preparation.
Adaptations:
- charts/: re-vendored (helm pull cilium 1.19.5 + capability/AppArmor patches)
- images/cilium/Dockerfile: ARG VERSION v1.19.3 -> v1.19.5
- images/cilium/patches/: BPF host patch context refreshed for v1.19.5
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Rebuilds the first-party kilo image to clear the published libpng advisories
carried by the stale pinned layers and to pick up current upstream:
- ARG VERSION: squat/kilo main fbce60d8 -> 944dff57 (the rebuild also refreshes
the golang:1.25 stdlib compiled into the kg / kgctl binaries)
- runtime and cni base: alpine 3.23 -> 3.24, which clears the libpng16-16 /
libpng advisories pulled in through the graphviz / font-noto chain
- CNI plugins: v1.9.0 -> v1.9.1
- values.yaml: re-pinned to the rebuilt multi-arch digest; the tag handle moves
from latest to v<version> to match the sibling first-party images
The in-repo cross-mesh-granularity feature patch still applies cleanly on the
new HEAD and is verified in the built binary (kg --mesh-granularity lists
`cross`). Adds the package's first helm-unittest coverage, pinning the image
ref and the default mesh-arg wiring.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Rebuilds the altinity-clickhouse-backup sidecar image off the upstream
altinity/clickhouse-backup 2.6.32 -> 2.7.2 release (multi-arch) and pins the
new digest. Picks up the published security fixes in the backup tool. The
clickhouse-server version (24.9.2) is intentionally left as-is: moving it is a
multi-major server upgrade, out of scope for this maintenance bump.
Extends the existing backup helm-unittest to assert the sidecar image tag, so
the bump is guarded against regressions.
Adaptations:
- images/altinity-clickhouse-backup/Dockerfile: FROM altinity/clickhouse-backup 2.6.32 -> 2.7.2
- images/altinity-clickhouse-backup.tag: pin rebuilt multi-arch image digest
- tests/backup_test.yaml: assert the backup sidecar image tag
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Re-vendors the multus-cni thick-mode daemonset from upstream v4.2.3 to v4.3.0
and rebuilds the cozystack image (multi-arch, golang:1.26 builder; v4.3.0's
go.mod and the published security fixes warrant the stdlib bump from 1.24). The
fix-del-without-cache and customize-deployment patches both re-apply cleanly to
v4.3.0. The rebuilt image is pinned by digest in the daemonset.
Folds the previously hand-edited `multusMasterCNI: "05-cilium.conflist"`
CNI-ordering fix into customize-deployment.patch so it survives every make
update (it was a raw daemonset edit that the re-vendor would otherwise wipe,
re-introducing the kube-ovn-before-cilium startup race).
Adds helm-unittest coverage (the package shipped none): asserts the daemonset
runs the cozystack-built image and that the daemon-config pins multusMasterCNI
to the cilium conflist.
Adaptations:
- images/multus-cni/Dockerfile: builder golang:1.24 -> 1.26, ARG VERSION v4.2.3 -> v4.3.0
- templates/multus-daemonset-thick.yml: re-vendored v4.3.0 + customize patch; pin rebuilt multi-arch image
- patches/customize-deployment.patch: carry the multusMasterCNI CNI-ordering fix
- Makefile: add test target
- tests/multus_test.yaml: new helm-unittest coverage
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Re-vendors the opencost chart from 1.41.0 to 2.5.23 (app 1.111.0 -> 1.120.3),
crossing the 1.x -> 2.x chart-major boundary, picking up the published security
fixes. The major bump's values-schema changes are additive (new clusterName,
pdb, extraObjects keys; no removals), so the cozystack overrides (external
prometheus vmselect endpoint, customPricing) stay valid -- confirmed by render.
Pins the update target to --version 2.5.23 and drops the upstream chart's own
snapshot-based helm-unittest suite (it fails in the cozystack render context).
Adds cozystack helm-unittest coverage: pins the image and the prometheus
endpoint wiring.
Adaptations:
- charts/: re-vendored via make update (helm pull opencost --version 2.5.23; upstream tests removed)
- Makefile: pin --version 2.5.23; add test target; strip upstream chart tests
- tests/opencost_test.yaml: new helm-unittest coverage
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>