Files
mesh-host/internal/compose/frombus/keep.go
T

101 lines
3.6 KiB
Go

package frombus
import (
"encoding/json"
"fmt"
"maps"
"slices"
"sort"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/declaration"
"git.novox.be/novox/mesh-sdk/go/delivery"
"github.com/novox/mesh-host/internal/compose"
"github.com/novox/mesh-host/internal/compose/resolution"
)
// **What runs is kept while a manifest does not yet say what shared code no longer infers** (novox/hq ADR 0601 §4). mesh-sdk
// knows the tool runner and the modules whose own secrets are the core's credentials only by what their manifests say
// (`tool-runner`, `core-credentials`), no longer by their names. A module placed on the composing node whose manifest (an
// older build's) does not say so yet, while what the node runs of it shows it (the tool runner's process, `<module>.runtime`;
// an own secret carried as the vault's box, the file's `vault-sealed`), is composed as what runs shows: its tool runner
// process and its sealed secrets alike are kept, never composed away, and the node says so until the manifest says it.
// Known by what runs, never by a module's name.
// keepWhatRuns marks, in in, each module placed on node that what runs shows is the tool runner or carries the core's
// credentials, where its manifest does not say so; it returns, sorted, what it marked, in words. The tool runner is marked
// only where no placed module's manifest says it is one.
func keepWhatRuns(in *compose.Input, node string, running []delivery.Composed) []string {
placed := assignedOn(*in, node)
if len(placed) == 0 || len(running) == 0 {
return nil
}
runner, sealed := "", map[string]bool{}
for _, run := range running {
for _, raw := range run.Resources {
var r struct {
ID string `json:"id"`
Type string `json:"type"`
}
if json.Unmarshal(raw, &r) != nil || r.ID == "" {
continue
}
owner := run.Module
if owner == "" {
owner, _ = declaration.ModuleGuess(r.ID)
}
if owner == "" || !slices.Contains(placed, owner) {
continue
}
if r.Type == "process" && r.ID == owner+"."+resolution.RuntimeProcessID() {
runner = owner
}
if r.Type == "file" {
var fields map[string]json.RawMessage
if json.Unmarshal(raw, &fields) == nil {
if _, ok := fields[catalogue.VaultSealedField]; ok {
sealed[owner] = true
}
}
}
}
}
var said []string
saysRunner := false
for _, m := range placed {
if man, ok := manifestOn(*in, node, m); ok && catalogue.IsToolRunner(man) {
saysRunner = true
}
}
mark := func(module string, set func(*catalogue.Manifest), words string) {
for i := range in.Nodes {
if in.Nodes[i].Name != node {
continue
}
if man, ok := in.Nodes[i].Kept[module]; ok {
set(&man)
in.Nodes[i].Kept[module] = man
said = append(said, words)
return
}
}
if man, ok := in.Catalogue[module]; ok {
set(&man)
in.Catalogue[module] = man
said = append(said, words)
}
}
if runner != "" && !saysRunner {
mark(runner, func(m *catalogue.Manifest) { m.ToolRunner = true }, fmt.Sprintf("%s runs the tool runner's process here and its "+
"manifest does not say it is the tool runner (tool-runner): it is composed as the tool runner it runs as, until its manifest says so", runner))
}
for _, m := range slices.Sorted(maps.Keys(sealed)) {
if man, ok := manifestOn(*in, node, m); ok && !catalogue.CarriesCoreCredentials(man) {
mark(m, func(m *catalogue.Manifest) { m.CoreCredentials = true }, fmt.Sprintf("%s carries its own secrets sealed by the vault here "+
"and its manifest does not say they are the core's credentials (core-credentials): they stay sealed, until its manifest says so", m))
}
}
sort.Strings(said)
return said
}