package catalogue import ( "strings" "testing" ) // A provision names what the consumer is coupled to (novox/hq ADR 0027). // // The fault this defends against does not look like a fault: resolution succeeds, the module // deploys, and the first query fails somewhere else entirely. Every earlier test had exactly one // provider of each name, so no mismatch was expressible and none was caught. func TestAModuleMayNotProvideAGenericDatabase(t *testing.T) { for _, hidden := range []string{"database", "db", "sql", "sql-database"} { _, err := ParseManifest([]byte(`{"module":"postgres","version":"1", "provides":[{"name":"` + hidden + `","scope":"mesh"}]}`)) if err == nil { t.Fatalf("providing %q was accepted; a requirement for it matches any engine", hidden) } for _, want := range []string{hidden, "postgres-database", "first query"} { if !strings.Contains(err.Error(), want) { t.Errorf("refusing %q did not mention %q, so nobody learns what to write:\n%v", hidden, want, err) } } } } // The rule is about coupling, not about specificity everywhere. Naming `route` after a particular // proxy would be the same error in the other direction. func TestARoleNameIsFineWhereTheConsumerCannotTellTheDifference(t *testing.T) { for _, role := range []string{"route", "resolver", "artifact-store", "postgres-database"} { if _, err := ParseManifest([]byte(`{"module":"m","version":"1", "provides":[{"name":"` + role + `","scope":"mesh"}]}`)); err != nil { t.Errorf("providing %q was refused, and it names what a consumer actually gets: %v", role, err) } } } // A module may not declare an action, and it is refused where it was written. // // The host refuses one arriving over the link, which is the bound the whole security argument // rests on (novox/hq ADR 0005) and is enforced in the right place. But a module's resources reach // a machine *over* the link, so a manifest carrying an action used to be accepted here, stored, // resolved and pushed — and then refused on the machine, in a log, with nothing tying it back to // the manifest. Enforced at the far end only is enforced and not usable. func TestAModuleMayNotDeclareAnAction(t *testing.T) { _, err := ParseManifest([]byte(`{"module":"probe","version":"1","resources":[ {"id":"migrate","type":"action","command":["/bin/true"],"verify":["/bin/true"]}]}`)) if err == nil { t.Fatal("a manifest declaring an action was accepted, and the machine would refuse it") } if !strings.Contains(err.Error(), "may not") || !strings.Contains(err.Error(), "0005") { t.Errorf("the refusal does not say what rule it is: %v", err) } // And it says what to do instead, because "you may not" without an alternative is where a // module author stops. if !strings.Contains(err.Error(), "ships a program") { t.Errorf("the refusal names no alternative: %v", err) } } // Every other shape a module may declare still passes, so the check above bounds one thing. func TestTheOtherShapesAreStillAccepted(t *testing.T) { _, err := ParseManifest([]byte(`{"module":"probe","version":"1","resources":[ {"id":"d","type":"directory","path":"/var/lib/probe","mode":"0700"}, {"id":"f","type":"file","path":"/var/lib/probe/x","content":"x\n"}, {"id":"n","type":"network","name":"probe"}, {"id":"c","type":"container","name":"probe","image":"probe@sha256:` + `0000000000000000000000000000000000000000000000000000000000000000"}]}`)) if err != nil { t.Fatalf("an ordinary manifest was refused: %v", err) } }