Node-engine: the seats are called by their names mesh-module-assigner and mesh-node-enroller (ADR 0634 §9; H-5; issue 1966)

This commit is contained in:
2026-11-05 14:17:46 +01:00
parent 570b66230c
commit 6ebad21cbe
8 changed files with 16 additions and 16 deletions
+2 -2
View File
@@ -14,7 +14,7 @@ import (
"github.com/novox/mesh-host/internal/link"
)
// enrolThroughSeat joins this machine through the seat mesh-enrolment (novox/hq ADR 0587 §6, issue 774): it redeems the token
// enrolThroughSeat joins this machine through the seat mesh-node-enroller (novox/hq ADR 0587 §6, issue 774): it redeems the token
// with the keys it made, verifies the vault's signed answer against the key the token carries before it keeps anything, keeps
// its membership and its login, dials as the login node-logins names and confirms. A bus that does not serve the seat to this
// token (link.ErrNoSeat) is said as the error: nothing was sent or kept.
@@ -64,7 +64,7 @@ func enrolThroughSeat(ctx context.Context, opts options, token identity.Token, n
if err != nil {
return err
}
fmt.Printf("\nenrolled as %s through the seat mesh-enrolment, dialled as %s and confirmed\n", answer.Node, answer.Login)
fmt.Printf("\nenrolled as %s through the seat mesh-node-enroller, dialled as %s and confirmed\n", answer.Node, answer.Login)
fmt.Printf(" identity %s\n", identityPath)
fmt.Println(" nothing is applied until the placement of this node names a module")
return nil
+1 -1
View File
@@ -819,7 +819,7 @@ func enrol(ctx context.Context, opts options) error {
detected := profile.Detect(ctx, profile.Default(nil), opts.timeout)
reported := profileAsReported(detected)
// Through the seat mesh-enrolment (novox/hq ADR 0587 §6), the one way in: the controller's enrolment subject ended
// Through the seat mesh-node-enroller (novox/hq ADR 0587 §6), the one way in: the controller's enrolment subject ended
// with the controller (issue 1126).
return enrolThroughSeat(ctx, opts, token, *name, mine, sealing, serving, reported, found, identityPath)
}
+2 -2
View File
@@ -173,7 +173,7 @@ func followTrust(ctx context.Context, session *link.Session, trust *meshTrust, s
}
}
// placedAllHave says whether every module the seat mesh-placement places on node has a have of its own, read from the
// placedAllHave says whether every module the seat mesh-module-assigner places on node has a have of its own, read from the
// bus: then the kept declaration is read no more (keptRetired). A node the seat does not place, or whose placement or haves
// cannot be read, keeps reading it.
func placedAllHave(ctx context.Context, session *link.Session, node string) (bool, string) {
@@ -228,7 +228,7 @@ func placedModules(node string, values map[string][]byte) (delivery.Placement, e
// apply refused from then on).
func allHave(p delivery.Placement, has func(module string) (delivery.Have, bool, error)) (bool, string) {
if len(p.Modules) == 0 {
return false, "the seat mesh-placement places no module here"
return false, "the seat mesh-module-assigner places no module here"
}
for _, m := range p.Modules {
h, ok, err := has(m.Module)
+2 -2
View File
@@ -2,13 +2,13 @@
// and the grants part compose with one composer over the same inputs (novox/hq ADR 0547 §2, ADR 0549 §3; issue 1126).
//
// **One composer, three callers.** compose.Compositions is the composer; Input is how each caller fills its
// compose.Input from the bus: the node agent for its own node (ADR 0547 §2), the seat mesh-placement's holder judging a
// compose.Input from the bus: the node agent for its own node (ADR 0547 §2), the seat mesh-module-assigner's holder judging a
// proposal for every node (ADR 0567 §4), and the grants part (ADR 0547 §5). Each reads the bus with its own credential
// through a Reader, so this package holds no bus client, no store and no timer: what it is given is all it reads.
//
// **What it reads, and from whom.**
// - which modules run on each node, with their pins, holdings, host ports, bindings and settings placement: the
// seat mesh-placement's state `placement`, one key per node (ADR 0567 §1);
// seat mesh-module-assigner's state `placement`, one key per node (ADR 0567 §1);
// - what a person decided of each node (its endpoint, site, hub, address on the private network, public domain and
// accounts): the same placement key, Placement.Decided;
// - what each node observes of itself (its tunnel key, capabilities, keys, certificate, links and networks): the
@@ -12,9 +12,9 @@ func placementVerbs() []mcat.Verb {
"place (node, module, ports, bindings), take-off (node, module), pin (node, provision, provider {node, module}), " +
"unpin (node, provision), hold (node, module, claim, scope, kind, site), unhold (node, module, claim), decide " +
"(node, field, value: a decided field of the node, its address among them), config (node, module, mesh-wide, " +
"layer, mesh-wide-values, values), add-node (node, decided, keys: a joining node, mesh-enrolment's alone, the " +
"layer, mesh-wide-values, values), add-node (node, decided, keys: a joining node, mesh-node-enroller's alone, the " +
"proposal's one change, with the enrolment's warrant, its tunnel key alone at the operator's yes; ADR 0587 §7), " +
"remove-node (node: a joining node never confirmed, taken off when its enrolment ends; mesh-enrolment's alone, " +
"remove-node (node: a joining node never confirmed, taken off when its enrolment ends; mesh-node-enroller's alone, " +
"on the same warrant)",
"items": map[string]any{"type": "object", "required": []string{"op", "node"}}}
return []mcat.Verb{
@@ -36,7 +36,7 @@ func placementVerbs() []mcat.Verb {
"on one host port, a provider not placed, a seat held once held twice, two nodes with one address, two " +
"hubs, a module the indexer does not hold, a node with no record). Otherwise the nodes it touches compose " +
"it in shadow and answer, and on a passing verdict the operator is asked to approve it. Who proposes is the " +
"caller, as the runtime proves it. An add-node from mesh-enrolment, whose warrant names its node and address, " +
"caller, as the runtime proves it. An add-node from mesh-node-enroller, whose warrant names its node and address, " +
"is written with no ask of its own: its Approve is the enrolment's (ADR 0587 §7).",
Input: map[string]any{"type": "object", "additionalProperties": false, "required": []string{"why", "changes"},
"properties": map[string]any{
+1 -1
View File
@@ -6,7 +6,7 @@ import (
)
// What a joining machine keeps of the enrolment's words: the tunnel it found, as it travels, and how long it asks
// while the seat mesh-enrolment says to ask again (Redeem). The enrolment through the controller's subject on the
// while the seat mesh-node-enroller says to ask again (Redeem). The enrolment through the controller's subject on the
// CONTROL stream ended with the controller (issue 1126).
// Approach is how a node reaches a mesh it does not yet belong to: the address, the certificate that address must
+4 -4
View File
@@ -15,7 +15,7 @@ import (
"git.novox.be/novox/mesh-sdk/go/delivery"
)
// Joining a mesh through the seat mesh-enrolment (novox/hq ADR 0587 §6, issue 774): the node-engine dials the bus as enrol.<node>
// Joining a mesh through the seat mesh-node-enroller (novox/hq ADR 0587 §6, issue 774): the node-engine dials the bus as enrol.<node>
// with the certificate's fingerprint pinned, calls `redeem` with the public halves of the keys it made where it runs and a
// proof signed with its identity key, refuses an answer not signed by the key its token carries, keeps its membership, dials
// again as the login node-logins names for it, and calls `confirm`. It is the one way in: the controller's enrolment subject
@@ -23,7 +23,7 @@ import (
// EnrolmentSeat is the seat that adopts a new machine, and its two verbs a node-engine calls.
const (
EnrolmentSeat = "mesh-enrolment"
EnrolmentSeat = "mesh-node-enroller"
EnrolmentRedeem = "redeem"
EnrolmentConfirm = "confirm"
)
@@ -35,7 +35,7 @@ func CalledSeatSubject(seat, verb, user string) string {
// ErrNoSeat is the bus saying nothing serves the seat for this caller: the enrolment user may not publish the seat's call, or
// no holder answers it.
var ErrNoSeat = errors.New("the seat mesh-enrolment is not served to this machine's token")
var ErrNoSeat = errors.New("the seat mesh-node-enroller is not served to this machine's token")
// VerifyRedeemAnswer holds an answer to what it must be before anything is kept (ADR 0587 §6): it names the node asked for,
// carries the signing key the token carries, and is signed by that key under the context of an enrolment's answer. An answer
@@ -187,7 +187,7 @@ func (j Joining) Run(ctx context.Context) (delivery.RedeemAnswer, error) {
return answer, fmt.Errorf("node-logins names %s for this node and the answer gave it %s: it is not confirmed", nl.Login, answer.Login)
}
if err := c.Confirm(ctx); err != nil {
return answer, fmt.Errorf("the enrolment is redeemed and not confirmed (a person ends it with mesh-enrolment.revoke): %w", err)
return answer, fmt.Errorf("the enrolment is redeemed and not confirmed (a person ends it with mesh-node-enroller.revoke): %w", err)
}
return answer, nil
}
+1 -1
View File
@@ -98,7 +98,7 @@ func TestTheEngineKeepsOnlyAnAnswerSignedByTheKeyItsTokenCarries(t *testing.T) {
if _, err := j.Run(ctx); err == nil || slices.Contains(steps, "confirm") {
t.Errorf("a key naming another login was confirmed: %v, %v", err, steps)
}
if CalledSeatSubject("mesh-enrolment", "redeem", "enrol.ace") != "mesh.seat.mesh-enrolment.call.redeem.enrol~ace" {
if CalledSeatSubject("mesh-node-enroller", "redeem", "enrol.ace") != "mesh.seat.mesh-node-enroller.call.redeem.enrol~ace" {
t.Error("the call's subject does not name its caller as the composer grants it")
}
}