diff --git a/pkg/connector/provider/registry.go b/pkg/connector/provider/registry.go index d0f2daf79..b2c32444a 100644 --- a/pkg/connector/provider/registry.go +++ b/pkg/connector/provider/registry.go @@ -93,6 +93,14 @@ func (r *Registry) Register(reg *Registration) error { return fmt.Errorf("cannot register connector provider %q: APIKeyBasicAuth, APIKeyHeader, and APIKeyAuthScheme are mutually exclusive", reg.Provider) } + // BuildTokenURLForDomain and BuildTokenURLForSite both build the token + // endpoint host, but from different sources (a callback param vs. the + // signed state). CompleteWithState checks them in order, so setting both + // is a programmer error with a silent winner. Reject it at startup. + if reg.BuildTokenURLForDomain != nil && reg.BuildTokenURLForSite != nil { + return fmt.Errorf("cannot register connector provider %q: BuildTokenURLForDomain and BuildTokenURLForSite are mutually exclusive", reg.Provider) + } + r.mu.Lock() defer r.mu.Unlock() diff --git a/pkg/connector/provider/registry_test.go b/pkg/connector/provider/registry_test.go index 3fb2b486b..672ca1c9c 100644 --- a/pkg/connector/provider/registry_test.go +++ b/pkg/connector/provider/registry_test.go @@ -109,6 +109,20 @@ func TestRegistry_Register(t *testing.T) { assert.Contains(t, err.Error(), "mutually exclusive") }) + t.Run("BuildTokenURLForDomain and BuildTokenURLForSite mutually exclusive", func(t *testing.T) { + t.Parallel() + + r := provider.NewRegistry() + err := r.Register(&provider.Registration{ + Provider: coredata.ConnectorProviderSlack, + DisplayName: "Slack", + BuildTokenURLForDomain: func(string) (string, error) { return "", nil }, + BuildTokenURLForSite: func(string) (string, error) { return "", nil }, + }) + require.Error(t, err) + assert.Contains(t, err.Error(), "mutually exclusive") + }) + t.Run("duplicate registration", func(t *testing.T) { t.Parallel()