diff --git a/internal/provider.go b/internal/provider.go index a11acf6..6ba9da1 100644 --- a/internal/provider.go +++ b/internal/provider.go @@ -35,7 +35,7 @@ func NewHoverProvider() *HoverProvider { return &HoverProvider{} } func (p *HoverProvider) Name() string { return "hover" } func (p *HoverProvider) Version() string { return Version } -// Initialize parses provider config and eagerly authenticates with Hover. +// Initialize parses provider config and constructs a lazy Hover client. // Required keys: // // username — Hover account username / email @@ -76,12 +76,6 @@ func (p *HoverProvider) Initialize(ctx context.Context, config map[string]any) e return fmt.Errorf("hover: client init: %w", err) } - // Eager login so config errors (bad creds, MFA failure) surface at - // Configure time rather than at first Plan/Apply invocation. - if err := c.Login(ctx); err != nil { - return fmt.Errorf("hover: initial login failed: %w", err) - } - p.client = c p.drivers = map[string]interfaces.ResourceDriver{ "infra.dns": drivers.NewDNSDriver(c), diff --git a/internal/provider_test.go b/internal/provider_test.go index 8c942f8..5606450 100644 --- a/internal/provider_test.go +++ b/internal/provider_test.go @@ -1,6 +1,10 @@ package internal import ( + "context" + "errors" + "net/http" + "sync/atomic" "testing" ) @@ -22,3 +26,30 @@ func TestHoverProvider_Capabilities_IncludesDelegation(t *testing.T) { } } } + +func TestHoverProvider_Initialize_DoesNotLogin(t *testing.T) { + var hits atomic.Int32 + orig := http.DefaultTransport + http.DefaultTransport = roundTripperFunc(func(*http.Request) (*http.Response, error) { + hits.Add(1) + return nil, errors.New("unexpected network call") + }) + defer func() { http.DefaultTransport = orig }() + + p := NewHoverProvider() + if err := p.Initialize(context.Background(), map[string]any{ + "username": "user@example.com", + "password": "password", + }); err != nil { + t.Fatalf("Initialize: %v", err) + } + if got := hits.Load(); got != 0 { + t.Fatalf("Initialize made %d network calls; login should happen lazily on API operations", got) + } +} + +type roundTripperFunc func(*http.Request) (*http.Response, error) + +func (f roundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) { + return f(r) +}