Merge pull request 'The bus node writes the grants part's signed user list alone once the lease is handed (issue 774)' (#194) from feat/l3-removal into main
This commit was merged in pull request #194.
This commit is contained in:
@@ -3,7 +3,7 @@ module github.com/novox/mesh-host
|
|||||||
go 1.26.0
|
go 1.26.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101151945-b2a27ed5cec4
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101235037-c21d8fd9692c
|
||||||
github.com/nats-io/nats-server/v2 v2.11.17
|
github.com/nats-io/nats-server/v2 v2.11.17
|
||||||
github.com/nats-io/nats.go v1.54.0
|
github.com/nats-io/nats.go v1.54.0
|
||||||
golang.org/x/crypto v0.57.0
|
golang.org/x/crypto v0.57.0
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101151945-b2a27ed5cec4 h1:xeuMBwOHNKrVUdGVg7Bdv5tkdueBvngwJFyk6n10rp0=
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101151945-b2a27ed5cec4 h1:xeuMBwOHNKrVUdGVg7Bdv5tkdueBvngwJFyk6n10rp0=
|
||||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101151945-b2a27ed5cec4/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101151945-b2a27ed5cec4/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||||
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101235037-c21d8fd9692c h1:/YCxh+NYfqry3PxZYY1nQXaccupobxpsFt8c9BYuGBg=
|
||||||
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101235037-c21d8fd9692c/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
||||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
|
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
|
||||||
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
|
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
|
||||||
|
|||||||
@@ -27,6 +27,11 @@
|
|||||||
// against the key's digest, and written to the same file (mode 0600) only when the file's digest differs; otherwise the
|
// against the key's digest, and written to the same file (mode 0600) only when the file's digest differs; otherwise the
|
||||||
// controller's compositions are the source, as before. Never both. The have says which it follows and this node's key,
|
// controller's compositions are the source, as before. Never both. The have says which it follows and this node's key,
|
||||||
// which the grants part seals to.
|
// which the grants part seals to.
|
||||||
|
//
|
||||||
|
// **From the lease write it never follows the controller's list again** (ADR 0571 clause 8, ADR 0547 clause 11). The
|
||||||
|
// grants part's key then says the lease is handed (delivery.GrantsUserList.LeaseHanded): a key that later cannot be read or
|
||||||
|
// is deleted is said, the key last heard stands, and the list loaded stays; no list is written from a composition of the
|
||||||
|
// controller.
|
||||||
package userlist
|
package userlist
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -250,23 +255,36 @@ func (f *Follower) busNode() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// takeGrants keeps the grants part's key as heard; a value it cannot read is said and leaves the controller's list
|
// takeGrants keeps the grants part's key as heard; a value it cannot read is said and leaves the controller's list
|
||||||
// followed (no list is followed that the node cannot check).
|
// followed (no list is followed that the node cannot check), unless the key last heard says the lease is handed: then
|
||||||
|
// the controller's list is never followed again (novox/hq ADR 0571 clause 8, ADR 0547 clause 11), the key as last heard
|
||||||
|
// stands, and the list loaded stays.
|
||||||
func (f *Follower) takeGrants(u agent.Update) {
|
func (f *Follower) takeGrants(u agent.Update) {
|
||||||
f.mu.Lock()
|
f.mu.Lock()
|
||||||
defer f.mu.Unlock()
|
defer f.mu.Unlock()
|
||||||
f.grantsRev = u.Revision
|
handed := f.grants != nil && f.grants.LeaseHanded
|
||||||
if u.Deleted {
|
if u.Deleted {
|
||||||
|
if handed {
|
||||||
|
f.sayOnceLocked("the grants part's user-list key is deleted, and the lease is handed, so the list loaded is kept")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f.grantsRev = u.Revision
|
||||||
f.grants = nil
|
f.grants = nil
|
||||||
f.keep(nil, 0)
|
f.keep(nil, 0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
g, err := delivery.DecodeGrantsUserList(u.Value)
|
g, err := delivery.DecodeGrantsUserList(u.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if handed {
|
||||||
|
f.sayOnceLocked("the grants part's user-list key cannot be read, and the lease is handed, so the list loaded is kept: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f.grantsRev = u.Revision
|
||||||
f.grants = nil
|
f.grants = nil
|
||||||
f.keep(nil, 0)
|
f.keep(nil, 0)
|
||||||
f.sayOnceLocked("the grants part's user-list key cannot be read, so the controller's list is followed: " + err.Error())
|
f.sayOnceLocked("the grants part's user-list key cannot be read, so the controller's list is followed: " + err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
f.grantsRev = u.Revision
|
||||||
f.grants = &g
|
f.grants = &g
|
||||||
f.keep(u.Value, u.Revision)
|
f.keep(u.Value, u.Revision)
|
||||||
}
|
}
|
||||||
@@ -278,7 +296,8 @@ func (f *Follower) keep(value []byte, rev uint64) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Following is which list the follower takes now: the grants part's while its key says so, the controller's otherwise.
|
// Following is which list the follower takes now: the grants part's while its key says so or says the lease is handed, the
|
||||||
|
// controller's otherwise.
|
||||||
func (f *Follower) Following() string {
|
func (f *Follower) Following() string {
|
||||||
f.mu.Lock()
|
f.mu.Lock()
|
||||||
defer f.mu.Unlock()
|
defer f.mu.Unlock()
|
||||||
@@ -286,7 +305,7 @@ func (f *Follower) Following() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Follower) followingLocked() string {
|
func (f *Follower) followingLocked() string {
|
||||||
if f.grants != nil && f.grants.Follow == delivery.FollowGrants {
|
if f.grants != nil && (f.grants.Follow == delivery.FollowGrants || f.grants.LeaseHanded) {
|
||||||
return delivery.FollowGrants
|
return delivery.FollowGrants
|
||||||
}
|
}
|
||||||
return delivery.FollowController
|
return delivery.FollowController
|
||||||
|
|||||||
@@ -132,6 +132,9 @@ type gput struct {
|
|||||||
otherKey, badDigest bool
|
otherKey, badDigest bool
|
||||||
// after puts it once the grants part's list was written, as a hand-back comes after a take-over.
|
// after puts it once the grants part's list was written, as a hand-back comes after a take-over.
|
||||||
after bool
|
after bool
|
||||||
|
// handed says the controller's lease is handed (ADR 0582 clause 3); unreadable and deleted make the key a value that
|
||||||
|
// does not read, or a deleted key, instead of a list (774/S31).
|
||||||
|
handed, unreadable, deleted bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type put struct {
|
type put struct {
|
||||||
@@ -226,6 +229,20 @@ func TestTheBusNodeWritesTheNewestSignedUserListAlone(t *testing.T) {
|
|||||||
{name: "in shadow the grants part's list is not taken",
|
{name: "in shadow the grants part's list is not taken",
|
||||||
before: []put{{module: "nats", fp: fpOf("a"), content: two}}, grants: []gput{{follow: delivery.FollowController, content: three}},
|
before: []put{{module: "nats", fp: fpOf("a"), content: two}}, grants: []gput{{follow: delivery.FollowController, content: three}},
|
||||||
wantWrites: []string{two}, wantUsers: 3, wantSource: "novox.nats." + fpOf("a")[len(delivery.SourcePrefix2):], wantFollows: delivery.FollowController},
|
wantWrites: []string{two}, wantUsers: 3, wantSource: "novox.nats." + fpOf("a")[len(delivery.SourcePrefix2):], wantFollows: delivery.FollowController},
|
||||||
|
// 774/S31 (ADR 0571 clause 8, ADR 0547 clause 11): once the key says the lease is handed, the controller's list is never
|
||||||
|
// followed again, whatever becomes of the key; without the flag the controller's list is still the fallback.
|
||||||
|
{name: "a handed lease: a grants key that turns unreadable keeps the loaded list and never writes the controller's",
|
||||||
|
before: []put{{module: "nats", fp: fpOf("a"), content: two}},
|
||||||
|
grants: []gput{{follow: delivery.FollowGrants, content: three, handed: true}, {unreadable: true, after: true}},
|
||||||
|
wantWrites: []string{three}, wantUsers: 4, wantSource: delivery.GrantsUserListSource, wantFollows: delivery.FollowGrants},
|
||||||
|
{name: "a handed lease: a grants key that is deleted keeps the loaded list and never writes the controller's",
|
||||||
|
before: []put{{module: "nats", fp: fpOf("a"), content: two}},
|
||||||
|
grants: []gput{{follow: delivery.FollowGrants, content: three, handed: true}, {deleted: true, after: true}},
|
||||||
|
wantWrites: []string{three}, wantUsers: 4, wantSource: delivery.GrantsUserListSource, wantFollows: delivery.FollowGrants},
|
||||||
|
{name: "no handed lease: a grants key that turns unreadable falls back to the controller's list",
|
||||||
|
before: []put{{module: "nats", fp: fpOf("a"), content: two}},
|
||||||
|
grants: []gput{{follow: delivery.FollowGrants, content: three}, {unreadable: true, after: true}},
|
||||||
|
wantWrites: []string{three, two}, wantUsers: 3, wantSource: "novox.nats." + fpOf("a")[len(delivery.SourcePrefix2):], wantFollows: delivery.FollowController},
|
||||||
{name: "a grants list that does not open to its digest is refused and the file kept",
|
{name: "a grants list that does not open to its digest is refused and the file kept",
|
||||||
before: []put{{module: "nats", fp: fpOf("a"), content: two}}, grants: []gput{{follow: delivery.FollowGrants, content: three, badDigest: true}},
|
before: []put{{module: "nats", fp: fpOf("a"), content: two}}, grants: []gput{{follow: delivery.FollowGrants, content: three, badDigest: true}},
|
||||||
onDisk: two, wantErr: "could not be had", wantRefused: true, wantSource: delivery.GrantsUserListSource},
|
onDisk: two, wantErr: "could not be had", wantRefused: true, wantSource: delivery.GrantsUserListSource},
|
||||||
@@ -256,6 +273,11 @@ func TestTheBusNodeWritesTheNewestSignedUserListAlone(t *testing.T) {
|
|||||||
gs = append(append([]gput(nil), gs...), *c.kept)
|
gs = append(append([]gput(nil), gs...), *c.kept)
|
||||||
}
|
}
|
||||||
for i, g := range gs {
|
for i, g := range gs {
|
||||||
|
if g.unreadable || g.deleted {
|
||||||
|
u := agent.Update{Key: delivery.GrantsUserListKey, Value: []byte("not a user-list key"), Revision: uint64(i + 1), Deleted: g.deleted}
|
||||||
|
grantsAfter = append(grantsAfter, u)
|
||||||
|
continue
|
||||||
|
}
|
||||||
to := nodeKey.PublicKey
|
to := nodeKey.PublicKey
|
||||||
if g.otherKey {
|
if g.otherKey {
|
||||||
other, _ := seal.GenerateKeyPair()
|
other, _ := seal.GenerateKeyPair()
|
||||||
@@ -271,7 +293,7 @@ func TestTheBusNodeWritesTheNewestSignedUserListAlone(t *testing.T) {
|
|||||||
}
|
}
|
||||||
sealed[delivery.UserListObjectName(digest)] = object
|
sealed[delivery.UserListObjectName(digest)] = object
|
||||||
raw, err := delivery.EncodeGrantsUserList(delivery.GrantsUserList{Follow: g.follow, Digest: digest,
|
raw, err := delivery.EncodeGrantsUserList(delivery.GrantsUserList{Follow: g.follow, Digest: digest,
|
||||||
Object: delivery.UserListObjectName(digest), SealedTo: delivery.SealingKeyID(to), Node: node, Revision: uint64(i + 1)})
|
Object: delivery.UserListObjectName(digest), SealedTo: delivery.SealingKeyID(to), Node: node, Revision: uint64(i + 1), LeaseHanded: g.handed})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user