Files
mesh-controller/internal/broker/declaration_files_test.go
T
jschoubben ceaa616d01 Send files over 64 KiB by digest through the bus's object bucket to nodes that read them, grant it, and warn at 75 percent (issues 1696, 1697, 1698; ADR 0486 step 3)
A node that reports file-references gets the digest and size of each file over 64 KiB that may travel so, and the content is put in
the bucket declaration-files before the declaration is sent; others get every content inline. The controller alone writes the
bucket and node-engines read an object by name (the four grants the node-engine's own fetch makes, no list, no write). An object
goes a day after no node's latest declaration names it. The near-limit condition warns at 75 percent, and a test holds the control
node's declaration, in the reference form, under half the bus's largest message.
2026-10-21 15:16:11 +02:00

81 lines
3.0 KiB
Go

package broker
import (
"slices"
"strings"
"testing"
)
// 1697/AC1: the composed accounts give a node-engine exactly the four reads of one object by its name, the controller the
// one write, and no other principal anything of the bucket.
func TestTheDeclarationBucketIsWrittenByTheControllerAndReadByNameByANodeEngine(t *testing.T) { // 1697/AC1
node, err := PermissionsFor(Principal{Kind: KindNode, Node: "alpha", PasswordHash: "x"})
if err != nil {
t.Fatal(err)
}
var mine []string
for _, s := range node.Publish {
if strings.Contains(s, DeclarationFilesStream) || strings.Contains(s, "$O."+DeclarationFilesBucket) {
mine = append(mine, s)
}
}
want := []string{
"$JS.API.CONSUMER.CREATE.OBJ_declaration-files.*.$O.declaration-files.C.*",
"$JS.API.CONSUMER.DELETE.OBJ_declaration-files.*",
"$JS.API.DIRECT.GET.OBJ_declaration-files.$O.declaration-files.M.*",
"$JS.FC.OBJ_declaration-files.>",
}
if !slices.Equal(mine, want) {
t.Fatalf("a node-engine may publish %q of the bucket, want exactly %q", mine, want)
}
// What would make a list or a write: none of it, in any pattern a node holds. (The real server's judgement of
// the wildcard forms is the live test's.)
for _, refused := range []string{
"$JS.API.STREAM.INFO.OBJ_declaration-files",
"$JS.API.STREAM.MSG.GET.OBJ_declaration-files",
"$JS.API.DIRECT.GET.OBJ_declaration-files",
"$JS.API.DIRECT.GET.OBJ_declaration-files.$O.declaration-files.M.abc.def",
"$JS.API.CONSUMER.CREATE.OBJ_declaration-files.x.$O.declaration-files.M.YWJj",
"$JS.API.CONSUMER.CREATE.OBJ_declaration-files.x.$O.declaration-files.M.YWJj.more",
"$JS.API.CONSUMER.CREATE.OBJ_declaration-files",
"$O.declaration-files.M.abc",
"$O.declaration-files.C.abc",
} {
if MayPublish(node, refused) {
t.Errorf("a node-engine may publish %s, which lists or writes the bucket", refused)
}
}
for _, kept := range []string{
"$JS.API.DIRECT.GET.OBJ_declaration-files.$O.declaration-files.M.YWJj",
"$JS.API.CONSUMER.CREATE.OBJ_declaration-files.h4sh.$O.declaration-files.C.NUID",
} {
if !MayPublish(node, kept) {
t.Errorf("a node-engine may not publish %s, which reads one object by its name", kept)
}
}
controller, err := PermissionsFor(Principal{Kind: KindController, PasswordHash: "x"})
if err != nil {
t.Fatal(err)
}
if !MayPublish(controller, "$O.declaration-files.M.abc") || !MayPublish(controller, "$O.declaration-files.C.nuid") {
t.Error("the controller may not write the bucket")
}
for _, p := range []Principal{
{Kind: KindModule, Module: "mesh-vault", PasswordHash: "x"},
{Kind: KindNodeTools, Node: "alpha", PasswordHash: "x"},
{Kind: KindPerson, Module: "jochen", Invokes: []string{"*"}, PasswordHash: "x"},
} {
perms, err := PermissionsFor(p)
if err != nil {
t.Fatal(err)
}
for _, s := range append(append([]string(nil), perms.Publish...), perms.Subscribe...) {
if strings.Contains(s, "declaration-files") {
t.Errorf("%s holds %s, and no account but the controller's and the node-engines' has any access", p.Username(), s)
}
}
}
}