mesh/delivery-group group feat/sdk1 rejected: composed together: the checker's verdict at the members' heads (428d048dd50a): unit: git.novox.be/novox/mesh-sdk/…
mesh/delivery closed: a newer head of the same pull request
mesh/check failed: unit: git.novox.be/novox/mesh-sdk/go/process.TestStatePutWritesAKeyWhole: a Put through a short blackout: 0, mesh-mail's state send…
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
272 lines
15 KiB
Go
272 lines
15 KiB
Go
package catalogue
|
|
|
|
// Node is what resolution needs to know about the machine.
|
|
type Node struct {
|
|
Name string
|
|
Site string
|
|
// Capabilities the machine actually has, as its profile reported them. Only the present ones
|
|
// — a capability that was looked for and not found is the same as one nobody looked for, as
|
|
// far as deciding what may run here goes.
|
|
Capabilities map[string]bool
|
|
// At is this machine's own name on the private network, empty if it is not on one. Needed to
|
|
// tell whether it can reach the node answering its requirements at all.
|
|
At string
|
|
// PublicDomain is the domain this node composes its routed names under, empty if it has none
|
|
// (novox/hq ADR 0066). A route contribution carries only a label — the subdomain — and the mesh
|
|
// joins <label>.<public-domain> to make the name it grants, interpreting neither half.
|
|
PublicDomain string
|
|
// Account is the operator's login on this machine, AccountHome where its home is (novox/hq
|
|
// to-be 29). What a home-scoped file is owned by and what ${machine:account} resolves to.
|
|
Account string
|
|
AccountHome string
|
|
// AgentAccount is the login agents run as here when it is not the operator's, AgentAccountHome its
|
|
// home when not derived (novox/hq ADR 0266). What ${machine:agent-account} resolves to; empty means
|
|
// agents run as the operator account.
|
|
AgentAccount string
|
|
AgentAccountHome string
|
|
}
|
|
|
|
// World is what the rest of the mesh already has.
|
|
//
|
|
// Some requirements cannot be answered on the machine that has them — a database runs somewhere
|
|
// and is reached over the network — so resolving one node needs to know what the others offer.
|
|
type World struct {
|
|
// Held is the claims already taken, for the scopes wider than one node.
|
|
Held []Held
|
|
// Holdings is every seat whose holder is **on record** (novox/hq ADR 0131): the one assignment
|
|
// that holds it, chosen by a handover. A seat absent here is held by derivation — the sole
|
|
// eligible assignment — as it always was. Present, it decides, and any other assignment whose
|
|
// module could hold the seat is eligible and silent rather than refused.
|
|
Holdings []Held
|
|
// Offered is what other nodes provide at mesh scope, and everything needed to use it.
|
|
Offered map[string][]Provider
|
|
// Pinned is which provider this machine was told to get a provision from, by name: a module and
|
|
// the node it runs on, both (novox/hq #258). Only consulted when more than one could answer -- a
|
|
// choice recorded before it was needed should not start meaning something the day a second
|
|
// provider appears, and one recorded and then made unnecessary should not quietly stop applying
|
|
// either.
|
|
Pinned map[string]Chosen
|
|
// Bound is where each of this machine's consumers was bound for a provision that keeps its data
|
|
// (novox/hq ADR 0232), by consumer module then provision: the provider it was last sent, as the
|
|
// store recorded it. A resolution that would answer such a consumer from anywhere else keeps it
|
|
// where it is and says so (Resolution.Kept); only a pin naming the other provider moves it.
|
|
Bound map[string]map[string]Chosen
|
|
// Licences is every provision answered by a **record rather than a node**, by provision name.
|
|
//
|
|
// novox/hq ADR 0024: a hosted model is on nobody's machine and is reached over the public
|
|
// internet, so the rule that refuses two ends sharing no private network must not apply to
|
|
// it. These are the candidates a refusal names.
|
|
Licences map[string][]Record
|
|
// Using is which record this node's modules were put on, keyed by module then provision.
|
|
//
|
|
// Per consumer, because that is the whole point: saying WHICH licence a given thing uses. Two
|
|
// modules on one machine using different accounts is ordinary rather than a collision.
|
|
Using map[string]map[string]Record
|
|
|
|
// Unchecked takes brokered requirements on trust instead of refusing when nothing answers
|
|
// them.
|
|
//
|
|
// For the first of two passes. Working out what a node offers the mesh needs that node
|
|
// resolved, and resolving it may need what the mesh offers — so the first pass answers only
|
|
// *what does each node offer*, and the second pass answers everything with that in hand. A
|
|
// declaration is never built from an unchecked resolution.
|
|
Unchecked bool
|
|
}
|
|
|
|
// Record is a provision answered by something the mesh holds rather than by a machine.
|
|
//
|
|
// The name is the operator's — *the personal account*, *the organisation's* — because the whole
|
|
// point is saying which one a consumer uses, and an anonymous credential hanging off a provider
|
|
// cannot be said (novox/hq ADR 0024).
|
|
type Record struct {
|
|
// Name is what a person calls it, and what a consumer is put on.
|
|
Name string
|
|
// Serves is what a consumer must know that is not secret — a base URL, a model name.
|
|
Serves map[string]any
|
|
}
|
|
|
|
// Provider is one node answering a mesh-scoped requirement.
|
|
type Provider struct {
|
|
// Node is the machine.
|
|
Node string
|
|
// At is its name on the private network, or empty if it is not on one. The mesh's half of
|
|
// the answer: a module can say it serves on port 5432, and only the mesh knows where.
|
|
At string
|
|
// Serves is what the providing module said a consumer needs to know, settled.
|
|
Serves map[string]any
|
|
// Module is which module on that node provides it. A provider is a (node, module) pair
|
|
// (novox/hq to-be 23), and the pair is what tells the holder of a seat apart from another module
|
|
// providing the same thing (ADR 0110).
|
|
Module string
|
|
// LeftOut says each served key left out of Serves because that node composes no name it asks
|
|
// for (novox/hq ADR 0346 §3): said under each consumer's need.
|
|
LeftOut []string
|
|
}
|
|
|
|
// Held is a claim somebody already has, used for the scopes wider than one node.
|
|
type Held struct {
|
|
Claim string
|
|
Scope string
|
|
Node string
|
|
Module string
|
|
Site string
|
|
// Kind is the kind a kinded bench is held as (novox/hq ADR 0234 §2): each kind is its own holder.
|
|
Kind string
|
|
}
|
|
|
|
// Resolution is what a node should run, and why.
|
|
type Resolution struct {
|
|
// Node is which machine this was resolved for, so a generator can be asked about it.
|
|
Node string
|
|
// At is this machine's own name on the private network, empty if it is not on one. Kept
|
|
// because a consumer bound to something answered on this same machine still has to be told
|
|
// where it is — the answer being local does not make the port guessable.
|
|
At string
|
|
// PublicDomain is the domain this node composes its routed names under, empty if it has none
|
|
// (novox/hq ADR 0066). Carried from the node so that composing <label>.<public-domain> for a
|
|
// route contribution needs no store lookup here — the join is a fact about this one machine.
|
|
PublicDomain string
|
|
// Account and AccountHome are the operator's login on this machine and where its home is
|
|
// (novox/hq to-be 29), carried from the node so a home-scoped file's owner and path resolve
|
|
// here without a store lookup.
|
|
Account string
|
|
AccountHome string
|
|
// AgentAccount and AgentAccountHome are the account agents run as here when it is not the
|
|
// operator's, and its home (novox/hq ADR 0266); empty when agents run as the operator account.
|
|
AgentAccount string
|
|
AgentAccountHome string
|
|
// Capabilities are the machine's, as its profile reported them, carried from the node so a
|
|
// contribution placed only where the machine has something (`if-capability`, novox/hq ADR 0255)
|
|
// is decided here without a store lookup.
|
|
Capabilities map[string]bool
|
|
|
|
// Modules in the order they were resolved: assigned first, then what they pulled in.
|
|
Modules []Manifest
|
|
// Because says why each module is here — assigned, or required by something.
|
|
Because map[string]string
|
|
// Claims is what this node's set holds, so wider scopes can be checked against it.
|
|
Claims []Held
|
|
// Needs is what this node's set gets from other nodes. Recorded rather than resolved away,
|
|
// because it is where a credential will have to be handed back once there is a mechanism for
|
|
// that, and because "what does this machine depend on that is not on it" has no other answer.
|
|
Needs []Needed
|
|
// Unhostable is what a person assigned to this machine that this machine cannot run — a module
|
|
// whose declared capability has no detector here. Kept out of Modules rather than refusing the
|
|
// whole set: a module put on the wrong machine is that one module's problem, and the healthy
|
|
// modules beside it still resolve, declare, and converge. Reported so it is neither silently
|
|
// dropped nor fatal to the rest. A module that is *required* by something running here is a
|
|
// different case — that set is incoherent and is refused (see checkCapabilities).
|
|
Unhostable []Unhostable
|
|
// Unheld is every dependency of this node's modules on a seat nothing here holds (novox/hq ADR
|
|
// 0207) — reported rather than refused while enforceSeatDependencies is off, so a node short of a
|
|
// holder still converges and `status` says what it is short of.
|
|
Unheld []Unheld
|
|
// Kept is every consumer this resolution would have moved to another provider of a provision
|
|
// that keeps its data, and did not (novox/hq ADR 0232): it stays bound where its data is, and the
|
|
// controller raises an urgent condition naming the move until a person pins one or the other.
|
|
Kept []KeptBinding
|
|
// Absent is every optional requirement of this node's modules that nothing assigned answers
|
|
// (novox/hq ADR 0330 §3): left unbound rather than refused, with nothing installed for it, and
|
|
// listed by `plan` and `node` (§7). It binds on the first composition after a provider is assigned.
|
|
Absent []Absent
|
|
}
|
|
|
|
// Unhostable is one directly-assigned module the machine cannot run.
|
|
type Unhostable struct {
|
|
// Module is the assigned module the machine cannot host.
|
|
Module string
|
|
// Missing is the capabilities it declares that this machine does not have.
|
|
Missing []string
|
|
}
|
|
|
|
// Needed is one thing this node's set takes from elsewhere in the mesh.
|
|
type Needed struct {
|
|
// Name is the provision, as required.
|
|
Name string
|
|
// From is the node providing it.
|
|
From string
|
|
// At is where that node is on the private network.
|
|
At string
|
|
// Serves is what the providing module said a consumer needs to know.
|
|
Serves map[string]any
|
|
// ByRecord means this was answered by something the mesh holds rather than by a machine, so
|
|
// there is no node to reach and no private network to share. Its credential comes from
|
|
// wherever that record's does, not from the pair-wise secret two machines share.
|
|
ByRecord bool
|
|
// Sealed is the credential, closed to this node. Filled in after resolving, because whose
|
|
// credential it is only becomes answerable once which node answers has been settled.
|
|
Sealed string
|
|
// For is the module that wanted it.
|
|
For string
|
|
// Local is the name this credential goes by inside that module, where the module wants several
|
|
// for one requirement (ADR 0094); empty for the ordinary one. Part of what identifies the pair
|
|
// credential, so two secrets from one provider to one module are two secrets.
|
|
Local string
|
|
// SharedOwn is set when the provision's credential is one of the provider's own secrets, shared
|
|
// by every consumer (novox/hq ADR 0158): the name of that secret in the provider's definition.
|
|
// The plan mints the pair's copy from the provider's value rather than a value of its own.
|
|
SharedOwn string
|
|
// CredentialForm is the credential form the provider's offer declares (Manifest.CredentialFormOf, issue 768),
|
|
// named in a handed consumer's plan for the vault; empty where the provider's manifest is not in hand.
|
|
CredentialForm string
|
|
// CredentialTool is the tool of the offer that the provider's software issues the credential through (issue 928).
|
|
CredentialTool string
|
|
// Manager is set when this holder is a refreshable-grant licence's MANAGER, delivered the refresh
|
|
// token rather than an access token (novox/hq ADR 0050). It changes one thing downstream: an empty
|
|
// Sealed is tolerated — the manager has not adopted a refresh token yet, which is a real waiting
|
|
// state, not a consumer missing its key. Set by the plan, which is the only layer that knows a
|
|
// licence's manager; empty for every consumer.
|
|
Manager bool
|
|
// LeftOut says each served key the provider left out, because its machine composes no name the
|
|
// value asks for (novox/hq ADR 0346 §3).
|
|
LeftOut []string
|
|
// Module is the providing module on From, empty for a need answered by a record or by nothing
|
|
// that serves it. A provider is a (node, module) pair (novox/hq to-be 23), and a binding to data
|
|
// is a binding to the pair (ADR 0232).
|
|
Module string
|
|
// KeepsData is set when the provision keeps what its consumer writes (novox/hq ADR 0232): the
|
|
// binding is to the consumer's data, recorded when it is sent and moved only by a pin.
|
|
KeepsData bool
|
|
// Identity is the longest consumer identity the answering provision keeps (novox/hq ADR 0225),
|
|
// from the provider's own offer: what the mesh judges this consumer's identity against, on the
|
|
// consumer's side for `status` and on the provider's before it grants. No bound for a provision
|
|
// answered by a record, which keeps no name of anybody's.
|
|
Identity IdentityBound
|
|
// IssuedToHolder is set when the vault keeps this need's credential for this holder alone (issue 757): the
|
|
// providing module is marked moved and its software issues the provision's credential for each holder (issue
|
|
// 749), kept as provision/<From>/<Name>/<node>/<For>. Where the consumer is handed to the provisioner, its
|
|
// machine's client asks the vault for it and the declaration carries no value. Set by the plan, which reads the
|
|
// provider's manifest.
|
|
IssuedToHolder bool
|
|
// ProviderMoved is set when the providing module is marked moved (issue 788): a handed consumer's template may
|
|
// then name `${bound:<provision>:<key>}` and `${secret:<provision>}`, which its machine's client fills from the
|
|
// provider's entry and the vault. Set by the plan, which reads the provider's manifest.
|
|
ProviderMoved bool
|
|
// AnsweredByHelper is set when the providing module's offer says the provider helper answers it (issue 792): a
|
|
// provision the seat mesh-provisioner keys whether or not its consumer is handed (Keyed). Set by the plan, which
|
|
// reads the provider's manifest.
|
|
AnsweredByHelper bool
|
|
}
|
|
|
|
// Offers is a list of node-scoped provisions, which is what nearly everything is.
|
|
func Offers(names ...string) []Offer {
|
|
out := make([]Offer, 0, len(names))
|
|
for _, n := range names {
|
|
out = append(out, Offer{Name: n})
|
|
}
|
|
return out
|
|
}
|
|
|
|
// FromAnywhere is a provision answered by whichever node in the mesh runs it.
|
|
func FromAnywhere(names ...string) []Offer {
|
|
out := make([]Offer, 0, len(names))
|
|
for _, n := range names {
|
|
out = append(out, Offer{Name: n, Scope: ScopeMesh})
|
|
}
|
|
return out
|
|
}
|
|
|
|
// ContainerGroups is the capability a node-engine reports when it reads a container's `groups` and passes each as a
|
|
// supplementary group (novox/hq ADR 0480 clause 7, issue 1638). An older engine refuses the key (strict decoding).
|
|
const ContainerGroups = "container-groups"
|