Commit ca8187d6b5

ca8187d6b59e59b2138f646d5bfcb5b32d86c3de

parent: 6ddd002e3a

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-28 06:27 UTC

runner next: say whether the build is trusted

Ref #255

Layout: unified · split

internal/control/build.go +13 −9
@@ -552,16 +552,20 @@ func runRunnerNext(c *Ctx, args []string) int {
552 } 552 }
553 } 553 }
554 d := struct { 554 d := struct {
555 ID int64 `json:"id"` 555 ID int64 `json:"id"`
556 Repo string `json:"repo"` 556 Repo string `json:"repo"`
557 Number int64 `json:"number"` 557 Number int64 `json:"number"`
558 Job string `json:"job"` 558 Job string `json:"job"`
559 SHA string `json:"sha"` 559 SHA string `json:"sha"`
560 Ref string `json:"ref"` 560 Ref string `json:"ref"`
561 Steps []string `json:"steps"` 561 Steps []string `json:"steps"`
562 Image string `json:"image,omitempty"` 562 Image string `json:"image,omitempty"`
563 // Trusted is always sent: a runner decides a build's home and
564 // secrets from it, and reads a missing field as untrusted (#255).
565 Trusted bool `json:"trusted"`
563 Secrets map[string]string `json:"secrets,omitempty"` 566 Secrets map[string]string `json:"secrets,omitempty"`
564 }{b.ID, repo.Path(), b.Number, b.Job, b.SHA, b.Ref, steps, b.Image, secrets} 567 }{ID: b.ID, Repo: repo.Path(), Number: b.Number, Job: b.Job, SHA: b.SHA, Ref: b.Ref,
568 Steps: steps, Image: b.Image, Trusted: b.Trusted, Secrets: secrets}
565 return c.emit(d, func(w io.Writer) { 569 return c.emit(d, func(w io.Writer) {
566 fmt.Fprintf(w, "build %d: %s %s @ %.10s\n", d.ID, d.Repo, d.Job, d.SHA) 570 fmt.Fprintf(w, "build %d: %s %s @ %.10s\n", d.ID, d.Repo, d.Job, d.SHA)
567 }) 571 })
internal/control/runnernext_test.go +21
@@ -245,3 +245,24 @@ func TestRunnerLogMarksStreamClosed(t *testing.T) {
245 t.Errorf("status %s, want still running until the runner reports", got.Status) 245 t.Errorf("status %s, want still running until the runner reports", got.Status)
246 } 246 }
247} 247}
248
249// The claim says whether a build is trusted in so many words. A runner
250// must not infer it from secrets being absent: a trusted repository with
251// no secrets looks the same (#255).
252func TestRunnerNextSaysWhetherTrusted(t *testing.T) {
253 st, repo, uid, root, baseSHA, _ := setupOrphanRepo(t)
254 for _, trusted := range []bool{true, false} {
255 if _, err := st.CreateBuild(repo.ID, "unit", baseSHA, "main", "[]", "", "", trusted); err != nil {
256 t.Fatal(err)
257 }
258 c, out := runnerCtx(st, uid, root)
259 c.JSON = true
260 if code := runRunnerNext(c, []string{"--untrusted"}); code != protocol.ExitOK {
261 t.Fatalf("runner next: exit %d, output:\n%s", code, out.String())
262 }
263 want := fmt.Sprintf(`"trusted":%v`, trusted)
264 if !strings.Contains(out.String(), want) {
265 t.Fatalf("claim of a trusted=%v build lacks %s:\n%s", trusted, want, out.String())
266 }
267 }
268}