The provisioner holds only a bad module, the vault keeps bus accounts by declaration, and silent faults from the release sweep speak up (issue 774) #565
@@ -189,12 +189,17 @@ func (v *Vault) mintOnce(w buscompose.WantedAccount, by string) (Minted, error)
|
||||
v.holdBack(w.User, err.Error())
|
||||
return Minted{}, err
|
||||
}
|
||||
if _, held, err := v.Store.Read(secret); err != nil {
|
||||
replacing := false
|
||||
if rec, held, err := v.Store.Read(secret); err != nil {
|
||||
return Minted{}, err
|
||||
} else if held {
|
||||
// Its value is held (the controller's, handed in, or one the vault minted): never minted anew (§4).
|
||||
v.noLongerHeld(w.User)
|
||||
return Minted{}, errHeldBack{secret + " is held already: an account the vault holds a value for is never minted anew (ADR 0561 §4)"}
|
||||
// A held value that is no account (kept before the vault judged it, the sweep of 2026-10-30) has no hash and
|
||||
// logs in nowhere on the bus: it is replaced by a minted account. Any other held value is never minted anew (§4).
|
||||
if value, err := openAtRest(rec, v); err != nil || BusAccountValue(secret, value) {
|
||||
v.noLongerHeld(w.User)
|
||||
return Minted{}, errHeldBack{secret + " is held already: an account the vault holds a value for is never minted anew (ADR 0561 §4)"}
|
||||
}
|
||||
replacing = true
|
||||
}
|
||||
if v.Accounts == nil {
|
||||
v.holdBack(w.User, "the vault has no state of bus accounts to write the hash to")
|
||||
@@ -230,11 +235,25 @@ func (v *Vault) mintOnce(w buscompose.WantedAccount, by string) (Minted, error)
|
||||
v.holdBack(w.User, err.Error())
|
||||
return Minted{}, err
|
||||
}
|
||||
c, err := v.keepLocked(secret, string(value), "the vault", "", OriginMade, keepOptions{neverReplace: true, quiet: true})
|
||||
opt := keepOptions{neverReplace: true, quiet: true}
|
||||
if replacing {
|
||||
// Only the value that is no account is replaced, judged again under the store's lock; the one replaced is kept.
|
||||
opt = keepOptions{quiet: true, keepPrevious: true, refuse: func(before Record) string {
|
||||
if was, err := openAtRest(before, v); err != nil || BusAccountValue(secret, was) {
|
||||
return secret + " is held as an account meanwhile: it is never minted anew (ADR 0561 §4)"
|
||||
}
|
||||
return ""
|
||||
}}
|
||||
}
|
||||
c, err := v.keepLocked(secret, string(value), "the vault", "", OriginMade, opt)
|
||||
if err != nil {
|
||||
v.holdBack(w.User, "its value could not be kept: "+err.Error())
|
||||
return Minted{}, err
|
||||
}
|
||||
if replacing {
|
||||
v.log("%s held a value that is no bus account, which no hash was taken of and which logs in nowhere: replaced by a "+
|
||||
"minted account (generation %d), the value it replaces kept beside it", secret, c.Generation)
|
||||
}
|
||||
out := Minted{User: w.User, Secret: secret, Generation: c.Generation, At: c.At}
|
||||
// The hash first, then account-issued, then secret-changed: the grants part composes the user before the node asks.
|
||||
if _, err := v.HashAccount(secret, false); err != nil {
|
||||
|
||||
@@ -242,3 +242,30 @@ func TestAFailedMintIsTriedAgainAtThePass(t *testing.T) {
|
||||
t.Errorf("not minted at the pass after the failure: %+v", v.MintState())
|
||||
}
|
||||
}
|
||||
|
||||
// A held value that is no account (kept before the vault judged it: broker-nats-tools, broker-address and
|
||||
// broker-management on 2026-10-30, issue 774) is replaced by a minted account when the grants part wants its user;
|
||||
// a held account still never is.
|
||||
func TestAHeldValueThatIsNoAccountIsReplacedByAMintedOne(t *testing.T) {
|
||||
v, accounts, _ := mintingVault(t, true)
|
||||
w := aWant("mod-x")
|
||||
if _, err := v.Put("own/ace/mod-x/broker", `{"password":"pw"}`, "the test"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
heldPlain(t, v.Vault, "own/ace/mod-x/broker", "a-random-value-the-controller-made")
|
||||
v.WantHeard(w.User, wantRaw(t, w), false)
|
||||
rec, _, _ := v.Store.Read("own/ace/mod-x/broker")
|
||||
value, err := openAtRest(rec, v.Vault)
|
||||
if err != nil || !BusAccountValue("own/ace/mod-x/broker", value) || rec.Generation != 3 || rec.Previous == nil {
|
||||
t.Fatalf("not replaced by a minted account: generation %d, previous kept %v, %v", rec.Generation, rec.Previous != nil, err)
|
||||
}
|
||||
var got struct{ Password string }
|
||||
_ = json.Unmarshal([]byte(value), &got)
|
||||
if !accounts.hashOf(w.User, got.Password, 3) {
|
||||
t.Errorf("%s's hash is not the minted password's: %+v", w.User, accounts.keys[w.User])
|
||||
}
|
||||
v.WantHeard(w.User, wantRaw(t, w), false)
|
||||
if again, _, _ := v.Store.Read("own/ace/mod-x/broker"); again.Generation != 3 {
|
||||
t.Errorf("a held account was minted anew: generation %d", again.Generation)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user