Stand up a Forgejo Actions runner on a service VM and run each repo's flake checks on pull requests #52

Open
opened 2026-09-11 21:18:34 +01:00 by allod-agent · 2 comments
Member

Stand up a Forgejo Actions runner on a service VM and run each public repo's flake checks on every pull request, so "green" is a fact the forge records instead of a claim typed into a PR body.

Primary goals:

  • Checks run by a machine — every PR against a public repo gets the repo's checks run by the forge with allod check, the per-step gate from allod/tools#239, with the result visible on the PR before merge. Same command the agents run by hand; nothing about the checks changes. Not nix flake check: it evaluates every machine and check in one process and is killed for memory on a fork with a real fleet.
  • One service VM, one job — the runner lives on the first service VM (the org profile already names service VMs as the home for runners), holds no age identity and no private checkout, and its forge token is scoped to reporting job status and nothing else.
  • Sized for the check sets — the archetypes checks force about 29 fixture systems and were the largest memory driver the microvm withdrawal (allod/strategy#46) exposed; the VM is sized for that, or that reduction is the first thing this work motivates.
  • Fast enough to keep — a warm Nix store or a binary cache so a PR does not rebuild nixpkgs; a run that takes longer than the human review will be routed around.
  • A dev plan before a runner — a machine that holds a forge token and executes code from pull requests is R3 at least: the token scope, the VM's isolation from every other machine, and what a compromised runner could reach are written down and reviewed before anything is built.

Current state and specifics

No repo has a .forgejo/workflows/ directory and no runner is registered. Branch protection on the forge rejects direct pushes for the agent account but runs nothing. The PR workflow in allod/memory (memory.md, PR Workflow) compensates with rules that every validation claim in a PR body is in scope for review, and the cross-family review pass exists partly to catch claims that were not run; a recorded check result removes that class of defect rather than policing it.

The forge is self-hosted Forgejo at the deployment's forge host; Forgejo Actions with forgejo-runner is the native path. A NixOS runner needs the nix daemon, network to the forge and to a substituter, and enough memory for the largest check set; it must not carry the age identity, a private checkout, or any token beyond the runner's own.

Public repos only. A runner for the private forks would hold private material and is a separate decision, taken after this one has run for a while.

Scope

In: the dev plan (token scope, isolation, blast radius of a compromised runner, VM size), the service VM profile in the framework, the runner registration, one workflow per public repo that runs the flake checks on pull requests, and the memory update that says a PR's checks are read from the forge. Out: per-commit build-cost measurement, which is the first consumer of this runner and is tracked in its own issue; a runner for the private forks; any change to what the checks test.

Stand up a Forgejo Actions runner on a service VM and run each public repo's flake checks on every pull request, so "green" is a fact the forge records instead of a claim typed into a PR body. Primary goals: - **Checks run by a machine** — every PR against a public repo gets the repo's checks run by the forge with `allod check`, the per-step gate from allod/tools#239, with the result visible on the PR before merge. Same command the agents run by hand; nothing about the checks changes. Not `nix flake check`: it evaluates every machine and check in one process and is killed for memory on a fork with a real fleet. - **One service VM, one job** — the runner lives on the first service VM (the org profile already names service VMs as the home for runners), holds no age identity and no private checkout, and its forge token is scoped to reporting job status and nothing else. - **Sized for the check sets** — the archetypes checks force about 29 fixture systems and were the largest memory driver the microvm withdrawal (allod/strategy#46) exposed; the VM is sized for that, or that reduction is the first thing this work motivates. - **Fast enough to keep** — a warm Nix store or a binary cache so a PR does not rebuild nixpkgs; a run that takes longer than the human review will be routed around. - **A dev plan before a runner** — a machine that holds a forge token and executes code from pull requests is R3 at least: the token scope, the VM's isolation from every other machine, and what a compromised runner could reach are written down and reviewed before anything is built. ### Current state and specifics No repo has a `.forgejo/workflows/` directory and no runner is registered. Branch protection on the forge rejects direct pushes for the agent account but runs nothing. The PR workflow in `allod/memory` (`memory.md`, PR Workflow) compensates with rules that every validation claim in a PR body is in scope for review, and the cross-family review pass exists partly to catch claims that were not run; a recorded check result removes that class of defect rather than policing it. The forge is self-hosted Forgejo at the deployment's forge host; Forgejo Actions with `forgejo-runner` is the native path. A NixOS runner needs the nix daemon, network to the forge and to a substituter, and enough memory for the largest check set; it must not carry the age identity, a private checkout, or any token beyond the runner's own. Public repos only. A runner for the private forks would hold private material and is a separate decision, taken after this one has run for a while. ### Scope In: the dev plan (token scope, isolation, blast radius of a compromised runner, VM size), the service VM profile in the framework, the runner registration, one workflow per public repo that runs the flake checks on pull requests, and the memory update that says a PR's checks are read from the forge. Out: per-commit build-cost measurement, which is the first consumer of this runner and is tracked in its own issue; a runner for the private forks; any change to what the checks test.
Contributor

One correction to the body before this is planned: the command CI runs should be the check gate, not nix flake check.

nix flake check evaluates every machine and check in one process. On a deployment fork with eight machines it was OOM-killed at 6.6 GiB on an 8 GiB machine, 45 seconds in, before it finished the check list. The per-step gate passed all 30 steps on the same machine. Numbers and method are in allod/tools#239, which moves that gate into allod/tools as one command for every repo.

That leaves two ways to satisfy "sized for the check sets" here: run the gate, or size the runner well above 8 GiB. Running the gate also means CI and a human run the same command. The body edit is on the allod/tools#239 checklist.

One correction to the body before this is planned: the command CI runs should be the check gate, not `nix flake check`. `nix flake check` evaluates every machine and check in one process. On a deployment fork with eight machines it was OOM-killed at 6.6 GiB on an 8 GiB machine, 45 seconds in, before it finished the check list. The per-step gate passed all 30 steps on the same machine. Numbers and method are in allod/tools#239, which moves that gate into `allod/tools` as one command for every repo. That leaves two ways to satisfy "sized for the check sets" here: run the gate, or size the runner well above 8 GiB. Running the gate also means CI and a human run the same command. The body edit is on the allod/tools#239 checklist.
Author
Member

Body edited, as announced in the comment above and listed on allod/tools#239: the first goal now says CI runs allod check, where it said nix flake check. Nothing else in the body changed. The command is merged in allod/tools; its documentation is docs/allod-check.md there.

One thing for the dev plan here: the runner needs an allod that carries the command, so its tools pin has to be at or after that merge.

Body edited, as announced in the comment above and listed on allod/tools#239: the first goal now says CI runs `allod check`, where it said `nix flake check`. Nothing else in the body changed. The command is merged in `allod/tools`; its documentation is `docs/allod-check.md` there. One thing for the dev plan here: the runner needs an `allod` that carries the command, so its tools pin has to be at or after that merge.
Sign in to join this conversation.
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.

Dependencies

No dependencies set

Reference
allod/strategy#52
No description provided.