diff --git a/internal/catalogue/ssh_client_test.go b/internal/catalogue/ssh_client_test.go index 7ed6b215..8981e319 100644 --- a/internal/catalogue/ssh_client_test.go +++ b/internal/catalogue/ssh_client_test.go @@ -1,10 +1,42 @@ package catalogue import ( + "io/fs" + "os" + "path/filepath" + "regexp" "strings" "testing" + + "github.com/novox/mesh-controller/internal/beside" ) +// boundKeys are every key the files of a module ask of ${bound:forge-account:}, read from the module's own +// tree on the shelf, so the test offers what ssh-client asks however often it asks one more (issue 985). +func boundKeys(t *testing.T, module, provision string) map[string]bool { + t.Helper() + ask := regexp.MustCompile(`\$\{bound:` + regexp.QuoteMeta(provision) + `:([A-Za-z0-9_.-]+)\}`) + keys := map[string]bool{} + root := filepath.Join(beside.Catalogue(t), module) + err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error { + if err != nil || d.IsDir() || strings.HasSuffix(path, "_test.go") { + return err + } + body, err := os.ReadFile(path) + if err != nil { + return err + } + for _, m := range ask.FindAllStringSubmatch(string(body), -1) { + keys[m[1]] = true + } + return nil + }) + if err != nil { + t.Fatalf("reading what %s asks of %s: %v", module, provision, err) + } + return keys +} + // The ssh-client module, composed as a machine receives it (novox/hq to-be 29, research 027/03): a // region at the START of the operator's ~/.ssh/config that includes ~/.ssh/config.d/* — first, // because ssh takes the first value it finds for each option — and the mesh's Host blocks as the @@ -15,10 +47,18 @@ func TestSSHClientOwnsTheOperatorsSSHConfig(t *testing.T) { // ssh-client requires forge-account since mesh-catalog #340 (novox/hq issue 955), answered by the forge's // holder on another node; this test is about the operator's config, so the forge is offered from there // (issue 985). + // Every key ssh-client's files ask is offered, read from them (boundKeys); a few have a realistic value. + serves := map[string]any{} + for key := range boundKeys(t, "ssh-client", "forge-account") { + serves[key] = "sample-" + key + } + for key, value := range map[string]any{"ssh_host": "marge.internal", "ssh_port": 222, + "known_host": "[marge.internal]:222 ssh-ed25519 AAAA", "ssh_base": "ssh://git@marge.internal:222/", + "https_base": "https://git.example.org/"} { + serves[key] = value + } forge := World{Offered: map[string][]Provider{ - "forge-account": {{Node: "marge", At: "marge.internal", Module: "gitea", Serves: map[string]any{ - "ssh_host": "marge.internal", "ssh_port": 222, "known_host": "[marge.internal]:222 ssh-ed25519 AAAA", - "ssh_base": "ssh://git@marge.internal:222/", "https_base": "https://git.example.org/"}}}}} + "forge-account": {{Node: "marge", At: "marge.internal", Module: "gitea", Serves: serves}}}} got, err := Resolve(shelf, []string{"ssh-client"}, Node{Name: "homer", At: "homer.internal", Account: "jo", AccountHome: "/home/jo"}, forge) if err != nil {