fix: harden config loading and ssh addresses, stop resolver on API errors
- read netssh.yaml from the user config directory only, not from the working directory - refuse addresses from NetBox or the cache that are neither an IP address nor a hostname (ssh read "-oProxyCommand=…" as an option) - resolver chain stops at an API failure; only "no address" falls through to the next strategy - netssh --help and -h show netssh's help - start at most one background cache refresh per 5 minutes - validate the legacy netbox.url - page through all IP addresses of a host - CI: run format check, vet, and tests on pull requests and main - changelog for v0.0.25 Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
1 parent
6e80b733dc
commit
4287b7b650
19 files changed
+317
-30
No files matched your search
Vendored
+20
@@ -83,6 +83,26 @@ func (c *Cache) NeedsRefresh(d time.Duration) bool {
|
||||
return time.Since(t) >= d
|
||||
}
|
||||
|
||||
// ClaimRefresh reports whether a background refresh should start now: the last
|
||||
// full refresh is older than d and no attempt was claimed within retry. It
|
||||
// records the attempt, so parallel shells and repeated commands start one
|
||||
// refresh per retry interval instead of one each.
|
||||
func (c *Cache) ClaimRefresh(d, retry time.Duration) bool {
|
||||
if !c.NeedsRefresh(d) {
|
||||
return false
|
||||
}
|
||||
attempt := filepath.Join(filepath.Dir(c.refreshStamp), "refresh_attempt")
|
||||
if info, err := os.Stat(attempt); err == nil && time.Since(info.ModTime()) < retry {
|
||||
return false
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(attempt), 0o755); err != nil {
|
||||
return true // cannot record the attempt; refreshing is still right
|
||||
}
|
||||
// Best effort: two processes racing here may both refresh once.
|
||||
_ = os.WriteFile(attempt, nil, 0o600)
|
||||
return true
|
||||
}
|
||||
|
||||
// SetRefreshed records the current time as the last successful full refresh.
|
||||
func (c *Cache) SetRefreshed() error {
|
||||
if c.refreshStamp == "" {
|
||||
|
||||
Vendored
+20
@@ -557,3 +557,23 @@ func TestStaticHosts(t *testing.T) {
|
||||
t.Fatalf("removed static host still on disk:\n%s", data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClaimRefreshThrottlesAttempts(t *testing.T) {
|
||||
c := New(filepath.Join(t.TempDir(), "netssh", "hosts.json"), 60)
|
||||
if !c.ClaimRefresh(24*time.Hour, time.Minute) {
|
||||
t.Fatal("a never refreshed cache must claim a refresh")
|
||||
}
|
||||
// NetBox is down: the stamp stays stale, but the attempt is remembered.
|
||||
if c.ClaimRefresh(24*time.Hour, time.Minute) {
|
||||
t.Error("a second refresh within the retry interval must not start")
|
||||
}
|
||||
if !c.ClaimRefresh(24*time.Hour, 0) {
|
||||
t.Error("after the retry interval a refresh must start again")
|
||||
}
|
||||
if err := c.SetRefreshed(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if c.ClaimRefresh(24*time.Hour, 0) {
|
||||
t.Error("a freshly refreshed cache must not claim a refresh")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user