90 lines
3.5 KiB
Go
90 lines
3.5 KiB
Go
package main
|
|
|
|
// The vault asks a software-issuing provider's tool itself (novox/hq ADR 0349 clause 10, issue 928).
|
|
//
|
|
// A provider whose offer says `issued-by: software` has its value taken from its tool, sealed to the vault, "when the
|
|
// provider starts, when the software's value changes and at least hourly". Only the controller's `secret issued` made
|
|
// the vault ask until now, so a holder that bound after the last such act waited for ever. The pass (once a minute and
|
|
// when the vault starts) now asks the tool for the holders the plans name that hold nothing yet, in the vault's own
|
|
// name and through the same path as the controller's verb. A holder that holds its value is left untouched: the
|
|
// forge mints anew on every ask, and a rotation is the software's (ADR 0305 §5, §9). A failed ask is said, keeps
|
|
// nothing, and is asked again at the next pass.
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// ownCaller is who a value the vault asked for itself is recorded as taken by.
|
|
const ownCaller = "mesh-vault"
|
|
|
|
// perHolderWhy is what a pass says of a provision whose plans name a credential per holder.
|
|
const perHolderWhy = "a plan names a credential per holder for it (issue 757): there is no one shared value"
|
|
|
|
// ownIssue is the pass's part for a provision whose plans name a credential per holder: when its offer is issued by
|
|
// the provider's software and the plans name the tool, the holders that hold nothing yet are asked of it.
|
|
func (v *Vault) ownIssue(k pairKey, b *binds) PairOutcome {
|
|
name := k.name()
|
|
said := PairOutcome{Name: name, Outcome: PairPerHolder, Why: perHolderWhy}
|
|
if v.Ask == nil || len(b.forms) != 1 || !b.forms[FormIssued] {
|
|
return said
|
|
}
|
|
held := func(why string) PairOutcome {
|
|
return PairOutcome{Name: name, Outcome: PairHeld, Why: why}
|
|
}
|
|
var tools []string
|
|
for t := range b.tools {
|
|
if t != "" {
|
|
tools = append(tools, t)
|
|
}
|
|
}
|
|
sort.Strings(tools)
|
|
switch {
|
|
case len(tools) == 0:
|
|
return held(fmt.Sprintf("the plans name %s from %s as issued by its software and name no tool that answers it; "+
|
|
"the vault cannot ask for it (issue 928)", k.provision, k.provider))
|
|
case len(tools) > 1 || b.tools[""]:
|
|
return held(fmt.Sprintf("the plans naming %s from %s disagree on its tool (%s); the vault asks none", k.provision,
|
|
k.provider, strings.Join(tools, ", ")))
|
|
case len(b.providerModules) != 1:
|
|
return held(fmt.Sprintf("no one plan names the module serving %s on %s, so the vault cannot tell whose tool to ask",
|
|
k.provision, k.provider))
|
|
}
|
|
var module string
|
|
for m := range b.providerModules {
|
|
module = m
|
|
}
|
|
var missing []Holder
|
|
for h := range b.holders {
|
|
secret, err := HolderSecret(k.provider, k.provision, h)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
if _, have, err := v.Store.Read(secret); err == nil && !have {
|
|
missing = append(missing, h)
|
|
}
|
|
}
|
|
if len(missing) == 0 {
|
|
return said
|
|
}
|
|
sort.Slice(missing, func(i, j int) bool { return missing[i].String() < missing[j].String() })
|
|
got, err := v.takeIssuedFor(ownCaller, k.provision, k.provider, module, tools[0], missing)
|
|
if err != nil {
|
|
return held(err.Error())
|
|
}
|
|
if len(got.NotAnswered) > 0 {
|
|
var who []string
|
|
for _, h := range got.NotAnswered {
|
|
who = append(who, h.String())
|
|
}
|
|
return held(fmt.Sprintf("its tool %s gave no value for %s", tools[0], strings.Join(who, ", ")))
|
|
}
|
|
var who []string
|
|
for _, h := range got.Holders {
|
|
who = append(who, h.Holder.String())
|
|
}
|
|
return PairOutcome{Name: name, Outcome: PairPerHolder, Why: fmt.Sprintf("the vault asked its tool %s and keeps a value "+
|
|
"for %s (issue 928)", tools[0], strings.Join(who, ", "))}
|
|
}
|