package main import ( "os" "path/filepath" "testing" ) func manifest(t *testing.T, root, module, resources string) { t.Helper() dir := filepath.Join(root, "modules", module) if err := os.MkdirAll(dir, 0o755); err != nil { t.Fatal(err) } body := `{"module":"` + module + `","resources":[` + resources + `]}` if err := os.WriteFile(filepath.Join(dir, "module.json"), []byte(body), 0o644); err != nil { t.Fatal(err) } } func TestASecretASettingCouldReplaceIsRefused(t *testing.T) { root := t.TempDir() // Refused: the key holds the vault's secret and nothing keeps a layer off it. manifest(t, root, "a", `{"id":"cfg","type":"file","merge":"json","content":"{\"password\": \"${secret:admin}\"}"}`) // Refused: nested below a key the file takes. manifest(t, root, "b", `{"id":"cfg","type":"file","merge":"json","takes-settings":["server"],`+ `"content":"{\"server\": {\"secret_key\": \"${secret:s}\", \"port\": 1}}"}`) // Kept: protected. manifest(t, root, "c", `{"id":"cfg","type":"file","merge":"json","protected":["password"],`+ `"content":"{\"password\": \"${secret:admin}\", \"user\": \"admin\"}"}`) // Kept: the file names its keys, and not this one. manifest(t, root, "d", `{"id":"cfg","type":"file","merge":"json","takes-settings":["ui"],`+ `"content":"{\"token\": \"${secret:t}\", \"ui\": {}}"}`) // Kept: a file that does not merge takes no setting. manifest(t, root, "e", `{"id":"cfg","type":"file","content":"{\"token\": \"${secret:t}\"}"}`) // Refused: protecting another key does not protect this one; a list element counts too. manifest(t, root, "f", `{"id":"cfg","type":"file","merge":"json","protected":["user"],`+ `"content":"{\"users\": [{\"password\": \"${secret:p}\"}]}"}`) found, err := Check(root) if err != nil { t.Fatal(err) } want := []string{"a cfg password", "b cfg server.secret_key", "f cfg users[0].password"} if len(found) != len(want) { t.Fatalf("found %v, want %v", found, want) } for i, f := range found { if f.String() != want[i] { t.Fatalf("found %v, want %v", found, want) } } } func TestTheKnownListOnlyShrinks(t *testing.T) { found := []Finding{{"b", "cfg", "server.secret_key"}, {"a", "cfg", "password"}} refused, stale := Judge(found, map[string]bool{"b cfg server.secret_key": true, "gone cfg token": true}) if len(refused) != 1 || refused[0].String() != "a cfg password" { t.Fatalf("refused %v", refused) } if len(stale) != 1 || stale[0] != "gone cfg token" { t.Fatalf("stale %v", stale) } } func TestTheCatalogueHoldsNoSecretASettingCouldReplace(t *testing.T) { found, err := Check("../..") if err != nil { t.Fatal(err) } known, err := Known("known") if err != nil { t.Fatal(err) } refused, stale := Judge(found, known) if len(refused) > 0 || len(stale) > 0 { t.Fatalf("refused %v, stale %v", refused, stale) } } func TestALineTheTrunkDoesNotHoldIsRefused(t *testing.T) { trunk := map[string]bool{"b cfg server.secret_key": true} // A key unprotected on the branch, and its line added to the list: refused, though it matches a finding. branch := map[string]bool{"b cfg server.secret_key": true, "a cfg password": true} if added := Added(branch, trunk); len(added) != 1 || added[0] != "a cfg password" { t.Fatalf("added %v", added) } // A line removed is no addition. if added := Added(map[string]bool{}, trunk); len(added) != 0 { t.Fatalf("added %v", added) } // Until the trunk holds a copy, the seed stands for it, and the list as committed is within it. known, err := Known("known") if err != nil { t.Fatal(err) } if added := Added(known, seed); len(added) != 0 { t.Fatalf("known holds lines the seed does not: %v", added) } } func TestTheCheckRefusesALineAddedAgainstTheTrunk(t *testing.T) { root := t.TempDir() manifest(t, root, "a", `{"id":"cfg","type":"file","merge":"json","content":"{\"password\": \"${secret:admin}\"}"}`) dir := t.TempDir() base := filepath.Join(dir, "base") if err := os.WriteFile(base, []byte("# the trunk's\n"), 0o644); err != nil { t.Fatal(err) } branch := map[string]bool{"a cfg password": true} found, err := Check(root) if err != nil { t.Fatal(err) } trunk, err := Known(base) if err != nil { t.Fatal(err) } refused, stale := Judge(found, branch) if len(refused) != 0 || len(stale) != 0 { t.Fatalf("the line hides the finding from Judge alone: %v %v", refused, stale) } if added := Added(branch, trunk); len(added) != 1 { t.Fatalf("an added line passed: %v", added) } }