From 961910a162969760a4b5ef8aa93e0d975ca334a1 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Sun, 22 Feb 2026 17:37:16 -0800 Subject: [PATCH] Add workflow validation via Dagger and pre-commit hook Add validate_workflows function to Dagger module using forgejo-runner validate --directory inside the upstream v12.7.0 container. All 6 workflows pass schema validation. Wire as mise task and pre-commit hook on .forgejo/workflows/ changes. Marks validate-workflows-against-v12 Mikado card complete. Co-Authored-By: Claude Opus 4.6 --- .dagger/src/blumeops_ci/main.py | 21 +++++ .pre-commit-config.yaml | 10 +++ .../validate-workflows-against-v12.md | 81 +++++-------------- mise-tasks/validate-workflows | 6 ++ 4 files changed, 58 insertions(+), 60 deletions(-) create mode 100755 mise-tasks/validate-workflows diff --git a/.dagger/src/blumeops_ci/main.py b/.dagger/src/blumeops_ci/main.py index 433faed..f24b9e8 100644 --- a/.dagger/src/blumeops_ci/main.py +++ b/.dagger/src/blumeops_ci/main.py @@ -233,6 +233,27 @@ class BlumeopsCi: .file(f"/output/{output_file}") ) + @function + async def validate_workflows( + self, + src: dagger.Directory, + runner_version: str = "12.7.0", + ) -> str: + """Validate Forgejo Actions workflow files against runner schema. + + Runs forgejo-runner validate (available v9.0+) against all workflow + files in .forgejo/workflows/. Returns validation output. Fails if + any workflow has schema errors. + """ + return await ( + dag.container() + .from_(f"code.forgejo.org/forgejo/runner:{runner_version}") + .with_directory("/workspace", src) + .with_workdir("/workspace") + .with_exec(["forgejo-runner", "validate", "--directory", "."]) + .stdout() + ) + @function async def flake_update( self, src: dagger.Directory, flake_path: str = "nixos/ringtail" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1797afc..1f5950a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -89,6 +89,16 @@ repos: args: ['-config-file', '.github/actionlint.yaml'] files: ^\.forgejo/workflows/ + # Forgejo workflow schema validation (via Dagger + forgejo-runner validate) + - repo: local + hooks: + - id: validate-workflows + name: validate-workflows + entry: mise run validate-workflows + language: system + files: ^\.forgejo/workflows/ + pass_filenames: false + # Container version consistency - repo: local hooks: diff --git a/docs/how-to/forgejo-runner/validate-workflows-against-v12.md b/docs/how-to/forgejo-runner/validate-workflows-against-v12.md index fd53a81..dec5d1c 100644 --- a/docs/how-to/forgejo-runner/validate-workflows-against-v12.md +++ b/docs/how-to/forgejo-runner/validate-workflows-against-v12.md @@ -1,6 +1,5 @@ --- title: Validate Workflows Against v12 -status: active modified: 2026-02-22 tags: - how-to @@ -12,70 +11,32 @@ tags: Run `forgejo-runner validate` (available from v9.0+) against all workflow files to catch schema issues before upgrading the k8s runner daemon. -## Background +## Result -Forgejo-runner v8.0 introduced workflow schema validation — workflows that don't pass are rejected at runtime. v9.0 made this stricter and added a `validate` CLI command. Since we're jumping from v6.3.1, we've never run validation. All six workflows in `.forgejo/workflows/` need checking. +All 6 workflows pass v12.7.0 schema validation with no changes needed: -## Approach: Dagger Pipeline - -Add a `validate_workflows` function to the [[dagger]] module (`.dagger/src/blumeops_ci/main.py`). This runs `forgejo-runner validate` inside the upstream runner container — no host-side binary management, reproducible, and version-pinned. - -```python -@function -async def validate_workflows( - self, - src: dagger.Directory, - runner_version: str = "12.7.0", -) -> str: - """Validate Forgejo Actions workflow files against runner schema.""" - return await ( - dag.container() - .from_(f"code.forgejo.org/forgejo/runner:{runner_version}") - .with_directory("/workspace", src) - .with_workdir("/workspace") - .with_exec([ - "sh", "-c", - "for f in .forgejo/workflows/*.yaml; do " - ' echo "=== $f ===" && forgejo-runner validate "$f"; ' - "done" - ]) - .stdout() - ) -``` - -Invoke locally with: - -```fish -dagger call validate-workflows --src=. -``` - -### Permanent guardrail - -Once the function exists, wire it into CI as a pre-commit hook or a mise task (`mise run validate-workflows`). This prevents future workflow regressions regardless of runner version changes. The `runner_version` parameter lets us pin to whatever version the k8s runner is actually running. - -## Workflows to Validate - -| File | Complexity | Notes | -|------|-----------|-------| -| `build-container.yaml` | High | Matrix strategy, conditional steps | -| `build-container-nix.yaml` | High | Matrix strategy, conditional steps | -| `build-blumeops.yaml` | High | Multi-step release pipeline | -| `deploy-fly.yaml` | Low | Simple deploy | -| `cv-deploy.yaml` | Medium | Version resolution + deploy | -| `branch-cleanup.yaml` | Low | Scheduled + manual dispatch | - -## Fix any failures - -If validation fails, fix the workflow schema issues in the same PR as the runner upgrade. Common issues in the v8/v9 changelog: -- Invalid `type:` values in `workflow_dispatch.inputs` -- Incorrect `if:` expression syntax -- Undeclared or misspelled keys +- `branch-cleanup.yaml` — OK +- `build-blumeops.yaml` — OK +- `build-container-nix.yaml` — OK +- `build-container.yaml` — OK +- `cv-deploy.yaml` — OK +- `deploy-fly.yaml` — OK ## Deliverables -1. `validate_workflows` function in `.dagger/src/blumeops_ci/main.py` -2. All 6 workflows passing validation (fix any schema issues) -3. A mise task or pre-commit hook wiring `dagger call validate-workflows` for ongoing use +1. `validate_workflows` function added to `.dagger/src/blumeops_ci/main.py` + - Uses `forgejo-runner validate --directory .` inside the upstream runner container + - `runner_version` parameter (default `12.7.0`) pins to deployed version +2. `mise run validate-workflows` task wired to `dagger call validate-workflows` +3. Pre-commit hook triggers on `.forgejo/workflows/` changes + +## Usage + +```fish +mise run validate-workflows +# or directly: +dagger call validate-workflows --src=. +``` ## Related diff --git a/mise-tasks/validate-workflows b/mise-tasks/validate-workflows new file mode 100755 index 0000000..e541870 --- /dev/null +++ b/mise-tasks/validate-workflows @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +#MISE description="Validate Forgejo workflow files against runner schema" + +set -euo pipefail + +dagger call validate-workflows --src=.