package resolution import ( "strings" "testing" mcat "git.novox.be/novox/mesh-sdk/go/catalogue" ) func outsideManifest(t *testing.T) mcat.Manifest { t.Helper() m, err := decodeForTest([]byte(`{"module":"assistant","version":"1", "own-secrets":{ "password":{"path":"/var/lib/assistant/password.secret","taken":"at-start"}, "vendor-key":{"path":"/var/lib/assistant/vendor-key.secret","taken":"at-start","issued-by":"outside"}}, "resources":[ {"id":"env","type":"file","path":"/var/lib/assistant/env","mode":"0600", "content":"PASSWORD=${secret:password}\nVENDOR_KEY=${secret:vendor-key}\n"}, {"id":"server","type":"container","name":"assistant","image":"assistant:1", "env-file":["/var/lib/assistant/env"], "volumes":["/var/lib/assistant/vendor-key.secret:/run/vendor-key:ro"], "secrets-in-environment":"reads its settings from the environment only"}]}`)) if err != nil { t.Fatal(err) } return m } func resourceAt(out []map[string]any, path string) map[string]any { for _, r := range out { if r["path"] == path { return r } } return nil } func resourceNamed(out []map[string]any, name string) map[string]any { for _, r := range out { if r["name"] == name { return r } } return nil } func TestAnOutsideSecretNotGivenIsNoFileAndAFileNamingItSaysEmpty(t *testing.T) { r := mcat.Resolution{Node: "server", Modules: []mcat.Manifest{outsideManifest(t)}} out, err := Declaration(r, mcat.Rendering{Needed: map[string]map[string]string{"assistant": {"password": "sealed-password"}}}) if err != nil { t.Fatalf("a module whose outside secret nobody gave did not compose: %v", err) } if got := resourceAt(out, "/var/lib/assistant/vendor-key.secret"); got != nil { t.Fatalf("a secret nobody gave was placed: %v", got) } env := resourceAt(out, "/var/lib/assistant/env") if env == nil { t.Fatal("the module's own file is not composed") } if content := env["content"].(string); content != "PASSWORD=${secret:password}\nVENDOR_KEY=\n" { t.Fatalf("the file names the secret nobody gave as %q", content) } secrets, _ := env["secrets"].(map[string]any) if len(secrets) != 1 || secrets["password"] != "sealed-password" { t.Fatalf("the file is filled from %v", secrets) } server := resourceNamed(out, "assistant") if on := strings.Join(stringsIn(server["restart-on"]), " "); strings.Contains(on, "vendor-key") { t.Fatalf("the container restarts on a secret nobody gave: %q", on) } } func TestAnOutsideSecretGivenIsPlacedAndFilled(t *testing.T) { r := mcat.Resolution{Node: "server", Modules: []mcat.Manifest{outsideManifest(t)}} out, err := Declaration(r, mcat.Rendering{Needed: map[string]map[string]string{"assistant": { "password": "sealed-password", "vendor-key": "sealed-vendor-key"}}}) if err != nil { t.Fatal(err) } placed := resourceAt(out, "/var/lib/assistant/vendor-key.secret") if placed == nil || placed["sealed"] != "sealed-vendor-key" { t.Fatalf("the secret given is placed as %v", placed) } env := resourceAt(out, "/var/lib/assistant/env") if content := env["content"].(string); content != "PASSWORD=${secret:password}\nVENDOR_KEY=${secret:vendor-key}\n" { t.Fatalf("the file was changed: %q", content) } if secrets, _ := env["secrets"].(map[string]any); secrets["vendor-key"] != "sealed-vendor-key" { t.Fatalf("the file is filled from %v", secrets) } server := resourceNamed(out, "assistant") if on := strings.Join(stringsIn(server["restart-on"]), " "); !strings.Contains(on, "assistant."+mcat.NeedID("vendor-key")) { t.Fatalf("the container does not restart on the secret given: %q", on) } } // A secret the mesh makes is still refused when it was not made: only an outside one is left out. func TestAnOwnSecretTheMeshMakesIsStillRefusedWhenNotMade(t *testing.T) { r := mcat.Resolution{Node: "server", Modules: []mcat.Manifest{outsideManifest(t)}} _, err := Declaration(r, mcat.Rendering{}) if nm, ok := err.(*NotMadeError); !ok || nm.Name != "password" { t.Fatalf("a secret the mesh makes, not made: %v", err) } }