The node-engine owns the composition it alone runs (H1, H2)
ADR 0593 §1 and §7: compose, its bus reader and runtime reader, takein, validate, the overlay generator, the composer's run and mesh-compose, and the judgement of a move leave mesh-sdk for the node-engine's internal packages, so no other module composes and a change to them rebuilds only the node-engine. The shapes others read (the composer's request and verdict, the overlay's names, compositions and answers) stay in mesh-sdk. The node's grant is now a golden file of what the grants part composes, since the composer of the bus's user list leaves mesh-sdk too. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/novox/mesh-host/internal/agent"
|
||||
"github.com/novox/mesh-host/internal/link"
|
||||
"github.com/novox/mesh-host/internal/nodegrant"
|
||||
"github.com/novox/mesh-host/internal/selfcompose"
|
||||
)
|
||||
|
||||
@@ -32,7 +33,7 @@ type itBed struct {
|
||||
t *testing.T
|
||||
conn *nats.Conn
|
||||
js nats.JetStreamContext
|
||||
// nodeConn and nodeJS are the node's own, under its real grant (buscompose.PermissionsFor, KindNode): the agent runs
|
||||
// nodeConn and nodeJS are the node's own, under its real grant (the grants part's, nodegrant.For): the agent runs
|
||||
// on them, so a watch or a read the grant does not allow fails here as it fails on the bus (issue 1126, 2026-10-27
|
||||
// 09:21: a watch of every have key stopped every node agent). conn is the test's, unrestricted, for setting up.
|
||||
nodeConn *nats.Conn
|
||||
@@ -51,13 +52,9 @@ type itBed struct {
|
||||
}
|
||||
|
||||
// aServer is an embedded bus with JetStream and two users: the test's, unrestricted, and the node's, granted exactly what
|
||||
// buscompose.PermissionsFor gives a node (KindNode); it answers a connection of each.
|
||||
func aServer(t *testing.T, principal buscompose.Principal, refused func(error)) (admin, node *nats.Conn) {
|
||||
// the grants part gives a node (nodegrant.For); it answers a connection of each.
|
||||
func aServer(t *testing.T, perms nodegrant.Permissions, refused func(error)) (admin, node *nats.Conn) {
|
||||
t.Helper()
|
||||
perms, err := buscompose.PermissionsFor(principal)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
granted := &server.Permissions{Publish: &server.SubjectPermission{Allow: perms.Publish, Deny: perms.PublishDeny},
|
||||
Subscribe: &server.SubjectPermission{Allow: perms.Subscribe}}
|
||||
if perms.AllowResponses {
|
||||
@@ -88,11 +85,11 @@ func aServer(t *testing.T, principal buscompose.Principal, refused func(error))
|
||||
|
||||
func newItBed(t *testing.T) *itBed {
|
||||
t.Helper()
|
||||
return newItBedAs(t, buscompose.Principal{Kind: buscompose.KindNode, Node: itNode})
|
||||
return newItBedAs(t, nodegrant.For(itNode))
|
||||
}
|
||||
|
||||
// newItBedAs is newItBed with the node's connection under the grant of principal, a node's (KindNode).
|
||||
func newItBedAs(t *testing.T, principal buscompose.Principal) *itBed {
|
||||
// newItBedAs is newItBed with the node's connection under the grant perms, a node's.
|
||||
func newItBedAs(t *testing.T, perms nodegrant.Permissions) *itBed {
|
||||
t.Helper()
|
||||
// Not skipped off Arch: a package manager that answers is put on PATH, so the apply of files runs on any build node.
|
||||
bin := t.TempDir()
|
||||
@@ -105,7 +102,7 @@ func newItBedAs(t *testing.T, principal buscompose.Principal) *itBed {
|
||||
t.Cleanup(func() { builtFor = was })
|
||||
|
||||
b := &itBed{t: t, dir: t.TempDir()}
|
||||
b.conn, b.nodeConn = aServer(t, principal, func(err error) {
|
||||
b.conn, b.nodeConn = aServer(t, perms, func(err error) {
|
||||
b.mu.Lock()
|
||||
b.refusals = append(b.refusals, err.Error())
|
||||
b.mu.Unlock()
|
||||
@@ -233,24 +230,10 @@ func within(t *testing.T, d time.Duration, what string, ok func() bool) {
|
||||
// in the node's own key, and nothing is applied for it (ADR 0559 §4, subtask 10 of the milestone).
|
||||
//
|
||||
// And (issue 1126, ADR 0560) it reads, through its own session under the grant the grants part composes for it
|
||||
// (buscompose.Users, so it carries ServedReads), the build of a placed module that declares one and the one config value
|
||||
// (nodegrant.For with the served key, as the grants part grants it), the build of a placed module that declares one and the one config value
|
||||
// a provider on another node serves from (a mail domain); under a grant without that served key the bus refuses the
|
||||
// read and the node composes nothing.
|
||||
func TestNatsANodeThePlacementNamesComposesAndAppliesItsOwn(t *testing.T) {
|
||||
users, err := buscompose.Users(buscompose.Records{Nodes: []string{itNode, "it2"},
|
||||
Assigned: map[string][]buscompose.Declared{"it2": {{Module: "mailer", Served: []string{"domain"}}}}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var principal buscompose.Principal
|
||||
for _, u := range users {
|
||||
if u.Kind == buscompose.KindNode && u.Node == itNode {
|
||||
principal = u
|
||||
}
|
||||
}
|
||||
if len(principal.ServedReads) != 1 {
|
||||
t.Fatalf("the grants part's principal of %s reads %v of the served keys", itNode, principal.ServedReads)
|
||||
}
|
||||
t.Run("without the served key the bus refuses the read", func(t *testing.T) {
|
||||
b := newItBed(t)
|
||||
stop, _ := h8(t, b, false)
|
||||
@@ -268,7 +251,7 @@ func TestNatsANodeThePlacementNamesComposesAndAppliesItsOwn(t *testing.T) {
|
||||
t.Errorf("composed and applied under a grant without the served key: %q", b.file("web"))
|
||||
}
|
||||
})
|
||||
b := newItBedAs(t, principal)
|
||||
b := newItBedAs(t, nodegrant.For(itNode, "it2.mailer.domain"))
|
||||
stop, st := h8(t, b, true)
|
||||
defer stop()
|
||||
placement, resolved, candidates := st.placement, st.resolved, st.candidates
|
||||
|
||||
Reference in New Issue
Block a user