mesh/delivery merged: source.main moved to novox/mesh-sdk@79eb58efe4b0
mesh/delivery-group group fix/1126-seed-same merged: every member is merged
mesh/check failed: integration: github.com/novox/mesh-host/cmd/mesh-host.TestNatsANodeThePlacementNamesComposesAndAppliesItsOwn: the node did not comp…
delivery.OwnNeedName reads <module>.needs-<name> and the bare needs-<name>; OwnValuesDiffer and the node agent use it. The fixtures carry the id shape captured from novox's shadow answer.
96 lines
3.6 KiB
Go
96 lines
3.6 KiB
Go
package delivery
|
|
|
|
// The own secrets a node's shadow answer finds the vault holds another value for than the node runs (novox/hq issue 1126,
|
|
// cause C4): the vault's `move-in` never replaces a value it holds, so a value the controller made anew later (a rotation
|
|
// at start, a re-issue) runs while the vault keeps the first one it was handed. The node opens both seals with its own
|
|
// key and its answer's shown bodies mask the value as MaskedAnotherValue; this reads which own secrets those are, for the
|
|
// node agent (which hands the vault what runs) and for the vault's `own_drift` (which lists them mesh-wide), so both read
|
|
// the answer one way.
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
// MaskedAnotherValue is the word a shown body masks a value with when the node opened both sides with its key and they
|
|
// are two values (MaskedPair, maskWord).
|
|
const MaskedAnotherValue = "<masked: another value>"
|
|
|
|
// OwnValueDiffers is one own secret of a module whose value composed (the vault's) is another than the one that runs.
|
|
type OwnValueDiffers struct {
|
|
Module string `json:"module"`
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
// ownNeedPrefix starts the id of the file a module's own secret is placed in (catalogue.NeedID).
|
|
var ownNeedPrefix = catalogue.NeedID("")
|
|
|
|
// OwnNeedName is the name of module's own secret whose file a resource id names, and whether it names one. On a node a
|
|
// resource's id carries its module's name (`only-office.needs-jwt`, as a live shadow answer shows it); the bare form a
|
|
// declaration composes (`needs-jwt`, catalogue.NeedID) is read too. An id of another module's is not this module's.
|
|
func OwnNeedName(module, id string) (string, bool) {
|
|
if module != "" {
|
|
id = strings.TrimPrefix(id, module+".")
|
|
}
|
|
name, own := strings.CutPrefix(id, ownNeedPrefix)
|
|
return name, own && name != "" && !strings.Contains(name, ".")
|
|
}
|
|
|
|
// OwnValuesDiffer is every own secret a's shown bodies say holds another value composed than running: a body of a
|
|
// module's own secret's file (OwnNeedName: `<module>.needs-<name>` on a node) masked MaskedAnotherValue on either side. Sorted by module and name, each
|
|
// once. A body the answer did not show (beyond MaxBodies) is not read.
|
|
func OwnValuesDiffer(a CandidateAnswer) []OwnValueDiffers {
|
|
seen := map[OwnValueDiffers]bool{}
|
|
var out []OwnValueDiffers
|
|
for _, d := range a.Differs {
|
|
for _, b := range d.Bodies {
|
|
name, own := OwnNeedName(d.Module, b.ID)
|
|
if !own || !anotherValue(b) {
|
|
continue
|
|
}
|
|
o := OwnValueDiffers{Module: d.Module, Name: name}
|
|
if !seen[o] {
|
|
seen[o] = true
|
|
out = append(out, o)
|
|
}
|
|
}
|
|
}
|
|
sort.Slice(out, func(i, j int) bool {
|
|
if out[i].Module != out[j].Module {
|
|
return out[i].Module < out[j].Module
|
|
}
|
|
return out[i].Name < out[j].Name
|
|
})
|
|
return out
|
|
}
|
|
|
|
// ValuesDiffer is how many shown bodies of a hold a value masked MaskedAnotherValue, own secrets and every other
|
|
// resource alike: the count a node's answer carries as CandidateAnswer.ValuesDiffer.
|
|
func ValuesDiffer(a CandidateAnswer) int {
|
|
n := 0
|
|
for _, d := range a.Differs {
|
|
for _, b := range d.Bodies {
|
|
if anotherValue(b) {
|
|
n++
|
|
}
|
|
}
|
|
}
|
|
return n
|
|
}
|
|
|
|
// WithValuesDiffer is answers with each one's ValuesDiffer counted.
|
|
func WithValuesDiffer(answers map[string]CandidateAnswer) map[string]CandidateAnswer {
|
|
out := make(map[string]CandidateAnswer, len(answers))
|
|
for g, a := range answers {
|
|
a.ValuesDiffer = ValuesDiffer(a)
|
|
out[g] = a
|
|
}
|
|
return out
|
|
}
|
|
|
|
func anotherValue(b ResourceBodies) bool {
|
|
return strings.Contains(b.Composed, MaskedAnotherValue) || strings.Contains(b.Running, MaskedAnotherValue)
|
|
}
|