`invokes: [<module>.<tool>]` now grants `mesh.mod.<module>.tool.<tool>` and the same with the machine as its last token, which is how a call reaches one machine's instance. The broker credential the mesh writes carries `claims`: each seat the module claims, its scope, and the verbs the seat promises, so the runtime serves them on the seat's subjects; the holder's grant, composed from the holding, is what admits the subscription.
107 lines
4.0 KiB
Go
107 lines
4.0 KiB
Go
package broker
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// A module that says it calls a tool may publish exactly that subject (novox/hq ADR 0152): the same
|
|
// grant a person gets, derived the same way, so one list answers "what may this ask" for everybody.
|
|
func TestAModuleMayAskOnlyTheToolsItInvokes(t *testing.T) {
|
|
perms, err := PermissionsFor(Principal{Kind: KindModule, Node: "desk", Module: "mesh-console",
|
|
Invokes: []string{"shop.price"}, PasswordHash: "x"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
has(t, perms.Publish, "mesh.mod.shop.tool.price")
|
|
hasNot(t, perms.Publish, "mesh.mod.shop.tool.refund")
|
|
hasNot(t, perms.Publish, "mesh.mod.*.tool.>")
|
|
}
|
|
|
|
// The console's grant: every tool, as one subject, and it reads as one.
|
|
func TestAModuleInvokingEverythingMayAskAnyTool(t *testing.T) {
|
|
perms, err := PermissionsFor(Principal{Kind: KindModule, Node: "desk", Module: "mesh-console",
|
|
Invokes: []string{"*"}, PasswordHash: "x"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
has(t, perms.Publish, "mesh.mod.*.tool.>")
|
|
}
|
|
|
|
// **A grant to call widens nothing else.** A module that invokes may not publish an event it did not
|
|
// declare, may not answer as another module, and subscribes nothing it did not consume — the
|
|
// difference between the console and a person is that the console is on a machine, not that it may
|
|
// do more.
|
|
func TestInvokingGrantsNothingButTheCall(t *testing.T) {
|
|
perms, err := PermissionsFor(Principal{Kind: KindModule, Node: "desk", Module: "mesh-console",
|
|
Invokes: []string{"*"}, PasswordHash: "x"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, p := range perms.Publish {
|
|
if strings.Contains(p, ".event.") {
|
|
t.Errorf("a module that only invokes may publish %q, an event it never declared", p)
|
|
}
|
|
// A role's tools are tools (ADR 0132); a role's work queue and events are not.
|
|
if strings.HasPrefix(p, "mesh.seat.") && !strings.Contains(p, ".tool.") {
|
|
t.Errorf("a module that only invokes may publish %q, a seat it neither holds nor uses", p)
|
|
}
|
|
}
|
|
for _, s := range perms.Subscribe {
|
|
if strings.Contains(s, ".tool.") && !strings.HasPrefix(s, "mesh.mod.mesh-console.") {
|
|
t.Errorf("a module that invokes may subscribe %q, another module's tools", s)
|
|
}
|
|
}
|
|
}
|
|
|
|
// A module that declares no invokes calls nothing, which is every module but the console.
|
|
func TestAModuleThatInvokesNothingCallsNothing(t *testing.T) {
|
|
perms, err := PermissionsFor(Principal{Kind: KindModule, Node: "one", Module: "shop",
|
|
Emits: []string{"order.placed"}, PasswordHash: "x"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, p := range perms.Publish {
|
|
if strings.Contains(p, ".tool.") {
|
|
t.Errorf("a module with no invokes may publish %q", p)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The malformed entry is refused for a module as it is for a person, and in the same words.
|
|
func TestAModulesToolGrantThatNamesNoToolIsRefused(t *testing.T) {
|
|
if _, err := PermissionsFor(Principal{Kind: KindModule, Node: "one", Module: "shop",
|
|
Invokes: []string{"telegram"}, PasswordHash: "x"}); err == nil {
|
|
t.Fatal("a grant naming a module but no tool was accepted")
|
|
}
|
|
}
|
|
|
|
// What a declaration says reaches the composed user, so a manifest's `invokes` is the grant.
|
|
func TestADeclaredInvokeReachesTheComposedUser(t *testing.T) {
|
|
users, err := Users(Records{
|
|
Nodes: []string{"desk"},
|
|
Assigned: map[string][]Declared{"desk": {{Module: "mesh-console", Invokes: []string{"*"}}}},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
perms, err := PermissionsFor(users[len(users)-1])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
has(t, perms.Publish, "mesh.mod.*.tool.>")
|
|
}
|
|
|
|
// A module's tool is addressed two ways (novox/hq ADR 0159): to whichever instance answers, and to
|
|
// the instance on one machine. A grant for the tool covers both and nothing wider.
|
|
func TestInvokingAToolMayAddressTheMachineToo(t *testing.T) {
|
|
got, err := invokedSubjects([]string{"postgres.postgres_query"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := []string{"mesh.mod.postgres.tool.postgres_query", "mesh.mod.postgres.tool.postgres_query.*"}
|
|
if len(got) != 2 || got[0] != want[0] || got[1] != want[1] {
|
|
t.Fatalf("the grant is %v, want %v", got, want)
|
|
}
|
|
}
|