Ask build-agent for the build modules that write references, whatever the builder says (issue 1886, ADR 0522 §6)

They push and answer each reference, so a key they write themselves can never
carry their own delivery; until R4g build-agent delivers them as it does the
builder.
This commit is contained in:
2026-10-23 00:53:25 +02:00
parent fae7710bed
commit f67342f0d8
2 changed files with 45 additions and 23 deletions
+39 -22
View File
@@ -38,9 +38,9 @@ func askingBuildAgent(t *testing.T) *[]string {
func TestAWalkAsksBuildAgentWhileTheBuilderDoesNotSayItWritesReferences(t *testing.T) {
theBuilderSays(t, false, nil)
asked := askingBuildAgent(t)
p, byName := aWalkOfOne("mesh-build-go")
askModule(t.Context(), p, "mesh-build-go", byName)
s := p.Modules["mesh-build-go"]
p, byName := aWalkOfOne("sudo")
askModule(t.Context(), p, "sudo", byName)
s := p.Modules["sudo"]
if s.Key || s.Build != "build-9" || s.State != "asked" || len(*asked) != 1 {
t.Fatalf("the module is not asked of build-agent: %+v, asked %v", s, *asked)
}
@@ -51,9 +51,9 @@ func TestAWalkAsksBuildAgentWhileTheBuilderDoesNotSayItWritesReferences(t *testi
func TestAWalkTakesTheKeyOnceTheBuilderSaysItWritesReferences(t *testing.T) {
theBuilderSays(t, true, nil)
asked := askingBuildAgent(t)
p, byName := aWalkOfOne("mesh-build-go")
askModule(t.Context(), p, "mesh-build-go", byName)
if s := p.Modules["mesh-build-go"]; !s.Key || s.Build != "" || len(*asked) != 0 {
p, byName := aWalkOfOne("sudo")
askModule(t.Context(), p, "sudo", byName)
if s := p.Modules["sudo"]; !s.Key || s.Build != "" || len(*asked) != 0 {
t.Fatalf("the module is not taken from its key: %+v, asked %v", s, *asked)
}
}
@@ -63,9 +63,9 @@ func TestAWalkTakesTheKeyOnceTheBuilderSaysItWritesReferences(t *testing.T) {
func TestASayNotReadLeavesTheModuleUnasked(t *testing.T) {
theBuilderSays(t, false, errors.New("the bus did not answer"))
asked := askingBuildAgent(t)
p, byName := aWalkOfOne("mesh-build-go")
askModule(t.Context(), p, "mesh-build-go", byName)
s := p.Modules["mesh-build-go"]
p, byName := aWalkOfOne("sudo")
askModule(t.Context(), p, "sudo", byName)
s := p.Modules["sudo"]
if s.State != "" || s.Key || len(*asked) != 0 || !strings.Contains(s.Why, "the bus did not answer") {
t.Fatalf("a say not read: %+v, asked %v", s, *asked)
}
@@ -102,15 +102,15 @@ func TestAnOpenWalkWaitingOnAnUnreferencedKeyIsAskedOfBuildAgent(t *testing.T) {
keyTakes.Unlock()
})
fp := "src2:" + strings.Repeat("e", 64)
unreferenced := builderkeys.Key{Module: "mesh-build-go", Fingerprint: fp, Found: true, Revision: 1,
unreferenced := builderkeys.Key{Module: "sudo", Fingerprint: fp, Found: true, Revision: 1,
Build: sdkdelivery.BuilderBuild{State: sdkdelivery.BuildDone, Manifest: strings.Repeat("b", 64),
Artifacts: []sdkdelivery.BuiltArtifact{{Name: "tools", Kind: "bundle", Digest: "sha256:1"}}}}
walk := func() (*inventory.Plan, map[string]inventory.Entry, planKeysOf) {
theBuilderSays(t, true, nil)
p, byName := aWalkOfOne("mesh-build-go")
askModule(t.Context(), p, "mesh-build-go", byName)
keys := planKeysOf{values: map[string]sdkdelivery.Module{"mesh-build-go@c0ffee0123456789": {FP2: fp}},
keys: map[string]builderkeys.Key{"mesh-build-go": unreferenced}}
p, byName := aWalkOfOne("sudo")
askModule(t.Context(), p, "sudo", byName)
keys := planKeysOf{values: map[string]sdkdelivery.Module{"sudo@c0ffee0123456789": {FP2: fp}},
keys: map[string]builderkeys.Key{"sudo": unreferenced}}
return p, byName, keys
}
take := func(string, sdkdelivery.Module, string) { t.Fatal("an unreferenced key was taken in") }
@@ -121,7 +121,7 @@ func TestAnOpenWalkWaitingOnAnUnreferencedKeyIsAskedOfBuildAgent(t *testing.T) {
if _, err := settleKeys(t.Context(), records, keys, p, p.Tiers[0], take); err != nil {
t.Fatal(err)
}
if s := p.Modules["mesh-build-go"]; s.State != "asked" || !s.Key || !strings.Contains(s.Why, "waits for the reference") {
if s := p.Modules["sudo"]; s.State != "asked" || !s.Key || !strings.Contains(s.Why, "waits for the reference") {
t.Fatalf("with the builder saying, the walk does not wait for the reference: %+v", s)
}
@@ -134,14 +134,14 @@ func TestAnOpenWalkWaitingOnAnUnreferencedKeyIsAskedOfBuildAgent(t *testing.T) {
if err != nil || !changed {
t.Fatalf("the walk was not judged again: %v %v", changed, err)
}
s := p.Modules["mesh-build-go"]
s := p.Modules["sudo"]
if s.Key || s.State != "" || p.State != inventory.PlanBuilding || !strings.Contains(s.Why, "does not say") {
t.Fatalf("the module is not handed back to be asked of build-agent: %+v %s", s, p.State)
}
for _, m := range unaskedOf(*p) {
askModule(t.Context(), p, m, byName)
}
if s := p.Modules["mesh-build-go"]; s.Key || s.Build != "build-9" || len(*asked) != 1 {
if s := p.Modules["sudo"]; s.Key || s.Build != "build-9" || len(*asked) != 1 {
t.Fatalf("the next look did not ask build-agent: %+v, asked %v", s, *asked)
}
}
@@ -150,17 +150,34 @@ func TestAnOpenWalkWaitingOnAnUnreferencedKeyIsAskedOfBuildAgent(t *testing.T) {
// asked of build-agent, whose build is the one delivered.
func TestAFailedKeyOfABuilderThatDoesNotSayFailsNoWalk(t *testing.T) {
theBuilderSays(t, true, nil)
p, byName := aWalkOfOne("mesh-build-go")
askModule(t.Context(), p, "mesh-build-go", byName)
p, byName := aWalkOfOne("sudo")
askModule(t.Context(), p, "sudo", byName)
_ = byName
fp := "src2:" + strings.Repeat("f", 64)
keys := planKeysOf{notSaid: true, values: map[string]sdkdelivery.Module{"mesh-build-go@c0ffee0123456789": {FP2: fp}},
keys: map[string]builderkeys.Key{"mesh-build-go": {Module: "mesh-build-go", Fingerprint: fp, Found: true,
keys := planKeysOf{notSaid: true, values: map[string]sdkdelivery.Module{"sudo@c0ffee0123456789": {FP2: fp}},
keys: map[string]builderkeys.Key{"sudo": {Module: "sudo", Fingerprint: fp, Found: true,
Build: sdkdelivery.BuilderBuild{State: sdkdelivery.BuildFailed, Error: "not stored: tools: no reference"}}}}
if _, err := settleKeys(t.Context(), recordsOf{}, keys, p, p.Tiers[0], func(string, sdkdelivery.Module, string) {}); err != nil {
t.Fatal(err)
}
if s := p.Modules["mesh-build-go"]; p.State != inventory.PlanBuilding || s.State != "" || s.Key {
if s := p.Modules["sudo"]; p.State != inventory.PlanBuilding || s.State != "" || s.Key {
t.Fatalf("a failed key of a builder that does not say failed the walk: %s %q %+v", p.State, p.Note, s)
}
}
// 1886/AC6 (ADR 0522 §6): the parts that write references, the builder and the build modules, are build-agent's own until
// R4g: asked of build-agent and never taken from keys they write themselves, whatever the builder says.
func TestTheReferenceWritersAreAskedOfBuildAgentWhateverTheBuilderSays(t *testing.T) {
theBuilderSays(t, true, nil)
asked := askingBuildAgent(t)
for _, m := range []string{"mesh-build-go", "mesh-build-node", "mesh-build-image", "mesh-delivery-builder"} {
p, byName := aWalkOfOne(m)
askModule(t.Context(), p, m, byName)
if s := p.Modules[m]; s.Key || s.Build != "build-9" {
t.Errorf("%s is not asked of build-agent: %+v", m, s)
}
}
if len(*asked) != 4 {
t.Fatalf("build-agent was asked %v", *asked)
}
}
+6 -1
View File
@@ -32,7 +32,12 @@ func isBuildersOwn(module string) bool { return buildersOwn(module) }
// repository's; and mesh-tools, the toolchain image build-agent's builds stand on. The builder writes no key of any of them,
// and a walk waiting for one would hold its tier for ever. mesh-tools-go is not among them: it builds from a Dockerfile in
// its own directory on a pinned base, and has its key from mesh-build-image.
var buildAgentsOwn = map[string]bool{sdkdelivery.BuilderModule: true, builder.AgentModule: true, "mesh-tools": true}
//
// **And the parts that write references** (ADR 0522 §6, issue 1886): the build modules push and answer each reference,
// and the builder writes it into the key, so none of them is ever taken from a key they write themselves. Until R4g
// build-agent is the way they are delivered whatever the builder says.
var buildAgentsOwn = map[string]bool{sdkdelivery.BuilderModule: true, builder.AgentModule: true, "mesh-tools": true,
"mesh-build-go": true, "mesh-build-node": true, "mesh-build-image": true}
// buildersOwn is isBuildersOwn's rule: a variable only so a test of the asks left (their bus waits, their plan key) may
// name modules of its own as build-agent's.