Files
mesh-host/internal/compose/resolution/own_secret_owner_test.go
T
jschoubben d68e241724 Take the catalogue's composition rules into the node-engine
ADR 0593 §7: the composer with its refusals leaves mesh-sdk, so mesh-sdk
carries no composition rule. The catalogue functions only the
node-engine's composition reaches (Resolve, Resolution's Compose,
Declaration, DataItems, LeftOut, Rules and the rest, the settings,
placeholder and template refusals, the rendering helpers) are copied
with their tests into internal/compose/resolution; a method of a
mesh-sdk shape becomes a function taking it first. The composition
calls its own copies, and the captured catalogue its tests read lives
here now, shared by mesh-compose's tests.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 19:15:55 +01:00

96 lines
3.8 KiB
Go

package resolution
import (
"testing"
mcat "git.novox.be/novox/mesh-sdk/go/catalogue"
)
// mailSenderManifest is the fixture every mail-sender issue builds on: the real parts of mesh-mail's manifest
// taken from mesh-catalog/modules/mesh-mail/module.json, extended as ADR 0436 §7-§8 describe, with `own` naming
// the account that owns the family's files.
func mailSenderManifest(t *testing.T, own string) mcat.Manifest {
t.Helper()
ownSecrets := `"mail-credential-*":{"path":"/var/lib/mesh-mail/mail-credential-*.secret","issued-by":"outside"`
if own != "" {
ownSecrets += `,"owner":"` + own + `"`
}
ownSecrets += `}`
m, err := decodeForTest([]byte(`{"module":"mesh-mail","version":"1","secrets-owner":"mesh-mail","own-secrets":{` +
ownSecrets + `},"resources":[{"id":"account","type":"user","name":"mesh-mail-send"}]}`))
if err != nil {
t.Fatalf("a manifest with own=%q was refused: %v", own, err)
}
return m
}
// 1170/AC1: a family owned by the module's own account lands at 0600, owned by that account — and a module's
// other own secrets (no per-secret owner declared) keep secrets-owner, unchanged.
func TestAnOwnSecretsOwnerIsGivenToItsFiles(t *testing.T) {
m := mailSenderManifest(t, "mesh-mail-send")
m.OwnSecrets["smtp-relay-key"] = mcat.OwnSecret{Path: "/var/lib/mesh-mail/smtp-relay-key", Taken: mcat.TakenAtStart}
r := mcat.Resolution{Node: "novox", Modules: []mcat.Manifest{m}}
out, err := Declaration(r, mcat.Rendering{
Needed: map[string]map[string]string{"mesh-mail": {"mail-credential-smtp": "sealed-credential", "smtp-relay-key": "sealed-relay"}},
})
if err != nil {
t.Fatalf("composing the declaration: %v", err)
}
var family, plain map[string]any
for _, res := range out {
if res["type"] != "file" {
continue
}
switch res["path"] {
case "/var/lib/mesh-mail/mail-credential-smtp.secret":
family = res
case "/var/lib/mesh-mail/smtp-relay-key":
plain = res
}
}
if family == nil {
t.Fatalf("the family member was not composed at all: %v", out)
}
if got := family["owner"]; got != "mesh-mail-send" {
t.Fatalf("the family member's owner: %v; want mesh-mail-send", got)
}
// review round 1, finding 7: asserted, not merely logged. ownedBy never sets "mode", so a sealed secret
// file carries none here either — the host applies 0600 to every one regardless (novox/hq ADR 0086) —
// and the owner clause must not have added one of its own that could override that.
if _, has := family["mode"]; has {
t.Fatalf("the family member carries its own mode %v; the owner clause must not set one, so the "+
"host's 0600 for every sealed secret file stands", family["mode"])
}
if plain == nil {
t.Fatalf("the module's other own secret was not composed at all: %v", out)
}
if got := plain["owner"]; got != "mesh-mail" {
t.Fatalf("a secret with no per-secret owner kept %v; want the module's secrets-owner %q", got, "mesh-mail")
}
}
// 1170/AC3: a manifest with no owner on any own secret composes exactly as it did before this clause existed:
// every secret file belongs to the module's secrets-owner (or nothing, when that is absent too).
func TestNoOwnerOnAnySecretComposesAsMainDoes(t *testing.T) {
m := mailSenderManifest(t, "")
r := mcat.Resolution{Node: "novox", Modules: []mcat.Manifest{m}}
out, err := Declaration(r, mcat.Rendering{
Needed: map[string]map[string]string{"mesh-mail": {"mail-credential-smtp": "sealed-credential"}},
})
if err != nil {
t.Fatalf("composing the declaration: %v", err)
}
var found bool
for _, res := range out {
if res["type"] == "file" && res["path"] == "/var/lib/mesh-mail/mail-credential-smtp.secret" {
found = true
if got := res["owner"]; got != "mesh-mail" {
t.Fatalf("with no per-secret owner declared, the file's owner: %v; want secrets-owner %q", got, "mesh-mail")
}
}
}
if !found {
t.Fatalf("the family member was not composed at all: %v", out)
}
}