package config import ( "os" "path/filepath" "reflect" "strings" "testing" ) func loadYAML(t *testing.T, data string) (*Config, error) { t.Helper() dir := t.TempDir() t.Setenv("XDG_CONFIG_HOME", dir) t.Setenv("HOME", t.TempDir()) if err := os.WriteFile(filepath.Join(dir, "netssh.yaml"), []byte(data), 0o600); err != nil { t.Fatal(err) } return Load() } func TestSSHOptionsLayering(t *testing.T) { cfg, err := loadYAML(t, ` netboxes: - name: prod url: https://prod.example.com ssh: proxy_jump: jh-prod.example.com host_key_checking: strict - name: staging url: https://staging.example.com ssh: host_key_checking: off ssh: proxy_jump: jh.example.com extra_args: ["-4"] options: ServerAliveInterval: 60 ServerAliveCountMax: 5 rules: - match: {tag: dmz} proxy_jump: jh-dmz.example.com options: {ServerAliveInterval: 10} - match: {instance: prod, name: "db*"} proxy_jump: none completion: max_results: 200 `) if err != nil { t.Fatal(err) } if cfg.Completion.MaxResults != 200 { t.Fatalf("max_results: %d", cfg.Completion.MaxResults) } for _, tc := range []struct { host SSHHost jump, keys, alive string }{ {SSHHost{Name: "web"}, "jh.example.com", "", "60"}, {SSHHost{Instance: "prod", Name: "web"}, "jh-prod.example.com", "strict", "60"}, {SSHHost{Instance: "staging", Name: "web", Tags: []string{"DMZ"}}, "jh-dmz.example.com", "off", "10"}, {SSHHost{Instance: "prod", Name: "db01", Tags: []string{"dmz"}}, "none", "strict", "10"}, } { got := cfg.SSHOptionsFor(tc.host) if got.ProxyJump != tc.jump || got.HostKeyChecking != tc.keys || got.Options["serveraliveinterval"] != tc.alive || got.Options["serveralivecountmax"] != "5" { t.Errorf("%+v: got %+v", tc.host, got) } if !reflect.DeepEqual(got.ExtraArgs, []string{"-4"}) { t.Errorf("extra args: %v", got.ExtraArgs) } } } func TestSSHOptionsValidation(t *testing.T) { for _, data := range []string{ "ssh:\n host_key_checking: maybe\n", "ssh:\n target: dns\n", "ssh:\n address_family: ipx\n", "ssh:\n proxy_jump: \"-oProxyCommand=x\"\n", "ssh:\n options:\n \"bad key\": 1\n", "ssh:\n rules:\n - proxy_jump: jh\n", "netboxes:\n - name: a\n url: https://a.example\n ssh:\n target: nope\n", } { if _, err := loadYAML(t, data); err == nil { t.Errorf("accepted invalid config:\n%s", data) } else if !strings.Contains(err.Error(), "ssh") { t.Errorf("unclear error %v", err) } } }