Files
mesh-delivery/modules/mesh-grants/grantsstate/grantsstate_test.go
T

119 lines
4.6 KiB
Go

package grantsstate
import (
"bytes"
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/keys"
"git.novox.be/novox/mesh-sdk/go/seal"
)
// 1394/B1b: a grant key round-trips; a want or held key is refused, naming it; a grant round-trips and one naming an
// empty account is refused.
func TestTheGrantsIssued(t *testing.T) {
fp := "src2:" + strings.Repeat("c", 64)
key, err := PartGrantKey("mesh-delivery-assigner", fp)
if err != nil || key != "mesh-delivery-assigner."+strings.Repeat("c", 64) {
t.Fatalf("PartGrantKey = %q, %v", key, err)
}
module, back, err := ParsePartGrantKey(key)
if err != nil || module != "mesh-delivery-assigner" || back != fp {
t.Errorf("ParsePartGrantKey = %q, %q, %v", module, back, err)
}
held := "mesh-mail." + strings.Repeat("c", 64) + ".held"
for _, bad := range []string{"want.ace.mesh-mail", held, "ace.mesh-mail", ""} {
if _, _, err := ParsePartGrantKey(bad); err == nil || !strings.Contains(err.Error(), "\""+bad+"\"") {
t.Errorf("ParsePartGrantKey(%q) = %v, want a refusal naming it", bad, err)
}
}
for _, g := range []Grant{{}, {Accounts: []string{"UABC", "UDEF"}}} {
data, err := EncodeGrant(g)
if err != nil {
t.Fatal(err)
}
got, err := DecodeGrant(data)
g.V = keys.Version
if err != nil || !SameGrant(got, g) {
t.Errorf("grant %+v came back %+v, %v", g, got, err)
}
}
if _, err := EncodeGrant(Grant{Accounts: []string{""}}); err == nil {
t.Errorf("a grant naming an empty account was accepted")
}
g := Grant{Accounts: []string{"ace.mesh-build-go", "shanks.mesh-mail.reader"}}
for _, c := range []struct {
g Grant
node, module string
names bool
}{
{g, "ace", "mesh-build-go", true},
{g, "shanks", "mesh-mail", true},
{g, "g14", "mesh-build-go", false},
{g, "ace", "mesh-build", false},
{Grant{}, "novox", "nats", true},
} {
if got := c.g.NamesNode(c.node, c.module); got != c.names {
t.Errorf("%v names %s.%s: %v, want %v", c.g.Accounts, c.node, c.module, got, c.names)
}
}
}
// The grants part's list sealed to the bus node (novox/hq ADR 0547 clause 7): the key's value round-trips and refuses what
// the bus node could not follow, and the object opens with the node's key alone, to the digest the key names.
func TestTheGrantsPartsSealedUserList(t *testing.T) {
list := []byte("accounts { MESH { users = [ { user: \"controller\" } ] } }\n")
digest := UserListDigest(list)
node, err := seal.GenerateKeyPair()
if err != nil {
t.Fatal(err)
}
other, _ := seal.GenerateKeyPair()
g := GrantsUserList{Follow: FollowGrants, Digest: digest, Object: UserListObjectName(digest),
SealedTo: SealingKeyID(node.PublicKey), Node: "novox", Revision: 1, Users: 1}
raw, err := EncodeGrantsUserList(g)
if err != nil {
t.Fatal(err)
}
back, err := DecodeGrantsUserList(raw)
if err != nil || back.Digest != digest || back.LeftOut == nil || back.Follow != FollowGrants {
t.Fatalf("decoded %+v, %v", back, err)
}
// Issue 1126 B4a (ADR 0590): a key written with the lease's flag still reads; the controller's list is no source.
if old, err := DecodeGrantsUserList([]byte(`{"v":1,"follow":"grants","digest":"","object":"","sealed_to":"",` +
`"node":"novox","revision":3,"users":40,"left_out":[],"at":"2026-10-30T10:00:00Z","lease-handed":true}`)); err != nil || old.Revision != 3 {
t.Errorf("a key with the lease's flag decodes %+v, %v", old, err)
}
for _, bad := range []GrantsUserList{{Follow: "both", Digest: digest, Object: g.Object}, {Follow: "controller"},
{Follow: FollowGrants, Digest: digest, Object: "other"}, {Follow: FollowGrants, Digest: "md5:x", Object: "md5:x"}} {
if _, err := EncodeGrantsUserList(bad); err == nil {
t.Errorf("%+v was written", bad)
}
}
if _, err := EncodeGrantsUserList(GrantsUserList{Follow: FollowGrants}); err != nil {
t.Errorf("a switch with no list yet refused: %v", err)
}
object, err := SealUserList(list, node.PublicKey)
if err != nil {
t.Fatal(err)
}
if bytes.Contains(object, []byte("controller")) {
t.Fatal("the object carries the list in the clear")
}
opener := func(priv string) func(seal.Box) ([]byte, error) {
return func(b seal.Box) ([]byte, error) { s, err := seal.Open(b, priv); return []byte(s), err }
}
if got, err := OpenUserList(object, digest, opener(node.PrivateKey)); err != nil || !bytes.Equal(got, list) {
t.Fatalf("opened %q, %v", got, err)
}
if _, err := OpenUserList(object, digest, opener(other.PrivateKey)); err == nil {
t.Error("another key opened the list")
}
if _, err := OpenUserList(object, "sha256:00", opener(node.PrivateKey)); err == nil {
t.Error("a list of another digest was taken")
}
if _, err := SealUserList(list, "not a key"); err == nil {
t.Error("a list was sealed to no key")
}
}