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.
81 lines
3.0 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|
|
}
|