mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-03 02:27:01 +09:00
3ece61ba04ccbdc404aad404ab1350ca3e41018c
210
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
76ad921fdd |
ci: harden workflow token permissions and pin actions by SHA
Raise the OpenSSF Scorecard Token-Permissions and Pinned-Dependencies checks (both currently 0/10) ahead of CNCF Incubation due diligence: - Declare a top-level read-only default (permissions: contents: read) in every workflow, plus an explicit per-job permissions: block that grants only the writes that job actually needs. Workflows that previously held write scopes at the workflow level (backport, pr-labeler, pr-size, stale) now hold them at job level instead. - Pin every GitHub-owned and third-party action to a full commit SHA with a version comment. scorecard.yml was already pinned in #2721. No triggers, job graph, or step logic change; only token scopes and action refs. Self-hosted release jobs keep the exact write scopes they already declared. Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> Assisted-By: Claude <noreply@anthropic.com> |
||
|
|
1a6dd6feef |
ci(tests): fix OCIR registry login in Release E2E workflow
The Release E2E build job referenced secrets OCI_REGISTRY_USERNAME / OCI_REGISTRY_PASSWORD, which do not exist in the repo, so docker/login-action received empty credentials and failed every run with "Username and password required". The workflow has never built since it was added (2026-05-02): v1.5.0-rc.2, v1.5.0-rc.3 and v1.5.0 all died at this step before any image was built or test run. Use the configured OCIR_USER / OCIR_TOKEN secrets, matching build-main.yaml and pull-requests.yaml, and isolate the Docker config per job (Set up Docker config step + DOCKER_CONFIG on the login and build steps) so login does not clobber the shared ~/.docker/config.json on the self-hosted runner. Assisted-By: Claude <noreply@anthropic.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
6329ffecfc |
fix(ci): create buildx builder in the build step's DOCKER_CONFIG (#2962)
## What this PR does The `Build cache (main)` workflow (`build-main.yaml`, added in #2948) failed on its first run: https://github.com/cozystack/cozystack/actions/runs/27929277423 The `Set up Buildx` step ran without `DOCKER_CONFIG`, so `docker/setup-buildx-action` created the docker-container builder under the runner's default `~/.docker`. The build step runs with `DOCKER_CONFIG=$RUNNER_TEMP/.docker` (seeded earlier, holding the OCIR auth), so buildx couldn't find the builder and failed immediately: ``` ERROR: no builder "builder-6fb46242-…" found ``` The post-job `docker buildx rm` still succeeded — because the action's cleanup runs under the default config where the builder actually lived — which confirms the builder existed but in the wrong config store. This sets `DOCKER_CONFIG` on the `Set up Buildx` step so the builder instance is created in the same config the build step reads. Impact: only the main cache-warmer was broken. PR builds `--cache-from` this ref, so a missing cache is a cold build, not a failure — but the warm-cache speedup from #2948 wasn't being delivered until this fix. ### Release note ```release-note NONE ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Improved build pipeline stability by ensuring consistent Docker configuration across workflow steps. This enhances the reliability of the container build and deployment process. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
1564081f76 |
ci(release): auto-patch-release only the 2 newest release lines (#2856)
## What this PR does
The **Auto Patch Release** cron (`.github/workflows/auto-release.yaml`)
walked
*every* `release-X.Y` branch — 21 of them, back to `release-0.9` — and
cut a
`vX.Y.(Z+1)` tag whenever a branch had commits after its latest
published
release. This fires patch releases on long-EOL lines (e.g. `v1.3.6`),
whose
release PRs then sit blocked on unrelated CI failures and accumulate
stray
draft releases, tags and changelog PRs.
This restricts the cron to the **2 newest minor lines**
(`SUPPORTED_LINE_COUNT`).
The window is derived from the live branch list, so it slides
automatically as
new `release-X.Y` branches are cut — once `release-1.5` exists the
window
becomes `{1.5, 1.4}` and the trailing line retires with no further
edits.
Currently active: `release-1.4`, `release-1.3`. Skipped: 19 EOL lines.
### Release note
```release-note
ci(release): the automated patch-release job now only cuts releases for the two newest release branches; older EOL lines no longer receive automatic patch tags.
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated the automated release workflow to focus patch automation on
only the two newest minor `release-X.Y` maintenance lines.
* Enhanced workflow logging to report the selected branches and any
older/EOL branches skipped.
* **Documentation**
* Refined release documentation to explain the sliding-window selection
for automated patch tagging, including how next patch versions are
determined and when tags are created.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
f9185e3f4b |
ci: add CodeQL workflow for Go (SAST) (#2851)
## What this PR does Raises the OpenSSF Scorecard **SAST** check (was **0/10**) by adding GitHub's recommended CodeQL static analysis for Go. CodeQL is free for public repositories and is the SAST tool Scorecard recognizes directly. - Triggers on push to `main`, PRs to `main`, and a weekly schedule (Mon 03:27 UTC, offset from the other Monday cron jobs). - Results are uploaded to the code-scanning dashboard via `github/codeql-action/analyze`. ### Why `autobuild` The Go analysis uses **`build-mode: autobuild`**. Go's CodeQL extractor only supports `autobuild` or `manual` (not `none`), so autobuild is the low-friction choice. It discovers every `go.mod` in the tree and extracts each module separately — the root module, `api/apps/v1alpha1`, and the three nested image modules a root `go build ./...` never reaches — giving broader coverage than a single root build. Before falling back to the Go build it first attempts `make` from the repo root, which runs the default Makefile goal (including a network `git fetch upstream --tags`). `setup-go` pins the toolchain to the `go.mod` version so the extractor uses the project's Go rather than whatever the runner ships. ### Security posture - Top-level token is **read-only**; the `analyze` job opts into `security-events: write` (plus `contents: read`, `actions: read`) only. - `actions/checkout` is pinned to **v6.0.2** (matching `scorecard.yml`) with `persist-credentials: false`. - `codeql-action/init` and `/analyze` are pinned to the **v4.36.2 SHA** — the same commit as `scorecard.yml`'s `upload-sarif`, keeping every codeql-action ref in the repo on one commit and clear of the v3 deprecation warning. ### Verification - `actionlint`: **exit 0**. - Valid YAML. - No `run:` steps → no untrusted-input injection surface. > SAST is a ramping check: Scorecard credits the CodeQL workflow's presence immediately and the score climbs toward full as subsequent merged PRs get analyzed. ### Release note ```release-note ci: add CodeQL static analysis (SAST) for Go, running on push/PR to main and weekly ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Enabled automated security scanning via CodeQL on pushes, pull requests targeting the main branch, and on a weekly schedule. * Added workflow controls for concurrency and longer execution time, with support for Go-based analysis using an autobuild setup. * Updated the SARIF upload step to use the latest CodeQL action version to improve reliability while maintaining secure, minimal permissions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
e7abea9576 |
fix(ci): create buildx builder in the build step's DOCKER_CONFIG
The "Set up Buildx" step in build-main.yaml ran without DOCKER_CONFIG, so docker/setup-buildx-action created the docker-container builder under the default ~/.docker. The build step runs with DOCKER_CONFIG=$RUNNER_TEMP/.docker (seeded before the builder existed and holding the OCIR auth), so it could not find the builder and failed immediately with `no builder "builder-<uuid>" found`. The post-job `docker buildx rm` still succeeded because the action's cleanup runs under the default config where the builder actually lived. Set DOCKER_CONFIG on the Set up Buildx step so the builder instance is created in the same config the build step reads. Assisted-By: Claude <noreply@anthropic.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
3bcab58453 |
ci(release): order skipped EOL branches numerically in the log
Address review feedback from lexfrei on .github/workflows/auto-release.yaml:82: the skipped-branches log used a lexicographic sort (release-0.9 after release-0.41). Reuse the existing lineNum helper so the log lists EOL branches in numeric order. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
94582fa07c |
ci(release): auto-patch-release only the 2 newest release lines
The Auto Patch Release cron walked every release-X.Y branch (21 of them,
back to release-0.9) and cut a vX.Y.(Z+1) tag whenever a branch had
commits after its latest published release. That fired patch releases on
long-EOL lines (e.g. v1.3.6), whose release PRs then sit blocked on
unrelated CI failures and accumulate stray draft releases, tags and
changelog PRs.
Restrict the cron to the SUPPORTED_LINE_COUNT (=2) newest minor lines.
The window is derived from the branch list, so it slides automatically as
new release-X.Y branches are cut — once release-1.5 exists the window
becomes {1.5, 1.4} and the trailing line retires with no further edits.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
|
||
|
|
f3914d2053 |
ci(build): disable credential persistence in build-cache checkout
The build-main cache warmer is a privileged workflow (packages:write + an OCIR push token) and never pushes git, so set persist-credentials: false to keep the checkout's GITHUB_TOKEN out of .git/config where a later build step could read it. (SHA-pinning the actions is handled repo-wide in #2849.) Addresses non-blocking follow-up 7 on #2948. Assisted-By: Claude <noreply@anthropic.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
89b6c401a6 |
ci(codeql): align checkout with scorecard.yml and drop redundant concurrency prefix
Address non-blocking review feedback from lexfrei: bump actions/checkout to the v6.0.2 SHA already used by scorecard.yml so the security workflows track one version, and remove the hardcoded 'codeql-' prefix from the concurrency group (github.workflow already expands to 'CodeQL'). Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
6b1212313a |
ci(codeql): fix the cron comment that mislabeled stale as a Monday job
Address review feedback from lexfrei on .github/workflows/codeql.yml:10: stale.yaml runs '37 4 * * *' (daily), but the comment listed it among the other Monday cron jobs. Note scorecard and labels as the Monday jobs and stale as daily. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
445a2fb1dc |
ci(codeql): correct the autobuild comment to match observed behavior
Address review feedback from lexfrei on .github/workflows/codeql.yml:43: the previous comment claimed autobuild 'runs the Go build the same way go build ./... does'. The run log shows autobuild discovers all five go.mod files and extracts each module separately (including the three nested image modules a root build never reaches), and first attempts make from the repo root, which triggers a network git fetch upstream --tags. Rewrite the comment to document this accurately. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
e40db8cd43 |
ci(codeql): pin codeql-action to v4.36.2 to clear the v3 deprecation warning
Address review feedback from lexfrei on .github/workflows/codeql.yml:60: v3 is on a deprecation path (the workflow's own run already warns about it) and v4 is GA. Bump init, analyze, and scorecard.yml's upload-sarif to the same v4.36.2 commit SHA. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
eba31194d7 |
ci(build): isolate each PR build on its own ephemeral runner VM (#2939)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
d3958c5bcb |
refactor(build): mode=max registry cache with a main-only warmer (#2938)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
8b4d31866e |
ci: add Go-scoped Renovate configuration (#2850)
## What this PR does Raises the OpenSSF Scorecard **Dependency-Update-Tool** check (was **0/10**) by adding a Renovate configuration at `.github/renovate.json`. Scorecard scores this check on the presence of a recognized config file, so the check turns green as soon as this merges. ### Why Renovate (not Dependabot) Renovate is already the cozystack org standard — it actively raises and merges PRs on `cozystack/ansible-cozystack`, and `cozystack/talm` + `cozystack/boot-to-talos` already ship `renovate.json`. The Renovate GitHub App is authorized on the org, so this config is picked up **without creating a new credential**. There is no Dependabot usage anywhere in the org. > If the app installation is scoped to "selected repositories", `cozystack/cozystack` needs to be toggled into the existing installation by an org admin — a one-click change, not a new auth artifact. The Scorecard check does not depend on that toggle. ### Scoped to Go dependencies only (per the 2026-05-27 decision) - **`enabledManagers: ["gomod"]`** — Renovate only ever touches Go modules. It will **not** open PRs for Dockerfiles, Helm charts, shipped component/operator versions, or GitHub Actions. Components and images stay hand-managed. - **`gomodTidy` + `gomodUpdateImportPaths`** run after each bump. The `gomod` manager auto-discovers both the root module and the `api/apps/v1alpha1` submodule. - **Kubernetes libraries grouped** (`sigs.k8s.io/controller-runtime` + `k8s.io/**`) so `client-go`/`apimachinery` never bump out of lockstep with controller-runtime (a split bump fails to compile). - **Go toolchain directive pinned** (`matchDepTypes: ["golang"]` disabled) — `go.mod` is generated and a toolchain bump needs a matching `setup-go` + codegen run, out of scope for an automated PR. ### "do not merge" on every bot PR (requirement) - `automerge` and `platformAutomerge` are **off**. - Every Renovate PR is labeled **`do-not-merge/hold`** + **`automated`** on creation. Both labels already exist in `.github/labels.yml`; `stale.yaml` already exempts `do-not-merge/hold` PRs from auto-close, so held bumps won't rot. - Bumps therefore stay parked until tests pass and a maintainer removes the label after a hands-on check. > Note: `do-not-merge/hold` is a **signal/marker** (cozystack uses native GitHub, not Prow Tide). Combined with automerge being off, nothing can auto-merge a held PR. Hard merge-blocking would need a status check tied to the label, which would require branch-protection changes that were explicitly excluded. ### Verification - `renovate-config-validator` (Renovate v42): **Config validated successfully.** - Valid JSON. ### Release note ```release-note ci: add a Go-scoped Renovate configuration (gomod only, no automerge, bot PRs held with do-not-merge/hold) to automate Go dependency updates ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Configured automated dependency management for Go modules, including synchronized updates for Kubernetes-related dependencies, rate limiting on concurrent updates, and manual approval requirements to ensure controlled rollouts. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
c961ffe286 |
feat(ci): test-impact analysis E2E (default-on) + release E2E workflow (#2559)
## What this PR does
Adds **test-impact analysis (TIA)** to the PR E2E workflow so that only
bats files affected by the diff are exercised, and a **release-time E2E
workflow** that runs the full suite on every release tag to keep
coverage on the shipped code.
### 1. Test-impact analysis selector — `hack/select-e2e.sh`
Reads `packages/core/platform/sources/*.yaml` (the PackageSource
dependency graph) and emits the bats files affected by a PR diff. The
walk is the same one `cozypkg dot` renders.
| Input | Output |
|---|---|
| `packages/apps/postgres/values.yaml` | `postgres` |
| `packages/system/postgres-operator/...` | `postgres harbor`
(transitive) |
| `packages/system/cilium/...` | full suite (cilium has many transitive
`*-application` dependents) |
| `packages/library/cozy-lib/...` | full suite (library affects
everything) |
| `hack/e2e-install-cozystack.bats` | full suite (shared install affects
all apps) |
| `hack/e2e-apps/redis.bats` | `redis` (per-app edit, never escalates) |
| `docs/agents/contributing.md` | (empty — no E2E impact) |
| `dashboards/gpu/gpu-fleet.json` | (empty) |
Conservative fallbacks:
- An unrecognised `packages/*` path or a system source with no
`*-application` descendants escalates to the full suite, so a path
inside the graph is never silently dropped.
- Per-app bats edits are matched **before** the full-suite trigger, so
editing one bats file selects only that app rather than escalating.
### 2. Default-on TIA + `full-e2e` opt-out — `pull-requests.yaml`
- The `Select E2E tests` step runs by default and produces `apps` +
`skip` outputs.
- `Run E2E tests` runs unless `skip=true` (docs / dashboards / `*.md`
only).
- Adding the `full-e2e` label skips the selector step (output empty) and
falls through to the unchanged full-bats-list path — the safety hatch
when reviewers want the full suite on a PR.
### 3. `release-e2e.yaml` — full E2E on every release tag
Triggered on `v*.*.*`, `v*.*.*-rc.*`, `v*.*.*-beta.*`, `v*.*.*-alpha.*`.
Builds images + Talos image, then runs the full suite. Independent of
`tags.yaml`'s release publish flow — failure here is an alarm, not a
release blocker.
This closes the coverage gap left by making PR runs default to TIA: the
full suite is now exercised at tag-cut time against the shipped code.
## Tests
`hack/select-e2e_test.bats` covers 11 cases — single app, transitive
operator, networking/library full-suite, docs/dashboards skip,
`kubernetes-application` two-bats mapping, shared E2E helper, install
bats, per-app bats no-escalation, release-e2e workflow change.
YAML parse verified for both new workflow files.
## Workflow injection safety
All `${{ }}` contexts that could carry untrusted data
(`github.base_ref`, label arrays) flow through env vars, never directly
into shell text. `github.workspace` is also indirected through
`WORKSPACE` env in the release workflow.
### Release note
```
NONE
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* CI now runs a Test Impact Analysis to pick only affected apps,
reducing E2E runtime.
* Added a release-level E2E workflow that runs full acceptance tests for
version tags with deterministic sandboxing, artifact capture,
conditional retries, teardown, and report upload.
* E2E jobs accept selected-apps metadata and support conditional
full-suite overrides.
* **Tests**
* New test suite validates selection logic, operator expansion,
full-suite escalation, and docs-only/no-op behaviors.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
0d6aaf93ac |
ci: use autobuild build-mode for CodeQL Go
CodeQL 2.25.x rejects build-mode 'none' for Go ('Go does not support the
none build mode; use autobuild or manual'), which failed the initial run.
Switch to autobuild and add a SHA-pinned setup-go (go-version-file: go.mod)
so the autobuilder uses the project's Go toolchain rather than whatever the
runner ships. go build ./... already compiles cleanly, so autobuild
succeeds.
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Assisted-By: Claude <noreply@anthropic.com>
|
||
|
|
540c4a1315 |
ci: add CodeQL workflow for Go (SAST)
Raise the OpenSSF Scorecard SAST check (was 0/10) by adding GitHub's recommended CodeQL analysis for Go. Runs on push and PR to main plus a weekly schedule, and uploads results to the code-scanning dashboard. - build-mode: none extracts Go source without compiling, so the job cannot fail on the monorepo's generated files, build tags, or the api/apps/v1alpha1 submodule. It still produces real alerts and is credited by Scorecard. Can be switched to autobuild later for deeper build-aware analysis. - Top-level token is read-only; the analyze job opts into security-events: write only. - codeql-action pinned to the same v3 SHA already used by scorecard.yml; checkout pinned by SHA. Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> Assisted-By: Claude <noreply@anthropic.com> |
||
|
|
ac56d4cea1 |
ci: add Go-scoped Renovate configuration
Raise the OpenSSF Scorecard Dependency-Update-Tool check (was 0/10) by adding a Renovate config. Renovate is already the cozystack org standard (active on ansible-cozystack, talm, boot-to-talos), so the app is authorized org-wide and this file is picked up without a new credential. Scoped deliberately so automated bumps only ever touch Go dependencies: - enabledManagers: [gomod] — Renovate ignores Dockerfiles, Helm charts, shipped component/operator versions, and GitHub Actions. Components and images stay hand-managed, per the 2026-05-27 decision. - gomodTidy + gomodUpdateImportPaths run after each bump; the gomod manager auto-discovers both the root module and the api/apps/v1alpha1 submodule. - controller-runtime and k8s.io/** are grouped so client-go and controller-runtime never bump out of lockstep. - The Go toolchain directive is pinned (matchDepTypes golang disabled): go.mod is generated and a toolchain bump needs a matching setup-go and a codegen run, out of scope for an automated PR. - automerge/platformAutomerge are off and every Renovate PR is labeled do-not-merge/hold + automated, so bumps are held until tests pass and a maintainer reviews them by hand. Validated with renovate-config-validator (config validated successfully). Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> Assisted-By: Claude <noreply@anthropic.com> |
||
|
|
53edfc1f50 |
test(e2e): capture COSI bucket state in failure diagnostics and cozyreport
Run 27057500380 failed on harbor's BucketClaim never reaching bucketReady=true, and neither artifact could explain why: the per-app diagnostics dump has no bucket objects, and cozyreport collects neither COSI resources nor objectstorage-controller / seaweedfs provisioner logs — by the time the report is taken, the bucket state has moved on. Add a COSI module to cozyreport.sh (bucketclaims/bucketaccesses/ buckets/classes as custom-column tables plus full YAML, controller and per-namespace provisioner logs) and a bucket-readiness snapshot to the per-app failure dump in the PR workflow. The COSI CRDs ship no printer columns, so plain kubectl get would show only NAME/AGE — readiness fields are pulled explicitly. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
d8d4c71e0f |
ci(pull-requests): dump cluster state on Install Cozystack failure
Mirror the diagnostics group already on `Run E2E tests` to the `Install Cozystack into sandbox` step. Without this, install-step failures (e.g. an HR not reaching Ready inside the bats `kubectl wait` window) surface only as "error: timed out waiting for the condition on helmreleases/<name>" with no cluster snapshot — re-running is the only way to triage, which is the exact pattern the parent commit removed. On failure, dump three groups: - `kubectl get hr -A -o wide` (last 100 lines): which HRs exist and their Ready/Status columns. - `kubectl describe hr` for each not-Ready HR (tail -50): the Conditions block surfaces helm install/upgrade errors, missing CRDs, and chart-render failures — the actual cause. - `kubectl get events -A --sort-by=.lastTimestamp` (last 50): cluster events that often pinpoint the failing pod/PVC/job. Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
199781a7a5 |
ci(pull-requests): report total attempt count in prepare-env retry log
Address review feedback from coderabbitai on .github/workflows/pull-requests.yaml:235: $attempt is incremented only on failure, so first-try success printed "completed after 0 attempts". Use $((attempt + 1)) so the message reflects the total number of runs. Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
e3b54cb201 |
ci(pull-requests): drop 3x retry on Run E2E + Install Cozystack
Audit of 30 successful PR runs found that across 5 sampled failure attempts, **25/25 retries** on `Run E2E tests` failed — the retry loop never recovered a flake, only stretched deterministic failures and tripled diagnostic wall-time. Same data shape on `Install Cozystack`. Drop both. `Prepare environment` keeps its 3x retry — that step is pure infrastructure (Talos image download, sandbox VM boot, network) where transient runner hiccups warrant a retry. On failure, the test step now captures `kubectl get hr -A -o wide` and `kubectl get events -A` under a collapsible group so triage starts with the actual broken-state snapshot. Depends on: - #2508 — installer namespace bootstrap (Helm namespace-ownership conflict) - #2509 — operator HelmRelease config knobs (`seaweedfs-system` 2-min wait race) - #2528 — harbor bucket-secret + BucketInfo gating (harbor ValuesError) - #2529 — objectstorage-controller BucketAccess conflict retry - the daniil/split-vminstance PR (vminstance disk race + VM IP/ready timeouts) - the daniil/split-event-driven PR (existence backstops surfacing real errors) Until those land, dropping the retry will fail CI for unrelated PRs that hit the seaweedfs / harbor / installer / vminstance races. Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> Assisted-By: Claude <noreply@anthropic.com> |
||
|
|
26574f08f3 |
ci(release): repair orphaned draft tag_name on retag (#2761)
## What this PR does When a release-cut PR is merged after the underlying git tag was deleted and re-created (e.g. the release branch was force-updated between the initial tag push and the merge), GitHub orphans the corresponding draft release — its `tag_name` becomes `untagged-<hash>` while `name` is preserved. The "Publish draft release" step in `pull-requests-release.yaml` looks up the draft strictly by `tag_name === tag` and throws `Draft release for <tag> not found`, blocking the release. Observed on run [#26558920814](https://github.com/cozystack/cozystack/actions/runs/26558920814/job/78236959976) cutting v1.4.2, and the same error fired on the earlier [v1.4.1 finalize run](https://github.com/cozystack/cozystack/actions/runs/26271301257). This change adds a fallback: when the primary lookup misses, search for a draft where `name === tag` and `tag_name` matches `/^untagged-/`. If found, repair the draft's `tag_name` to the real tag via `updateRelease` before publishing, so the released artifact correctly points at the git tag created earlier in the same job. The strict-fail path is preserved when neither lookup matches. The fix is forward-only and does **not** auto-recover the currently stuck v1.4.2 draft — that needs a one-time manual `tag_name` patch + job re-run, or publishing the draft via the GitHub UI. ### Release note ```release-note ci(release): the release-finalize workflow now repairs an orphaned draft release (tag_name == `untagged-<hash>` after a tag delete + re-create) by re-linking it to the actual tag before publishing. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Improved the robustness of the release publication process to handle edge cases when locating draft releases, ensuring more reliable and consistent release deployments. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2761?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
bac670d07b |
ci: bump cozyvalues-gen to v1.6.0 in pre-commit workflow
v1.6.0 adds the date-time string-format alias and the @example annotation. Both are additive, opt-in directives: charts that do not use them regenerate byte-identical schema, README and Go type output, so the pre-commit check stays green without touching any committed artifact. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
22187e069d |
ci(release): repair orphaned draft tag_name on retag
When the git tag was deleted and re-created between draft creation and merge, GitHub orphaned the draft release: tag_name became "untagged-<hash>" while `name` was preserved. The finalize step looked up the draft by tag_name and threw `Draft release for <tag> not found`, blocking the release. Fall back to matching by `name` only when the candidate is the GitHub-orphaned form (tag_name matches /^untagged-/), repair the draft's tag_name via updateRelease, then publish. Hard-fail is preserved when neither lookup matches. Same failure recurred on the v1.4.1 finalize run; this commit prevents recurrence but does not auto-recover the stuck v1.4.2 draft. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
3756f5c459 |
feat(networking): Gateway API support via Cilium (supersedes #2213) (#2470)
## What this PR does
Replaces ingress-nginx as the default ingress layer for cozystack-native
services with **Cilium Gateway API**, materialised per-tenant via a new
`TenantGateway` CRD reconciled by `cozystack-controller`. Supersedes
#2213 / #2208. Stacked on top of #2468.
## Architecture
The chart renders one `gateway.cozystack.io/v1alpha1 TenantGateway` CR
per tenant that owns its own Gateway. The cozystack-controller
reconciles the actual `Gateway`, per-tenant `Issuer`, `Certificate`
(wildcard or per-listener), and HTTP→HTTPS redirect `HTTPRoute` from
there. Helm does not render `Gateway` or `Certificate` directly — that
prevents the Helm-vs-controller race on `Gateway.spec.listeners` that
route-driven listener additions would otherwise cause.
```
┌── TenantGateway CR (rendered by extra/gateway chart for owning tenants)
│
└──▶ cozystack-controller reconciles:
├─ Gateway (with dynamic listeners, label-based allowedRoutes)
├─ Issuer (per-tenant ACME account)
├─ Certificate(s) — wildcard + per-child SANs in DNS-01, per-listener in HTTP-01
├─ HTTPRoute (controller-owned http→https redirect)
├─ Namespace label patching (cozy-* system namespaces from spec.AttachedNamespaces)
└─ Watches HTTPRoute / TLSRoute attachments to materialise listeners
```
## Inheritance: tenants attach by default, opt into their own Gateway
A tenant gets a dedicated Gateway (own LB Service, own LB IP, own
Certificate) only when it explicitly asks via
`tenant.spec.gateway=true`. Every other tenant in the tree publishes
through the Gateway of the nearest ancestor that owns one — same shape
as the existing `_namespace.ingress` inheritance.
The `apps/tenant` chart writes a `namespace.cozystack.io/gateway` label
on each tenant namespace, carrying either the tenant's own name (when
owning a Gateway) or the inherited ancestor name (when inheriting). The
Gateway's listener `allowedRoutes.namespaces.selector` is keyed on that
label, so the same selector admits routes from every namespace pointing
at the owner — descendants and cozy-* system namespaces alike.
cozystack-controller patches the same label onto every namespace in
`tgw.Spec.AttachedNamespaces` and garbage-collects labels it wrote when
an entry is removed from the attach list (annotation-gated GC so labels
written by the apps/tenant chart are never stripped).
In DNS-01 mode, the controller extends the parent's wildcard Certificate
with `<child-apex>` + `*.<child-apex>` SANs per inheriting child, and
adds a `*.<child-apex>` HTTPS listener per child apex referencing the
same cert. Without this expansion the parent's single-level wildcard
cannot match a child route's hostname (`harbor.alice.example.org` is two
labels past the parent's `*.example.org`).
Opt-out into own Gateway is the right choice when: a tenant needs its
own LB IP (DNS pinned, firewall rule), the apex is not derived from the
parent (custom `host` value the ancestor's cert can't cover), or the
tenant wants its own ACME account / cert authority. Otherwise leave
`gateway` unset and inherit.
## End-to-end flow
1. Platform: `gateway.enabled=true` toggles cert-manager solver,
switches per-system-app templates from Ingress to HTTPRoute / TLSRoute.
2. Per tenant: explicit `tenant.spec.gateway=true` renders a
`TenantGateway` CR and triggers the controller to materialise the owner
Gateway. Tenants with the field unset inherit through
`_namespace.gateway` propagation in the tenant chart.
3. Adding a published app under any tenant (owner or inheriting) is just
deploying its HTTPRoute. The controller picks up the hostname, adds a
per-listener Certificate (HTTP-01) or extends the wildcard cert's SANs
(DNS-01), and updates the owner Gateway's listeners.
Defaults stay legacy: `gateway.enabled=false`,
`tenant.spec.gateway=false`. Existing clusters upgrade unchanged.
## External IP allocation — mechanism-agnostic
The per-tenant Gateway's auto-created `LoadBalancer` Service draws its
IP from whatever LB allocator the cluster admin has configured at the
platform layer — same shape as ingress-nginx today. The tenant API stays
mechanism-agnostic — no `gatewayIP` field, no allocator-specific
manifest in the tenant chart. Cozystack itself ships MetalLB installed
but does not render any `IPAddressPool` / `L2Advertisement` /
`BGPAdvertisement` from this chart; admins set up the allocator that
suits their environment (MetalLB pool with L2 / BGP, Cilium LB-IPAM with
announcer, robotlb against a cloud provider, or
`Service.spec.externalIPs` pinning).
If a tenant needs a specific address (DNS already pinned, firewall rule,
etc.), the operator pre-allocates it on the admin side: either
pre-create the Service with `loadBalancerIP` set, or hand the tenant a
reference to a named admin-managed pool. Per-Service IP uniqueness is
the allocator's responsibility — same as for any other LoadBalancer
Service.
## Cert mode: HTTP-01 (default) vs DNS-01 (opt-in)
`publishing.certificates.solver` selects how the controller sources TLS
certs.
**HTTP-01 (default)** — per-app HTTPS listener + per-app Certificate.
New apps require zero platform-side config: deploy the HTTPRoute,
controller does the rest. Inheriting children's hostnames pick up
per-listener certs the same way the owner's own apps do.
**DNS-01 (opt-in)** — single wildcard Certificate (`<apex>` +
`*.<apex>`) covering every published app under the apex, plus per-child
SANs (`<child-apex>` + `*.<child-apex>`) for every inheriting tenant.
Pick this for clusters where many apps share the apex and Let's Encrypt
rate limits matter. The DNS provider account must be able to write TXT
records under every apex level the parent serves — for deeply-nested
inherited children that requires zone delegation or a wide-scope
provider credential.
| `publishing.certificates.dns01.provider` | Required
`publishing.certificates.dns01.<provider>` keys |
| --- | --- |
| `cloudflare` (default) | `cloudflare.secretName`,
`cloudflare.secretKey` |
| `route53` | `route53.region`, `route53.secretName` (and `accessKeyID`
if not on IRSA) |
| `digitalocean` | `digitalocean.secretName` |
| `rfc2136` | `rfc2136.nameserver`, `rfc2136.tsigKeyName`,
`rfc2136.secretName` |
The platform chart wires every provider's keys into `_cluster.dns01-*`;
the per-tenant gateway chart and the cluster-wide `cluster-issuers.yaml`
both read them.
## Strengthens admission coverage on apps.cozystack.io/*
The `cozystack-tenant-host-policy` probe in `gateway.bats` initially
looked like a flake — the apply that was supposed to be VAP-rejected
just succeeded. Investigation traced it to the custom REST handler at
`pkg/registry/apps/application/rest.go`. genericapiserver hands every
storage method a callback into the validating admission chain:
`createValidation` for Create, `updateValidation` for Update,
`deleteValidation` for Delete. `Update` was correctly invoking its
callback since
|
||
|
|
2cb16d5ae6 |
refactor(build): standardize image tagging to fix concurrent PR push conflicts (#2711)
## What this PR does Concurrent PR builds were racing in the OCIR registry. Every package Makefile tagged its images via `settag`, which on any non-release commit collapsed to `:latest` — so every image across every PR was pushed to the same tag, and parallel builds got 409s on the manifest PUT. Two outliers (`metallb`, `redis-operator`) used hardcoded version tags and collided across PRs unconditionally. This PR replaces `settag` and the `TAG=latest` fallback in `hack/common-envs.mk` with a single `image-tags` macro driven by three env vars: | Env | Meaning | |---|---| | `IMAGE_TAG` | Build-unique tag, always pushed | | `PUBLISH_VERSIONED` | Also push `:<component-version>` (when provided) | | `PUBLISH_FLOATING` | Also push `:latest` | Wired into the two workflows: - **`pull-requests.yaml`** — `IMAGE_TAG=pr-<N>-<sha>`, both `PUBLISH_*` off. Every PR build pushes a unique tag set; no collisions, no `:latest` move. - **`tags.yaml`** — `IMAGE_TAG=<ref_name>`, both `PUBLISH_*` on. Release output preserved (component versions + `:latest`) plus a uniform `:<git-tag>` handle on every image for traceability. - **Local** — defaults to `IMAGE_TAG=dev`, no flags, `PUSH=0`. All 30 package Makefiles converted to `$(call image-tags,<repo>,<versioned-tag>)`. Image consumers reference digests pinned into `values.yaml` by each Makefile, so the tag is decorative for cluster-side pulls — the build-unique tag is sufficient for E2E. Also drops the redundant `:<component-version>-<git-tag>` form (cilium, linstor, matchbox, ubuntu-container-disk, kubevirt-*, cluster-autoscaler). Nothing in the repo or downstream values.yaml consumed it; the same information is preserved via the new `:<git-tag>` plus the existing `:<component-version>` tags on release. `ubuntu-container-disk` builds a separate image per Kubernetes version in a loop, so its primary tag became `:<k8s-ver>-<IMAGE_TAG>` to prevent loop iterations within a single build from pushing to the same tag. Verified by dry-running `make -n image` across representative packages (simple, dual-tag, skopeo, flux-push, loop) under all four contexts (PR / release / main / dev) — tag sets are unique and behave as expected. ### Release note ```release-note refactor(build): PR CI now pushes images under a unique `pr-<N>-<sha>` tag per build instead of `:latest`. Concurrent PR builds no longer race in the registry. Release builds keep the existing `:<component-version>` and `:latest` tags and additionally publish a uniform `:<git-tag>` handle across every image. The redundant `:<component-version>-<git-tag>` tag (cilium, linstor, matchbox, ubuntu-container-disk, kubevirt-*, cluster-autoscaler) is no longer published — image references in values.yaml are digest-pinned and were the only legitimate consumers. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Centralized and simplified container image tagging across build workflows. * PR builds now use unique image tags derived from PR metadata for better isolation. * Added configurable flags to control publishing of versioned and floating tags, making release tagging behavior more predictable. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2711?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
943441b0c7 |
ci: bump cozyvalues-gen pin to v1.5.0
v1.5.0 adds the @immutable annotation support (cozystack/cozyvalues-gen#24). Without the bump, pre-commit re-runs make generate with the v1.4.0 binary, silently strips any x-kubernetes-validations entries that downstream PRs add to values.schema.json / embedded openAPISchema, and reports drift against the committed artefacts. This is a no-op for the current main: no chart currently uses @immutable, so regeneration with v1.5.0 produces identical output to v1.4.0. Unblocks cozystack/cozystack#2639 (apply @immutable to storageClass across stateful apps). Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
d2e851f63b |
feat: Gateway API support via Cilium
Replace ingress-nginx as the default ingress layer for cozystack-native
services with Cilium Gateway API, materialised per-tenant via a new
TenantGateway CRD reconciled by cozystack-controller.
The extra/gateway chart renders one gateway.cozystack.io/v1alpha1
TenantGateway per tenant; the controller owns the resulting Gateway,
per-tenant Issuer, Certificate(s), and the http->https redirect
HTTPRoute. This avoids the helm-vs-controller race on
Gateway.spec.listeners when route-driven listeners are added.
publishing.certificates.solver selects HTTP-01 (default; per-app HTTPS
listener + per-app Certificate) or DNS-01 (opt-in; single wildcard
Certificate per apex; providers: cloudflare, route53, digitalocean,
rfc2136). HTTP-01 keeps zero-config per-app onboarding; DNS-01 saves
Let's Encrypt budget on apex-shared clusters.
Security model -- seven independent layers, all admission-time gates
fail-closed:
1. Listener allowedRoutes namespace whitelist via the
kube-apiserver-written kubernetes.io/metadata.name label;
plain-HTTP listener is strictly narrower than HTTPS, and HTTPS /
passthrough listeners restrict allowedRoutes.kinds to
HTTPRoute / TLSRoute respectively.
2. cozystack-gateway-hostname-policy VAP on Gateway.
3. cozystack-gateway-attached-namespaces-policy VAP on Package --
blocks tenant-* in gateway.attachedNamespaces.
4. cozystack-tenant-host-policy VAP on Tenant -- blocks spec.host
writes from non-trusted callers.
5. cozystack-namespace-host-label-policy VAP on Namespace -- blocks
writes to namespace.cozystack.io/host from non-trusted callers.
6. Render-time fail in cozystack-basics for tenant-* in
gateway.attachedNamespaces.
7. cozystack-route-hostname-policy VAP on HTTPRoute / TLSRoute,
scoped to tenant-* namespaces.
Within-apex cross-namespace hostname conflict is resolved at reconcile
time by a HostnameConflict condition (cozy-* namespace wins).
Five reconcile paths refuse to rewrite pre-existing objects with the
controller-derived name but no OwnerReference back to the
TenantGateway: Gateway, redirect HTTPRoute, per-tenant Issuer, wildcard
Certificate, per-listener Certificate.
Derived-apex tenants (tenants whose host is a subdomain of a parent
tenant's) auto-enable Gateway when the platform-level gateway.enabled
is on.
Bonus fix: pkg/registry/apps/application/rest.go was ignoring the
createValidation and deleteValidation callbacks that genericapiserver
hands to every storage method, silently bypassing admission for Create
and Delete on every apps.cozystack.io resource (Tenant, MariaDB,
Postgres, Kubernetes, ...). Aligned with the existing updateValidation
pattern.
Always-on changes: cilium.envoy.enabled + cilium.gatewayAPI.enabled
flip to true (extra cilium-envoy DaemonSet, ~100 MB RAM/node idle),
and the cozystack-api admission-chain fix. Everything else is gated
behind gateway.enabled=false and tenant.spec.gateway=false; existing
clusters see no behavioural change until an operator opts in.
Tests: 60+ Go cases in internal/controller/tenantgateway/, admission-
chain regression tests in pkg/registry/apps/application/, helm-unittest
across 7 charts (extra/gateway, core/platform, apps/tenant,
system/cozystack-basics, system/cert-manager-issuers,
system/cozystack-api, system/dashboard), and 14 e2e bats scenarios in
hack/e2e-apps/gateway.bats. New make test-controllers target wired
into pull-requests.yaml.
Deps: sigs.k8s.io/gateway-api v1.4.1, cert-manager v1.17.4.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
|
||
|
|
688f73f8f0 |
ci: pin Scorecard workflow actions by SHA
The initial Scorecard workflow used floating major-version tags (@v2, @v4, @v3). ossf/scorecard-action does not publish a floating v2 tag — only specific patch releases — so the first scheduled run failed with `Unable to resolve action ossf/scorecard-action@v2`. Pin every action by its full commit SHA with a trailing comment showing the human-readable version. This also satisfies the `Pinned-Dependencies` Scorecard check itself. - actions/checkout@de0fac2 (v6.0.2) - ossf/scorecard-action@4eaacf0 (v2.4.3) - actions/upload-artifact@043fb46 (v7.0.1) - github/codeql-action/upload-sarif@03e4368 (v3) Signed-off-by: Timur Tukaev <timur.tukaev@aenix.io> |
||
|
|
2396d08ee5 |
ci: add OpenSSF Scorecard workflow
Runs the OpenSSF Scorecard action on: - weekly schedule (Mon 06:00 UTC) - branch protection rule changes - pushes to main - manual dispatch Publishes results to: - the public OpenSSF Scorecard API (scorecard.dev) for transparency - the GitHub code-scanning dashboard (Security tab) for triage No README badge is added yet — the badge will be introduced in a follow-up PR once the first scans have run and any quick-win improvements (token permissions, dependency pinning) have landed. Aligns with the project's CNCF Incubation readiness work and the security self-assessment in progress. Signed-off-by: Timur Tukaev <timur.tukaev@aenix.io> |
||
|
|
7cc0194f20 |
ci(pre-commit): bump cozyvalues-gen to v1.4.0
v1.4.0 adds the `intOrString` type alias used by the postgres package's
`postgresql.parameters` schema in this PR. CI must install v1.4.0 so the
"Verify generated code is up to date" check regenerates the same schema
shape (anyOf + x-kubernetes-int-or-string: true) rather than reverting
to {type: string}.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
|
||
|
|
ed0297eb87 |
refactor(build): standardize image tagging to fix concurrent PR push conflicts
Every package Makefile tagged images via `settag` which, on a non-release commit, collapsed to `:latest`. Concurrent PR builds therefore raced on every image's `:latest` manifest in the OCIR registry. Two outliers (metallb, redis-operator) used hardcoded version tags and collided across PRs even when `settag` would not have. Replace `settag` and the `TAG=latest` fallback with an `image-tags` macro driven by three env vars: - IMAGE_TAG — build-unique tag, always pushed - PUBLISH_VERSIONED — also push :<component-version> - PUBLISH_FLOATING — also push :latest PR CI sets IMAGE_TAG=pr-<N>-<sha> with both PUBLISH_* off, so every push is unique across runs. Release CI sets IMAGE_TAG=<git-tag> with both PUBLISH_* on, preserving the previous release output and adding a uniform :<git-tag> tag across every image. Local builds default to IMAGE_TAG=dev with PUSH=0 already off. Image consumers reference digests pinned into values.yaml by each Makefile, so the tag is decorative for cluster-side pulls; the build-unique tag is sufficient for E2E. Drops the redundant `:<component-version>-<git-tag>` form (cilium, linstor, matchbox, ubuntu-container-disk, kubevirt-*, cluster-autoscaler) — nothing in the repo or downstream values.yaml consumed it. The same information is preserved via the new uniform `:<git-tag>` plus the existing `:<component-version>` on release. ubuntu-container-disk builds a separate image per Kubernetes version in a loop. Switched its primary tag to `:<k8s-ver>-<IMAGE_TAG>` so loop iterations within a single build do not push to the same tag. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
00d47ee684 |
ci(tags): include data/versions in website docs commit
`release_next.sh` and `init_version.sh` (via `update-all → init-version`)
create `data/versions/<DOC_VERSION>.yaml` for new versions, but the
`update-website-docs` job only staged `content` and `hugo.yaml`. The new
file was silently dropped from the website PR, breaking
`{{< version-pin >}}` lookups for the released minor.
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
|
||
|
|
71c713f002 |
ci(workflows): rebuild breakpoint authorized-users from active contributors
Replace MAINTAINERS.md snapshot with a list derived from actual recent activity on main (commits, merged PRs and reviews over the last three months). MAINTAINERS.md had drifted in both directions — listing people no longer active on the project while missing several current maintainers — so copying it verbatim was both handing SSH access to inactive accounts and locking out people who would actually use this debug feature. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Andrei Kvapil <kvapss@gmail.com> |
||
|
|
6c8e111ab6 |
ci(workflows): add SSH breakpoint on E2E failure for debug/release PRs
When the e2e job fails on a PR carrying the `debug` or `release` label (release PRs are bot-created, so the label implies maintainer authorship), hold the runner and open an SSH breakpoint via cozystack/breakpoint-action (a fork of namespacelabs/breakpoint-action pinned by SHA) so a maintainer can attach, inspect Talos/Cozystack state, and resume. The fork adds three things on top of upstream: * `mode: pause-idle` — waits 20m for the first SSH connection, then keeps the workflow paused while sessions are active, exiting 10m after the last session disconnects. Saves runner-minutes vs a fixed timeout. * `endpoint` step output + `::notice::` annotation — surfaces the SSH endpoint while the step is still paused (step logs are buffered until step completion, so the endpoint would otherwise be invisible). * A dedicated Check Run "Breakpoint Open" with conclusion=failure carrying the SSH endpoint and sandbox-entry hint in output.summary (Markdown, rendered in the UI). Surfaces as a standard ✗ in `gh pr checks` so any CI watcher sees the open breakpoint without bespoke marker parsing. Updated to conclusion=success when the breakpoint exits. The step is configured via the `BREAKPOINT_ENDPOINT` repo variable. In fork PRs, repo variables are not exposed, so the step is naturally skipped and forks cannot reach the self-hosted rendezvous server. The `authorized-users` list is kept as a second defense layer at the breakpoint level. Permissions on the e2e job: `checks: write` (for Check Run create+update). Upstream PR: namespacelabs/breakpoint-action#16 Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Andrei Kvapil <kvapss@gmail.com> |
||
|
|
b7fd200e4b |
ci(tags): make generate-changelog non-blocking
Mark the generate-changelog job with continue-on-error and switch the update-website-docs gate to always() so a failed or skipped changelog generation no longer blocks the website docs update. prepare-release remains the hard gate. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
315802d8fc |
ci(pull-requests): raise E2E job timeout from 120m to 180m
The 2-hour ceiling on the E2E job was clipping otherwise-working runs on the oracle-vm-24cpu-96gb-x86-64 runners: image pulls, multi-stage Talos bootstrap, full helm-release fan-out plus the post-install bats matrix routinely consume 100-180 minutes of wall-clock, and runs that would have eventually gone green were getting cancelled by GitHub at the timeout. Recent successful E2E runs on the same runner pool sit between 60 and 184 minutes; lift the cap to 180m to cover the long tail without inviting truly-stuck jobs to linger forever. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
8da1e7a40a |
feat(platform): implement backup strategy for postgres (#2552)
<!-- Thank you for making a contribution! Here are some tips for you: - Use Conventional Commits for the PR title: `type(scope): description` - Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore - Scopes are not an exhaustive list — pick the most specific scope for the change and extend the list when a genuinely new area appears. Examples: - System components: dashboard, platform, operator, cilium, kube-ovn, linstor, fluxcd, cluster-api - Managed apps: postgres, mariadb, redis, kafka, clickhouse, virtual-machine, kubernetes - Development and maintenance: api, hack, tests, ci, docs, maintenance - Breaking changes: append `!` after type/scope (`feat(api)!: ...`) or add a `BREAKING CHANGE:` footer - If it's a work in progress, consider creating this PR as a draft. - Don't hesistate to ask for opinion and review in the community chats, even if it's still a draft. - Add the label `backport` if it's a bugfix that needs to be backported to a previous version. --> ## What this PR does ### Screenshots <!-- REQUIRED for UI changes: attach screenshots or screen recordings demonstrating the visual impact of your changes. PRs with UI changes without screenshots will not be merged. --> ### Release note <!-- Write a release note: - Explain what has changed internally and for users. - Start with the same `type(scope):` prefix as in the PR title - Follow the guidelines at https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md. --> ```release-note Implemented CNPG-strategy controller for postgres backups with supporting in-place and to-copy restores. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * CNPG-based backup strategy for PostgreSQL with S3-backed object store and controller support * Option to reference existing Kubernetes Secret for S3 credentials (configurable key names) * Controller supports scheduled/ad-hoc backups and both in-place and to-copy restores; safer credential handling (no inline keys) * **Examples** * Complete manifests: bucket, credentials, CNPG strategy, BackupClass, Plan, BackupJob, RestoreJob, Postgres source/target * **Security/RBAC** * Controller RBAC expanded for CNPG resources; tests enforce no cluster-wide Secret read * **Documentation** * README, chart values/schema and UI schema updated to document secret-reference workflow and restore guidance * **Tests** * New end-to-end and unit tests covering CNPG flows, restore semantics, cleanup behavior and RBAC constraints <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
ed5ae16e36 |
feat(platform): implement backup strategy for postgres application
Signed-off-by: Andrey Kolkov <androndo@gmail.com> |
||
|
|
af317f16a4 |
fix(ci): stop backport workflow from cascading on its own PRs
Two compounding issues caused merging a backport PR to spawn another
backport (e.g. #2581 [Backport release-1.2] [Backport release-1.3] ...
from #2579):
1. pr-labeler auto-added the `backport` label to any PR whose title
started with `[Backport release-X.Y]` (regression introduced in
|
||
|
|
4672d88f72 |
fix(ci): fetch full history in E2E checkout for TIA selector
The "Select E2E tests" step runs `git diff --name-only
origin/${BASE_REF}...HEAD` inside the sandbox copy of the workspace.
Without fetch-depth: 0 the e2e job's checkout only resolves a single
commit, so origin/main is missing and the diff aborts with
"ambiguous argument 'origin/main...HEAD': unknown revision".
Mirror the Build job's setup and request full history.
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
|
||
|
|
0788e94a7c |
feat(ci): test-impact analysis E2E (default-on) + release E2E workflow
Three changes that compose into a single E2E policy:
1. **Test-impact analysis selector** (`hack/select-e2e.sh`).
Reads `packages/core/platform/sources/*.yaml` (the PackageSource
dependency graph also rendered by `cozypkg dot`) and emits the bats
files affected by a PR diff. Library/core/networking/CI changes,
shared `hack/*.sh` helpers, the install bats, and the
`pull-requests` / `release-e2e` workflows trigger the full suite.
Doc/dashboard/`*.md` diffs select nothing. Per-app bats edits
select only that app. Anything inside `packages/` with no graph
entry, or a system source whose graph has no `*-application`
descendants, falls back to the full suite (conservative).
2. **Default-on TIA in `pull-requests.yaml`** with `full-e2e`
opt-out. Drops the previous `e2e-tia` opt-in shape — the
selector's behaviour has been validated, so making it the default
gives PR runtime savings out of the box. PRs that need the full
suite (e.g. cross-cutting refactors that the selector can't
reason about) carry the `full-e2e` label and get the unchanged
pre-TIA flow. Docs-only PRs (selector emits nothing) skip the
`Run E2E tests` step entirely.
3. **`release-e2e.yaml`** runs the full suite on every tag push
(`v*`). Independent of `tags.yaml`'s release publish flow — a
failure here is an alarm, not a release blocker. Closes the
coverage gap left by making PR runs use TIA: the full suite is
now exercised against shipped code at tag-cut time.
Bug fixes vs. the original `feat/select-e2e-script` draft:
- `dashboard/` -> `dashboards/` (path is plural in this repo).
- `hack/e2e-apps/<name>.sh` and `hack/<name>.bats` were silently
ignored; they now trigger the full suite (test infrastructure
affecting all apps).
- A path matching the graph but yielding zero `*-application`
descendants now falls back to the full suite instead of silently
emitting nothing (system-only changes are no longer silently
skipped).
- Per-app bats edits are matched before the full-suite pattern, so
editing one bats file no longer escalates to the full suite.
- Removed the dead `skip_pattern` variable (PCRE syntax that
`grep -qE` doesn't support; it was never matched).
Tests: `hack/select-e2e_test.bats` covers all 11 cases (the original
6 plus 5 for the bug fixes above).
Workflow inputs are passed via env vars rather than direct `${{ }}`
expansion into shell commands, per workflow injection guidance.
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Assisted-By: Claude <noreply@anthropic.com>
|
||
|
|
9432cdfac8 |
chore(ci): replace Dosu stale and size labeling with native workflows (#2504)
## What this PR does
Replace Dosu's stale-management and PR-size labeling with native GitHub
Actions ahead of disabling the Dosu app on this repo, and migrate the
six `size:*` labels to the canonical `size/*` namespace while we're
rewriting the sizing path.
**Background**: Dosu (the SaaS) currently writes `lifecycle/stale`
lifecycle and `size:*` labels via its bot. Audit of `.github/workflows/`
(full grep) confirmed zero hard dependencies on Dosu's outputs —
`backport*` is human-applied, `release` is auto-applied by `tags.yaml`
itself, and nothing else consumes Dosu-applied labels in any workflow.
### `.github/workflows/stale.yaml` (new)
Daily cron at 04:37 UTC plus manual dispatch. Uses `actions/stale@v10`:
- Stale after 60 days idle: applies `lifecycle/stale`.
- Closes 14 days later, applying `lifecycle/rotten`.
- `remove-stale-when-updated: true` — activity un-stales automatically.
- 100 ops/run.
Issue and PR exempt lists differ on purpose: an accepted issue
(`triage/accepted`) is a known long-tail task, not stale; a held PR
(`do-not-merge/hold`) is paused intentionally.
Priority/security/regression labels protect issues someone explicitly
decided to keep visible.
### `.github/workflows/pr-size.yaml` (new)
Triggers on `opened`, `synchronize`, `reopened` (`pull_request_target`).
Inline `actions/github-script@v7` — no third-party labeler dependency.
Diff-line count with thresholds matching the descriptions in
`.github/labels.yml`:
| label | lines |
|---|---|
| `size/XS` | 0–9 |
| `size/S` | 10–29 |
| `size/M` | 30–99 |
| `size/L` | 100–499 |
| `size/XL` | 500–999 |
| `size/XXL` | 1000+ |
Inline ignore patterns skip:
- vendored Go deps (`vendor/**`)
- kubebuilder/openapi inline generated files
(`zz_generated.{deepcopy,conversion,defaults,openapi}.go`)
- whole code-generated trees: any path under `generated/`, plus
`*.pb.go`
- vendored Helm charts (`packages/system/*/charts/**`)
- lockfiles (`go.sum`, `*.lock`, `*.lockb`)
Concurrency group keyed on PR number with `cancel-in-progress: true`
(latest push wins). `removeLabel` is wrapped in `try/catch` tolerating
404 for races between event payload and execution.
### `size:` → `size/` namespace migration
The legacy `size:X` (colon) form was an artefact of the previous sizing
bot; with that bot being replaced and every other label namespace in the
repo using slashes (`kind/`, `area/`, `priority/`, `triage/`,
`lifecycle/`, `do-not-merge/`, `security/`), `size/` is the consistent
form. Migration via aliases in `labels.yml` — IDs preserved, every
existing labelled PR follows the rename automatically.
The new `pr-size.yaml` emits `size/*` from day 1 and accepts both
prefixes when looking up the previous size label, to handle the brief
window between merge and the next labels-sync run.
### Out of scope (intentional)
- **`lgtm` replacement** — deferred. 33/33 of `lgtm` events in the last
100 PRs come from Dosu; humans never apply it manually. Whether
reviewers actually rely on it is unclear — observe for 7 days
post-Dosu-disable before adding a `pull_request_review`-on-approve
workflow.
- **LLM-based issue auto-classification** (`kind/bug`/`kind/feature` on
inbound issues) — accepted loss; manual triage replaces.
- **Cleanup of `wontfix`/`invalid`** in `labels.yml` — separate cleanup
PR.
### Release note
```release-note
NONE
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
- Pull requests now automatically receive size labels (XS, S, M, L, XL,
XXL) based on lines changed.
- Issues and pull requests are automatically marked as stale after 60
days of inactivity and closed 14 days later if still inactive.
* **Chores**
- PR size label namespace updated to a slash-based format (size/...)
while preserving the old names as aliases for backward compatibility.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
30729d7f00 |
fix(ci): generate changelog from release tag, not from main (#2530)
## What this PR does The `generate-changelog` job in `.github/workflows/tags.yaml` previously checked out `main` and ran the AI agent there. The agent followed `docs/agents/changelog.md`, which instructed it to compute the release range with `git log <previous_version>..HEAD`. That works for minor releases (cut from `main`), but it breaks for any patch release cut from a `release-X.Y` branch — `HEAD-on-main` is a strict superset of the tag and contains commits that were merged to `main` both before and after the tag. The v1.3.1 changelog generated by this workflow (#2480) demonstrated the failure mode: 8 PRs that were merged to `main` but never shipped in v1.3.1, 6 backport PRs that landed on `release-1.3` *after* v1.3.1 was tagged, both originals and their backports as separate entries, a hallucinated 2024 PR (#435), and the `cozystack-ci` bot in the contributors list. The corrected v1.3.1 changelog is in #2480. This PR fixes the root cause and tightens the agent guardrails: * **`tags.yaml`** — check out the release tag commit (`ref: ${{ steps.tag.outputs.tag }}`) instead of `main`, so `HEAD == release commit` and `git log v<prev>..HEAD` corresponds to what the tag actually contains. The "Create changelog branch" step still creates the PR branch from `origin/main`, so PRs continue to merge cleanly. * **`tags.yaml`** — the AI prompt now states explicitly that `HEAD` is the release commit and that the upper bound of the range is the new tag, never `main`. * **`docs/agents/changelog.md`** — every example replaces `..HEAD` with `..v<new_version>`, so the instruction is unambiguous regardless of which branch is checked out. * **`docs/agents/changelog.md`** — hard rule: backport PRs MUST be combined with the original into a single entry (`#1606, backport #1609`), never listed as a second entry. Documented edge case: if the original isn't in the range, drop the entry entirely (it shipped in a previous release). * **`docs/agents/changelog.md`** — forbid using the brief description verbatim as the detailed description (the failure was `* **fix(foo): X**: fix(foo): X (...)`), and forbid inventing entries for PRs outside the release range. * **`docs/agents/changelog.md`** — filter bot/CI accounts (`app/*`, `*[bot]`, `cozystack-ci`, `github-actions`, `dependabot`, `renovate`) out of the human Contributors list. Bot attribution on individual entries is still valid. The v1.3.1 changelog correction itself lives in #2480 (separate scope). ### Release note ```release-note fix(ci): tags.yaml now generates the release changelog from the tag commit instead of `main`, fixing patch-release changelogs (e.g. v1.3.1) that previously included unrelated commits from `main`. The AI prompt and `docs/agents/changelog.md` were tightened to forbid duplicate backport entries, title-as-description, fabricated PRs, and bot accounts in the Contributors list. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Changelog generation now checks out the release tag commit and verifies whether the release changelog already exists on main before generating. * Updated prompts and tooling to treat the release tag as the upper bound and avoid using HEAD when computing diffs. * Enforced combining original and backport PRs into single changelog entries with explicit “backport #…”. * **Documentation** * Strengthened authoring rules (distinct brief/detail, forbid invented entries, PRs must fall within tag-to-tag ranges). * Updated examples and guidance to use tag-to-tag comparisons and improved contributor extraction to use bold @user attribution while excluding automation accounts and the current release file. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
39605f213f |
docs(agents,ci): finish "tag-not-HEAD" sweep and fix changelog-exists gate
- tags.yaml: the check_changelog step now looks at origin/main rather than
the working tree. After Round 2 we check out the release tag, which never
has the changelog file (the PR opened by this job merges to main after
the tag is cut), so the previous `[ -f ]` test always returned false and
the gate was effectively dead on reruns.
- changelog.md: Step 6's `RELEASE_END=$(git log -1 --format=%ai HEAD)`
(lines 179, 222) was missed in the previous "never HEAD" sweep — now
uses v<new_version>, matching Step 5.
- changelog.md: Step 2 ("on main branch") was incompatible with the CI flow
which now runs detached at the release tag. Relaxed it to list both
configurations (interactive on main; CI detached at v<version>), while
the "Scope and boundaries" section continues to forbid the agent from
switching branches.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
|
||
|
|
ce63bfcdb0 |
docs(agents): fix new-contributor detection and tags.yaml/doc drift
- tags.yaml: drop "(or HEAD)" from the changelog prompt; the doc says "never HEAD" and the workflow now matches. - docs/agents/changelog.md: exclude the current release file from the "previous contributors" set used for first-time-contributor detection. The previous globbing on `docs/changelogs/v*.md` swept up the file being generated, so `comm -23` would never report any newcomers. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> |
||
|
|
7d2fe2f7d1 |
fix(ci): pass app token to Publish draft release step
The Publish draft release step used the workflow's default GITHUB_TOKEN, which does not return draft releases from listReleases — so the script failed with "Draft release for vX.Y.Z not found" and every release tag had to be undrafted manually. This same bug was fixed once before in |