Ask every consumer for usable configuration, not just the one in hand
The keycloak check was written while keycloak was the module being
worked on, which is how a check ends up proving one thing about one
file. It now runs over every example that requires something, and asks
the two questions that matter for all of them: that no ${bound:...}
reached the machine as a value, and that anything named PASSWORD is
still a hole only the host can fill.
The first is the one worth having. A placeholder written through is read
as a value by whatever parses the file — a connection to a host called
"${bound:postgres-database:at}" — and the failure names neither the
module nor the mesh.
Modules whose requirements nothing in the examples answers are logged
and passed over, because that is a fact about the example set rather
than about them.
This commit is contained in:
@@ -360,62 +360,105 @@ func secretsUsedForTest(content string) []string {
|
||||
return used
|
||||
}
|
||||
|
||||
// The real manifests, resolved together, produce a connection a program could use.
|
||||
// Every module that requires something produces configuration a program could use.
|
||||
//
|
||||
// **Parsing is not working, and this file has now learned that twice.** These modules parsed and
|
||||
// resolved for a day while their credentials went into files nothing could read; they would have
|
||||
// parsed and resolved just as happily with a connection string that named no user. What has to be
|
||||
// true is that the bytes reaching the machine are usable, so that is what this asks.
|
||||
func TestKeycloakGetsAConnectionAProgramCouldUse(t *testing.T) {
|
||||
// resolved for a day while their credentials went into files nothing could read; they would parse
|
||||
// and resolve just as happily with a connection string naming no user, or with a placeholder
|
||||
// written through as a hostname. What has to be true is that the bytes reaching the machine are
|
||||
// usable, so that is what this asks — of every consumer, not of the one that was being worked on.
|
||||
func TestEveryConsumerGetsConfigurationAProgramCouldUse(t *testing.T) {
|
||||
found, err := filepath.Glob("*.json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
shelf := map[string]catalogue.Manifest{}
|
||||
for _, name := range []string{"postgres.json", "keycloak.json"} {
|
||||
for _, name := range found {
|
||||
m := read(t, name)
|
||||
shelf[m.Module] = m
|
||||
}
|
||||
resolved, err := catalogue.Resolve(shelf, []string{"keycloak"},
|
||||
|
||||
var checked int
|
||||
for _, m := range shelf {
|
||||
if len(m.Requires) == 0 {
|
||||
continue
|
||||
}
|
||||
out := declareOnItsOwn(t, shelf, m)
|
||||
if out == nil {
|
||||
continue
|
||||
}
|
||||
checked++
|
||||
for _, r := range out {
|
||||
content, ok := r["content"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// A placeholder written through is read as a value by whatever parses the file — a
|
||||
// connection to a host literally called "${bound:postgres-database:at}", failing
|
||||
// somewhere that names neither the module nor the mesh.
|
||||
if strings.Contains(content, "${bound:") {
|
||||
t.Errorf("%s: %v reached the machine with a placeholder in it:\n%s",
|
||||
m.Module, r["id"], content)
|
||||
}
|
||||
// The password is the one that must survive: only the host may fill it, and only on
|
||||
// the machine. If it is gone, something composed it here.
|
||||
for _, line := range strings.Split(content, "\n") {
|
||||
if strings.Contains(line, "PASSWORD") || strings.Contains(line, "PASSWD") {
|
||||
if !strings.Contains(line, "${secret:") {
|
||||
t.Errorf("%s: %v carries %q, which is not a hole the host fills",
|
||||
m.Module, r["id"], line)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if checked == 0 {
|
||||
t.Fatal("no example requires anything, so this test proves nothing")
|
||||
}
|
||||
}
|
||||
|
||||
// declareOnItsOwn resolves one consumer against a mesh that answers everything it requires, and
|
||||
// returns what would reach the machine. Nil when its requirements cannot be answered from the
|
||||
// examples, which is not this test's business to complain about.
|
||||
func declareOnItsOwn(t *testing.T, shelf map[string]catalogue.Manifest,
|
||||
m catalogue.Manifest) []map[string]any {
|
||||
t.Helper()
|
||||
|
||||
// Everything it requires, answered from somewhere else in the mesh, with whatever the
|
||||
// providing example says it serves.
|
||||
offered := map[string][]catalogue.Provider{}
|
||||
for _, want := range m.Requires {
|
||||
serves := map[string]any{}
|
||||
for _, other := range shelf {
|
||||
if s, said := other.Serves[want]; said {
|
||||
serves = s
|
||||
}
|
||||
}
|
||||
offered[want] = []catalogue.Provider{
|
||||
{Node: "anchor", At: "anchor.internal", Serves: serves}}
|
||||
}
|
||||
resolved, err := catalogue.Resolve(shelf, []string{m.Module},
|
||||
catalogue.Node{Name: "workstation", At: "workstation.internal",
|
||||
Capabilities: map[string]bool{"container-runtime": true}},
|
||||
catalogue.World{Offered: map[string][]catalogue.Provider{
|
||||
"postgres-database": {{Node: "anchor", At: "anchor.internal",
|
||||
Serves: map[string]any{"port": float64(5432)}}},
|
||||
}})
|
||||
catalogue.World{Offered: offered})
|
||||
if err != nil {
|
||||
t.Fatalf("the real manifests do not resolve: %v", err)
|
||||
t.Logf("%s does not resolve on its own: %v", m.Module, err)
|
||||
return nil
|
||||
}
|
||||
for i := range resolved.Needs {
|
||||
resolved.Needs[i].Sealed = "sealed"
|
||||
}
|
||||
out, err := resolved.Declaration(catalogue.Rendering{
|
||||
Needed: map[string]map[string]string{"keycloak": {"admin": "sealed-admin"}},
|
||||
})
|
||||
own := map[string]map[string]string{}
|
||||
for name := range m.OwnSecrets {
|
||||
if own[m.Module] == nil {
|
||||
own[m.Module] = map[string]string{}
|
||||
}
|
||||
own[m.Module][name] = "sealed"
|
||||
}
|
||||
out, err := resolved.Declaration(catalogue.Rendering{Needed: own})
|
||||
if err != nil {
|
||||
t.Fatalf("the real manifests do not declare: %v", err)
|
||||
}
|
||||
|
||||
var env string
|
||||
for _, r := range out {
|
||||
if r["path"] == "/var/lib/keycloak/database.env" {
|
||||
env, _ = r["content"].(string)
|
||||
}
|
||||
}
|
||||
if env == "" {
|
||||
t.Fatal("keycloak was given no database configuration at all")
|
||||
}
|
||||
// Every part of a connection, and nothing left unfilled. A leftover ${...} would be read as
|
||||
// a value by whatever parses this.
|
||||
for _, wanted := range []string{
|
||||
"KC_DB_URL=jdbc:postgresql://anchor.internal:5432/keycloak",
|
||||
"KC_DB_USERNAME=mesh_workstation_keycloak",
|
||||
} {
|
||||
if !strings.Contains(env, wanted) {
|
||||
t.Errorf("the connection is missing %q:\n%s", wanted, env)
|
||||
}
|
||||
}
|
||||
if strings.Contains(env, "${bound:") {
|
||||
t.Errorf("a placeholder reached the machine as a value:\n%s", env)
|
||||
}
|
||||
// The password is the one hole that stays, because only the host may fill it.
|
||||
if !strings.Contains(env, "KC_DB_PASSWORD=${secret:postgres-database}") {
|
||||
t.Errorf("the password is not left for the host to fill:\n%s", env)
|
||||
t.Errorf("%s resolves and does not declare: %v", m.Module, err)
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user