Files
mesh-delivery/modules/mesh-delivery-indexer/judge/objects_test.go
T
jschoubben 540b88a946 IX21: the validator reads a manifest's version MAJOR.MINOR and the finding stream and ask of a findings state
The refusal of a status in a manifest (IX20) relies on strict decoding: a manifest
field naming a status is an unknown field and is refused. The `*` emitter of
consumes (design 47 G §386) is held for the design writer's answer on model-usage's
`*.usage.*`.

Builds: design 47 G §89, §368, §387

Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
2026-11-11 11:32:05 +01:00

79 lines
3.5 KiB
Go

package judge
import (
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// knowledge is mesh-knowledge's manifest as ADR 0592 has it: an object bucket granted by its trusted value readers (a
// trusted file takes it), and
// two streams that keep their history.
const knowledge = `{"module":"mesh-knowledge","version":"1.0",
"resources":[{"id":"state","type":"directory","mode":"0700","place":"."},
{"id":"readers","trusted":true,"type":"file","path":"${dir:state}/readers.json","mode":"0600",
"merge":"json","takes-settings":["readers"],"content":"{\"readers\": {}}"}],
"objects":[{"name":"sections","max-mib":2048,"grant":{"config":"readers"}}],
"streams":[{"name":"versions","retention":"history","max-mib":4096,"events":["version.stored"]},
{"name":"reviews","retention":"history","events":["review.stored"]}]}`
// ADR 0592 §5, §6, §9, §25: a module's own object bucket and a stream that keeps its history are taken as declared (the
// history stream's bounds are in TestAWorkQueueStreamsValuesAreBounded); each bound and form of a bucket is refused, a
// bucket's name has one owner on the bus, and a module reads another's bucket only where the owner grants it.
func TestObjectBucketsAreJudgedAsADR0592Says(t *testing.T) {
if _, err := ParseManifest([]byte(knowledge)); err != nil {
t.Fatalf("mesh-knowledge's manifest was refused: %v", err)
}
for _, c := range []struct{ change, want string }{
{`"max-mib":2048,"grant"`, `"max-mib":0,"grant"`}, // no size: there is no default
{`"max-mib":2048,"grant"`, `"max-mib":8193,"grant"`}, // over the bound
{`"name":"sections"`, `"name":"Sections"`}, // not a plain local name
{`"name":"sections"`, `"name":"sections"},{"name":"sections","max-mib":1`}, // one bucket per name
{`"grant":{"config":"readers"}`, `"grant":{"config":"nobody"}`}, // a grant not by a trusted value
} {
raw := strings.Replace(knowledge, c.change, c.want, 1)
if raw == knowledge {
t.Fatalf("the change %q found nothing to change", c.change)
}
if _, err := ParseManifest([]byte(raw)); err == nil {
t.Errorf("%s was taken", c.want)
}
}
// A bucket whose name on the bus starts with what the mesh derives names with is refused.
if _, err := ParseManifest([]byte(`{"module":"kv","version":"1.0","objects":[{"name":"x","max-mib":1}]}`)); err == nil ||
!strings.Contains(err.Error(), "KV_") {
t.Errorf("a bucket kv_x was taken: %v", err)
}
parse := func(raw string) catalogue.Manifest {
t.Helper()
m, err := ParseManifest([]byte(raw))
if err != nil {
t.Fatal(err)
}
return m
}
owner := parse(knowledge)
reader := parse(`{"module":"records-page","version":"1.0","reads":["mesh-knowledge.sections"]}`)
shelf := catalogue.Shelf{"mesh-knowledge": owner, "records-page": reader}
if p := objectProblemsOf(CatalogueProblems(shelf)); len(p) > 0 {
t.Fatalf("a granted read was refused: %v", p)
}
ungranted := parse(strings.Replace(knowledge, `,"grant":{"config":"readers"}`, "", 1))
shelf["mesh-knowledge"] = ungranted
if p := objectProblemsOf(CatalogueProblems(shelf)); len(p) != 1 || !strings.Contains(p[0], "records-page") {
t.Errorf("a read of a bucket its owner grants nobody: %v", p)
}
}
// objectProblemsOf are the problems that name an object bucket or a history stream.
func objectProblemsOf(all []string) []string {
var out []string
for _, p := range all {
if strings.Contains(p, "object bucket") || strings.Contains(p, "history") {
out = append(out, p)
}
}
return out
}