Files
mesh-controller/internal/catalogue/bound_into_files.go
T
jschoubben 9b7ba2e20c identity: a consumer's identity fits the tightest backend, via a slug (ADR 0054)
A module may declare a short `slug`; the mesh derives mesh_<node>_<slug|name> and
refuses at assignment (naming the slug as the remedy) when it would still overflow —
identityLimit is now 20, an S3 access key's, the tightest of the backends a login
reaches (04-ISSUES/010). The slug rides the grant so the provider derives the same
login the consumer does, even across nodes. CheckIdentity is now wired, in grantsFor.

Also, the minted secret shrinks to 40 chars (30 bytes) from 43: an S3 secret key is
8-40, the same fit-the-tightest-backend rule on the credential's other half.

Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
2026-09-05 02:51:39 +02:00

151 lines
4.9 KiB
Go

package catalogue
import (
"fmt"
"regexp"
"sort"
"strings"
)
// The half of a connection that is not secret, put where the program reading it can find it.
//
// **The asymmetry this removes was backwards** (novox/hq 04-ISSUES/023). A sealed credential can
// be placed inside any configuration file a module writes: the module leaves a hole, the mesh
// delivers the value sealed beside it, and the host — the only thing that sees both — fills it in.
// The host and the port and the name to present are ordinary facts the mesh holds in the clear,
// and they were the ones stuck: readable only inside a JSON binding, which a program reading
// `KEY=value` cannot use.
//
// So the same shape, and simpler. These values are not secret, so **the control plane substitutes
// them itself** before the declaration is sent. Nothing new reaches the host, which learns no
// formats and gains no fields.
//
// **It stays name-agnostic** ([ADR 0027]). The mesh does not learn what a `postgres-database` is:
// `at`, `as` and `from` are facts about any provision at all, and everything else comes from what
// the provider said it serves — whose keys are agreed by the requirement's name, not by this file.
// bound is where a module says a value from one of its bindings belongs:
// ${bound:<provision>.<key>}.
var bound = regexp.MustCompile(`\$\{bound:([a-z0-9][a-z0-9.-]*[a-z0-9]):([a-z0-9][a-z0-9_-]*)\}`)
// boundUsed are the (provision, key) pairs a file's content asks for, first appearance first.
func boundUsed(content string) [][2]string {
var used [][2]string
seen := map[string]bool{}
for _, m := range bound.FindAllStringSubmatch(content, -1) {
if key := m[1] + ":" + m[2]; !seen[key] {
seen[key] = true
used = append(used, [2]string{m[1], m[2]})
}
}
return used
}
// knownFor is everything a module may name from one of its bindings.
//
// Three facts the mesh states about any provision, plus whatever the provider said it serves. A
// module may not reach a binding it does not have — the same boundary as a secret, for the same
// reason.
func knownFor(m Manifest, needs []Needed, node string) map[string]map[string]string {
out := map[string]map[string]string{}
for _, want := range m.Wants() {
for i := range needs {
n := needs[i]
if n.Name != want || n.For != m.Module {
continue
}
values := map[string]string{
"at": n.At,
"from": n.From,
"as": ConsumerIdentity(node, IdentitySource(m.Slug, m.Module)),
}
for key, value := range n.Serves {
// The provider's own vocabulary. Rendered plainly: a port is 5432, not 5432.000000,
// which is what a float would write and what a connection string would refuse.
values[key] = plainly(value)
}
out[want] = values
}
}
return out
}
// plainly renders a served value as a program would expect to read it.
func plainly(value any) string {
switch v := value.(type) {
case string:
return v
case float64:
if v == float64(int64(v)) {
return fmt.Sprintf("%d", int64(v))
}
return strings.TrimRight(strings.TrimRight(fmt.Sprintf("%f", v), "0"), ".")
case bool:
return fmt.Sprintf("%t", v)
case nil:
return ""
default:
return fmt.Sprint(v)
}
}
// boundInto replaces a file's ${bound:…} placeholders with what the mesh knows.
//
// A placeholder naming something the module does not require, or a key the provider does not
// serve, is refused. Left as it was, the literal `${bound:x:y}` would be written into a
// configuration file and read as a value — a connection to a host called `${bound:x:y}`, failing
// somewhere that names neither the module nor the mesh.
func boundInto(resource map[string]any, known map[string]map[string]string, module string) error {
if fmt.Sprint(resource["type"]) != "file" {
return nil
}
content, ok := resource["content"].(string)
if !ok {
return nil
}
for _, pair := range boundUsed(content) {
provision, key := pair[0], pair[1]
values, has := known[provision]
if !has {
return fmt.Errorf(
"%s has a file that says ${bound:%s:%s}, and %s does not require %q. It may name %s",
module, provision, key, module, provision, orNothing(namesOfBindings(known)))
}
value, said := values[key]
if !said {
return fmt.Errorf(
"%s asks its %s binding for %q, and what answers it says %s",
module, provision, key, orNothing(namesOfKeys(values)))
}
resource["content"] = strings.ReplaceAll(
content, fmt.Sprintf("${bound:%s:%s}", provision, key), value)
content = resource["content"].(string)
}
return nil
}
func namesOfBindings(known map[string]map[string]string) []string {
var names []string
for name := range known {
names = append(names, fmt.Sprintf("%q", name))
}
sort.Strings(names)
return names
}
func namesOfKeys(values map[string]string) []string {
var names []string
for key := range values {
names = append(names, fmt.Sprintf("%q", key))
}
sort.Strings(names)
return names
}
func orNothing(names []string) string {
if len(names) == 0 {
return "nothing"
}
return join(names)
}