mesh-grants: grants_accounts reads the account consumers' differences in shadow, where no condition is raised (issue 774, ADR 0561 §6, §9)
This commit is contained in:
@@ -120,8 +120,10 @@ func toolsOf(p *grants.Part) []stdio.Tool {
|
||||
{Name: grants.ToolAccounts, Description: "The bus accounts the mesh wants (novox/hq ADR 0561 §2, §9): every account the vault " +
|
||||
"mints that placement composes (a module's, a process's, a machine's provisioner client's), as the grants part last " +
|
||||
"wrote it to its state accounts, which the vault alone reads: user, kind, node, module, process, the bus's address and " +
|
||||
"fingerprint, a module's claims with the verbs each seat promises, and when the key was written; one user's or all; and " +
|
||||
"what the last pass wrote, deleted or kept. Never a password. Read-only: grants_compose_now writes them again.",
|
||||
"fingerprint, a module's claims with the verbs each seat promises, and when the key was written; one user's or all; " +
|
||||
"what the last pass wrote, deleted or kept; and the durable consumers the accounts need as the last pass found them " +
|
||||
"(missing, differing and why, created; whether the lease is handed away). Never a password. Read-only: " +
|
||||
"grants_compose_now writes them again.",
|
||||
Input: schema(map[string]string{"user": "one bus user, e.g. ace.mesh-build-go"}),
|
||||
Run: func(a map[string]any) (any, error) { return p.Accounts(grants.Answer(a, "user")) }},
|
||||
{Name: grants.ToolConsumerMatch, Description: "Bring one durable consumer an account needs (a module's on EVENTS, a process's on " +
|
||||
|
||||
@@ -1771,6 +1771,10 @@ func TestGrants(t *testing.T) {
|
||||
if _, err := p.Accounts("b.mod-y"); err == nil {
|
||||
t.Error("the tool reads an account no longer wanted")
|
||||
}
|
||||
p.Pass()
|
||||
if all, _ := p.Accounts(""); all.(map[string]any)["consumers"] == nil {
|
||||
t.Errorf("the tool does not say the account consumers in shadow: %v", all)
|
||||
}
|
||||
// With no bus address no account is written, and the pass says why.
|
||||
bare := partOn(fixture())
|
||||
if res := bare.Compose(); res.Accounts != nil || !strings.Contains(strings.Join(res.Errors, " "), "no bus address") {
|
||||
|
||||
@@ -138,6 +138,11 @@ func (p *Part) Accounts(user string) (any, error) {
|
||||
if json.Unmarshal(raw, &res) == nil && res.Accounts != nil {
|
||||
answer["last_pass"] = res.Accounts
|
||||
}
|
||||
// And the durable consumers the accounts need, as the last pass found them: missing and differing ones are read
|
||||
// here in shadow too, where no condition is raised (ADR 0561 §6, §9).
|
||||
if res.Consumers != nil {
|
||||
answer["consumers"] = res.Consumers
|
||||
}
|
||||
}
|
||||
return answer, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user