ci: Add verify-nix pipeline #27

Merged
martin merged 4 commits from verify-nix-pipeline into master 2026-08-16 10:41:25 +00:00
Owner
No description provided.
martin self-assigned this 2026-08-12 16:38:43 +00:00
ci: Add verify-nix pipeline
Some checks failed
ci/woodpecker/pr/pr-review Pipeline was successful
ci/woodpecker/pr/verify Pipeline was successful
ci/woodpecker/pr/verify-nix Pipeline failed
413ba44291
Collaborator

Review Summary

This revision clears nearly all of the previous feedback: the trigger glob is widened to **/*.nix (which does reach the real derivations under .nix/), commands use the repo's $${VAR} escaping, the step builds .#recurring-events-image right away (no more default-package gap), nix path-info .#recurring-events-image is flakeref-scoped, depends_on with optional: true is fine on this instance's Woodpecker 3.16, and the redundant push trigger was dropped so the pipeline is PR/manual-only — its unique value. The flake.lock bump to my-nix-lib v0.1.2 correctly syncs with the ref = "v0.1.2" already in flake.nix.

The blocker carried over from the prior round remains: cachix authtoken $${CACHIX_AUTH_TOKEN} is the only unguarded cachix command, but Woodpecker does not expose secrets to pull_request events by default. On a PR run the token is empty and this command can fail the step (or silently no-op the caching), while the guarded push means PR builds never populate the cache regardless. Recommend guarding cachix setup+push on token presence (if [ -n "${CACHIX_AUTH_TOKEN:-}" ]) or restricting auth/push to events where the secret is available.

Worth tightening as well: the trailing || echo "⚠️ ... skipped" masks genuine push failures (registry down, revoked token) on manual runs, and without set -o pipefail a failing nix path-info pipes empty stdin into cachix push, which can exit 0 and swallow the real error. And because the repo mixes .yml/.yaml pipeline files, push.yaml/deploy.yaml still only exclude .woodpecker/*.yml — a default-branch push touching only this new config (which its own trigger lists) will spuriously rebuild/push the image and bump the cluster environment.


*🤖 Review by opencode (opencode/deepseek-v4-flash-free) — verdict: changes

# Review Summary This revision clears nearly all of the previous feedback: the trigger glob is widened to `**/*.nix` (which does reach the real derivations under `.nix/`), commands use the repo's `$${VAR}` escaping, the step builds `.#recurring-events-image` right away (no more `default`-package gap), `nix path-info .#recurring-events-image` is flakeref-scoped, `depends_on` with `optional: true` is fine on this instance's Woodpecker 3.16, and the redundant `push` trigger was dropped so the pipeline is PR/manual-only — its unique value. The `flake.lock` bump to `my-nix-lib` v0.1.2 correctly syncs with the `ref = "v0.1.2"` already in `flake.nix`. The blocker carried over from the prior round remains: `cachix authtoken $${CACHIX_AUTH_TOKEN}` is the only unguarded cachix command, but Woodpecker does not expose secrets to `pull_request` events by default. On a PR run the token is empty and this command can fail the step (or silently no-op the caching), while the guarded push means PR builds never populate the cache regardless. Recommend guarding cachix setup+push on token presence (`if [ -n "${CACHIX_AUTH_TOKEN:-}" ]`) or restricting auth/push to events where the secret is available. Worth tightening as well: the trailing `|| echo "⚠️ ... skipped"` masks genuine push failures (registry down, revoked token) on manual runs, and without `set -o pipefail` a failing `nix path-info` pipes empty stdin into `cachix push`, which can exit 0 and swallow the real error. And because the repo mixes `.yml`/`.yaml` pipeline files, `push.yaml`/`deploy.yaml` still only exclude `.woodpecker/*.yml` — a default-branch push touching only this new config (which its own trigger lists) will spuriously rebuild/push the image and bump the cluster environment. --- *🤖 Review by opencode (opencode/deepseek-v4-flash-free) — verdict: **changes** <!-- forgejo-opencode-review -->
clank-bot left a comment

Code review findings from opencode.

Code review findings from opencode. <!-- forgejo-opencode-review -->
@ -0,0 +3,4 @@
- event: pull_request
path:
include:
- "*.nix"
Collaborator
[bug] `*.nix` only matches Nix files at the repository root (doublestar `*` does not cross `/`). The package derivations live under `.nix/` (`pkgs.nix`, `image.nix`, `openapi-to-rust.nix`), so a change to any of them will not trigger this pipeline — defeating its purpose of catching Nix build failures. Use `**/*.nix` or add `.nix/*.nix` to the include list (both here and in the push block at line 13).
<!-- forgejo-opencode-review --> [bug] `*.nix` only matches Nix files at the repository root (doublestar `*` does not cross `/`). The package derivations live under `.nix/` (`pkgs.nix`, `image.nix`, `openapi-to-rust.nix`), so a change to any of them will not trigger this pipeline — defeating its purpose of catching Nix build failures. Use `**/*.nix` or add `.nix/*.nix` to the include list (both here and in the push block at line 13).
martin marked this conversation as resolved
@ -0,0 +15,4 @@
- ".woodpecker/verify-nix.yaml"
depends_on:
- name: verify
Collaborator
[style] The `depends_on` entry as an object with `optional: true` was only added in Woodpecker 3.15 (May 2026) — on an older instance this config would be rejected as invalid. The other pipelines in this repo (`push.yaml`, `deploy.yaml`) use the plain string form. Please confirm the Woodpecker version supports this, or keep the existing plain `- verify` form for consistency.
<!-- forgejo-opencode-review --> [style] The `depends_on` entry as an object with `optional: true` was only added in Woodpecker 3.15 (May 2026) — on an older instance this config would be rejected as invalid. The other pipelines in this repo (`push.yaml`, `deploy.yaml`) use the plain string form. Please confirm the Woodpecker version supports this, or keep the existing plain `- verify` form for consistency.
Author
Owner

It is 3.16

It is 3.16
martin marked this conversation as resolved
@ -0,0 +26,4 @@
from_secret: cachix_auth_token
CACHE_NAME: martials
commands:
- cachix authtoken $CACHIX_AUTH_TOKEN
Collaborator
[bug] Woodpecker does not expose secrets to `pull_request` events by default (and never to fork PRs). Since this pipeline triggers on `event: pull_request`, `CACHIX_AUTH_TOKEN` will be empty there and `cachix authtoken $CACHIX_AUTH_TOKEN` — the only cachix command without an `||` guard — may fail the whole step (or silently no-op the caching). Guard the cachix setup/push on token presence (e.g. `if [ -n "${CACHIX_AUTH_TOKEN:-}" ]; then ...; fi`) or restrict the auth/push work to push/tag events. Also note: if the secret is enabled for PR events, executing untrusted PR code with the cache write token is a security risk.
<!-- forgejo-opencode-review --> [bug] Woodpecker does not expose secrets to `pull_request` events by default (and never to fork PRs). Since this pipeline triggers on `event: pull_request`, `CACHIX_AUTH_TOKEN` will be empty there and `cachix authtoken $CACHIX_AUTH_TOKEN` — the only cachix command without an `||` guard — may fail the whole step (or silently no-op the caching). Guard the cachix setup/push on token presence (e.g. `if [ -n "${CACHIX_AUTH_TOKEN:-}" ]; then ...; fi`) or restrict the auth/push work to push/tag events. Also note: if the secret is enabled for PR events, executing untrusted PR code with the cache write token is a security risk.
Collaborator
[style] Use the repo's established `$${VAR}` escaping and quoting convention for variables referenced in commands (see `push.yaml:47-49` which uses `$${CACHIX_AUTH_TOKEN}`/`$${CACHE_NAME}`). Bare `$VAR` is subject to Woodpecker's own variable interpolation, which can behave unexpectedly (e.g. unparseable variable-name warnings) when a variable isn't resolvable, and unquoted expansion risks word-splitting.
<!-- forgejo-opencode-review --> [style] Use the repo's established `$${VAR}` escaping and quoting convention for variables referenced in commands (see `push.yaml:47-49` which uses `$${CACHIX_AUTH_TOKEN}`/`$${CACHE_NAME}`). Bare `$VAR` is subject to Woodpecker's own variable interpolation, which can behave unexpectedly (e.g. unparseable variable-name warnings) when a variable isn't resolvable, and unquoted expansion risks word-splitting.
martin marked this conversation as resolved
Update flake lockfile
All checks were successful
ci/woodpecker/pr/pr-review Pipeline was successful
ci/woodpecker/pr/verify Pipeline was successful
ci/woodpecker/pr/verify-nix Pipeline was successful
28c30d6823
clank-bot left a comment

Code review findings from opencode.

Code review findings from opencode. <!-- forgejo-opencode-review -->
Collaborator
[style] The pipeline only builds the `default` package. The `recurring-events-image` derivation (nix2container-based, what `push.yaml` ships to prod) and the repo's treefmt formatting check (`nix flake check`, defined in `flake.nix`) are not verified, so a broken image or formatting derivation would still only be caught in the push pipeline. Consider adding `nix build .#recurring-events-image` and/or `nix flake check` so the pipeline fully verifies what it claims to.
<!-- forgejo-opencode-review --> [style] The pipeline only builds the `default` package. The `recurring-events-image` derivation (nix2container-based, what `push.yaml` ships to prod) and the repo's treefmt formatting check (`nix flake check`, defined in `flake.nix`) are not verified, so a broken image or formatting derivation would still only be caught in the push pipeline. Consider adding `nix build .#recurring-events-image` and/or `nix flake check` so the pipeline fully verifies what it claims to.
martin marked this conversation as resolved
Collaborator
[performance] `nix path-info` with no arguments enumerates every valid path in the local store, not just the built derivation's closure. In the `cachix-flakes` image the store is usually fresh so this is bounded, but if the runner reuses a warm store this pushes a lot of unrelated paths. Scoping to the build output (`nix path-info -r $(nix build --no-link --print-out-paths)`) is more precise; the current blanket form is acceptable but worth being aware of.
<!-- forgejo-opencode-review --> [performance] `nix path-info` with no arguments enumerates every valid path in the local store, not just the built derivation's closure. In the `cachix-flakes` image the store is usually fresh so this is bounded, but if the runner reuses a warm store this pushes a lot of unrelated paths. Scoping to the build output (`nix path-info -r $(nix build --no-link --print-out-paths)`) is more precise; the current blanket form is acceptable but worth being aware of.
martin marked this conversation as resolved
ci: Build image instead of drv
Some checks failed
ci/woodpecker/pr/pr-review Pipeline was successful
ci/woodpecker/pr/verify Pipeline was successful
ci/woodpecker/pr/verify-nix Pipeline failed
8ab1005378
clank-bot left a comment

Code review findings from opencode.

Code review findings from opencode. <!-- forgejo-opencode-review -->
@ -0,0 +6,4 @@
- "**/*.nix"
- "flake.lock"
- ".woodpecker/verify-nix.yaml"
- event: push
Collaborator
[performance] On default-branch pushes, `push.yaml` already builds `.#recurring-events-image` under `cachix watch-exec` and pushes its closure to the same `martials` cache (push.yaml:49-50), and it is not excluded for `.nix/*.nix` changes. The `push` trigger here therefore re-runs the same build + cache push on every nix-touching default-branch push — duplicated CI time (and a second full build if it lands on a different runner with a cold store) for no additional coverage. Consider dropping the `push` trigger and keeping this pipeline as PR/manual-only, since that is its unique value.
<!-- forgejo-opencode-review --> [performance] On default-branch pushes, `push.yaml` already builds `.#recurring-events-image` under `cachix watch-exec` and pushes its closure to the same `martials` cache (push.yaml:49-50), and it is not excluded for `.nix/*.nix` changes. The `push` trigger here therefore re-runs the same build + cache push on every nix-touching default-branch push — duplicated CI time (and a second full build if it lands on a different runner with a cold store) for no additional coverage. Consider dropping the `push` trigger and keeping this pipeline as PR/manual-only, since that is its unique value.
@ -0,0 +12,4 @@
include:
- "**/*.nix"
- "flake.lock"
- ".woodpecker/verify-nix.yaml"
Collaborator
[bug] `push.yaml` and `deploy.yaml` exclude only `.woodpecker/*.yml` (note: `.yml`), but these pipeline files use the `.yaml` extension. A default-branch push touching only `.woodpecker/verify-nix.yaml` (which this pipeline itself lists in its trigger) will therefore also start the `push` and `deploy` pipelines — rebuilding/pushing the image and auto-bumping the cluster deployment for a pure CI-config change. Add a `".woodpecker/*.yaml"` exclusion to `push.yaml` and `deploy.yaml` (ideally in this PR), or the repo's `.yml`/`.yaml` divergence will keep causing spurious deploys.
<!-- forgejo-opencode-review --> [bug] `push.yaml` and `deploy.yaml` exclude only `.woodpecker/*.yml` (note: `.yml`), but these pipeline files use the `.yaml` extension. A default-branch push touching only `.woodpecker/verify-nix.yaml` (which this pipeline itself lists in its trigger) will therefore also start the `push` and `deploy` pipelines — rebuilding/pushing the image and auto-bumping the cluster deployment for a pure CI-config change. Add a `".woodpecker/*.yaml"` exclusion to `push.yaml` and `deploy.yaml` (ideally in this PR), or the repo's `.yml`/`.yaml` divergence will keep causing spurious deploys.
@ -0,0 +29,4 @@
- cachix authtoken $${CACHIX_AUTH_TOKEN}
- cachix use $${CACHE_NAME}
- nix build .#recurring-events-image --print-build-logs --no-link
- nix path-info .#recurring-events-image | cachix push $${CACHE_NAME} || echo "⚠️ Cachix push skipped, continuing..."
Collaborator
[bug] The `|| echo` guard swallows *all* cachix push errors, not just the missing-token case on PRs. On a push event where the token is set, a real failure (registry down, revoked token, disk full) exits 0 and the pipeline is green while the cache silently stays stale. Additionally, without `set -o pipefail`, a `nix path-info` failure (e.g. flake eval error) makes `cachix push` read empty stdin and exit 0, masking that failure too. Prefer guarding cachix setup/push on token presence (`if [ -n "$CACHIX_AUTH_TOKEN" ]; then ...; fi`) and letting genuine push failures fail the step.
<!-- forgejo-opencode-review --> [bug] The `|| echo` guard swallows *all* cachix push errors, not just the missing-token case on PRs. On a push event where the token is set, a real failure (registry down, revoked token, disk full) exits 0 and the pipeline is green while the cache silently stays stale. Additionally, without `set -o pipefail`, a `nix path-info` failure (e.g. flake eval error) makes `cachix push` read empty stdin and exit 0, masking that failure too. Prefer guarding cachix setup/push on token presence (`if [ -n "$CACHIX_AUTH_TOKEN" ]; then ...; fi`) and letting genuine push failures fail the step.
ci: Remove push event on verify-nix
Some checks failed
ci/woodpecker/pr/pr-review Pipeline was successful
ci/woodpecker/pr/verify-nix unknown status
ci/woodpecker/pr/verify Pipeline was canceled
1b5027b56f
clank-bot left a comment

Code review findings from opencode.

Code review findings from opencode. <!-- forgejo-opencode-review -->
@ -0,0 +5,4 @@
include:
- "**/*.nix"
- "flake.lock"
- ".woodpecker/verify-nix.yaml"
Collaborator
[style] This trigger lists `.woodpecker/verify-nix.yaml`, but `push.yaml`/`deploy.yaml` only exclude `.woodpecker/*.yml` (the repo mixes `.yml` and `.yaml`). A default-branch push touching only this config file will therefore also start `push` and `deploy`, rebuilding/pushing the image and auto-bumping the cluster env for a pure CI-config change. Add `".woodpecker/*.yaml"` to those pipelines' exclusions, ideally in this PR.
<!-- forgejo-opencode-review --> [style] This trigger lists `.woodpecker/verify-nix.yaml`, but `push.yaml`/`deploy.yaml` only exclude `.woodpecker/*.yml` (the repo mixes `.yml` and `.yaml`). A default-branch push touching only this config file will therefore also start `push` and `deploy`, rebuilding/pushing the image and auto-bumping the cluster env for a pure CI-config change. Add `".woodpecker/*.yaml"` to those pipelines' exclusions, ideally in this PR.
@ -0,0 +19,4 @@
from_secret: cachix_auth_token
CACHE_NAME: martials
commands:
- cachix authtoken $${CACHIX_AUTH_TOKEN}
Collaborator
[bug] `cachix authtoken $${CACHIX_AUTH_TOKEN}` is the only unguarded cachix command. Woodpecker does not expose secrets to `pull_request` events by default (never for fork PRs), so on a PR run the token is empty and this can fail the step or silently no-op the caching — while the guarded push means PR builds never populate the cache anyway. Guard cachix setup + push on token presence (`if [ -n "${CACHIX_AUTH_TOKEN:-}" ]; then ...; fi`) or move auth/push work to events where the secret is available.
<!-- forgejo-opencode-review --> [bug] `cachix authtoken $${CACHIX_AUTH_TOKEN}` is the only unguarded cachix command. Woodpecker does not expose secrets to `pull_request` events by default (never for fork PRs), so on a PR run the token is empty and this can fail the step or silently no-op the caching — while the guarded push means PR builds never populate the cache anyway. Guard cachix setup + push on token presence (`if [ -n "${CACHIX_AUTH_TOKEN:-}" ]; then ...; fi`) or move auth/push work to events where the secret is available.
Author
Owner

It is exposed to pull requests

It is exposed to pull requests
@ -0,0 +22,4 @@
- cachix authtoken $${CACHIX_AUTH_TOKEN}
- cachix use $${CACHE_NAME}
- nix build .#recurring-events-image --print-build-logs --no-link
- nix path-info .#recurring-events-image | cachix push $${CACHE_NAME} || echo "⚠️ Cachix push skipped, continuing..."
Collaborator
[bug] The `|| echo "skipped"` swallows every cachix push failure (auth failure, registry down, revoked token) and reports green while the cache silently stays stale. Combined with the pipe and no `set -o pipefail`, a `nix path-info` failure also goes unnoticed if `cachix push` reads empty stdin and exits 0. Prefer guarding cachix commands on token presence and letting genuine push failures fail the step.
<!-- forgejo-opencode-review --> [bug] The `|| echo "skipped"` swallows every cachix push failure (auth failure, registry down, revoked token) and reports green while the cache silently stays stale. Combined with the pipe and no `set -o pipefail`, a `nix path-info` failure also goes unnoticed if `cachix push` reads empty stdin and exits 0. Prefer guarding cachix commands on token presence and letting genuine push failures fail the step.
martin force-pushed verify-nix-pipeline from 1b5027b56f
Some checks failed
ci/woodpecker/pr/pr-review Pipeline was successful
ci/woodpecker/pr/verify-nix unknown status
ci/woodpecker/pr/verify Pipeline was canceled
to 1aaf0946ed
Some checks failed
ci/woodpecker/pr/pr-review Pipeline failed
ci/woodpecker/pr/verify Pipeline was successful
ci/woodpecker/pr/verify-nix Pipeline was successful
2026-08-16 10:28:17 +00:00
Compare
martin merged commit a105ee3c3b into master 2026-08-16 10:41:25 +00:00
martin deleted branch verify-nix-pipeline 2026-08-16 10:41:26 +00:00
martin referenced this pull request from a commit 2026-08-16 10:41:26 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
martin/recurring-events!27
No description provided.