The wanted accounts' layout leaves mesh-sdk for the grants part's package grantsstate (ADR 0634 section 1, ADR 0635 section 4, issue 1966)
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
package grantsstate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/buscompose"
|
||||
)
|
||||
|
||||
// **The accounts the grants part wants** (novox/hq ADR 0561 §1, §2; ADR 0634 §1, ADR 0635 §4: the layout of a state is its
|
||||
// owner's, published with it). For each account the mesh mints (a module's, a module's process's, a machine's provisioner
|
||||
// client's, a ledger's), the grants part writes one key of its state `accounts`, keyed by the bus user, holding the account's
|
||||
// fields that are not secret. The vault reads that state, mints the user it holds no value for, and keeps the value as the
|
||||
// module's own secret on that node, built by HeldCredential. The node accounts, the controller's own, an enrolment user and a
|
||||
// person are never wanted here: the vault mints none of them (ADR 0561 §4, §5).
|
||||
|
||||
// AccountsState is the grants part's state of wanted accounts, by bus user.
|
||||
const AccountsState = "accounts"
|
||||
|
||||
// GrantsAccounts is that state as a reader names it in `reads` (`<owner>.<name>`).
|
||||
const GrantsAccounts = "mesh-grants." + AccountsState
|
||||
|
||||
// LedgersSecret is the tool runner's own secret holding its machine's ledger accounts, a map of module to credential
|
||||
// (ADR 0597 §9).
|
||||
const LedgersSecret = "ledgers"
|
||||
|
||||
// mintedKinds are the kinds of account the vault mints (ADR 0561 §1).
|
||||
var mintedKinds = []buscompose.Kind{buscompose.KindModule, buscompose.KindNodeTools, buscompose.KindProcess, buscompose.KindProvisioner, buscompose.KindLedger}
|
||||
|
||||
// safeSubject refuses a name that would change the meaning of a subject rather than sit inside one.
|
||||
var safeSubject = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
|
||||
|
||||
// ClaimedSeat is one seat a module claims, as its runtime needs it (the controller's seatClaimed): the name, the scope (a
|
||||
// node-scoped seat's verb carries the machine) and the verbs the runtime serves for it.
|
||||
type ClaimedSeat struct {
|
||||
Seat string `json:"seat"`
|
||||
Scope string `json:"scope"`
|
||||
Serves []string `json:"serves,omitempty"`
|
||||
}
|
||||
|
||||
// WantedAccount is one key of the grants part's state `accounts`: an account the mesh needs, without its password.
|
||||
type WantedAccount struct {
|
||||
User string `json:"user"`
|
||||
// Kind is buscompose.KindModule (buscompose.KindNodeTools for the runtime, named as a module is), buscompose.KindProcess, buscompose.KindProvisioner or
|
||||
// buscompose.KindLedger.
|
||||
Kind buscompose.Kind `json:"kind"`
|
||||
Node string `json:"node"`
|
||||
Module string `json:"module"`
|
||||
// Process is a buscompose.KindProcess account's process id.
|
||||
Process string `json:"process,omitempty"`
|
||||
// URL is the bus's address as that node reaches it, `nats://<host>:<port>`; Fingerprint the bus certificate's.
|
||||
URL string `json:"url"`
|
||||
Fingerprint string `json:"fingerprint,omitempty"`
|
||||
// Claims are a module's claims with the verbs each seat promises: none for a process or a provisioner client.
|
||||
Claims []ClaimedSeat `json:"claims,omitempty"`
|
||||
// At is when the grants part wrote the key: not compared (Same).
|
||||
At time.Time `json:"at"`
|
||||
}
|
||||
|
||||
// principal is the account as the composer names it.
|
||||
func (w WantedAccount) principal() buscompose.Principal {
|
||||
return buscompose.Principal{Kind: w.Kind, Node: w.Node, Module: w.Module, Process: w.Process}
|
||||
}
|
||||
|
||||
// Valid says why w is not an account the vault may mint, or nil: a kind it mints, every name a subject token, the user
|
||||
// the one the composer derives from them, and an address to reach the bus at.
|
||||
func (w WantedAccount) Valid() error {
|
||||
if !slices.Contains(mintedKinds, w.Kind) {
|
||||
return fmt.Errorf("%s is a %s account, which the vault never mints (ADR 0561 §4)", w.User, w.Kind)
|
||||
}
|
||||
for what, v := range map[string]string{"node": w.Node, "module": w.Module} {
|
||||
if !safeSubject.MatchString(v) {
|
||||
return fmt.Errorf("%s: the %s %q is not a name the mesh writes", w.User, what, v)
|
||||
}
|
||||
}
|
||||
if w.Kind == buscompose.KindProcess && !safeSubject.MatchString(w.Process) {
|
||||
return fmt.Errorf("%s: the process %q is not a name the mesh writes", w.User, w.Process)
|
||||
}
|
||||
if w.Kind != buscompose.KindProcess && w.Process != "" {
|
||||
return fmt.Errorf("%s: only a process's account names a process", w.User)
|
||||
}
|
||||
if want := w.principal().Username(); w.User != want {
|
||||
return fmt.Errorf("%s is not the user of a %s account of %s on %s (that is %s)", w.User, w.Kind, w.Module, w.Node, want)
|
||||
}
|
||||
if !strings.HasPrefix(w.URL, "nats://") || len(w.URL) == len("nats://") {
|
||||
return fmt.Errorf("%s names no bus address (url, nats://<host>:<port>)", w.User)
|
||||
}
|
||||
if len(w.Claims) > 0 && w.Kind != buscompose.KindModule && w.Kind != buscompose.KindNodeTools {
|
||||
return fmt.Errorf("%s: a %s account holds no seat, so it carries no claims", w.User, w.Kind)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Same says whether two wanted accounts want the same account: every field but when it was written.
|
||||
func (w WantedAccount) Same(o WantedAccount) bool {
|
||||
a, b := w, o
|
||||
a.At, b.At = time.Time{}, time.Time{}
|
||||
ra, _ := json.Marshal(a)
|
||||
rb, _ := json.Marshal(b)
|
||||
return string(ra) == string(rb)
|
||||
}
|
||||
|
||||
// OwnSecret is the module's own secret the account is held in: `broker`, `broker-<process id>` or `provisioner-broker`
|
||||
// (the controller's names, ADR 0436 §2, ADR 0349 §11); a ledger account in the tool runner's `ledgers`, which keeps every
|
||||
// ledger account of its machine, by module (ADR 0597 §9).
|
||||
func (w WantedAccount) OwnSecret() string {
|
||||
switch w.Kind {
|
||||
case buscompose.KindLedger:
|
||||
return LedgersSecret
|
||||
case buscompose.KindProcess:
|
||||
return "broker-" + w.Process
|
||||
case buscompose.KindProvisioner:
|
||||
return "provisioner-broker"
|
||||
}
|
||||
return "broker"
|
||||
}
|
||||
|
||||
// ReadWantedAccount reads the key user of the state: refused when it is not a valid wanted account of that user.
|
||||
func ReadWantedAccount(user string, raw []byte) (WantedAccount, error) {
|
||||
var w WantedAccount
|
||||
if err := json.Unmarshal(raw, &w); err != nil {
|
||||
return WantedAccount{}, fmt.Errorf("%s %s is not a wanted account: %w", GrantsAccounts, user, err)
|
||||
}
|
||||
if w.User != user {
|
||||
return WantedAccount{}, fmt.Errorf("%s %s names the user %q", GrantsAccounts, user, w.User)
|
||||
}
|
||||
return w, w.Valid()
|
||||
}
|
||||
|
||||
// HeldCredential is the value the account's holder reads, exactly as the controller builds it today (issueWith,
|
||||
// sealProcess and sealProvisionerClient): a module's `{url, fingerprint, node, module, user, password, claims}`, a
|
||||
// process's without claims, a provisioner client's without module or claims; an empty fingerprint or claims left out.
|
||||
func HeldCredential(w WantedAccount, password string) ([]byte, error) {
|
||||
if err := w.Valid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if password == "" {
|
||||
return nil, fmt.Errorf("%s: an account is held with its password", w.User)
|
||||
}
|
||||
switch w.Kind {
|
||||
case buscompose.KindProcess:
|
||||
return json.Marshal(struct {
|
||||
URL string `json:"url"`
|
||||
Fingerprint string `json:"fingerprint,omitempty"`
|
||||
Node string `json:"node"`
|
||||
Module string `json:"module"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
}{URL: w.URL, Fingerprint: w.Fingerprint, Node: w.Node, Module: w.Module, User: w.User, Password: password})
|
||||
case buscompose.KindProvisioner:
|
||||
return json.Marshal(struct {
|
||||
URL string `json:"url"`
|
||||
Fingerprint string `json:"fingerprint,omitempty"`
|
||||
Node string `json:"node"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
}{URL: w.URL, Fingerprint: w.Fingerprint, Node: w.Node, User: w.User, Password: password})
|
||||
}
|
||||
return json.Marshal(struct {
|
||||
URL string `json:"url"`
|
||||
Fingerprint string `json:"fingerprint,omitempty"`
|
||||
Node string `json:"node"`
|
||||
Module string `json:"module"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
Claims []ClaimedSeat `json:"claims,omitempty"`
|
||||
}{URL: w.URL, Fingerprint: w.Fingerprint, Node: w.Node, Module: w.Module, User: w.User, Password: password,
|
||||
Claims: w.Claims})
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package grantsstate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/buscompose"
|
||||
)
|
||||
|
||||
// The wanted account is the grants part's state layout: a state `accounts` read as mesh-grants.accounts, each key the
|
||||
// bus user, valid only when the user is the one the composer derives, held in the module's own secret (a ledger's in the
|
||||
// tool runner's `ledgers`), and given to its holder in the shape the controller's credential had.
|
||||
func TestAWantedAccountIsTheStatesLayout(t *testing.T) {
|
||||
if AccountsState != "accounts" || GrantsAccounts != "mesh-grants.accounts" || LedgersSecret != "ledgers" {
|
||||
t.Errorf("the state is %q read as %q, the ledgers' secret %q", AccountsState, GrantsAccounts, LedgersSecret)
|
||||
}
|
||||
url := "nats://10.0.0.1:4222"
|
||||
for name, c := range map[string]struct {
|
||||
w WantedAccount
|
||||
secret string
|
||||
bad string
|
||||
}{
|
||||
"module": {WantedAccount{User: "a.m", Kind: buscompose.KindModule, Node: "a", Module: "m", URL: url}, "broker", ""},
|
||||
"ledger": {WantedAccount{User: "ledger.a.m", Kind: buscompose.KindLedger, Node: "a", Module: "m", URL: url}, LedgersSecret, ""},
|
||||
"process": {WantedAccount{User: "a.m.p", Kind: buscompose.KindProcess, Node: "a", Module: "m", Process: "p", URL: url}, "broker-p", ""},
|
||||
"provisioner": {WantedAccount{User: "provisioner.a", Kind: buscompose.KindProvisioner, Node: "a", Module: "m", URL: url}, "provisioner-broker", ""},
|
||||
"other user": {WantedAccount{User: "x.m", Kind: buscompose.KindModule, Node: "a", Module: "m", URL: url}, "", "is not the user"},
|
||||
"a node": {WantedAccount{User: "node.a", Kind: buscompose.KindNode, Node: "a", Module: "m", URL: url}, "", "never mints"},
|
||||
"no address": {WantedAccount{User: "a.m", Kind: buscompose.KindModule, Node: "a", Module: "m"}, "", "no bus address"},
|
||||
} {
|
||||
err := c.w.Valid()
|
||||
if c.bad == "" {
|
||||
if err != nil || c.w.OwnSecret() != c.secret {
|
||||
t.Errorf("%s: %v, held in %q, want %q", name, err, c.w.OwnSecret(), c.secret)
|
||||
}
|
||||
raw, _ := json.Marshal(c.w)
|
||||
if back, err := ReadWantedAccount(c.w.User, raw); err != nil || !back.Same(c.w) {
|
||||
t.Errorf("%s: read back %+v, %v", name, back, err)
|
||||
}
|
||||
if _, err := ReadWantedAccount("someone.else", raw); err == nil {
|
||||
t.Errorf("%s: a key of another user was read", name)
|
||||
}
|
||||
if held, err := HeldCredential(c.w, "pw"); err != nil || !strings.Contains(string(held), `"password":"pw"`) {
|
||||
t.Errorf("%s: held %s, %v", name, held, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err == nil || !strings.Contains(err.Error(), c.bad) {
|
||||
t.Errorf("%s: %v, want a refusal saying %q", name, err, c.bad)
|
||||
}
|
||||
}
|
||||
if _, err := HeldCredential(WantedAccount{User: "a.m", Kind: buscompose.KindModule, Node: "a", Module: "m", URL: url}, ""); err == nil {
|
||||
t.Error("an account was held with no password")
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
package buscompose
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-grants/grantsstate"
|
||||
)
|
||||
|
||||
// **The accounts the grants part wants, and the one shape a held account takes** (novox/hq ADR 0561 §1, §2; issue 774).
|
||||
@@ -21,11 +19,23 @@ import (
|
||||
// The node accounts, the controller's own, an enrolment user and a person are never wanted here: the vault mints none
|
||||
// of them (ADR 0561 §4, §5).
|
||||
|
||||
// AccountsState is the grants part's state of wanted accounts, by bus user.
|
||||
const AccountsState = "accounts"
|
||||
// The layout of the state is the grants part's published package (grantsstate; ADR 0634 §1): the vault imports it from there, and
|
||||
// this composer names it.
|
||||
const (
|
||||
AccountsState = grantsstate.AccountsState
|
||||
GrantsAccounts = grantsstate.GrantsAccounts
|
||||
LedgersSecret = grantsstate.LedgersSecret
|
||||
)
|
||||
|
||||
// GrantsAccounts is that state as a reader names it (`<owner>.<name>`).
|
||||
const GrantsAccounts = GrantsModule + "." + AccountsState
|
||||
type (
|
||||
ClaimedSeat = grantsstate.ClaimedSeat
|
||||
WantedAccount = grantsstate.WantedAccount
|
||||
)
|
||||
|
||||
var (
|
||||
ReadWantedAccount = grantsstate.ReadWantedAccount
|
||||
HeldCredential = grantsstate.HeldCredential
|
||||
)
|
||||
|
||||
// AccountsBucket is the bucket the state lives in.
|
||||
var AccountsBucket = BucketName(GrantsModule, AccountsState)
|
||||
@@ -39,110 +49,6 @@ const AccountIssuedEvent = "account-issued"
|
||||
// AccountIssuedSubject is where it says it, as the runtime addresses mesh-vault's events.
|
||||
const AccountIssuedSubject = "mesh.mod." + VaultSeat + ".event." + AccountIssuedEvent
|
||||
|
||||
// ClaimedSeat is one seat a module claims, as its runtime needs it (the controller's seatClaimed): the name, the scope (a
|
||||
// node-scoped seat's verb carries the machine) and the verbs the runtime serves for it.
|
||||
type ClaimedSeat struct {
|
||||
Seat string `json:"seat"`
|
||||
Scope string `json:"scope"`
|
||||
Serves []string `json:"serves,omitempty"`
|
||||
}
|
||||
|
||||
// WantedAccount is one key of the grants part's state `accounts`: an account the mesh needs, without its password.
|
||||
type WantedAccount struct {
|
||||
User string `json:"user"`
|
||||
// Kind is KindModule (KindNodeTools for the runtime, named as a module is), KindProcess, KindProvisioner or
|
||||
// KindLedger.
|
||||
Kind Kind `json:"kind"`
|
||||
Node string `json:"node"`
|
||||
Module string `json:"module"`
|
||||
// Process is a KindProcess account's process id.
|
||||
Process string `json:"process,omitempty"`
|
||||
// URL is the bus's address as that node reaches it, `nats://<host>:<port>`; Fingerprint the bus certificate's.
|
||||
URL string `json:"url"`
|
||||
Fingerprint string `json:"fingerprint,omitempty"`
|
||||
// Claims are a module's claims with the verbs each seat promises: none for a process or a provisioner client.
|
||||
Claims []ClaimedSeat `json:"claims,omitempty"`
|
||||
// At is when the grants part wrote the key: not compared (Same).
|
||||
At time.Time `json:"at"`
|
||||
}
|
||||
|
||||
// LedgersSecret is the tool runner's own secret holding its machine's ledger accounts, a map of module to credential
|
||||
// (ADR 0597 §9).
|
||||
const LedgersSecret = "ledgers"
|
||||
|
||||
// mintedKinds are the kinds of account the vault mints (ADR 0561 §1).
|
||||
var mintedKinds = []Kind{KindModule, KindNodeTools, KindProcess, KindProvisioner, KindLedger}
|
||||
|
||||
// principal is the account as the composer names it.
|
||||
func (w WantedAccount) principal() Principal {
|
||||
return Principal{Kind: w.Kind, Node: w.Node, Module: w.Module, Process: w.Process}
|
||||
}
|
||||
|
||||
// Valid says why w is not an account the vault may mint, or nil: a kind it mints, every name a subject token, the user
|
||||
// the one the composer derives from them, and an address to reach the bus at.
|
||||
func (w WantedAccount) Valid() error {
|
||||
if !slices.Contains(mintedKinds, w.Kind) {
|
||||
return fmt.Errorf("%s is a %s account, which the vault never mints (ADR 0561 §4)", w.User, w.Kind)
|
||||
}
|
||||
for what, v := range map[string]string{"node": w.Node, "module": w.Module} {
|
||||
if !safeSubject.MatchString(v) {
|
||||
return fmt.Errorf("%s: the %s %q is not a name the mesh writes", w.User, what, v)
|
||||
}
|
||||
}
|
||||
if w.Kind == KindProcess && !safeSubject.MatchString(w.Process) {
|
||||
return fmt.Errorf("%s: the process %q is not a name the mesh writes", w.User, w.Process)
|
||||
}
|
||||
if w.Kind != KindProcess && w.Process != "" {
|
||||
return fmt.Errorf("%s: only a process's account names a process", w.User)
|
||||
}
|
||||
if want := w.principal().Username(); w.User != want {
|
||||
return fmt.Errorf("%s is not the user of a %s account of %s on %s (that is %s)", w.User, w.Kind, w.Module, w.Node, want)
|
||||
}
|
||||
if !strings.HasPrefix(w.URL, "nats://") || len(w.URL) == len("nats://") {
|
||||
return fmt.Errorf("%s names no bus address (url, nats://<host>:<port>)", w.User)
|
||||
}
|
||||
if len(w.Claims) > 0 && w.Kind != KindModule && w.Kind != KindNodeTools {
|
||||
return fmt.Errorf("%s: a %s account holds no seat, so it carries no claims", w.User, w.Kind)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Same says whether two wanted accounts want the same account: every field but when it was written.
|
||||
func (w WantedAccount) Same(o WantedAccount) bool {
|
||||
a, b := w, o
|
||||
a.At, b.At = time.Time{}, time.Time{}
|
||||
ra, _ := json.Marshal(a)
|
||||
rb, _ := json.Marshal(b)
|
||||
return string(ra) == string(rb)
|
||||
}
|
||||
|
||||
// OwnSecret is the module's own secret the account is held in: `broker`, `broker-<process id>` or `provisioner-broker`
|
||||
// (the controller's names, ADR 0436 §2, ADR 0349 §11); a ledger account in the tool runner's `ledgers`, which keeps every
|
||||
// ledger account of its machine, by module (ADR 0597 §9).
|
||||
func (w WantedAccount) OwnSecret() string {
|
||||
switch w.Kind {
|
||||
case KindLedger:
|
||||
return LedgersSecret
|
||||
case KindProcess:
|
||||
return "broker-" + w.Process
|
||||
case KindProvisioner:
|
||||
return "provisioner-broker"
|
||||
}
|
||||
return "broker"
|
||||
}
|
||||
|
||||
// ReadWantedAccount reads the key user of the state: refused when it is not a valid wanted account of that user.
|
||||
func ReadWantedAccount(user string, raw []byte) (WantedAccount, error) {
|
||||
var w WantedAccount
|
||||
if err := json.Unmarshal(raw, &w); err != nil {
|
||||
return WantedAccount{}, fmt.Errorf("%s %s is not a wanted account: %w", GrantsAccounts, user, err)
|
||||
}
|
||||
if w.User != user {
|
||||
return WantedAccount{}, fmt.Errorf("%s %s names the user %q", GrantsAccounts, user, w.User)
|
||||
}
|
||||
return w, w.Valid()
|
||||
}
|
||||
|
||||
// AccountIssued is the vault's account-issued: which account it minted, and its generation. Never a value or a hash.
|
||||
type AccountIssued struct {
|
||||
User string `json:"user"`
|
||||
@@ -153,44 +59,3 @@ type AccountIssued struct {
|
||||
Generation int `json:"generation"`
|
||||
At time.Time `json:"at"`
|
||||
}
|
||||
|
||||
// HeldCredential is the value the account's holder reads, exactly as the controller builds it today (issueWith,
|
||||
// sealProcess and sealProvisionerClient): a module's `{url, fingerprint, node, module, user, password, claims}`, a
|
||||
// process's without claims, a provisioner client's without module or claims; an empty fingerprint or claims left out.
|
||||
func HeldCredential(w WantedAccount, password string) ([]byte, error) {
|
||||
if err := w.Valid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if password == "" {
|
||||
return nil, fmt.Errorf("%s: an account is held with its password", w.User)
|
||||
}
|
||||
switch w.Kind {
|
||||
case KindProcess:
|
||||
return json.Marshal(struct {
|
||||
URL string `json:"url"`
|
||||
Fingerprint string `json:"fingerprint,omitempty"`
|
||||
Node string `json:"node"`
|
||||
Module string `json:"module"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
}{URL: w.URL, Fingerprint: w.Fingerprint, Node: w.Node, Module: w.Module, User: w.User, Password: password})
|
||||
case KindProvisioner:
|
||||
return json.Marshal(struct {
|
||||
URL string `json:"url"`
|
||||
Fingerprint string `json:"fingerprint,omitempty"`
|
||||
Node string `json:"node"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
}{URL: w.URL, Fingerprint: w.Fingerprint, Node: w.Node, User: w.User, Password: password})
|
||||
}
|
||||
return json.Marshal(struct {
|
||||
URL string `json:"url"`
|
||||
Fingerprint string `json:"fingerprint,omitempty"`
|
||||
Node string `json:"node"`
|
||||
Module string `json:"module"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
Claims []ClaimedSeat `json:"claims,omitempty"`
|
||||
}{URL: w.URL, Fingerprint: w.Fingerprint, Node: w.Node, Module: w.Module, User: w.User, Password: password,
|
||||
Claims: w.Claims})
|
||||
}
|
||||
|
||||
@@ -15,49 +15,51 @@ package buscompose
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.novox.be/novox/mesh-contracts/go/seats/meshbroker"
|
||||
"git.novox.be/novox/mesh-contracts/identity-and-access/go/seats/meshnodeenroller"
|
||||
"regexp"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/go/seats/meshbroker"
|
||||
"git.novox.be/novox/mesh-contracts/identity-and-access/go/seats/meshnodeenroller"
|
||||
|
||||
mv "git.novox.be/novox/mesh-contracts/identity-and-access/go/seats/meshvault"
|
||||
sdkbc "git.novox.be/novox/mesh-sdk/go/buscompose"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
)
|
||||
|
||||
// A Kind is what a principal is, which decides the shape of its authority rather than its
|
||||
// contents: a module's comes from its declaration, a host's from its node, and the controller's
|
||||
// and the enrolment user's are fixed.
|
||||
type Kind string
|
||||
type Kind = sdkbc.Kind
|
||||
|
||||
const (
|
||||
KindModule Kind = "module"
|
||||
KindNode Kind = "node"
|
||||
KindEnrolment Kind = "enrolment"
|
||||
KindModule = sdkbc.KindModule
|
||||
KindNode = sdkbc.KindNode
|
||||
KindEnrolment = sdkbc.KindEnrolment
|
||||
// KindPerson is somebody reaching the mesh's tools from a workstation (design 25 §7). Its
|
||||
// authority is a list of tools and nothing else — not control, not declarations, not builds,
|
||||
// and no ability to answer anything, because a person asks.
|
||||
KindPerson Kind = "person"
|
||||
KindPerson = sdkbc.KindPerson
|
||||
// KindNodeTools is a machine's tool runtime (novox/hq ADR 0175, to-be 38): one process per
|
||||
// node, on the host side, serving every assigned module's tools and every held seat's verbs.
|
||||
// Its authority is the union of what the modules it carries would each have had for their
|
||||
// tools — and nothing of what they consume, because tools are what it runs, not reactions.
|
||||
KindNodeTools Kind = "node-tools"
|
||||
KindNodeTools = sdkbc.KindNodeTools
|
||||
// KindProvisioner is a machine's provisioner client (novox/hq ADR 0349 clauses 6 and 11, design 57 P3): a
|
||||
// service of the module holding NodeProvisionerSeat, outside the tool runner, under an account of its own so
|
||||
// the vault can tell it from an agent. Its authority is provisionerGrants and nothing else.
|
||||
KindProvisioner Kind = "provisioner"
|
||||
KindProvisioner = sdkbc.KindProvisioner
|
||||
// KindProcess is one process of a module that declares bus (novox/hq ADR 0436 §1, §2): a service of that
|
||||
// module, outside the tool runner and outside the module's own account, under a bus account scoped to
|
||||
// exactly what its bus says — never root, never the operator account, and never able to answer a tool
|
||||
// call or a seat's verb (§3). One per process and machine.
|
||||
KindProcess Kind = "process"
|
||||
KindProcess = sdkbc.KindProcess
|
||||
// KindLedger is one module assignment's ledger credential (novox/hq ADR 0597 §9, design 25 § 12.4): held by that
|
||||
// machine's tool runner, never by the module's own code, and the only account that publishes on that module's ledger
|
||||
// histories and snapshots. One per module assignment, whose module asks for a ledger in `requires`.
|
||||
KindLedger Kind = "ledger"
|
||||
KindLedger = sdkbc.KindLedger
|
||||
)
|
||||
|
||||
// The node's tool runner (novox/hq ADR 0175) is the module whose manifest says it is (`tool-runner`, Declared.ToolRunner;
|
||||
|
||||
Reference in New Issue
Block a user