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
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
package resolution
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
mcat "git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
)
|
||||
|
||||
const twoSecrets = `{"module":"ca","version":"1","requires":["secret"],
|
||||
"secrets":{"secret":{"root-key":"/var/lib/ca/root.key","root-pass":"/var/lib/ca/root.pass"}},
|
||||
"resources":[{"id":"state","type":"directory","path":"/var/lib/ca","mode":"0700"}]}`
|
||||
|
||||
func vaultAndCA() map[string]mcat.Manifest {
|
||||
ca, _ := decodeForTest([]byte(twoSecrets))
|
||||
vault := mcat.Manifest{Module: "mesh-vault", Version: "1", Provides: mcat.FromAnywhere("secret"),
|
||||
Grants: map[string]string{"secret": "/var/lib/vault/grants"},
|
||||
Receives: map[string]string{"secret": "/var/lib/vault/grants/mesh.json"}}
|
||||
// A second consumer of the same provision that keeps ONE file, mentioned before the one that
|
||||
// keeps two: the lab found the expansion done on the first module to mention the provision,
|
||||
// and the second consumer given one credential and no file.
|
||||
cache := mcat.Manifest{Module: "cache", Version: "1", Requires: []string{"secret"},
|
||||
Secrets: map[string]string{"secret": "/var/lib/cache/secret"}}
|
||||
return shelf(vault, cache, ca)
|
||||
}
|
||||
|
||||
func TestEachLocalNameIsANeedAFileAndAHolderOfItsOwn(t *testing.T) {
|
||||
got, err := Resolve(vaultAndCA(), []string{"mesh-vault", "cache", "ca"}, workstation(), mcat.World{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var locals, cacheLocals []string
|
||||
for _, n := range got.Needs {
|
||||
if n.Name == "secret" && n.For == "ca" {
|
||||
locals = append(locals, n.Local)
|
||||
}
|
||||
if n.Name == "secret" && n.For == "cache" {
|
||||
cacheLocals = append(cacheLocals, n.Local)
|
||||
}
|
||||
}
|
||||
if strings.Join(locals, ",") != "root-key,root-pass" {
|
||||
t.Fatalf("two secrets from one provider are two needs: %v", got.Needs)
|
||||
}
|
||||
if len(cacheLocals) != 1 || cacheLocals[0] != "" {
|
||||
t.Fatalf("the one-file consumer keeps one need with no local name: %v", got.Needs)
|
||||
}
|
||||
for i := range got.Needs {
|
||||
got.Needs[i].Sealed = "sealed-" + got.Needs[i].Local
|
||||
}
|
||||
out, err := Declaration(got, mcat.Rendering{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
seen := map[string]string{}
|
||||
for _, r := range out {
|
||||
if r["type"] == "file" && strings.HasPrefix(r["path"].(string), "/var/lib/ca/root.") {
|
||||
seen[r["id"].(string)] = r["sealed"].(string)
|
||||
}
|
||||
}
|
||||
if seen["ca."+mcat.SecretID("root-key")] != "sealed-root-key" || seen["ca."+mcat.SecretID("root-pass")] != "sealed-root-pass" {
|
||||
t.Fatalf("each local name is its own file with its own credential: %v", seen)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAProviderSeesEachLocalNameAsAHolderOfItsOwn(t *testing.T) {
|
||||
r := mcat.Resolution{Modules: []mcat.Manifest{vaultAndCA()["mesh-vault"]}}
|
||||
got, err := resolutionContributions(r, mcat.SettingsBy{}, []mcat.Grant{
|
||||
{Provision: "secret", Consumer: "workstation", From: "ca", Local: "root-key", Sealed: "x"},
|
||||
{Provision: "secret", Consumer: "workstation", From: "ca", Local: "root-pass", Sealed: "y"},
|
||||
}, map[string]string{"secret": "/var/lib/vault/grants"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
given := got["secret"]
|
||||
if len(given) != 2 {
|
||||
t.Fatalf("two holders: %+v", given)
|
||||
}
|
||||
if given[0].As != "mesh_workstation_ca_root_key" && given[0].As != "mesh_workstation_ca_root-key" {
|
||||
t.Fatalf("the holder is the consumer's identity with the local name after it: %q", given[0].As)
|
||||
}
|
||||
if given[0].Secret == given[1].Secret {
|
||||
t.Fatalf("two holders share one file on the provider: %q", given[0].Secret)
|
||||
}
|
||||
}
|
||||
|
||||
// And on the provider's machine, two files with two ids — the lab's first run had the declaration
|
||||
// refused for two resources with one identity.
|
||||
func TestAProviderKeepsOneFilePerHolder(t *testing.T) {
|
||||
got, err := Resolve(vaultAndCA(), []string{"mesh-vault", "cache", "ca"}, workstation(), mcat.World{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
out, err := Declaration(got, mcat.Rendering{Grants: []mcat.Grant{
|
||||
{Provision: "secret", Consumer: "workstation", From: "ca", Local: "root-key", Sealed: "x"},
|
||||
{Provision: "secret", Consumer: "workstation", From: "ca", Local: "root-pass", Sealed: "y"},
|
||||
}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ids := map[string]string{}
|
||||
for _, r := range out {
|
||||
if id, _ := r["id"].(string); strings.Contains(id, "grant-secret") {
|
||||
ids[id] = r["path"].(string)
|
||||
}
|
||||
}
|
||||
if len(ids) != 2 {
|
||||
t.Fatalf("two holders are two grant files: %v", ids)
|
||||
}
|
||||
}
|
||||
|
||||
// One file under a local name is still a local name (review C1): the need carries it, the file
|
||||
// is written, and ${secret:<name>} is filled.
|
||||
func TestOneLocalNameIsStillALocalName(t *testing.T) {
|
||||
only, _ := decodeForTest([]byte(`{"module":"one","version":"1","requires":["secret"],
|
||||
"secrets":{"secret":{"only":"/var/lib/one/only"}}}`))
|
||||
vault := vaultAndCA()["mesh-vault"]
|
||||
got, err := Resolve(shelf(vault, only), []string{"mesh-vault", "one"}, workstation(), mcat.World{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var found *mcat.Needed
|
||||
for i, n := range got.Needs {
|
||||
if n.For == "one" && n.Name == "secret" {
|
||||
found = &got.Needs[i]
|
||||
}
|
||||
}
|
||||
if found == nil || found.Local != "only" {
|
||||
t.Fatalf("the one named file did not become a need under its name: %v", got.Needs)
|
||||
}
|
||||
found.Sealed = "sealed-only"
|
||||
out, err := Declaration(got, mcat.Rendering{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var written bool
|
||||
for _, r := range out {
|
||||
if r["path"] == "/var/lib/one/only" && r["sealed"] == "sealed-only" {
|
||||
written = true
|
||||
}
|
||||
}
|
||||
if !written {
|
||||
t.Fatal("the file under the one local name was not written")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user