diff --git a/modules/mesh-vault/cmd/mesh-vault/adopt.go b/modules/mesh-vault/cmd/mesh-vault/adopt.go index 5f1a8aeb..2e6e998b 100644 --- a/modules/mesh-vault/cmd/mesh-vault/adopt.go +++ b/modules/mesh-vault/cmd/mesh-vault/adopt.go @@ -54,7 +54,7 @@ type Adoption struct { // adoptionKept is what the vault keeps of its last adoption, for its tools and to skip a have that says the same. type adoptionKept struct { last *Adoption - handed string // the From and To of the handing last adopted with nothing refused + handed string // the From and To of the handing last taken in a complete pass failed string // why the last look found nothing to adopt, or "" } @@ -103,8 +103,8 @@ func (v *Vault) AdoptNow(caller string) (Adoption, error) { return v.AdoptFrom(node, raw, someoneOr(caller, "a tool"), true) } -// AdoptFrom adopts from the have of the bus module on node: unless force, nothing when it hands what the last adoption -// took whole. +// AdoptFrom adopts from the have of the bus module on node: unless force, nothing when it hands what the last complete +// adoption took. func (v *Vault) AdoptFrom(node string, raw []byte, by string, force bool) (Adoption, error) { a, err := v.adopt(node, raw, by, force) v.mu.Lock() @@ -207,11 +207,11 @@ func (v *Vault) adopt(node string, raw []byte, by string, force bool) (Adoption, } } } - if len(a.Refused) == 0 { - v.mu.Lock() - v.adoption.handed = handed - v.mu.Unlock() - } + // A complete pass, refusals and all: the same handing is not opened again at the next change of the have (a + // refused user stays refused until the list changes, and the last adoption names it). + v.mu.Lock() + v.adoption.handed = handed + v.mu.Unlock() return a, nil } @@ -266,6 +266,9 @@ func (v *Vault) adoptionSaid() map[string]any { v.mu.Lock() defer v.mu.Unlock() out := map[string]any{"last": v.adoption.last} + if v.adoption.last != nil && len(v.adoption.last.Refused) > 0 { + out["refused"] = v.adoption.last.Refused + } if v.adoption.failed != "" { out["why"] = v.adoption.failed } diff --git a/modules/mesh-vault/cmd/mesh-vault/tools_test.go b/modules/mesh-vault/cmd/mesh-vault/tools_test.go index 14cd215b..415bf5d9 100644 --- a/modules/mesh-vault/cmd/mesh-vault/tools_test.go +++ b/modules/mesh-vault/cmd/mesh-vault/tools_test.go @@ -235,10 +235,14 @@ func TestSecretOwnListsFingerprintsOfOwnSecretsOnly(t *testing.T) { sealedTo := v.Own.PublicKey have := func() []byte { var accounts []delivery.HandedAccount - for _, u := range []string{"controller", "node.ace", "g14.dunst"} { - accounts = append(accounts, delivery.HandedAccount{User: u, Hash: handing[u]}) + for _, u := range []string{"controller", "node.ace", "g14.dunst", "bad.user"} { + if hash, ok := handing[u]; ok { + accounts = append(accounts, delivery.HandedAccount{User: u, Hash: hash}) + } } - handed, err := delivery.HandAccounts(accounts, sealedTo, "sha256:"+handing["node.ace"][7:15], time.Now()) + // The list's digest, as the node says it: another list (another hash or user) is another digest. + list, _ := json.Marshal(accounts) + handed, err := delivery.HandAccounts(accounts, sealedTo, Fingerprint(string(list)), time.Now()) if err != nil { t.Fatal(err) } @@ -300,6 +304,17 @@ func TestSecretOwnListsFingerprintsOfOwnSecretsOnly(t *testing.T) { if acc.keys["g14.dunst"] != dunst { t.Errorf("a user whose value the vault holds was adopted over: %+v", acc.keys["g14.dunst"]) } + // A refused user is named in the last adoption, and the same handing is not opened again at the next change. + sealedTo, handing["bad.user"] = v.Own.PublicKey, "not-bcrypt" + if a, err := v.AdoptFrom("novox", have(), "the watch", false); err != nil || a.Refused["bad.user"] == "" || a.Handed != 4 { + t.Fatalf("a refused user: %+v, %v", a, err) + } + if a, err := v.AdoptFrom("novox", have(), "the watch", false); err != nil || !a.At.IsZero() { + t.Fatalf("the same handing was opened again after a refusal: %+v, %v", a, err) + } + if said := v.adoptionSaid(); said["refused"] == nil { + t.Errorf("the refusal is not said: %v", said) + } if _, err := v.AdoptFrom("ace", have(), "the test", true); err == nil || !strings.Contains(err.Error(), "does not hold the bus") { t.Errorf("a handing from a node not holding the bus: %v", err) }