Prepare forgejo-runner v12 upgrade (leaf nodes) (#250)

## Summary
- Review runner config against v12.7.0 defaults — added `shutdown_timeout: 3h`, no breaking changes found
- Add `validate_workflows` Dagger function using `forgejo-runner validate --directory .` inside upstream container
- All 6 workflows pass v12.7.0 schema validation
- Wire `mise run validate-workflows` task and pre-commit hook on `.forgejo/workflows/` changes
- Mark both leaf Mikado cards (`review-runner-config-v12`, `validate-workflows-against-v12`) complete

## Mikado State
After merge, `upgrade-k8s-runner` goal card has no unmet dependencies — ready to execute the actual image bump in a follow-up PR.

## Test Plan
- [x] `dagger call validate-workflows --src=.` passes (all 6 workflows OK)
- [x] Pre-commit hooks pass
- [ ] Reviewer: confirm `shutdown_timeout: 3h` addition to ConfigMap looks reasonable

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/250
This commit is contained in:
Erich Blume 2026-02-22 17:38:32 -08:00
commit 0f6a1898f0
7 changed files with 76 additions and 98 deletions

View file

@ -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"

View file

@ -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:

View file

@ -5,6 +5,7 @@ metadata:
namespace: forgejo-runner
data:
config.yaml: |
# Reviewed against v12.7.0 defaults (2026-02-22)
log:
level: info
@ -12,6 +13,7 @@ data:
file: /data/.runner
capacity: 2
timeout: 3h
shutdown_timeout: 3h
# Env vars injected into all job containers
envs:
DOCKER_HOST: tcp://127.0.0.1:2375

View file

@ -0,0 +1 @@
Prepare forgejo-runner v12 upgrade: review config compatibility, add workflow schema validation via Dagger, wire pre-commit hook

View file

@ -1,6 +1,5 @@
---
title: Review Runner Config for v12
status: active
modified: 2026-02-22
tags:
- how-to
@ -12,48 +11,26 @@ tags:
Compare the current runner ConfigMap against the v12.7.0 default config to identify new, changed, or deprecated keys.
## Background
## Findings
The runner config in `argocd/manifests/forgejo-runner/configmap.yaml` was written for v6.3.1. Six major versions may have introduced new config keys, changed defaults, or deprecated options.
Compared `forgejo-runner generate-config` output from v6.3.1 and v12.7.0. Our config is minimal and remains valid for v12.
## Current Config
### New sections in v12 (not adopted)
```yaml
log:
level: info
runner:
file: /data/.runner
capacity: 2
timeout: 3h
envs:
DOCKER_HOST: tcp://127.0.0.1:2375
TZ: America/Los_Angeles
container:
network: "host"
docker_host: tcp://127.0.0.1:2375
```
## Steps
1. Fetch the v12.7.0 example config:
```fish
curl -L "https://code.forgejo.org/forgejo/runner/raw/tag/v12.7.0/.forgejo-runner.example.yaml"
```
2. Diff against our current config — note new sections/keys
3. Check the release notes for each major version (v7v12) for config-related changes:
- v7.0: `FORGEJO_*` env vars (backward compat with `GITHUB_*`)
- v8.0: Default container image change
- v12.7: `server.connections` for multi-server polling; secret URLs; ephemeral mode
4. Decide which new keys to adopt (if any) and update the ConfigMap
5. Pay attention to `container.valid_volumes` and `container.options` (added in v6.x for security) — we may want to configure these
## Key Areas to Check
- **`container.valid_volumes`** — allowlist for volume mounts in job containers (security hardening from v6.x)
- **`container.options`** — allowlist for container options
- **`runner.envs`** — are `FORGEJO_*` vars needed alongside `GITHUB_*`?
- **Ephemeral mode** (v12.7) — one-shot runners that de-register after a job. Not needed now but worth noting.
- **`server.connections`** — multi-server polling. Not needed (single Forgejo instance).
- **`cache.secret_url`** — load cache secret from file URL. Not needed.
- **`runner.report_retry`** — retry config for log uploads. Defaults are fine.
### Changed semantics
- **`container.docker_host`** — v12 supports `unix://` and `ssh://` URLs. Our explicit `tcp://127.0.0.1:2375` still correct for DinD sidecar.
- **`cache`** section restructured with proxy/server split and better docs. We don't configure cache, so defaults apply.
### Config update applied
Added `shutdown_timeout: 3h` to allow graceful job completion on pod termination (v12 default, was missing from our v6 config). Added review date comment.
`container.valid_volumes` and `container.options` left empty — our jobs use host networking and don't mount volumes. Can harden later if needed.
## Related

View file

@ -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

6
mise-tasks/validate-workflows Executable file
View file

@ -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=.