Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Phase 4: a run record names the machine, not the toolchain

379dad1e7417b9153a4913402cfc97bb51ce1bb4 · Keenan Nemetz · 16d ago · parent 72797dcd

Phase 4: a run record names the machine, not the toolchain

A finished attempt now says which operating system and architecture ran it,
in record.md beside the exit code and the signer, so the two fields ride the
signature that is the attestation. A result a clone carries says what kind
of machine produced it, not only which job it was — which is what turns
"one macOS runner in a Linux pool" into a question somebody can answer
after the fact, and the first half of the targeting work that remains.

The roadmap also asked for the runner's Go version and that was dropped
deliberately: runtime.Version() names the toolchain the *runner binary* was
compiled with, which is not the Go that builds anything in a job. A step
running `go build` uses whatever is on PATH in the checkout, usually a
different install, so in a signed record the field would be a confident
answer to a question nobody asked. OS and architecture survive the same
objection because they describe the machine, which is the fact this was for.

The keys are optional and an absent machine writes nothing at all rather
than an empty line, because a record is never rewritten and history that
predates a field has to stay readable. runs.db mirrors the pair the way it
mirrors the log and the artifacts — only while the runner still holds the
lease, so an overtaken runner leaves no claim behind — and `vole index
rebuild` restores it from the branch.

Measured: TestRunRecordIsPortable carries the machine through the record,
the row, the rebuild and the page; TestRecordWithoutMachineStillReads and
TestMachineIsRecordedOnlyWhileTheLeaseIsHeld pin the two edges.

internal/server/integration_test.go +12

@@ -17,6 +17,7 @@ import (
17 17 "os"
18 18 "os/exec"
19 19 "path/filepath"
20 "runtime"
20 21 "strings"
21 22 "sync"
22 23 "syscall"
@@ -2791,6 +2792,17 @@ jobs:
2791 2792 restoredAtt.Fingerprint != att.Fingerprint {
2792 2793 t.Fatalf("restored attestation = %+v", restoredAtt)
2793 2794 }
2795
2796 // The machine the attempt ran on travelled with the record: it is on the row after
2797 // the rebuild, and the page says so, which is the reason to store it at all.
2798 // The runner reported its own build target, so the fixture knows what to expect.
2799 wantOS, wantArch := runtime.GOOS, runtime.GOARCH
2800 if restored.OS != wantOS || restored.Arch != wantArch {
2801 t.Fatalf("restored machine = %q/%q, want %q/%q", restored.OS, restored.Arch, wantOS, wantArch)
2802 }
2803 if _, page := f.get("/r/" + f.repo + "/runs/" + done.ID); !strings.Contains(page, "ran on "+wantOS+"/"+wantArch) {
2804 t.Fatalf("the run page does not say which machine ran it:\n%s", page)
2805 }
2794 2806 }
2795 2807
2796 2808 // TestKilledRunnerIsRequeued is the other half of the contract: killing a runner