Let a plan of provisions alone fill nothing, so a module not handed can have one for its route (issue 774)
mesh/delivery merged: source.main moved to novox/mesh-catalog@cb91a4b9c292
mesh/check being carried to 7522961ae3b0 on cb91a4b9c292 | from 5d9cead336ab

A plan with no templates archive made the client fetch an empty source and fail the module's report. The next
mesh-provisioner composes such plans (a module not handed gets one for what a provider's helper answers, its route), so
this reaches the nodes first.

Quick fix: none (a failed report per routed module). Thorough fix (chosen): a plan with no archive is read as provisions
alone by the one client every node runs.
This commit is contained in:
2026-10-30 21:42:03 +01:00
parent 395a37ddda
commit 7522961ae3
2 changed files with 22 additions and 0 deletions
@@ -855,3 +855,19 @@ func TestAFailureKeepsWhenItBeganWhileItsWordsChange(t *testing.T) {
}
}
}
// A plan of provisions alone, a module not handed whose route the helper answers (issue 774), names no templates:
// nothing is fetched and nothing filled, where a fetch of no source failed the module's report.
func TestAPlanOfProvisionsAloneFetchesNoTemplates(t *testing.T) {
s := &templateStore{dir: t.TempDir(), fetch: func(context.Context, string) ([]byte, error) {
t.Fatal("a plan with no templates fetched")
return nil, nil
}}
texts, err := s.load(context.Background(), Templates{})
if err != nil || len(texts) != 0 {
t.Fatalf("loaded %v: %v", texts, err)
}
if targets, wrong := fillTargets(Plan{}, texts); wrong != "" || len(targets) != 0 {
t.Fatalf("filled %v: %s", targets, wrong)
}
}
@@ -69,7 +69,13 @@ type templateStore struct {
}
// load is every template's text of the archive the plan names, by its path inside the archive.
//
// A plan that names no archive is a plan of provisions alone (issue 774: a module not handed has one for what a
// provider's helper answers of it, its route): there is nothing to fetch and nothing to fill.
func (s *templateStore) load(ctx context.Context, t Templates) (map[string]string, error) {
if t.Source == "" && t.Digest == "" {
return map[string]string{}, nil
}
if texts, ok := s.texts[t.Digest]; ok {
return texts, nil
}