Refuse, in the one function every ask goes through, an ask of build-agent for any module but the builder's own (issue 1851, A12, ADR 0453 §5)
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// A12 (ADR 0453 §5, ADR 0498 §7; issue 1851): the one function every ask goes through refuses any module but the
|
||||
// builder's own, naming the builder's key it is taken from instead; the builder's own module passes the refusal.
|
||||
func TestBuildAgentIsAskedForTheBuildersOwnModuleAlone(t *testing.T) {
|
||||
was := askedModuleOf
|
||||
t.Cleanup(func() { askedModuleOf = was })
|
||||
askedModuleOf = func(_ context.Context, _ buildSource, path string) (string, error) {
|
||||
return strings.TrimPrefix(path, "modules/"), nil
|
||||
}
|
||||
_, err := askABuild(t.Context(), buildSource{Repository: "novox/mesh-catalog", Seat: "git"}, "modules/sudo", "main")
|
||||
if !errors.Is(err, errNotTheBuildersOwn) || !strings.Contains(err.Error(), "sudo is taken from the builder's done key") ||
|
||||
!strings.Contains(err.Error(), "mesh-delivery-builder_builds") {
|
||||
t.Fatalf("an ask of another module: %v", err)
|
||||
}
|
||||
if err := onlyTheBuildersOwn(t.Context(), buildSource{Repository: "novox/mesh-delivery", Seat: "git"},
|
||||
"modules/mesh-delivery-builder"); err != nil {
|
||||
t.Fatalf("the builder's own module is refused: %v", err)
|
||||
}
|
||||
askedModuleOf = func(context.Context, buildSource, string) (string, error) { return "", errors.New("no store") }
|
||||
if err := onlyTheBuildersOwn(t.Context(), buildSource{Repository: "novox/x"}, ""); !errors.Is(err, errNotTheBuildersOwn) {
|
||||
t.Fatalf("an ask whose module cannot be read went on: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// A12: a walk of the builder's own module and one other asks build-agent for the first alone; the other is taken from
|
||||
// its key.
|
||||
func TestAWalkAsksBuildAgentForTheBuildersOwnModuleAlone(t *testing.T) {
|
||||
var asked []string
|
||||
was := askABuild
|
||||
askABuild = func(_ context.Context, _ buildSource, path, _ string) (string, error) {
|
||||
asked = append(asked, path)
|
||||
return "build-1", nil
|
||||
}
|
||||
t.Cleanup(func() { askABuild = was })
|
||||
p, byName := aWalkOfOne("sudo")
|
||||
p.Tiers = [][]string{{"mesh-delivery-builder", "sudo"}}
|
||||
byName["mesh-delivery-builder"] = byName["sudo"]
|
||||
e := byName["mesh-delivery-builder"]
|
||||
e.Source.Repository, e.Source.Path = "novox/mesh-delivery", "modules/mesh-delivery-builder"
|
||||
byName["mesh-delivery-builder"] = e
|
||||
for _, m := range p.Tiers[0] {
|
||||
askModule(t.Context(), p, m, byName)
|
||||
}
|
||||
if len(asked) != 1 || asked[0] != "modules/mesh-delivery-builder" {
|
||||
t.Fatalf("build-agent was asked for %v, want the builder's own module alone", asked)
|
||||
}
|
||||
if s := p.Modules["mesh-delivery-builder"]; s.Key || s.Build != "build-1" {
|
||||
t.Fatalf("the builder's own module is not asked: %+v", s)
|
||||
}
|
||||
if s := p.Modules["sudo"]; !s.Key || s.Build != "" {
|
||||
t.Fatalf("the other module is not taken from its key: %+v", s)
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
sdkdelivery "git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
"os"
|
||||
"slices"
|
||||
"sort"
|
||||
@@ -410,11 +411,59 @@ var askABuild func(ctx context.Context, source buildSource, path, ref string) (s
|
||||
|
||||
func init() {
|
||||
askABuild = func(ctx context.Context, source buildSource, path, ref string) (string, error) {
|
||||
// **Only the builder's own module is asked of build-agent** (novox/hq ADR 0453 §5, ADR 0498 §7; issue 1851,
|
||||
// A12): refused here, in the one function every ask goes through, whoever calls it.
|
||||
if err := onlyTheBuildersOwn(ctx, source, path); err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Kept by each asker with its own name once the ask is made (novox/hq issue 325).
|
||||
return buildOneAsked(ctx, source, path, ref, 0, false, "")
|
||||
}
|
||||
}
|
||||
|
||||
// errNotTheBuildersOwn says an ask of build-agent was refused: from R4e build-agent builds the builder's own module
|
||||
// alone, and every other is taken from the builder's done key.
|
||||
var errNotTheBuildersOwn = errors.New("build-agent is asked for the builder's own module alone (ADR 0453 §5)")
|
||||
|
||||
// askedModuleOf is the module the catalogue builds from a source and path, empty when it builds none from it. A variable
|
||||
// so a test needs no store.
|
||||
var askedModuleOf = func(ctx context.Context, source buildSource, path string) (string, error) {
|
||||
open, err := openStores(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer open.Close()
|
||||
entries, err := open.inventory.Catalogued(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
forms := newSourceForms(ctx, open.inventory)
|
||||
for _, e := range entries {
|
||||
if forms.same(e.Source.Repository, e.Source.Seat, source.Repository, source.Seat) &&
|
||||
strings.Trim(e.Source.Path, "/") == strings.Trim(path, "/") {
|
||||
return e.Manifest.Module, nil
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// onlyTheBuildersOwn refuses an ask of any module but the builder's own, naming the key it is taken from instead.
|
||||
func onlyTheBuildersOwn(ctx context.Context, source buildSource, path string) error {
|
||||
module, err := askedModuleOf(ctx, source, path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: which module %s at %q is cannot be read, so nothing is asked: %v", errNotTheBuildersOwn,
|
||||
source, orRoot(path), err)
|
||||
}
|
||||
if isBuildersOwn(module) {
|
||||
return nil
|
||||
}
|
||||
if module == "" {
|
||||
module = fmt.Sprintf("%s at %q", source, orRoot(path))
|
||||
}
|
||||
return fmt.Errorf("%w: %s is taken from the builder's done key of its fingerprint in %s (ADR 0501), and no build "+
|
||||
"of it is asked", errNotTheBuildersOwn, module, sdkdelivery.BuilderBuildsBucket)
|
||||
}
|
||||
|
||||
// pullsOfWalk are the pull requests of the merges a walk answers, each once: what its end lets go of (forgetChecksOfWalk)
|
||||
// and what a check of one was (same_program.go).
|
||||
func pullsOfWalk(p *inventory.Plan) []link.PullRef {
|
||||
|
||||
Reference in New Issue
Block a user