diff --git a/go/buscompose/accounts.go b/go/buscompose/accounts.go index 924afc7..38c79a1 100644 --- a/go/buscompose/accounts.go +++ b/go/buscompose/accounts.go @@ -31,7 +31,8 @@ type ClaimedSeat struct { // 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 or KindProvisioner. + // 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"` @@ -46,8 +47,12 @@ type WantedAccount struct { 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} +var mintedKinds = []Kind{KindModule, KindNodeTools, KindProcess, KindProvisioner, KindLedger} // principal is the account as the composer names it. func (w WantedAccount) principal() Principal { @@ -93,9 +98,12 @@ func (w WantedAccount) Same(o WantedAccount) bool { } // OwnSecret is the module's own secret the account is held in: `broker`, `broker-` or `provisioner-broker` -// (the controller's names, ADR 0436 §2, ADR 0349 §11). +// (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: diff --git a/go/buscompose/names_test.go b/go/buscompose/names_test.go index dd76d2a..da93c34 100644 --- a/go/buscompose/names_test.go +++ b/go/buscompose/names_test.go @@ -18,4 +18,12 @@ func TestTheBusNamesAgree(t *testing.T) { if LogStreamName("mesh-delivery-builder", "build-log") == "" || LogSubject("mesh-delivery-builder", "build-log") == "" { t.Fatal("a log has no stream or subject") } + // 1966/AC23: a wanted account of kind ledger for m on a names the user ledger.a.m and the own secret ledgers. + ledger := WantedAccount{User: "ledger.a.m", Kind: KindLedger, Node: "a", Module: "m", URL: "nats://10.0.0.1:4222"} + if got := (Principal{Kind: KindLedger, Node: "a", Module: "m"}).Username(); got != "ledger.a.m" { + t.Fatalf("a ledger account is named %q", got) + } + if err := ledger.Valid(); err != nil || ledger.OwnSecret() != "ledgers" { + t.Fatalf("a wanted ledger account: %v, held in %q", err, ledger.OwnSecret()) + } } diff --git a/go/buscompose/nats.go b/go/buscompose/nats.go index 72cd670..c0f2618 100644 --- a/go/buscompose/nats.go +++ b/go/buscompose/nats.go @@ -44,6 +44,10 @@ const ( // 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" + // 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" ) // Seat is a role on the bus as a principal relates to it: the subjects it accepts, and those it @@ -272,6 +276,10 @@ func (p Principal) Username() string { return p.Login } return "node." + p.Node + case KindLedger: + // `ledger..`: never `.`, which is the module's own account or the tool runner's, + // so the module's code never holds it. + return "ledger." + p.Node + "." + p.Module case KindProvisioner: // Named for the machine, as a node is: one client per machine, whichever module runs it, and never // `.`, which is the module's own account or the tool runner's.