Merge pull request 'The vault mints ledger accounts and keeps a machine's in node-tools' own secret ledgers (issue 1966, B1)' (#602) from feat/bus-state into main
This commit was merged in pull request #602.
This commit is contained in:
@@ -224,6 +224,9 @@ const ProcessSecretPrefix = "broker-"
|
|||||||
// `broker-<process id>`. The vault cannot tell core or moved from a module's manifest; the controller, which can, is the
|
// `broker-<process id>`. The vault cannot tell core or moved from a module's manifest; the controller, which can, is the
|
||||||
// only caller that may hand one in, and the name keeps what it hands to these.
|
// only caller that may hand one in, and the name keeps what it hands to these.
|
||||||
func Covered(secret string) bool {
|
func Covered(secret string) bool {
|
||||||
|
if _, _, ok := ledgerAccountOf(secret); ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
parts := strings.Split(secret, "/")
|
parts := strings.Split(secret, "/")
|
||||||
if len(parts) != 4 || parts[0] != "own" {
|
if len(parts) != 4 || parts[0] != "own" {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// The ledger accounts of a machine and the tool runner's own secret `ledgers` (novox/hq ADR 0597 §9, design 25 § 12.4,
|
||||||
|
// issue 1966 V1 and V2). Nothing here is the custody ledger of ledger.go (ADR 0085): this file is about the bus account
|
||||||
|
// of kind ledger, one per module assignment that asks for a ledger.
|
||||||
|
//
|
||||||
|
// The tool runner of a machine holds its machine's ledger accounts together as its own secret `ledgers`
|
||||||
|
// (`own/<node>/node-tools/ledgers`): a JSON map of module to credential, `{}` when there is none, so its composition
|
||||||
|
// never refuses a secret the vault did not make. The vault makes it as `{}` for every machine whose tool runner is
|
||||||
|
// wanted, and rewrites it on each ledger account minted or retired, saying `secret-changed` once per rewrite.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.novox.be/novox/mesh-sdk/go/buscompose"
|
||||||
|
)
|
||||||
|
|
||||||
|
// toolRunnerModule is the module whose own secret `ledgers` is: the tool runner (mesh-tools node-tools).
|
||||||
|
const toolRunnerModule = "node-tools"
|
||||||
|
|
||||||
|
// ledgersSecret is the vault's name of node's `ledgers`.
|
||||||
|
func ledgersSecret(node string) (string, error) {
|
||||||
|
return OwnSecret(node, toolRunnerModule, buscompose.LedgersSecret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// toolRunnerNodes are the machines whose tool runner is wanted, sorted.
|
||||||
|
func (v *Vault) toolRunnerNodes() []string {
|
||||||
|
v.minting.mu.Lock()
|
||||||
|
defer v.minting.mu.Unlock()
|
||||||
|
var out []string
|
||||||
|
for _, w := range v.minting.wants {
|
||||||
|
if w.Kind == buscompose.KindNodeTools {
|
||||||
|
out = append(out, w.Node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// LedgersPass makes `ledgers` as `{}` on every machine whose tool runner is wanted and for which the vault holds none,
|
||||||
|
// at the vault's minute pass (and when the tool runner's want is heard).
|
||||||
|
func (v *Vault) LedgersPass() {
|
||||||
|
for _, node := range v.toolRunnerNodes() {
|
||||||
|
v.ensureLedgers(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensureLedgers keeps node's `ledgers` as `{}` when the vault holds none: a held one is never touched here.
|
||||||
|
func (v *Vault) ensureLedgers(node string) {
|
||||||
|
secret, err := ledgersSecret(node)
|
||||||
|
if err != nil {
|
||||||
|
v.log("%s's ledgers are not made: %v", node, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, held, err := v.Store.Read(secret)
|
||||||
|
if err != nil || held {
|
||||||
|
if err != nil {
|
||||||
|
v.log("%s is not read, so its ledgers are not made: %v", secret, err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
empty, _ := json.Marshal(map[string]json.RawMessage{})
|
||||||
|
if _, err := v.keepLocked(secret, string(empty), "the vault", "", OriginMade, keepOptions{neverReplace: true}); err != nil {
|
||||||
|
v.log("%s is not made, tried again at the next pass: %v", secret, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v.log("made %s as {}: no ledger account is held for its machine yet", secret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ledgerAccountPrefix starts the name a ledger account is kept under: `ledger/<machine>/<module>`. It is the account's
|
||||||
|
// own record, never an own secret (so `own` hands no module its ledger account); the machine's `ledgers` is made of them.
|
||||||
|
const ledgerAccountPrefix = "ledger/"
|
||||||
|
|
||||||
|
// LedgerAccountSecret is the vault's name of the credential of the ledger account of module on node.
|
||||||
|
func LedgerAccountSecret(node, module string) (string, error) {
|
||||||
|
for what, v := range map[string]string{"the machine": node, "the module": module} {
|
||||||
|
if !namePart.MatchString(v) {
|
||||||
|
return "", fmt.Errorf("%s %q is not a name the mesh writes", what, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ledgerAccountPrefix + node + "/" + module, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ledgerAccountOf says secret is a ledger account's name, with its machine and module.
|
||||||
|
func ledgerAccountOf(secret string) (node, module string, ok bool) {
|
||||||
|
parts := strings.Split(secret, "/")
|
||||||
|
if len(parts) != 3 || parts[0] != "ledger" || !namePart.MatchString(parts[1]) || !namePart.MatchString(parts[2]) {
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
return parts[1], parts[2], true
|
||||||
|
}
|
||||||
|
|
||||||
|
// rewriteLedgers makes node's `ledgers` of the ledger accounts that stand: held, not retired, and wanted (once the wanted
|
||||||
|
// accounts are read whole; before that every one held stands, so a start never drops what it has not heard yet). It
|
||||||
|
// says `secret-changed` only when the map changed.
|
||||||
|
func (v *Vault) rewriteLedgers(node string) {
|
||||||
|
v.minting.ledgersMu.Lock()
|
||||||
|
defer v.minting.ledgersMu.Unlock()
|
||||||
|
secret, err := ledgersSecret(node)
|
||||||
|
if err != nil {
|
||||||
|
v.log("%s's ledgers are not rewritten: %v", node, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
records, err := v.Store.ListPrefix(ledgerAccountPrefix + node + "/")
|
||||||
|
if err != nil {
|
||||||
|
v.log("%s is not rewritten, the ledger accounts of %s could not be read: %v", secret, node, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v.minting.mu.Lock()
|
||||||
|
read := v.minting.retiring.wantsRead
|
||||||
|
v.minting.mu.Unlock()
|
||||||
|
standing := map[string]json.RawMessage{}
|
||||||
|
for _, r := range records {
|
||||||
|
_, module, ok := ledgerAccountOf(r.Name)
|
||||||
|
if !ok || r.Retired != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, wanted := v.wanted("ledger." + node + "." + module); read && !wanted {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
value, err := openAtRest(r, v)
|
||||||
|
if err != nil || !BusAccountValue(r.Name, value) {
|
||||||
|
v.log("%s is not an account the vault can open, so it is left out of %s", r.Name, secret)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
standing[module] = json.RawMessage(value)
|
||||||
|
}
|
||||||
|
raw, err := json.Marshal(standing)
|
||||||
|
if err != nil {
|
||||||
|
v.log("%s is not rewritten: %v", secret, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err := v.keepLocked(secret, string(raw), "the vault", "", OriginMade, keepOptions{}); err != nil {
|
||||||
|
v.log("%s is NOT REWRITTEN (%d ledger accounts stand): %v", secret, len(standing), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.novox.be/novox/mesh-sdk/go/buscompose"
|
||||||
|
"git.novox.be/novox/mesh-sdk/go/seal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Ledger accounts and the tool runner's own secret `ledgers` (novox/hq ADR 0597 §9, issue 1966). Not the custody
|
||||||
|
// ledger of ledger.go (ADR 0085), which is another thing.
|
||||||
|
|
||||||
|
// nodeToolsWant is the wanted account of a machine's tool runner, as the grants part writes it.
|
||||||
|
func nodeToolsWant(node string) buscompose.WantedAccount {
|
||||||
|
w := aWant("node-tools")
|
||||||
|
w.Kind, w.Node, w.User = buscompose.KindNodeTools, node, node+".node-tools"
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
// ledgerWant is the wanted ledger account of a module on a machine.
|
||||||
|
func ledgerWant(node, module string) buscompose.WantedAccount {
|
||||||
|
w := aWant(module)
|
||||||
|
w.Kind, w.Node, w.User, w.Claims = buscompose.KindLedger, node, "ledger."+node+"."+module, nil
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
// ledgersOf is what the vault's `own` answers the machine as node-tools' `ledgers`: the map of module to credential,
|
||||||
|
// and whether the secret is there at all.
|
||||||
|
func ledgersOf(t *testing.T, v testVault, priv string) (map[string]json.RawMessage, bool) {
|
||||||
|
t.Helper()
|
||||||
|
own, err := v.OwnOfNode("node.ace")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, o := range own.Own {
|
||||||
|
if o.Module == "node-tools" && o.Name == buscompose.LedgersSecret {
|
||||||
|
value, err := seal.Open(o.Sealed, priv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
got := map[string]json.RawMessage{}
|
||||||
|
if err := json.Unmarshal([]byte(value), &got); err != nil {
|
||||||
|
t.Fatalf("ledgers is not a JSON map: %v", err)
|
||||||
|
}
|
||||||
|
return got, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// changesOf counts the secret-changed events said for name since the first of events.
|
||||||
|
func changesOf(v testVault, since int, name string) int {
|
||||||
|
n := 0
|
||||||
|
for _, e := range v.bus.events[since:] {
|
||||||
|
if body, _ := e["body"].(map[string]any); e["event"] == ChangedEvent && body["name"] == name {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// redacted says a credential's shape without its password, for a failure message.
|
||||||
|
func redacted(raw json.RawMessage) string {
|
||||||
|
var c map[string]any
|
||||||
|
if json.Unmarshal(raw, &c) != nil {
|
||||||
|
return "not JSON"
|
||||||
|
}
|
||||||
|
delete(c, "password")
|
||||||
|
out, _ := json.Marshal(c)
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
@@ -350,6 +350,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
env.Vault.HashOwed()
|
env.Vault.HashOwed()
|
||||||
env.Vault.MintOwed()
|
env.Vault.MintOwed()
|
||||||
|
env.Vault.LedgersPass()
|
||||||
env.Vault.RetirePass()
|
env.Vault.RetirePass()
|
||||||
env.Vault.RotationPass()
|
env.Vault.RotationPass()
|
||||||
env.Vault.LoginsPass()
|
env.Vault.LoginsPass()
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ type minting struct {
|
|||||||
retiring retiring
|
retiring retiring
|
||||||
// mintMu keeps one mint at a time: a want heard, the switch turning on, and issue-account.
|
// mintMu keeps one mint at a time: a want heard, the switch turning on, and issue-account.
|
||||||
mintMu sync.Mutex
|
mintMu sync.Mutex
|
||||||
|
// ledgersMu keeps one rewrite of a machine's `ledgers` at a time (ledgers.go).
|
||||||
|
ledgersMu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Minted is what one mint did: the account and its secret, never its value or its hash.
|
// Minted is what one mint did: the account and its secret, never its value or its hash.
|
||||||
@@ -169,7 +171,11 @@ func (v *Vault) busAccount(secret, value string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AccountSecret is the vault's name of the own secret a wanted account is held in.
|
// AccountSecret is the vault's name of the own secret a wanted account is held in.
|
||||||
|
// A ledger account is the exception: it is kept as LedgerAccountSecret, and its machine's `ledgers` is made of it.
|
||||||
func AccountSecret(w buscompose.WantedAccount) (string, error) {
|
func AccountSecret(w buscompose.WantedAccount) (string, error) {
|
||||||
|
if w.Kind == buscompose.KindLedger {
|
||||||
|
return LedgerAccountSecret(w.Node, w.Module)
|
||||||
|
}
|
||||||
return OwnSecret(w.Node, w.Module, w.OwnSecret())
|
return OwnSecret(w.Node, w.Module, w.OwnSecret())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,9 +199,16 @@ func (v *Vault) WantHeard(user string, raw []byte, deleted bool) {
|
|||||||
v.minting.wants[user] = w
|
v.minting.wants[user] = w
|
||||||
v.minting.mu.Unlock()
|
v.minting.mu.Unlock()
|
||||||
v.wantBack(user)
|
v.wantBack(user)
|
||||||
|
if w.Kind == buscompose.KindNodeTools {
|
||||||
|
v.ensureLedgers(w.Node)
|
||||||
|
}
|
||||||
if _, err := v.mintWanted(w, "the grants part's want of "+user); err != nil {
|
if _, err := v.mintWanted(w, "the grants part's want of "+user); err != nil {
|
||||||
v.log("%s is not minted: %v", user, err)
|
v.log("%s is not minted: %v", user, err)
|
||||||
}
|
}
|
||||||
|
if w.Kind == buscompose.KindLedger {
|
||||||
|
// Wanted again, or held already: the machine's ledgers say what is wanted now (nothing said when unchanged).
|
||||||
|
v.rewriteLedgers(w.Node)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// errHeldBack is a want the vault does not mint now, with why: not an error of the vault.
|
// errHeldBack is a want the vault does not mint now, with why: not an error of the vault.
|
||||||
@@ -303,7 +316,12 @@ func (v *Vault) mintOnce(w buscompose.WantedAccount, by string) (Minted, error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
v.announce(c)
|
if w.Kind == buscompose.KindLedger {
|
||||||
|
// A ledger account is no own secret of its module: its machine's `ledgers` is rewritten and says secret-changed.
|
||||||
|
v.rewriteLedgers(w.Node)
|
||||||
|
} else {
|
||||||
|
v.announce(c)
|
||||||
|
}
|
||||||
v.minting.mu.Lock()
|
v.minting.mu.Lock()
|
||||||
if v.minting.minted == nil {
|
if v.minting.minted == nil {
|
||||||
v.minting.minted = map[string]Minted{}
|
v.minting.minted = map[string]Minted{}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.novox.be/novox/mesh-sdk/go/buscompose"
|
"git.novox.be/novox/mesh-sdk/go/buscompose"
|
||||||
"git.novox.be/novox/mesh-sdk/go/seal"
|
"git.novox.be/novox/mesh-sdk/go/seal"
|
||||||
@@ -99,6 +100,109 @@ func TestTheVaultMintsAWantedAccountOnceAndNothingItHolds(t *testing.T) {
|
|||||||
if st := v.MintState(); len(st.HeldBack) != 0 || len(st.Minted) != 1 {
|
if st := v.MintState(); len(st.HeldBack) != 0 || len(st.Minted) != 1 {
|
||||||
t.Errorf("vault_status says %+v: an adopted user is not held back, one account minted", st)
|
t.Errorf("vault_status says %+v: an adopted user is not held back, one account minted", st)
|
||||||
}
|
}
|
||||||
|
t.Run("ledgers", func(t *testing.T) {
|
||||||
|
for _, c := range []struct {
|
||||||
|
name string
|
||||||
|
run func(t *testing.T, v testVault, accounts *fakeAccounts, priv string)
|
||||||
|
}{
|
||||||
|
// 1966/AC24 (issue 1966 V1): a machine carrying node-tools, with no ledger account, has `ledgers` as {}.
|
||||||
|
{"an empty ledgers on a machine with node-tools", func(t *testing.T, v testVault, accounts *fakeAccounts, priv string) {
|
||||||
|
if _, ok := ledgersOf(t, v, priv); ok {
|
||||||
|
t.Fatal("ledgers is there before node-tools is wanted")
|
||||||
|
}
|
||||||
|
w := nodeToolsWant("ace")
|
||||||
|
v.WantHeard(w.User, wantRaw(t, w), false)
|
||||||
|
before := len(v.bus.events)
|
||||||
|
v.LedgersPass()
|
||||||
|
got, ok := ledgersOf(t, v, priv)
|
||||||
|
if !ok || len(got) != 0 {
|
||||||
|
t.Fatalf("ledgers is %v (held %v), want {}", got, ok)
|
||||||
|
}
|
||||||
|
v.LedgersPass()
|
||||||
|
if n := changesOf(v, before, "own/ace/node-tools/ledgers"); n != 0 {
|
||||||
|
t.Errorf("a second pass said secret-changed %d times for a value that did not change", n)
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
// 1966/AC25 (issue 1966 V2): wanted ledger accounts for m and k on a machine are minted and hashed like every
|
||||||
|
// kind, kept together in the machine's `ledgers`, each mint said once as a change of `ledgers` and never of
|
||||||
|
// the account's own record.
|
||||||
|
{"ledger accounts minted into ledgers", func(t *testing.T, v testVault, accounts *fakeAccounts, priv string) {
|
||||||
|
tools := nodeToolsWant("ace")
|
||||||
|
v.WantHeard(tools.User, wantRaw(t, tools), false)
|
||||||
|
v.LedgersPass()
|
||||||
|
for i, module := range []string{"m", "k"} {
|
||||||
|
w := ledgerWant("ace", module)
|
||||||
|
before := len(v.bus.events)
|
||||||
|
v.WantHeard(w.User, wantRaw(t, w), false)
|
||||||
|
if n := changesOf(v, before, "own/ace/node-tools/ledgers"); n != 1 {
|
||||||
|
t.Errorf("minting %s said secret-changed %d times for ledgers, want once", module, n)
|
||||||
|
}
|
||||||
|
if n := eventsNamed(v, before, ChangedEvent); n != 1 {
|
||||||
|
t.Errorf("minting %s said %d secret-changed in all, want the one of ledgers", module, n)
|
||||||
|
}
|
||||||
|
got, _ := ledgersOf(t, v, priv)
|
||||||
|
if len(got) != i+1 {
|
||||||
|
t.Fatalf("after %s ledgers holds %d credentials, want %d", module, len(got), i+1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
got, _ := ledgersOf(t, v, priv)
|
||||||
|
for _, module := range []string{"m", "k"} {
|
||||||
|
var cred struct{ User, Password string }
|
||||||
|
if err := json.Unmarshal(got[module], &cred); err != nil || cred.User != "ledger.ace."+module || len(cred.Password) != 40 {
|
||||||
|
t.Fatalf("ledgers[%s] is %s (%v)", module, redacted(got[module]), err)
|
||||||
|
}
|
||||||
|
if !accounts.hashOf(cred.User, cred.Password, 1) {
|
||||||
|
t.Errorf("%s's hash is not in bus-accounts or not of the minted password", cred.User)
|
||||||
|
}
|
||||||
|
if _, held, _ := v.Store.Read("own/ace/" + module + "/ledgers"); held {
|
||||||
|
t.Errorf("the ledger account of %s is also kept as an own secret of its module", module)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
// 1966/AC26: m's wanted key deleted: m leaves ledgers at once, its hash is retired within ADR 0230's bounds,
|
||||||
|
// k stays; wanted again, m is back in ledgers.
|
||||||
|
{"a ledger account no longer wanted leaves ledgers", func(t *testing.T, v testVault, accounts *fakeAccounts, priv string) {
|
||||||
|
clock := time.Date(2026, 11, 3, 9, 0, 0, 0, time.UTC)
|
||||||
|
v.Now = func() time.Time { return clock }
|
||||||
|
for _, w := range []buscompose.WantedAccount{nodeToolsWant("ace"), ledgerWant("ace", "m"), ledgerWant("ace", "k")} {
|
||||||
|
v.WantHeard(w.User, wantRaw(t, w), false)
|
||||||
|
}
|
||||||
|
v.WantsRead()
|
||||||
|
before := len(v.bus.events)
|
||||||
|
v.WantHeard("ledger.ace.m", nil, true)
|
||||||
|
got, _ := ledgersOf(t, v, priv)
|
||||||
|
if _, in := got["m"]; in || len(got) != 1 {
|
||||||
|
t.Fatalf("after m's want went, ledgers holds %d credentials, m among them: %v", len(got), in)
|
||||||
|
}
|
||||||
|
if n := changesOf(v, before, "own/ace/node-tools/ledgers"); n != 1 {
|
||||||
|
t.Errorf("m's retirement said secret-changed %d times for ledgers, want once", n)
|
||||||
|
}
|
||||||
|
for i := 0; i < 6; i++ {
|
||||||
|
clock = clock.Add(3 * time.Minute)
|
||||||
|
v.RetirePass()
|
||||||
|
}
|
||||||
|
if _, ok := accounts.keys["ledger.ace.m"]; ok {
|
||||||
|
t.Errorf("m's hash is still in bus-accounts: %+v", v.RetireState())
|
||||||
|
}
|
||||||
|
if _, ok := accounts.keys["ledger.ace.k"]; !ok {
|
||||||
|
t.Error("k's hash was retired with m's")
|
||||||
|
}
|
||||||
|
if got, _ := ledgersOf(t, v, priv); len(got) != 1 {
|
||||||
|
t.Errorf("the retirement changed ledgers to %d credentials", len(got))
|
||||||
|
}
|
||||||
|
w := ledgerWant("ace", "m")
|
||||||
|
v.WantHeard(w.User, wantRaw(t, w), false)
|
||||||
|
if got, _ := ledgersOf(t, v, priv); len(got) != 2 || accounts.keys["ledger.ace.m"].Hash == "" {
|
||||||
|
t.Errorf("wanted again, m is not back in ledgers (%d) with its hash", len(got))
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
} {
|
||||||
|
t.Run(c.name, func(t *testing.T) {
|
||||||
|
v, accounts, priv := mintingVault(t)
|
||||||
|
c.run(t, v, accounts, priv)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 774/AC8, after research 072's gap "vault mints after the lease": the vault is the one issuer, so a wanted account is
|
// 774/AC8, after research 072's gap "vault mints after the lease": the vault is the one issuer, so a wanted account is
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.novox.be/novox/mesh-sdk/go/buscompose"
|
||||||
)
|
)
|
||||||
|
|
||||||
// retiring is what the passes keep of the accounts no longer wanted, under minting.mu.
|
// retiring is what the passes keep of the accounts no longer wanted, under minting.mu.
|
||||||
@@ -64,9 +66,14 @@ func (v *Vault) WantsRead() {
|
|||||||
// wantGone is a wanted account's key deleted: forgotten as wanted, its retirement left to the passes.
|
// wantGone is a wanted account's key deleted: forgotten as wanted, its retirement left to the passes.
|
||||||
func (v *Vault) wantGone(user string) {
|
func (v *Vault) wantGone(user string) {
|
||||||
v.minting.mu.Lock()
|
v.minting.mu.Lock()
|
||||||
defer v.minting.mu.Unlock()
|
gone, was := v.minting.wants[user]
|
||||||
delete(v.minting.wants, user)
|
delete(v.minting.wants, user)
|
||||||
delete(v.minting.heldBack, user)
|
delete(v.minting.heldBack, user)
|
||||||
|
v.minting.mu.Unlock()
|
||||||
|
if was && gone.Kind == buscompose.KindLedger {
|
||||||
|
// Its credential leaves the machine's ledgers at once; its hash is retired by the passes, as every kind's.
|
||||||
|
v.rewriteLedgers(gone.Node)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wantBack is a wanted account's key written: a retired account of it is re-enabled at once.
|
// wantBack is a wanted account's key written: a retired account of it is re-enabled at once.
|
||||||
@@ -221,6 +228,9 @@ func (v *Vault) retireOne(user, why, by string) error {
|
|||||||
v.minting.mu.Lock()
|
v.minting.mu.Lock()
|
||||||
v.minting.retiring.retired = append(v.minting.retiring.retired, user)
|
v.minting.retiring.retired = append(v.minting.retiring.retired, user)
|
||||||
v.minting.mu.Unlock()
|
v.minting.mu.Unlock()
|
||||||
|
if node, _, ok := ledgerAccountOf(a.Of); ok {
|
||||||
|
v.rewriteLedgers(node)
|
||||||
|
}
|
||||||
v.log("retired the bus account %s (%s): its hash is out of %s and its value kept, marked; %s", user, a.Of,
|
v.log("retired the bus account %s (%s): its hash is out of %s and its value kept, marked; %s", user, a.Of,
|
||||||
BusAccountsState, why)
|
BusAccountsState, why)
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module mesh-vault
|
|||||||
go 1.26.0
|
go 1.26.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261102191058-f02f142af128
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261103142843-f8bd12e4b7b1
|
||||||
github.com/nats-io/nats-server/v2 v2.11.17
|
github.com/nats-io/nats-server/v2 v2.11.17
|
||||||
github.com/nats-io/nats.go v1.54.0
|
github.com/nats-io/nats.go v1.54.0
|
||||||
golang.org/x/crypto v0.57.0
|
golang.org/x/crypto v0.57.0
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261102191058-f02f142af128 h1:aI1DhZAuqVBXbybSqhLNOGX5rUOrn9T0cHNCDUQF7IQ=
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261103142843-f8bd12e4b7b1 h1:T66tg9T/1hHg6KN/bDScHPT41IHkxLAGGO8VJiAOlb8=
|
||||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261102191058-f02f142af128/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261103142843-f8bd12e4b7b1/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
||||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
|
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
|
||||||
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
|
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
|
||||||
|
|||||||
Reference in New Issue
Block a user