package catalogue import ( "strings" "testing" ) // A secret family (novox/hq ADR 0283): one own secret per part the settings name, issued outside the mesh, each // given by its full name, never made by the mesh. func familyManifest(t *testing.T, ownSecrets string) (Manifest, error) { t.Helper() return ParseManifest([]byte(`{"module":"mounts","version":"1","own-secrets":{` + ownSecrets + `}}`)) } func TestAFamilyIsDeclaredIssuedOutsideWithOneStar(t *testing.T) { m, err := familyManifest(t, `"smb-password-*":{"path":"/var/lib/mounts/smb-password-*.secret","issued-by":"outside"}`) if err != nil { t.Fatalf("a well-formed family was refused: %v", err) } if got := m.OwnSecrets.Families(); len(got) != 1 || got[0] != "smb-password-*" { t.Fatalf("families: %v", got) } if len(m.OwnSecrets.Plain()) != 0 { t.Fatalf("a family counted as a secret declared by name: %v", m.OwnSecrets.Plain()) } } func TestAMalformedFamilyIsRefused(t *testing.T) { for name, c := range map[string]struct{ own, says string }{ "made by the mesh": {`"smb-password-*":{"path":"/s/smb-password-*.secret","taken":"at-start"}`, "issued-by"}, "no star in its path": {`"smb-password-*":{"path":"/s/smb-password.secret","issued-by":"outside"}`, "exactly one *"}, "two stars in its path": {`"smb-password-*":{"path":"/s/*/smb-password-*.secret","issued-by":"outside"}`, "exactly one *"}, "a star inside a name": {`"smb*password":{"path":"/s/x","issued-by":"outside"}`, "only ends a family"}, "a name that is also a member": {`"smb-password-*":{"path":"/s/p-*","issued-by":"outside"}, "smb-password-games":{"path":"/s/games","issued-by":"outside"}`, "also a member"}, } { if _, err := familyManifest(t, c.own); err == nil || !strings.Contains(err.Error(), c.says) { t.Errorf("%s: %v; want a refusal saying %q", name, err, c.says) } } } func TestAMemberIsFoundByItsFullNameAndLandsWhereTheStarIs(t *testing.T) { o := OwnSecrets{ "smb-password-*": {Path: "/s/smb-password-*.secret", IssuedBy: IssuedOutside}, "smb-password-big-*": {Path: "/big/*.secret", IssuedBy: IssuedOutside}, "token": {Path: "/s/token", IssuedBy: IssuedOutside}, } s, family, ok := o.Lookup("smb-password-games") if !ok || family != "smb-password-*" || s.Path != "/s/smb-password-games.secret" || s.IssuedBy != IssuedOutside { t.Fatalf("a member: %+v %q %v", s, family, ok) } if s, family, ok := o.Lookup("smb-password-big-one"); !ok || family != "smb-password-big-*" || s.Path != "/big/one.secret" { t.Fatalf("the longest family that fits: %+v %q %v", s, family, ok) } if s, family, ok := o.Lookup("token"); !ok || family != "" || s.Path != "/s/token" { t.Fatalf("a secret declared by name: %+v %q %v", s, family, ok) } for _, name := range []string{"smb-password-*", "smb-password-", "smb-password-../etc", "smb-password-a/b", "smb-password-a.b", "smb-password-Games", "smb-password--x", "other"} { if _, _, ok := o.Lookup(name); ok { t.Errorf("%q was found as a secret", name) } } } // A member given is one file at its path; one not given is nothing, and the machine still composes — the mesh never // makes a member. func TestAMemberGivenIsPlacedAndOneNotGivenIsNothing(t *testing.T) { m, err := familyManifest(t, `"smb-password-*":{"path":"/var/lib/mounts/smb-password-*.secret","issued-by":"outside"}`) if err != nil { t.Fatal(err) } r := Resolution{Node: "workstation", Modules: []Manifest{m}} out, err := r.Declaration(Rendering{Needed: map[string]map[string]string{"mounts": {"smb-password-games": "sealed"}}}) if err != nil { t.Fatalf("a module with one member given did not compose: %v", err) } var paths []string for _, res := range out { if res["sealed"] != nil { paths = append(paths, res["path"].(string)) } } if len(paths) != 1 || paths[0] != "/var/lib/mounts/smb-password-games.secret" { t.Fatalf("placed: %v", paths) } out, err = r.Declaration(Rendering{}) if err != nil { t.Fatalf("a module with no member given did not compose: %v", err) } for _, res := range out { if res["sealed"] != nil { t.Fatalf("a member nobody gave was placed: %v", res) } } }