feat(configure): edit every config option in the configurator
After the NetBox instances, netssh configure now opens a menu with all sections: SSH defaults, global SSH options (jump host, host key checking, target, address family, extra args, -o options), SSH rules, resolver & cache (including the cache file), shortcuts & command alias, and completion.max_results. SSH options can also be set per instance. The wizard rebuilt the config from its own fields, so re-running it dropped global SSH options, ssh.rules and completion.max_results from the file. It now edits a copy of the loaded config, and save validates SSH options and rules before writing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ac713ac97b
commit
d51c040d9f
8 files changed
+630
-174
No files matched your search
@@ -455,3 +455,46 @@ func TestSaveKeepsSSHOptions(t *testing.T) {
|
||||
t.Fatalf("ssh settings lost:\n%+v\n%+v", loaded.SSH, loaded.NetBoxes[0].SSH)
|
||||
}
|
||||
}
|
||||
|
||||
// Re-running the configurator must keep settings that have no form field of
|
||||
// their own or were not touched in the menu.
|
||||
func TestPrepareKeepsUnmanagedSettings(t *testing.T) {
|
||||
cfg := config.Config{
|
||||
NetBox: config.NetBoxConfig{URL: "https://legacy.example", Token: "t"},
|
||||
SSH: config.SSHConfig{
|
||||
DefaultUser: "root",
|
||||
SSHOptions: config.SSHOptions{ProxyJump: "jh.example.com", Options: map[string]string{"forwardagent": "yes"}},
|
||||
Rules: []config.SSHRule{{Match: config.SSHMatch{Tag: "dmz"}, SSHOptions: config.SSHOptions{ProxyJump: "none"}}},
|
||||
},
|
||||
Completion: config.CompletionConfig{MaxResults: 50},
|
||||
Cache: config.CacheConfig{Path: "/var/cache/netssh/hosts.json"},
|
||||
}
|
||||
sources := []config.NetBoxConfig{{Name: "default", URL: "https://legacy.example", Token: "t"}}
|
||||
got := prepare(cfg, sources)
|
||||
|
||||
if !reflect.DeepEqual(got.SSH, cfg.SSH) || got.Completion != cfg.Completion || got.Cache.Path != cfg.Cache.Path {
|
||||
t.Fatalf("settings lost: %+v", got)
|
||||
}
|
||||
if got.NetBox.URL != "" || !reflect.DeepEqual(got.NetBoxes, sources) {
|
||||
t.Fatalf("legacy instance not migrated: %+v / %+v", got.NetBox, got.NetBoxes)
|
||||
}
|
||||
if !reflect.DeepEqual(got.Resolver.Strategies, []string{"primary_ip"}) || got.Cache.TTL != 3600 {
|
||||
t.Fatalf("defaults missing: %+v %+v", got.Resolver, got.Cache)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveRejectsInvalidSSHOptions(t *testing.T) {
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
cfg := config.Config{
|
||||
NetBoxes: []config.NetBoxConfig{{Name: "prod", URL: "https://prod.example", Token: "t"}},
|
||||
Resolver: config.ResolverConfig{Strategies: []string{"primary_ip"}},
|
||||
SSH: config.SSHConfig{Rules: []config.SSHRule{{SSHOptions: config.SSHOptions{ProxyJump: "none"}}}},
|
||||
}
|
||||
if err := save(cfg); err == nil {
|
||||
t.Fatal("rule without match was saved")
|
||||
}
|
||||
if _, err := os.Stat(config.Path()); !os.IsNotExist(err) {
|
||||
t.Fatalf("config file written despite error: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user