Skip to content

ci: every workflow step is one task, and Task from go.mod - #214

Merged
aledbf merged 3 commits into
mainfrom
taskgate
Oct 24, 2026
Merged

aledbf merged 3 commits into
mainfrom
taskgate

Conversation

@aledbf

@aledbf aledbf commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Every run: step of every workflow is now one go tool task <name>, and task lint holds the repository to that with go-tools' taskgate, and to pnpm through Socket Firewall with sfw check.

Depends on spin-stack/go-tools#50 (not merged yet). go.mod pins go-tools at that PR's commit 8cf54b0. When #50 merges, re-pin with go get github.com/spin-stack/go-tools@<main's commit>.

What changed

  • go.mod. go-tools moves to ci: the chain says what it does, and the lab takes a build one way #50's commit. cmd/taskgate, cmd/sfw and Task (github.com/go-task/task/v3/cmd/task@v3.54.0) are added as tools. 3.54.0 is the version versions.yaml already pins for the image. That task entry stays, because the image's install-dev-tools.sh and hack/release read it.
  • Workflows. The go-task/setup-task step is gone from all nine, so they need only setup-go. In report.yml, setup-go moves above "What this runner has", because that step is now a task.
  • The 37 steps that ran their own shell, and the task each became:
    • ci.yml:
      • Coverage summary → coverage
      • What this change broke → mutate. mutate now works out the base in CI from GITHUB_EVENT_NAME, GITHUB_BASE_REF and BEFORE; locally it still defaults to origin/main.
      • Load vhost_vsock → vsock
    • compat.yml:
      • A BuildKit that keeps its cache → boot:buildkit
      • The machine before, and this one → boot:here
      • Every ROM → the existing boot:roms
      • A checkpoint resumes → the existing boot:compat
    • osv.yml: Bring the issues → osv:issues
    • qemu/kernel/image.yml:
      • Does the change reach X → touches -- <entries> -- <paths>. The lists stay in the YAML, beside the path filters they mirror.
      • The builds → qemu:build, kernel:build, e2fsprogs:build and image:build. CACHE_BACKEND and CACHE_EXPORT now go in the step's env:.
      • What this X is → qemu:summary, kernel:summary, image:summary
      • Read the pinned QEMU version → qemu:version
      • Publish the runtime image → qemu:publish
      • Load vhost_vsock → vsock
    • lab.yml: lab:unpack, lab:fetch, lab:place, lab:vars, lab:about, lab:run, lab:found
    • release.yml: release:version, release:notes, release:provenance, release:sign, release:tag. "Tag the commit" now reads VERSION from env: and no longer from ${{ }} in the script.
    • report.yml: report:runner, report:unpack, report:compare, report:publish
  • Where the tasks write. Writes to $GITHUB_OUTPUT, $GITHUB_ENV and $GITHUB_STEP_SUMMARY moved into the tasks. Outside CI they go to stdout. Scripts that ran under Actions' bash -e now start with set -e, so a failure stops them as before.
  • Calling Task from a Taskfile. The Taskfiles call Task through {{.TASK_EXE}} (lint, default, bump, lab:run), because no task binary is on PATH in CI any more.
  • TASK_OUTPUT: interleaved is set for the lab, report and release jobs. Task's prefixed output puts [name] before ::error::, and GitHub then no longer reads it as a workflow command.
  • attestgate (workflows/workflows_test.go) is told that qemu:publish and report:publish upload and that release:sign attests. The YAML now names only the tasks.
  • No taskgate exemptions. There is no .github/taskgate-allow.txt.

Verified

  • go tool taskgate: "every workflow step runs a task (0 exempt)".
  • go tool sfw check: OK. There is no JavaScript in this repository.
  • go tool task lint passes: gofmt, vet, the Taskfiles parse, shell, ctxlife, testquality, refs, mutate -stale-exempts, taskgate, sfw, actionlint, and every action pinned by commit.
  • go tool task test passes (89.6%). go test ./workflows/ (attestgate) passes.
  • Every task name a workflow calls exists (--list-all).
  • Run locally with their CI environment faked:
    • coverage (with and without coverage.out)
    • touches
    • qemu:version
    • release:version: given, generated, and refusing a bad version
    • mutate: the PR base, the push base, the HEAD~1 fallback, the local default, an explicit BASE
    • lab:vars: accepted, refused, and reserved names
    • lab:fetch: no runs, and a bad run id
    • lab:place: beside and instead, on a fake tree
    • lab:about
    • lab:run: nested TASK_EXE and the log tee
    • lab:found
    • report:runner: through a sudo that fails
  • --dry renders of boot:here and qemu:publish.
  • Checked that the environment beats a Taskfile's env: in Task 3.54, which compat.yml's ROM and checkpoint steps rely on.

Not verified

These need KVM, a release download, registry or release credentials, or a real CI run:

  • vsock (sudo chmod on the host)
  • boot:buildkit (would make a builder on the host)
  • boot:here, boot:roms and boot:compat end to end
  • qemu/kernel/image:summary and qemu:publish, which need builds
  • osv:issues (it writes issues)
  • release:notes, release:sign, release:tag and release:provenance
  • lab:unpack, report:unpack, report:compare and report:publish

The first run of each workflow on this branch is the check for those.

Worth knowing

  • What it found (lab.yml) may have been printing an empty block. The experiment's log was Task-prefixed, so its ^\s{4} grep found nothing. With interleaved output it now gets the test's lines.
  • qemu:publish tags ghcr.io/$GITHUB_REPOSITORY/qemu, as before. Outside CI it falls back to spin-stack/spin-machine.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

aledbf and others added 2 commits October 24, 2026 15:37
A step that ran its own shell was a second copy of the build that only
ever ran on a push. Each of the 37 is now `go tool task <name>`: an
existing task where one already did the same thing (boot:roms,
boot:compat), a new one beside it otherwise, with what only the
workflow knows in the step's env: and its outputs, env and summary
written by the task (to stdout outside CI).

Task is a go.mod tool at 3.54.0, the version versions.yaml pins for
the image, so a workflow needs only setup-go, and the Taskfiles call
themselves through TASK_EXE. go-tools moves to spin-stack/go-tools#50
for its two new gates, which task lint runs: taskgate, with no
exemption, and sfw, which finds no JavaScript here and holds the first
package.json to pnpm through Socket Firewall.

attestgate is told which tasks publish (qemu:publish, report:publish)
and which attests (release:sign), since the YAML now names them only.
lab, report and release run Task with interleaved output: a prefixed
line hides the ::error:: commands their tasks print.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
spin-stack/go-tools#50 and #51 are on main: the pin moves from the PR's commit to main's, which
also finds the Task go.mod pins for refs and holds pnpm run to installing nothing on its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@aledbf
aledbf marked this pull request as ready for review October 24, 2026 19:00
… task

Through spin-stack/go-tools#52: refs ran the path `go tool -n task` printed, a build directory
that in CI was gone once go returned, and lint failed on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@aledbf
aledbf merged commit bda2fef into main Oct 24, 2026
7 checks passed
@aledbf
aledbf deleted the taskgate branch October 24, 2026 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant