diff --git a/modules/mesh-vault/cmd/mesh-vault/ledgers.go b/modules/mesh-vault/cmd/mesh-vault/ledgers.go index 65067bff1..32c4c36b3 100644 --- a/modules/mesh-vault/cmd/mesh-vault/ledgers.go +++ b/modules/mesh-vault/cmd/mesh-vault/ledgers.go @@ -15,6 +15,8 @@ import ( "sort" "strings" + "git.novox.be/novox/mesh-delivery/modules/mesh-grants/grantsstate" + "git.novox.be/novox/mesh-sdk/go/buscompose" ) @@ -23,13 +25,13 @@ 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) + return OwnSecret(node, toolRunnerModule, grantsstate.LedgersSecret) } // isLedgersSecret says secret is a machine's `ledgers`: `own//node-tools/ledgers`. func isLedgersSecret(secret string) bool { parts := strings.Split(secret, "/") - return len(parts) == 4 && parts[0] == "own" && parts[2] == toolRunnerModule && parts[3] == buscompose.LedgersSecret + return len(parts) == 4 && parts[0] == "own" && parts[2] == toolRunnerModule && parts[3] == grantsstate.LedgersSecret } // toolRunnerNodes are the machines whose tool runner is wanted, sorted. diff --git a/modules/mesh-vault/cmd/mesh-vault/ledgers_test.go b/modules/mesh-vault/cmd/mesh-vault/ledgers_test.go index 3ded3b55a..116f53911 100644 --- a/modules/mesh-vault/cmd/mesh-vault/ledgers_test.go +++ b/modules/mesh-vault/cmd/mesh-vault/ledgers_test.go @@ -4,6 +4,8 @@ import ( "encoding/json" "testing" + "git.novox.be/novox/mesh-delivery/modules/mesh-grants/grantsstate" + "git.novox.be/novox/mesh-sdk/go/buscompose" "git.novox.be/novox/mesh-sdk/go/seal" ) @@ -12,14 +14,14 @@ import ( // 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 { +func nodeToolsWant(node string) grantsstate.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 { +func ledgerWant(node, module string) grantsstate.WantedAccount { w := aWant(module) w.Kind, w.Node, w.User, w.Claims = buscompose.KindLedger, node, "ledger."+node+"."+module, nil return w @@ -34,7 +36,7 @@ func ledgersOf(t *testing.T, v testVault, priv string) (map[string]json.RawMessa t.Fatal(err) } for _, o := range own.Own { - if o.Module == "node-tools" && o.Name == buscompose.LedgersSecret { + if o.Module == "node-tools" && o.Name == grantsstate.LedgersSecret { value, err := seal.Open(o.Sealed, priv) if err != nil { t.Fatal(err) diff --git a/modules/mesh-vault/cmd/mesh-vault/mint.go b/modules/mesh-vault/cmd/mesh-vault/mint.go index c550b8c90..05d05a56c 100644 --- a/modules/mesh-vault/cmd/mesh-vault/mint.go +++ b/modules/mesh-vault/cmd/mesh-vault/mint.go @@ -32,11 +32,13 @@ import ( "sync" "time" + "git.novox.be/novox/mesh-delivery/modules/mesh-grants/grantsstate" + "git.novox.be/novox/mesh-sdk/go/buscompose" ) // WantedRead is the grants part's state of wanted accounts, as the vault's manifest reads it. -const WantedRead = buscompose.GrantsAccounts +const WantedRead = grantsstate.GrantsAccounts // AccountIssuedEvent is what the vault says when it minted an account (mesh-sdk buscompose.AccountIssued). const AccountIssuedEvent = buscompose.AccountIssuedEvent @@ -46,7 +48,7 @@ const AccountIssuedEvent = buscompose.AccountIssuedEvent type minting struct { mu sync.Mutex // wants are the wanted accounts, by user, as last heard. - wants map[string]buscompose.WantedAccount + wants map[string]grantsstate.WantedAccount // heldBack are the wanted users the vault did not mint, with why (vault_status). heldBack map[string]string // owed are the wanted users whose mint failed, tried again at the pass (MintOwed). @@ -92,7 +94,7 @@ func (v *Vault) MintState() MintState { m := &v.minting m.mu.Lock() out := MintState{On: true, Why: mintingWhy, Wanted: len(m.wants), HeldBack: map[string]string{}, Minted: []Minted{}} - wants := map[string]buscompose.WantedAccount{} + wants := map[string]grantsstate.WantedAccount{} for u, why := range m.heldBack { out.HeldBack[u] = why if w, ok := m.wants[u]; ok { @@ -113,7 +115,7 @@ func (v *Vault) MintState() MintState { } // holdsAccount says the vault holds a bus account as w's own secret: a value that is an account. -func (v *Vault) holdsAccount(w buscompose.WantedAccount) bool { +func (v *Vault) holdsAccount(w grantsstate.WantedAccount) bool { secret, err := AccountSecret(w) if err != nil { return false @@ -172,7 +174,7 @@ func (v *Vault) busAccount(secret, value string) bool { // 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 grantsstate.WantedAccount) (string, error) { if w.Kind == buscompose.KindLedger { return LedgerAccountSecret(w.Node, w.Module) } @@ -186,7 +188,7 @@ func (v *Vault) WantHeard(user string, raw []byte, deleted bool) { v.wantGone(user) return } - w, err := buscompose.ReadWantedAccount(user, raw) + w, err := grantsstate.ReadWantedAccount(user, raw) if err != nil { v.log("the wanted account %s is not read, so nothing is minted for it: %v", user, err) v.holdBack(user, "its wanted key is not readable: "+err.Error()) @@ -194,7 +196,7 @@ func (v *Vault) WantHeard(user string, raw []byte, deleted bool) { } v.minting.mu.Lock() if v.minting.wants == nil { - v.minting.wants = map[string]buscompose.WantedAccount{} + v.minting.wants = map[string]grantsstate.WantedAccount{} } v.minting.wants[user] = w v.minting.mu.Unlock() @@ -218,7 +220,7 @@ func (e errHeldBack) Error() string { return e.why } // mintWanted mints w when minting is on, the vault holds no value for it and adopted no hash of it; otherwise it says // why not and, where that is a hold, keeps it for vault_status. -func (v *Vault) mintWanted(w buscompose.WantedAccount, by string) (Minted, error) { +func (v *Vault) mintWanted(w grantsstate.WantedAccount, by string) (Minted, error) { m, err := v.mintOnce(w, by) var held errHeldBack v.owe(w.User, err != nil && !errors.As(err, &held) && w.Valid() == nil) @@ -226,7 +228,7 @@ func (v *Vault) mintWanted(w buscompose.WantedAccount, by string) (Minted, error } // mintOnce is one try of mintWanted. -func (v *Vault) mintOnce(w buscompose.WantedAccount, by string) (Minted, error) { +func (v *Vault) mintOnce(w grantsstate.WantedAccount, by string) (Minted, error) { v.minting.mintMu.Lock() defer v.minting.mintMu.Unlock() if err := w.Valid(); err != nil { @@ -274,7 +276,7 @@ func (v *Vault) mintOnce(w buscompose.WantedAccount, by string) (Minted, error) if _, err := rand.Read(raw); err != nil { return Minted{}, err } - value, err := buscompose.HeldCredential(w, base64.RawURLEncoding.EncodeToString(raw)) + value, err := grantsstate.HeldCredential(w, base64.RawURLEncoding.EncodeToString(raw)) if err != nil { v.holdBack(w.User, err.Error()) return Minted{}, err @@ -407,7 +409,7 @@ func (v *Vault) IssueAccount(caller, user string) (any, error) { return nil, fmt.Errorf("the grants part holds no wanted account %s: the vault mints only what placement composes "+ "(grants_accounts lists them)", user) } - w, err := buscompose.ReadWantedAccount(user, raw) + w, err := grantsstate.ReadWantedAccount(user, raw) if err != nil { return nil, err } @@ -427,7 +429,7 @@ func (v *Vault) wantedUsers() []string { return out } -func (v *Vault) wanted(user string) (buscompose.WantedAccount, bool) { +func (v *Vault) wanted(user string) (grantsstate.WantedAccount, bool) { v.minting.mu.Lock() defer v.minting.mu.Unlock() w, ok := v.minting.wants[user] diff --git a/modules/mesh-vault/cmd/mesh-vault/mint_integration_test.go b/modules/mesh-vault/cmd/mesh-vault/mint_integration_test.go index a7b4549ad..0a8d18aaa 100644 --- a/modules/mesh-vault/cmd/mesh-vault/mint_integration_test.go +++ b/modules/mesh-vault/cmd/mesh-vault/mint_integration_test.go @@ -26,13 +26,14 @@ import ( "testing" "time" + "git.novox.be/novox/mesh-delivery/modules/mesh-grants/grantsstate" + "github.com/nats-io/nats.go" "github.com/nats-io/nats.go/jetstream" "golang.org/x/crypto/bcrypt" "golang.org/x/crypto/nacl/box" "git.novox.be/novox/mesh-contracts/identity-and-access/go/seats/meshvault" - "git.novox.be/novox/mesh-sdk/go/buscompose" "git.novox.be/novox/mesh-sdk/go/seal" "git.novox.be/novox/mesh-sdk/go/testbus" ) @@ -592,7 +593,7 @@ func TestTheVaultWholeMintsOnTheBusWhoeverHoldsTheLease(t *testing.T) { } var held struct{ Password string } _ = json.Unmarshal([]byte(value), &held) - shape, _ := buscompose.HeldCredential(x, held.Password) + shape, _ := grantsstate.HeldCredential(x, held.Password) if value != string(shape) { t.Errorf("the minted value %q is not the controller's shape %q", value, shape) } diff --git a/modules/mesh-vault/cmd/mesh-vault/mint_test.go b/modules/mesh-vault/cmd/mesh-vault/mint_test.go index 697ab9011..94e5fe336 100644 --- a/modules/mesh-vault/cmd/mesh-vault/mint_test.go +++ b/modules/mesh-vault/cmd/mesh-vault/mint_test.go @@ -6,17 +6,19 @@ import ( "testing" "time" + "git.novox.be/novox/mesh-delivery/modules/mesh-grants/grantsstate" + "git.novox.be/novox/mesh-sdk/go/buscompose" "git.novox.be/novox/mesh-sdk/go/seal" ) // aWant is a wanted account of a module on ace, as the grants part writes it. -func aWant(module string) buscompose.WantedAccount { - return buscompose.WantedAccount{User: "ace." + module, Kind: buscompose.KindModule, Node: "ace", Module: module, - URL: "nats://novox.mesh:4222", Fingerprint: "ab:cd", Claims: []buscompose.ClaimedSeat{{Seat: "s", Scope: "node"}}} +func aWant(module string) grantsstate.WantedAccount { + return grantsstate.WantedAccount{User: "ace." + module, Kind: buscompose.KindModule, Node: "ace", Module: module, + URL: "nats://novox.mesh:4222", Fingerprint: "ab:cd", Claims: []grantsstate.ClaimedSeat{{Seat: "s", Scope: "node"}}} } -func wantRaw(t *testing.T, w buscompose.WantedAccount) []byte { +func wantRaw(t *testing.T, w grantsstate.WantedAccount) []byte { t.Helper() raw, err := json.Marshal(w) if err != nil { @@ -59,7 +61,7 @@ func TestTheVaultMintsAWantedAccountOnceAndNothingItHolds(t *testing.T) { } var got struct{ Password string } _ = json.Unmarshal([]byte(value), &got) - shape, _ := buscompose.HeldCredential(w, got.Password) + shape, _ := grantsstate.HeldCredential(w, got.Password) if len(got.Password) != 40 || value != string(shape) { t.Errorf("the minted value is %q, not the controller's shape %q", value, shape) } @@ -164,7 +166,7 @@ func TestTheVaultMintsAWantedAccountOnceAndNothingItHolds(t *testing.T) { {"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")} { + for _, w := range []grantsstate.WantedAccount{nodeToolsWant("ace"), ledgerWant("ace", "m"), ledgerWant("ace", "k")} { v.WantHeard(w.User, wantRaw(t, w), false) } v.WantsRead() @@ -244,7 +246,7 @@ func TestTheVaultMintsWhoeverHoldsTheLease(t *testing.T) { } // An older controller's covered account, handed with origin issued: refused, the vault's value kept. x := aWant("mod-x") - theirs, _ := buscompose.HeldCredential(x, "the-controllers-password") + theirs, _ := grantsstate.HeldCredential(x, "the-controllers-password") if _, err := handIssued(t, v, ControllerCaller, "own/ace/mod-x/broker", string(theirs)); err == nil || !strings.Contains(err.Error(), "the vault minted") { t.Errorf("a controller's issued value over the vault's mint: %v", err) @@ -258,7 +260,7 @@ func TestTheVaultMintsWhoeverHoldsTheLease(t *testing.T) { v.minting.wants[z.User] = z v.minting.mu.Unlock() v.holdBack(z.User, "held back for a reason that has passed") - value, _ := buscompose.HeldCredential(z, "moved-in") + value, _ := grantsstate.HeldCredential(z, "moved-in") if _, err := v.keep("own/ace/mod-z/broker", string(value), "the move", ControllerCaller, OriginMade); err != nil { t.Fatal(err) } diff --git a/modules/mesh-vault/cmd/mesh-vault/vault_test.go b/modules/mesh-vault/cmd/mesh-vault/vault_test.go index 30c44b300..bb086b76f 100644 --- a/modules/mesh-vault/cmd/mesh-vault/vault_test.go +++ b/modules/mesh-vault/cmd/mesh-vault/vault_test.go @@ -21,6 +21,8 @@ import ( "testing" "time" + "git.novox.be/novox/mesh-delivery/modules/mesh-grants/grantsstate" + stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/buscompose" "git.novox.be/novox/mesh-sdk/go/seal" @@ -935,7 +937,7 @@ func TestABusAccountIsKeptOnlyAsAnAccount(t *testing.T) { t.Errorf("%s: kept %v, err %v", row.name, err == nil, err) } } - w := buscompose.WantedAccount{User: "novox.nats.nats-tools", Kind: buscompose.KindProcess, Node: "novox", + w := grantsstate.WantedAccount{User: "novox.nats.nats-tools", Kind: buscompose.KindProcess, Node: "novox", Module: "nats", Process: "nats-tools", URL: "nats://novox.mesh:4222", Fingerprint: "ab:cd"} if err := w.Valid(); err != nil { t.Fatal(err) diff --git a/modules/mesh-vault/go.mod b/modules/mesh-vault/go.mod index 9ad0c80ff..1918a6a07 100644 --- a/modules/mesh-vault/go.mod +++ b/modules/mesh-vault/go.mod @@ -3,6 +3,14 @@ module mesh-vault go 1.26.0 require ( + git.novox.be/novox/mesh-delivery/contracts/go/clients/containerimageregistryclient v0.0.0-00010101000000-000000000000 // indirect + git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient v0.0.0-00010101000000-000000000000 // indirect + git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry v0.0.0-00010101000000-000000000000 // indirect + git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog v0.0.0-00010101000000-000000000000 // indirect + git.novox.be/novox/mesh-delivery/contracts/go/seats/ociartifactregistry v0.0.0-00010101000000-000000000000 // indirect + git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds v0.0.0-00010101000000-000000000000 // indirect + git.novox.be/novox/mesh-delivery/modules/mesh-grants/grantsstate v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-delivery/sdk v0.0.0-00010101000000-000000000000 // indirect git.novox.be/novox/mesh-contracts/go/seats/nodeengine v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner v0.0.0-00010101000000-000000000000 diff --git a/modules/mesh-vault/module.json b/modules/mesh-vault/module.json index 1312f04c1..1e3f51004 100644 --- a/modules/mesh-vault/module.json +++ b/modules/mesh-vault/module.json @@ -1,6 +1,9 @@ { "module": "mesh-vault", "version": "1", + "packages": { + "grantsstate": "0.1" + }, "runs-as": "mesh-vault", "provides": [ {