From f3f34a170e3fd856bbeeb24e1ac4549653fc3580 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 4 Oct 2026 12:52:03 +0200 Subject: [PATCH] Hold ssh-client to its new shape: an include region first, the mesh's hosts in config.d (mesh-catalog #266) --- internal/catalogue/ssh_client_test.go | 58 +++++++++++++++++++-------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/internal/catalogue/ssh_client_test.go b/internal/catalogue/ssh_client_test.go index 0799ab5..06ef03c 100644 --- a/internal/catalogue/ssh_client_test.go +++ b/internal/catalogue/ssh_client_test.go @@ -5,20 +5,24 @@ import ( "testing" ) -// The ssh-client module, composed as a machine receives it (novox/hq to-be 29): every other node's -// Host block written into a marked region of the operator's ~/.ssh/config, owned by the account, -// with ~/.ssh created 0700 — the operator's own config kept. +// 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 +// whole of ~/.ssh/config.d/00-mesh, every other node with its account. ~/.ssh and ~/.ssh/config.d +// are created 0700 and owned by the account; the operator's own config below the region is kept. func TestSSHClientOwnsTheOperatorsSSHConfig(t *testing.T) { shelf := shelf(catalogueManifest(t, "ssh-client")) got, err := Resolve(shelf, []string{"ssh-client"}, - Node{Name: "homer", At: "homer.internal", Account: "jo"}, World{}) + Node{Name: "homer", At: "homer.internal", Account: "jo", AccountHome: "/home/jo"}, World{}) if err != nil { t.Fatal(err) } - names := map[string]string{"homer.internal": "10.10.0.1", "marge.internal": "10.10.0.2"} + names := map[string]string{"homer.internal": "10.10.0.1", "marge.internal": "10.10.0.2", + "bart.internal": "10.10.0.3"} out, err := got.Declaration(Rendering{ - Names: names, Machines: names, Accounts: map[string]string{"homer": "jo", "marge": "jo"}, - Suffix: "internal", + Names: names, Machines: names, + Accounts: map[string]string{"homer": "jo", "marge": "jo", "bart": "op"}, + Suffix: "internal", }) if err != nil { t.Fatal(err) @@ -28,19 +32,39 @@ func TestSSHClientOwnsTheOperatorsSSHConfig(t *testing.T) { by[r["id"].(string)] = r } - dir := by["ssh-client.ssh-dir"] - if dir == nil || dir["path"] != "/home/jo/.ssh" || dir["owner"] != "jo" || dir["mode"] != "0700" { - t.Fatalf("~/.ssh is not created 0700 owned by the account: %v", dir) + for id, path := range map[string]string{ + "ssh-client.ssh-dir": "/home/jo/.ssh", "ssh-client.config-d": "/home/jo/.ssh/config.d"} { + dir := by[id] + if dir == nil || dir["type"] != "directory" || dir["path"] != path || dir["owner"] != "jo" || dir["mode"] != "0700" { + t.Fatalf("%s is not created 0700 owned by the account: %v", path, dir) + } } - cfg := by["ssh-client.fact-ssh-config"] - if cfg == nil || cfg["path"] != "/home/jo/.ssh/config" || cfg["owner"] != "jo" || cfg["into"] != "block" { - t.Fatalf("the ssh config is not written into the operator's ~/.ssh/config as a region: %v", cfg) + + cfg := by["ssh-client.config"] + if cfg == nil || cfg["path"] != "/home/jo/.ssh/config" || cfg["owner"] != "jo" || + cfg["into"] != "block" || cfg["at"] != "start" { + t.Fatalf("the mesh's region is not the first thing in the operator's ~/.ssh/config: %v", cfg) } - body := cfg["content"].(string) - if !strings.Contains(body, "Host marge marge.internal") || !strings.Contains(body, "User jo") { - t.Fatalf("the config does not name the peer node and its account:\n%s", body) + if body := cfg["content"].(string); !strings.Contains(body, "\nInclude ~/.ssh/config.d/*\n") || strings.Contains(body, "\nHost ") { + t.Fatalf("the region does not just include config.d:\n%s", body) + } + + var hosts map[string]any + for _, r := range out { + if r["path"] == "/home/jo/.ssh/config.d/00-mesh" { + hosts = r + } + } + if hosts == nil || hosts["type"] != "file" || hosts["into"] != nil { + t.Fatalf("the mesh's hosts are not the whole of ~/.ssh/config.d/00-mesh: %v", hosts) + } + body := hosts["content"].(string) + for _, want := range []string{"Host marge marge.internal", "Host bart bart.internal", "User jo", "User op"} { + if !strings.Contains(body, want) { + t.Fatalf("00-mesh does not say %q — every other node with its account:\n%s", want, body) + } } if strings.Contains(body, "Host homer ") { - t.Fatalf("the config names the machine itself, not only its peers:\n%s", body) + t.Fatalf("00-mesh names the machine itself, not only its peers:\n%s", body) } }