The checks running are readable through reads and carry when each started (issue 1155)

This commit is contained in:
2026-10-18 20:55:18 +02:00
parent 3b49d7044f
commit 0273609090
6 changed files with 159 additions and 4 deletions
@@ -0,0 +1,60 @@
package broker
import (
"slices"
"testing"
)
// 1155/AC1: a module whose manifest reads mesh-controller.checks-running may watch and get every key of the bucket and
// write none.
func TestAModuleReadingChecksRunningReadsAndWritesNone(t *testing.T) { // 1155/AC1
if !slices.Contains(ControllerMirrors(), "checks-running") || BucketName(ControllerSeat, "checks-running") != CheckRunningBucket {
t.Fatalf("a module cannot name %s in `reads`: %v", CheckRunningBucket, ControllerMirrors())
}
perms, err := PermissionsFor(Principal{Kind: KindModule, Node: "one", Module: "mesh-delivery-watchman", PasswordHash: "x",
Reads: []string{"mesh-controller.checks-running"}})
if err != nil {
t.Fatal(err)
}
stream := "KV_" + CheckRunningBucket
has(t, perms.Publish, "$JS.API.STREAM.INFO."+stream)
has(t, perms.Publish, "$JS.API.DIRECT.GET."+stream+".>")
has(t, perms.Publish, "$JS.API.CONSUMER.CREATE."+stream+".>")
for _, p := range perms.Publish {
if SubjectsOverlap(p, "$KV."+CheckRunningBucket+".any.key") {
t.Errorf("the reading module may write %s through %q", CheckRunningBucket, p)
}
}
}
// 1155/AC3: the writers table names checks-running's writer as the build seat's holders, and the rule that a mirror is
// written by the controller alone names it as the exception, with its reason.
func TestChecksRunningIsAMirrorWrittenByTheBuildSeatsHolders(t *testing.T) { // 1155/AC3
why := MirrorsWrittenByAnother["checks-running"]
if why == "" {
t.Fatal("the mirrors written by another do not name checks-running with a reason")
}
subject := "$KV." + CheckRunningBucket + ".novox.a.7"
var rows int
for _, row := range WritersTable {
for _, s := range row.Subjects {
if s != "$KV."+CheckRunningBucket+".>" {
continue
}
rows++
holder := Principal{Kind: KindModule, Module: "builder", Node: "one", Holds: []Seat{{Name: TheBuildSeat}}}
other := Principal{Kind: KindModule, Module: "mesh-delivery-watchman", Node: "one"}
if row.Writes == nil || !row.Writes(holder, subject) || row.Writes(other, subject) {
t.Errorf("%q is not written by the build seat's holders alone", row.State)
}
}
}
if rows != 1 {
t.Fatalf("%d rows of the writers table write %s, want one", rows, CheckRunningBucket)
}
for m := range MirrorsWrittenByAnother {
if m != "checks-running" {
t.Errorf("the mirror %q is written by another and is not checks-running", m)
}
}
}
+15 -2
View File
@@ -56,7 +56,7 @@ var (
// check ends; a key not renewed within the bucket's age is a builder that died, and is gone. A builder that takes a
// waiting request for a head and trunk commit a key names drops it. **Written by the build seat's holders, several by
// design** — each the key of the check it runs.
CheckRunningBucket = BucketName(ControllerSeat, "checks-running")
CheckRunningBucket = BucketName(ControllerSeat, ChecksRunning)
// DeliveryMergesBucket holds the merges mesh-delivery announced it made, each with the ask whose Approve it merged
// on (novox/hq ADR 0420 §7, issue 1025): per merge a key `<owner>/<repo>/<number>/<head sha>` holding the
// announcement, kept DeliveryMergesKeptFor. What lets the build of a moved module register it from its new
@@ -133,9 +133,22 @@ func ChainBuckets() []string { return []string{BuildsBucket, RolloutsBucket, Ass
// ControllerMirrors are the local names of the controller's buckets a module may read: the record mirrors and the
// chain's buckets.
func ControllerMirrors() []string {
return []string{MirrorAssignments, MirrorDeclaredConfig, MirrorPredefined, ChainBuilds, ChainRollouts}
return []string{MirrorAssignments, MirrorDeclaredConfig, MirrorPredefined, ChainBuilds, ChainRollouts, ChecksRunning}
}
// MirrorsWrittenByAnother are the controller's mirrors whose writer is not the controller, each with its reason: the rule
// that a mirror is written by the controller alone (TestTheMirrorsListAndTheWritersTableAgree) has these exceptions and no
// other.
var MirrorsWrittenByAnother = map[string]string{
ChecksRunning: "the checks running are said by the builders themselves: every machine holding the build seat puts the " +
"key of the check it runs, at its start and at each heartbeat, and deletes it when the check ends, so the " +
"controller asserts the bucket and writes none of its keys (ADR 0406 §3); it is readable through `reads` so " +
"the watchman sees a check that stopped (ADR 0433 §6)",
}
// ChecksRunning is the local name of the bucket of the checks running, as a reader names it in `reads`.
const ChecksRunning = "checks-running"
// The mirrors' caps (design 54 §5): one value per key, no age, 64 KiB a value, 64 MiB a bucket.
const (
MirrorValueBytes = 64 << 10
@@ -135,6 +135,12 @@ func TestTheMirrorsListAndTheWritersTableAgree(t *testing.T) {
for _, m := range ControllerMirrors() {
bucket := BucketName(ControllerSeat, m)
listed[bucket] = true
if why, other := MirrorsWrittenByAnother[m]; other { // 1155/AC3: the exception, with its reason
if why == "" {
t.Errorf("the mirror %s is written by another and says no reason", bucket)
}
continue
}
if !rowed[bucket] {
t.Errorf("the mirror %s is listed and no row of the writers table writes it", bucket)
}