package resolution import ( "strings" "testing" mcat "git.novox.be/novox/mesh-sdk/go/catalogue" ) const misspelledShell = "${shel:zsh:first}" const undeclaredSetting = "${setting:Undeclared}" const misspelledMachine = "${machnie:address}" const shellsOwn = "${XDG_CACHE_HOME:-x}" // The shell's operators after a word the mesh also uses, in any case: the shell's, and passed. const shellsOperators = "${PORT:-8080} ${SHELL:-/bin/sh} ${SECRET:?unset} ${dir:-/tmp}" // Composition refuses the same placeholders in the same words — a manifest the store already holds // was never parsed by this binary — and a namespace the mesh knows, written in a field its pass does // not read, is refused there too, because it would reach the machine as the same literal text. func TestAMisspelledPlaceholderIsRefusedAtComposition(t *testing.T) { for _, c := range []struct { field string r map[string]any token string }{ {"content", map[string]any{"id": "rc", "type": "file", "path": "/etc/speller.rc", "content": "a=" + misspelledShell + "\n"}, misspelledShell}, {"content", map[string]any{"id": "rc", "type": "file", "path": "/etc/speller.rc", "content": "b=" + undeclaredSetting + "\n"}, undeclaredSetting}, {"content", map[string]any{"id": "rc", "type": "file", "path": "/etc/speller.rc", "content": "c=" + misspelledMachine + "\n"}, misspelledMachine}, {"env.NAME", map[string]any{"id": "rc", "type": "process", "name": "speller", "env": map[string]any{"NAME": "${machine:name}"}}, "${machine:name}"}, {"content", map[string]any{"id": "rc", "type": "file", "path": "/etc/speller.rc", "content": "${Machine:address}"}, "${Machine:address}"}, {"content", map[string]any{"id": "rc", "type": "file", "path": "/etc/speller.rc", "content": "${machine:.address}"}, "${machine:.address}"}, {"content", map[string]any{"id": "rc", "type": "file", "path": "/etc/speller.rc", "content": "${machine: address}"}, "${machine: address}"}, {"content", map[string]any{"id": "rc", "type": "file", "path": "/etc/speller.rc", "content": "${Dir:x}"}, "${Dir:x}"}, {"content", map[string]any{"id": "rc", "type": "file", "path": "/etc/speller.rc", "content": "a=${machine:address\nb=1"}, "${machine:address"}, } { m := mcat.Manifest{Module: "speller", Version: "1", Resources: []map[string]any{c.r}} r := mcat.Resolution{Node: "workstation", Account: "op", Modules: []mcat.Manifest{m}} _, err := Declaration(r, mcat.Rendering{}) if err == nil || !strings.Contains(err.Error(), "speller's resource rc holds "+c.token+" in its "+c.field) { t.Errorf("%s in its %s was composed rather than refused by name: %v", c.token, c.field, err) } } m := mcat.Manifest{Module: "speller", Version: "1", Resources: []map[string]any{ {"id": "rc", "type": "file", "path": "/etc/speller.rc", "content": "d=" + shellsOwn + " " + shellsOperators + "\n"}, {"id": "server", "type": "process", "name": "server", "env": map[string]any{"PORT": "${PORT:-80}"}}, }} out, err := Declaration(mcat.Resolution{Node: "workstation", Account: "op", Modules: []mcat.Manifest{m}}, mcat.Rendering{}) if err != nil { t.Fatalf("the shell's own syntax was refused: %v", err) } if got := contentOf(t, out, "speller.rc"); got != "d="+shellsOwn+" "+shellsOperators+"\n" { t.Fatalf("the shell's own syntax did not pass through as written: %q", got) } } // contentOf is the content of the composed resource with this id, failing when it was not composed. func contentOf(t *testing.T, out []map[string]any, id string) string { t.Helper() for _, res := range out { if res["id"] == id { return plainly(res["content"]) } } t.Fatalf("%s was not composed: %v", id, out) return "" } // What a value puts into a file is its software's text, not the definition's, and is never swept // (review of mesh-controller #211): an operator's setting holding `${labels:instance}` filled through // ${setting:…}, and a JSON setting `${level:upper}` merged into a mergeable file, reach the machine as // set — software that templates its own configuration (Log4j's `${env:…}`, Spring's `${timeout:30}`) // is configured exactly this way. func TestAValueHoldingAPlaceholderShapeComposesUnchanged(t *testing.T) { m := mcat.Manifest{Module: "templater", Version: "1", Resources: []map[string]any{ {"id": "conf", "type": "file", "path": "/etc/templater.conf", "content": "template=${setting:template}\n"}, {"id": "json", "type": "file", "path": "/etc/templater.json", "merge": mcat.MergeJSON, "content": `{"fmt":"plain"}`}, }} settings := mcat.SettingsBy{"templater": {{From: "the operator", Values: map[string]any{ "template": "${labels:instance}", "fmt": "${level:upper}", }}}} out, err := Declaration(mcat.Resolution{Node: "workstation", Account: "op", Modules: []mcat.Manifest{m}}, mcat.Rendering{Settings: settings}) if err != nil { t.Fatalf("a value holding a placeholder's shape was refused as the definition's: %v", err) } if got := contentOf(t, out, "templater.conf"); got != "template=${labels:instance}\n" { t.Errorf("the setting did not reach the file as set: %q", got) } if got := contentOf(t, out, "templater.json"); !strings.Contains(got, `${level:upper}`) { t.Errorf("the merged setting did not reach the file as set: %q", got) } } // Contributed shell code is the shell's, and no pass reads it (novox/hq ADR 0204): zsh's own // `${path:t}` is namespace-shaped, and reaches the holder's file untouched. func TestContributedShellCodeIsNotSwept(t *testing.T) { modules := []mcat.Manifest{zshHolder(), {Module: "modifier", Shell: []mcat.ShellCode{ {For: "zsh", Slot: "normal", Code: "echo ${path:t} ${shel:zsh:first}"}, }}} out, err := Declaration(mcat.Resolution{Node: "workstation", Account: "op", Modules: modules}, mcat.Rendering{}) if err != nil { t.Fatalf("contributed shell code was swept: %v", err) } if got := contentOf(t, out, "zsh.zshrc"); !strings.Contains(got, "echo ${path:t} ${shel:zsh:first}") { t.Fatalf("the contributed code did not reach the holder's file as written: %q", got) } }