ADR 0593 §7: the composer with its refusals leaves mesh-sdk, so mesh-sdk carries no composition rule. The catalogue functions only the node-engine's composition reaches (Resolve, Resolution's Compose, Declaration, DataItems, LeftOut, Rules and the rest, the settings, placeholder and template refusals, the rendering helpers) are copied with their tests into internal/compose/resolution; a method of a mesh-sdk shape becomes a function taking it first. The composition calls its own copies, and the captured catalogue its tests read lives here now, shared by mesh-compose's tests. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
68 lines
4.7 KiB
Go
68 lines
4.7 KiB
Go
package resolution
|
|
|
|
import (
|
|
mcat "git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
// enrolmentDecision is the record that made the seat.
|
|
const enrolmentDecision = "novox/hq ADR 0587"
|
|
|
|
// enrolmentVerbs are the seat's verbs: what reads all it holds and does by hand all it does (ADR 0587 §8). Not optional:
|
|
// the seat is new with its holder, so no holder of before serves fewer.
|
|
func enrolmentVerbs() []mcat.Verb {
|
|
str := func(description string) map[string]any {
|
|
return map[string]any{"type": "string", "description": description}
|
|
}
|
|
return []mcat.Verb{
|
|
{Name: mcat.EnrolmentVerbIssue, Description: "Issue a one-time token for a new machine, on the operator's Approve: " +
|
|
"refused at once, naming every finding, for a name that is not a node name or that a node record, a placement " +
|
|
"key or an open enrolment holds, and for every call before the controller's lease is handed away. Otherwise " +
|
|
"reserves the lowest free private-network address, asks the operator under the seat's own name and, on the " +
|
|
"warrant, adds the node to placement with its tunnel key, asks the vault for the token and says enrolment-issued. " +
|
|
"The token itself is read only through tokens.",
|
|
Input: schema(map[string]string{
|
|
"node": "the new machine's name in the mesh",
|
|
"why": "why it joins, shown to the operator with the ask",
|
|
"expires": "how long the token lasts, a duration such as 1h or 24h: one hour when not given, at most 24 hours",
|
|
// The operator's decision of 2026-11-02 01:05: the tunnel key is given at issue, so on the Approve the node
|
|
// enters placement with it and the hub peers it before redeem.
|
|
"overlay_key": "the new machine's private network (tunnel) public key, as `nox-mesh-host key` prints it",
|
|
}, []string{"node", "why", "overlay_key"})},
|
|
{Name: mcat.EnrolmentVerbRedeem, Description: "Spend a token: asked by a joining node-engine dialled as enrol.<node> " +
|
|
"alone, with the public halves of its keys and its identity key's proof over them. Spends the token, asks the " +
|
|
"vault for the node's account and certificate, writes the node into placement, and answers the account sealed " +
|
|
"to the node, its certificate and the vault's public half, signed by the vault. Asked again with the same keys " +
|
|
"it finishes what is not done and answers the same; with other keys it is refused.",
|
|
Input: map[string]any{"type": "object", "additionalProperties": false,
|
|
"required": []string{"node", "public_key", "sealing_key", "proof"},
|
|
"properties": map[string]any{
|
|
"node": str("the node the token was issued for"),
|
|
"public_key": str("the identity key's public half, base64"),
|
|
"overlay_key": str("the private network key's public half"),
|
|
"sealing_key": str("the sealing key's public half, which the account is sealed to"),
|
|
"serving_key": str("the serving key's public half, which the certificate binds"),
|
|
"profile": map[string]any{"type": "object", "description": "what the machine is, as its record says it"},
|
|
"tunnel": map[string]any{"type": "object", "description": "a tunnel found on the machine: everything but its private key"},
|
|
"proof": str("the identity key's signature over the redeem's proof bytes (delivery.RedeemProof), base64"),
|
|
}}},
|
|
{Name: mcat.EnrolmentVerbConfirm, Description: "Confirm an enrolment: asked by the node-engine dialled as its own " +
|
|
"node login alone, the runtime's proof of that caller being the confirmation. Says node-enrolled and ends the " +
|
|
"enrolment.",
|
|
Input: schema(map[string]string{}, nil)},
|
|
{Name: mcat.EnrolmentVerbRevoke, Description: "End an enrolment at any stage, with why, without an Approve: withdraws " +
|
|
"an open ask, deletes the node's key and its address, has the vault retire an account it already minted for " +
|
|
"it, records the act as a hand act and says enrolment-revoked.",
|
|
Input: schema(map[string]string{"node": "the node", "why": "why, recorded with the hand act"},
|
|
[]string{"node", "why"})},
|
|
{Name: mcat.EnrolmentVerbTokens, Description: "Read every open enrolment, or one: its stage, expiry, ask and revision, " +
|
|
"the bucket's fill against its cap. For a node at live, its " +
|
|
"token sealed to the operator key, asked of the vault at that moment and relayed as the vault sealed it. With " +
|
|
"history, the ended enrolments from the seat's events, as far back as the events are kept.",
|
|
Input: schema(map[string]string{"node": "one node", "history": "\"true\": the ended enrolments too"},
|
|
nil, "history")},
|
|
{Name: mcat.EnrolmentVerbAgain, Description: "Raise an issue's ask again when the operator's channel does not hold it, " +
|
|
"and nothing more.",
|
|
Input: schema(map[string]string{"node": "the node whose ask is raised again"}, []string{"node"})},
|
|
}
|
|
}
|