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
106 lines
3.6 KiB
Go
106 lines
3.6 KiB
Go
package resolution
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
mcat "git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
// aProviderWithABundle is a provider whose code is a bundle the node's runtime runs — the shape
|
|
// every TypeScript provisioner has since ADR 0198.
|
|
func aProviderWithABundle() mcat.Manifest {
|
|
return mcat.Manifest{
|
|
Module: "mongodb", Version: "1",
|
|
Provides: mcat.FromAnywhere("mongodb-database"),
|
|
Receives: map[string]string{"mongodb-database": "/var/lib/mongodb/grants/mesh.json"},
|
|
Grants: map[string]string{"mongodb-database": "/var/lib/mongodb/grants"},
|
|
Bundles: []mcat.Bundle{{Name: "code", Language: "typescript"}},
|
|
Resources: []map[string]any{{
|
|
"id": "server", "type": "container", "name": "mongodb-server",
|
|
"image": "mongo@sha256:" + strings.Repeat("a", 64),
|
|
}},
|
|
}
|
|
}
|
|
|
|
func TestAGrantSecretIsOwnedByTheAccountThatProvisions(t *testing.T) {
|
|
r, err := Resolve(shelf(aProviderWithABundle()), []string{"mongodb"}, reachable(), mcat.World{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
r.Account = "operator"
|
|
out, err := Declaration(r, mcat.Rendering{Grants: []mcat.Grant{{
|
|
Provision: "mongodb-database", Consumer: "workstation", From: "photos", Slug: "photos",
|
|
Values: map[string]any{}, Sealed: "c2VhbGVk",
|
|
}}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var secret map[string]any
|
|
for _, res := range out {
|
|
if res["type"] == "file" && strings.HasSuffix(fmtPath(res), ".secret") {
|
|
secret = res
|
|
}
|
|
}
|
|
if secret == nil {
|
|
t.Fatalf("no grant secret was composed at all: %v", out)
|
|
}
|
|
if got := secret["owner"]; got != "operator" {
|
|
t.Fatalf("the grant secret at %v belongs to %v; the provisioner runs as %q and a "+
|
|
"root-owned 0600 file is one it cannot read — which is silent, because the harness "+
|
|
"calls it \"not readable yet\"", fmtPath(secret), got, "operator")
|
|
}
|
|
// A grant whose offer presents no credential (form none, issue 1126) carries nothing sealed: no secret file is
|
|
// written for it, as none is for a need with no credential, and the provider still learns who asked.
|
|
out, err = Declaration(r, mcat.Rendering{Grants: []mcat.Grant{{
|
|
Provision: "mongodb-database", Consumer: "workstation", From: "photos", Slug: "photos", Values: map[string]any{}}}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
asked := false
|
|
for _, res := range out {
|
|
if res["type"] == "file" && strings.HasSuffix(fmtPath(res), ".secret") {
|
|
t.Errorf("a grant with no credential writes %v", res)
|
|
}
|
|
asked = asked || fmtPath(res) == "/var/lib/mongodb/grants/mesh.json"
|
|
}
|
|
if !asked {
|
|
t.Errorf("the provider no longer learns who asked: %v", out)
|
|
}
|
|
}
|
|
|
|
// And a provider whose code still runs in a container keeps the owner it declares, so this
|
|
// changes nothing for the modules the runtime has not taken.
|
|
func TestAContainerProvidersGrantSecretKeepsItsDeclaredOwner(t *testing.T) {
|
|
m := aProviderWithABundle()
|
|
m.Bundles = nil
|
|
m.SecretsOwner = "65534:65534"
|
|
r, err := Resolve(shelf(m), []string{"mongodb"}, reachable(), mcat.World{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
r.Account = "operator"
|
|
out, err := Declaration(r, mcat.Rendering{Grants: []mcat.Grant{{
|
|
Provision: "mongodb-database", Consumer: "workstation", From: "photos", Slug: "photos",
|
|
Values: map[string]any{}, Sealed: "c2VhbGVk",
|
|
}}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, res := range out {
|
|
if res["type"] == "file" && strings.HasSuffix(fmtPath(res), ".secret") {
|
|
if got := res["owner"]; got != "65534:65534" {
|
|
t.Fatalf("a container provider's grant secret belongs to %v, not what it declares", got)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
t.Fatal("no grant secret was composed")
|
|
}
|
|
|
|
func fmtPath(r map[string]any) string {
|
|
p, _ := r["path"].(string)
|
|
return p
|
|
}
|