Registration.ExtraSettings was a single flat list, but the API-key and client-credentials connect dialogs need different fields whenever a provider offers both paths, because a different create resolver and a different driver sits behind each. Replace it with APIKeyExtraSettings and ClientCredentialsExtraSettings, and split the GraphQL surface to match so a client cannot render one path's settings on the other. This fixes two connectors that could not be connected at all. 1Password declared accountId and region only, which are the client-credentials shape. The API-key dialog therefore rendered those two fields, mapAPIKeyExtraSettingToField returned nil for both so buildExtraFields discarded them, and the SCIM-bridge driver failed on an empty SCIMBridgeURL. The console already mapped scimBridgeUrl, but no registration declared that key, so the branch was dead. It now declares scimBridgeUrl on the API-key path and accountId + region on client credentials. Langfuse declared baseUrl as required, but mapAPIKeyExtraSettingToField had no LANGFUSE case, so buildExtraFields dropped the value the customer typed and the mutation failed with "langfuseBaseUrl is required". Every other extra-settings provider had a case. The GraphQL input field, the settings struct, the probe builder and the driver were all already correct; only the console mapping was missing. buildExtraFields now takes the settings list explicitly instead of reading it off the provider, so each dialog passes its own path's list and cannot silently iterate the other one. Register rejects a settings list for a path the provider does not offer, and an empty or duplicate setting key within one list. A key repeated across the two lists is allowed: that is how a dual-path provider declares a setting both dialogs need. The new resolver tests walk the whole chain the console walks, from the key a Registration declares through the mutation input field to the persisted settings struct, so a key renamed on one side and not the other fails in CI instead of at connect time. Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
517 lines
18 KiB
Go
517 lines
18 KiB
Go
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
|
|
package provider_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.probo.inc/probo/pkg/connector"
|
|
"go.probo.inc/probo/pkg/connector/provider"
|
|
"go.probo.inc/probo/pkg/coredata"
|
|
)
|
|
|
|
// TestEveryProviderRegistered asserts that every
|
|
// coredata.ConnectorProvider constant has a matching Registration in
|
|
// the registry, that the registration carries the minimum metadata
|
|
// (Provider, DisplayName), and that the access-review NewDriver
|
|
// closure is wired — so the provider can actually drive a review.
|
|
func TestEveryProviderRegistered(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewBuiltinRegistry()
|
|
|
|
for _, p := range coredata.ConnectorProviders() {
|
|
t.Run(string(p), func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
reg, ok := r.Get(p)
|
|
require.Truef(t, ok, "provider %q has no Registration", p)
|
|
require.NotNil(t, reg, "provider %q Registration is nil", p)
|
|
require.Equalf(t, p, reg.Provider, "provider %q has mismatching Registration.Provider", p)
|
|
assert.NotEmptyf(t, reg.DisplayName, "provider %q has empty DisplayName", p)
|
|
assert.NotNilf(t, reg.NewDriver, "provider %q has nil NewDriver", p)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestEveryProviderSettingsReachADialog asserts that every builtin
|
|
// registration declares its extra settings on a connect path it actually
|
|
// offers. A list on an unoffered path is a dead declaration: no dialog reads
|
|
// it, so the settings never reach the create mutation and the connect attempt
|
|
// fails on a field the customer was never asked for. Register rejects the same
|
|
// condition at startup; this pins it per provider so the failure names the
|
|
// offender rather than panicking inside NewBuiltinRegistry.
|
|
func TestEveryProviderSettingsReachADialog(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewBuiltinRegistry()
|
|
|
|
for _, reg := range r.All() {
|
|
t.Run(string(reg.Provider), func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if len(reg.APIKeyExtraSettings) > 0 {
|
|
assert.Truef(
|
|
t,
|
|
reg.SupportsAPIKey || reg.ManagedAPIKey,
|
|
"provider %q declares APIKeyExtraSettings but offers no API-key path",
|
|
reg.Provider,
|
|
)
|
|
}
|
|
|
|
if len(reg.ClientCredentialsExtraSettings) > 0 {
|
|
assert.Truef(
|
|
t,
|
|
reg.SupportsClientCredentials,
|
|
"provider %q declares ClientCredentialsExtraSettings but offers no client-credentials path",
|
|
reg.Provider,
|
|
)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestRegistry_Register exercises the validation and duplicate-detection
|
|
// paths on Register. Programmer errors at NewBuiltinRegistry time —
|
|
// nil, empty Provider, empty DisplayName, duplicate — must all surface
|
|
// as errors rather than silently registering a malformed entry.
|
|
func TestRegistry_Register(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("nil Registration", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
err := r.Register(nil)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "nil Registration")
|
|
})
|
|
|
|
t.Run("empty Provider", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
err := r.Register(&provider.Registration{DisplayName: "X"})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "missing Provider")
|
|
})
|
|
|
|
t.Run("empty DisplayName", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
err := r.Register(&provider.Registration{Provider: coredata.ConnectorProviderSlack})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "missing DisplayName")
|
|
})
|
|
|
|
t.Run("APIKeyBasicAuth and APIKeyHeader mutually exclusive", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
err := r.Register(&provider.Registration{
|
|
Provider: coredata.ConnectorProviderSlack,
|
|
DisplayName: "Slack",
|
|
APIKeyBasicAuth: true,
|
|
APIKeyHeader: "x-api-key",
|
|
})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "mutually exclusive")
|
|
})
|
|
|
|
t.Run("APIKeyAuthScheme and APIKeyHeader mutually exclusive", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
err := r.Register(&provider.Registration{
|
|
Provider: coredata.ConnectorProviderSlack,
|
|
DisplayName: "Slack",
|
|
APIKeyAuthScheme: "SSWS",
|
|
APIKeyHeader: "x-api-key",
|
|
})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "mutually exclusive")
|
|
})
|
|
|
|
t.Run("APIKeyBasicAuthUserPass and APIKeyHeader mutually exclusive", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
err := r.Register(&provider.Registration{
|
|
Provider: coredata.ConnectorProviderSlack,
|
|
DisplayName: "Slack",
|
|
APIKeyBasicAuthUserPass: true,
|
|
APIKeyHeader: "x-api-key",
|
|
})
|
|
require.Error(t, err)
|
|
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("APIKeyExtraSettings requires an API-key path", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
err := r.Register(&provider.Registration{
|
|
Provider: coredata.ConnectorProviderSlack,
|
|
DisplayName: "Slack",
|
|
APIKeyExtraSettings: []provider.ExtraSetting{{Key: "baseUrl", Label: "Base URL"}},
|
|
})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "APIKeyExtraSettings requires SupportsAPIKey or ManagedAPIKey")
|
|
})
|
|
|
|
// A ManagedAPIKey provider (Crisp) collects settings without a customer
|
|
// key, so its API-key list is legitimate even with SupportsAPIKey false.
|
|
t.Run("APIKeyExtraSettings accepted on a ManagedAPIKey provider", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
err := r.Register(&provider.Registration{
|
|
Provider: coredata.ConnectorProviderSlack,
|
|
DisplayName: "Slack",
|
|
ManagedAPIKey: true,
|
|
APIKeyExtraSettings: []provider.ExtraSetting{{Key: "websiteId", Label: "Website ID"}},
|
|
})
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("ClientCredentialsExtraSettings requires SupportsClientCredentials", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
err := r.Register(&provider.Registration{
|
|
Provider: coredata.ConnectorProviderSlack,
|
|
DisplayName: "Slack",
|
|
SupportsAPIKey: true,
|
|
ClientCredentialsExtraSettings: []provider.ExtraSetting{{Key: "region", Label: "Region"}},
|
|
})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "ClientCredentialsExtraSettings requires SupportsClientCredentials")
|
|
})
|
|
|
|
t.Run("duplicate setting key within one list", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
err := r.Register(&provider.Registration{
|
|
Provider: coredata.ConnectorProviderSlack,
|
|
DisplayName: "Slack",
|
|
SupportsAPIKey: true,
|
|
APIKeyExtraSettings: []provider.ExtraSetting{
|
|
{Key: "region", Label: "Region"},
|
|
{Key: "region", Label: "Region (again)"},
|
|
},
|
|
})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), `APIKeyExtraSettings declares duplicate setting key "region"`)
|
|
})
|
|
|
|
// One setting both dialogs need is declared in both lists; that is not a
|
|
// duplicate, because each list keys a separate form.
|
|
t.Run("setting key repeated across the two lists", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
err := r.Register(&provider.Registration{
|
|
Provider: coredata.ConnectorProviderSlack,
|
|
DisplayName: "Slack",
|
|
SupportsAPIKey: true,
|
|
SupportsClientCredentials: true,
|
|
APIKeyExtraSettings: []provider.ExtraSetting{{Key: "region", Label: "Region"}},
|
|
ClientCredentialsExtraSettings: []provider.ExtraSetting{{Key: "region", Label: "Region"}},
|
|
})
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("setting with an empty Key", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
err := r.Register(&provider.Registration{
|
|
Provider: coredata.ConnectorProviderSlack,
|
|
DisplayName: "Slack",
|
|
SupportsAPIKey: true,
|
|
APIKeyExtraSettings: []provider.ExtraSetting{{Label: "Region"}},
|
|
})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "APIKeyExtraSettings declares a setting with an empty Key or Label")
|
|
})
|
|
|
|
t.Run("setting with an empty Label", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
err := r.Register(&provider.Registration{
|
|
Provider: coredata.ConnectorProviderSlack,
|
|
DisplayName: "Slack",
|
|
SupportsClientCredentials: true,
|
|
ClientCredentialsExtraSettings: []provider.ExtraSetting{{Key: "region"}},
|
|
})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "ClientCredentialsExtraSettings declares a setting with an empty Key or Label")
|
|
})
|
|
|
|
t.Run("RequiresManagedResourceID requires ManagedAPIKey", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
err := r.Register(&provider.Registration{
|
|
Provider: coredata.ConnectorProviderSlack,
|
|
DisplayName: "Slack",
|
|
RequiresManagedResourceID: true,
|
|
})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "RequiresManagedResourceID requires ManagedAPIKey")
|
|
})
|
|
|
|
t.Run("duplicate registration", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
require.NoError(t, r.Register(&provider.Registration{
|
|
Provider: coredata.ConnectorProviderSlack,
|
|
DisplayName: "Slack",
|
|
}))
|
|
err := r.Register(&provider.Registration{
|
|
Provider: coredata.ConnectorProviderSlack,
|
|
DisplayName: "Slack-bis",
|
|
})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "duplicate registration")
|
|
})
|
|
|
|
t.Run("valid Registration round-trips through Get", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
want := &provider.Registration{
|
|
Provider: coredata.ConnectorProviderSlack,
|
|
DisplayName: "Slack",
|
|
}
|
|
require.NoError(t, r.Register(want))
|
|
|
|
got, ok := r.Get(coredata.ConnectorProviderSlack)
|
|
require.True(t, ok)
|
|
assert.Same(t, want, got)
|
|
})
|
|
}
|
|
|
|
// TestRegistry_All asserts the registry returns the same number of
|
|
// entries that have been registered. The builtin registry is the
|
|
// canonical source of truth: every coredata.ConnectorProvider has
|
|
// exactly one matching Registration, no more.
|
|
func TestRegistry_All(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewBuiltinRegistry()
|
|
assert.Len(t, r.All(), len(coredata.ConnectorProviders()))
|
|
}
|
|
|
|
// TestRegistry_ProviderDisplayName covers the fallback path: an
|
|
// unregistered provider returns its raw constant string.
|
|
func TestRegistry_ProviderDisplayName(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewBuiltinRegistry()
|
|
assert.Equal(t, "Slack", r.ProviderDisplayName(coredata.ConnectorProviderSlack))
|
|
assert.Equal(t, "UNKNOWN", r.ProviderDisplayName(coredata.ConnectorProvider("UNKNOWN")))
|
|
}
|
|
|
|
// TestRegistry_ProviderOAuth2Scopes covers the nil path for an
|
|
// unregistered provider and the populated path for a registered one.
|
|
func TestRegistry_ProviderOAuth2Scopes(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewBuiltinRegistry()
|
|
assert.NotEmpty(t, r.ProviderOAuth2Scopes(coredata.ConnectorProviderSlack))
|
|
assert.Nil(t, r.ProviderOAuth2Scopes(coredata.ConnectorProvider("UNKNOWN")))
|
|
}
|
|
|
|
// TestRegistry_ProbeURL covers the registered and unregistered paths.
|
|
// Slack ships a probe URL in its Registration; an unknown provider
|
|
// returns the empty string.
|
|
func TestRegistry_ProbeURL(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewBuiltinRegistry()
|
|
assert.NotEmpty(t, r.ProbeURL("SLACK"))
|
|
assert.Empty(t, r.ProbeURL("UNKNOWN"))
|
|
}
|
|
|
|
// TestRegistry_ManagedAPIKey covers the deactivated default (no key
|
|
// configured), a configured key, and that an empty key is a no-op so
|
|
// the provider stays deactivated.
|
|
func TestRegistry_ManagedAPIKey(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
|
|
key, ok := r.ManagedAPIKey(coredata.ConnectorProviderCrisp)
|
|
assert.False(t, ok)
|
|
assert.Empty(t, key)
|
|
|
|
r.SetManagedAPIKey(coredata.ConnectorProviderCrisp, "")
|
|
_, ok = r.ManagedAPIKey(coredata.ConnectorProviderCrisp)
|
|
assert.False(t, ok, "empty key must not configure the provider")
|
|
|
|
r.SetManagedAPIKey(coredata.ConnectorProviderCrisp, "identifier:secret")
|
|
key, ok = r.ManagedAPIKey(coredata.ConnectorProviderCrisp)
|
|
assert.True(t, ok)
|
|
assert.Equal(t, "identifier:secret", key)
|
|
}
|
|
|
|
func TestRegistry_ManagedResourceID(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
|
|
id, ok := r.ManagedResourceID(coredata.ConnectorProviderCrisp)
|
|
assert.False(t, ok)
|
|
assert.Empty(t, id)
|
|
|
|
r.SetManagedResourceID(coredata.ConnectorProviderCrisp, "")
|
|
_, ok = r.ManagedResourceID(coredata.ConnectorProviderCrisp)
|
|
assert.False(t, ok, "empty resource id must not configure the provider")
|
|
|
|
r.SetManagedResourceID(coredata.ConnectorProviderCrisp, "plugin-id")
|
|
id, ok = r.ManagedResourceID(coredata.ConnectorProviderCrisp)
|
|
assert.True(t, ok)
|
|
assert.Equal(t, "plugin-id", id)
|
|
}
|
|
|
|
// TestCrispIsManagedAPIKey pins Crisp's Model B shape: it is a managed
|
|
// API-key provider that does not accept a customer-pasted key, so the
|
|
// driver catalog hides it until the operator configures the plugin
|
|
// token.
|
|
func TestCrispIsManagedAPIKey(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewBuiltinRegistry()
|
|
reg, ok := r.Get(coredata.ConnectorProviderCrisp)
|
|
require.True(t, ok)
|
|
assert.True(t, reg.ManagedAPIKey)
|
|
assert.False(t, reg.SupportsAPIKey)
|
|
assert.True(t, reg.APIKeyBasicAuthUserPass)
|
|
assert.True(t, reg.RequiresManagedResourceID, "crisp needs the plugin ID before it can connect")
|
|
}
|
|
|
|
// TestRegistry_ManagedConnectorReady pins that a provider requiring a resource
|
|
// ID (Crisp's plugin ID) is reported ready, and thus surfaced in the catalog,
|
|
// only once BOTH the managed key and the resource ID are configured.
|
|
func TestRegistry_ManagedConnectorReady(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("crisp needs both key and resource id", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewBuiltinRegistry()
|
|
assert.False(t, r.ManagedConnectorReady(coredata.ConnectorProviderCrisp), "unconfigured")
|
|
|
|
r.SetManagedAPIKey(coredata.ConnectorProviderCrisp, "identifier:secret")
|
|
assert.False(t, r.ManagedConnectorReady(coredata.ConnectorProviderCrisp), "key set but plugin id missing")
|
|
|
|
r.SetManagedResourceID(coredata.ConnectorProviderCrisp, "plugin-id")
|
|
assert.True(t, r.ManagedConnectorReady(coredata.ConnectorProviderCrisp), "key and plugin id set")
|
|
})
|
|
|
|
t.Run("non-managed provider is never ready", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewBuiltinRegistry()
|
|
r.SetManagedAPIKey(coredata.ConnectorProviderTally, "some-key")
|
|
assert.False(t, r.ManagedConnectorReady(coredata.ConnectorProviderTally))
|
|
})
|
|
}
|
|
|
|
// TestRegistry_RejectsManagedPlusCustomerCredential pins that a
|
|
// ManagedAPIKey registration cannot also advertise a customer-supplied
|
|
// credential path, whose value would be silently discarded.
|
|
func TestRegistry_RejectsManagedPlusCustomerCredential(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewRegistry()
|
|
err := r.Register(&provider.Registration{
|
|
Provider: coredata.ConnectorProviderCrisp,
|
|
DisplayName: "Crisp",
|
|
ManagedAPIKey: true,
|
|
SupportsAPIKey: true,
|
|
})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "mutually exclusive")
|
|
}
|
|
|
|
// TestRegistry_ApplyManagedAPIKey verifies the key is injected fresh into a
|
|
// managed provider's connection (so rotation propagates and the key is not
|
|
// persisted), while non-managed providers are left untouched.
|
|
func TestRegistry_ApplyManagedAPIKey(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewBuiltinRegistry()
|
|
r.SetManagedAPIKey(coredata.ConnectorProviderCrisp, "identifier:secret")
|
|
|
|
managed := &coredata.Connector{
|
|
Provider: coredata.ConnectorProviderCrisp,
|
|
Connection: &connector.APIKeyConnection{BasicAuthUserPass: true},
|
|
}
|
|
require.NoError(t, r.ApplyManagedAPIKey(managed))
|
|
assert.Equal(t, "identifier:secret", managed.Connection.(*connector.APIKeyConnection).APIKey)
|
|
|
|
// Non-managed provider: the connection is left untouched.
|
|
other := &coredata.Connector{
|
|
Provider: coredata.ConnectorProviderSlack,
|
|
Connection: &connector.APIKeyConnection{APIKey: "customer-key"},
|
|
}
|
|
require.NoError(t, r.ApplyManagedAPIKey(other))
|
|
assert.Equal(t, "customer-key", other.Connection.(*connector.APIKeyConnection).APIKey)
|
|
}
|
|
|
|
// TestRegistry_ApplyManagedAPIKey_Unconfigured verifies that a managed
|
|
// provider whose key was never configured (deactivated) errors rather than
|
|
// silently building a keyless client.
|
|
func TestRegistry_ApplyManagedAPIKey_Unconfigured(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := provider.NewBuiltinRegistry()
|
|
managed := &coredata.Connector{
|
|
Provider: coredata.ConnectorProviderCrisp,
|
|
Connection: &connector.APIKeyConnection{BasicAuthUserPass: true},
|
|
}
|
|
err := r.ApplyManagedAPIKey(managed)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "not configured")
|
|
}
|