feat: add support for optional external auth providers (#12021)

This commit is contained in:
Kayla Washburn-Love
2024-02-21 11:18:38 -07:00
committed by GitHub
parent 78c9f82719
commit 475c3650ca
39 changed files with 1495 additions and 727 deletions
+3
View File
@@ -11828,6 +11828,9 @@ const docTemplate = `{
"id": {
"type": "string"
},
"optional": {
"type": "boolean"
},
"type": {
"type": "string"
}
+3
View File
@@ -10709,6 +10709,9 @@
"id": {
"type": "string"
},
"optional": {
"type": "boolean"
},
"type": {
"type": "string"
}
+1 -1
View File
@@ -1247,7 +1247,7 @@ func (api *API) CreateInMemoryProvisionerDaemon(dialCtx context.Context, name st
Tags: provisionersdk.MutateTags(uuid.Nil, nil),
LastSeenAt: sql.NullTime{Time: dbtime.Now(), Valid: true},
Version: buildinfo.Version(),
APIVersion: proto.VersionCurrent.String(),
APIVersion: proto.CurrentVersion.String(),
})
if err != nil {
return nil, xerrors.Errorf("failed to create in-memory provisioner daemon: %w", err)
+1 -2
View File
@@ -928,8 +928,7 @@ func (s *MethodTestSuite) TestTemplate() {
JobID: jobID,
})
check.Args(database.UpdateTemplateVersionExternalAuthProvidersByJobIDParams{
JobID: jobID,
ExternalAuthProviders: []string{},
JobID: jobID,
}).Asserts(t1, rbac.ActionUpdate).Returns()
}))
s.Run("GetTemplateInsights", s.Subtest(func(db database.Store, check *expects) {
+4 -4
View File
@@ -219,7 +219,7 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
CreatedAt: now.Add(-14 * 24 * time.Hour),
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-7 * 24 * time.Hour).Add(time.Minute)},
Version: "1.0.0",
APIVersion: proto.VersionCurrent.String(),
APIVersion: proto.CurrentVersion.String(),
})
require.NoError(t, err)
_, err = db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
@@ -230,7 +230,7 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
CreatedAt: now.Add(-8 * 24 * time.Hour),
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-8 * 24 * time.Hour).Add(time.Hour)},
Version: "1.0.0",
APIVersion: proto.VersionCurrent.String(),
APIVersion: proto.CurrentVersion.String(),
})
require.NoError(t, err)
_, err = db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
@@ -243,7 +243,7 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
},
CreatedAt: now.Add(-9 * 24 * time.Hour),
Version: "1.0.0",
APIVersion: proto.VersionCurrent.String(),
APIVersion: proto.CurrentVersion.String(),
})
require.NoError(t, err)
_, err = db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
@@ -257,7 +257,7 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
CreatedAt: now.Add(-6 * 24 * time.Hour),
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-6 * 24 * time.Hour)},
Version: "1.0.0",
APIVersion: proto.VersionCurrent.String(),
APIVersion: proto.CurrentVersion.String(),
})
require.NoError(t, err)
+1 -1
View File
@@ -821,7 +821,7 @@ CREATE TABLE template_versions (
readme character varying(1048576) NOT NULL,
job_id uuid NOT NULL,
created_by uuid NOT NULL,
external_auth_providers text[],
external_auth_providers jsonb DEFAULT '[]'::jsonb NOT NULL,
message character varying(1048576) DEFAULT ''::character varying NOT NULL,
archived boolean DEFAULT false NOT NULL
);
@@ -0,0 +1,61 @@
-- We cannot alter the column type while a view depends on it, so we drop it and recreate it.
DROP VIEW template_version_with_user;
-- Does the opposite of `migrate_external_auth_providers_to_jsonb`
-- eg. `'[{"id": "github"}, {"id": "gitlab"}]'::jsonb` would become `'{github,gitlab}'::text[]`
CREATE OR REPLACE FUNCTION revert_migrate_external_auth_providers_to_jsonb(jsonb)
RETURNS text[]
LANGUAGE plpgsql
AS $$
DECLARE
result text[];
BEGIN
SELECT
array_agg(id::text) INTO result
FROM (
SELECT
jsonb_array_elements($1) ->> 'id' AS id) AS external_auth_provider_ids;
RETURN result;
END;
$$;
-- Remove the non-null constraint and default
ALTER TABLE template_versions
ALTER COLUMN external_auth_providers DROP DEFAULT;
ALTER TABLE template_versions
ALTER COLUMN external_auth_providers DROP NOT NULL;
-- Update the column type and migrate the values
ALTER TABLE template_versions
ALTER COLUMN external_auth_providers TYPE text[]
USING revert_migrate_external_auth_providers_to_jsonb(external_auth_providers);
-- Recreate `template_version_with_user` as described in dump.sql
CREATE VIEW template_version_with_user AS
SELECT
template_versions.id,
template_versions.template_id,
template_versions.organization_id,
template_versions.created_at,
template_versions.updated_at,
template_versions.name,
template_versions.readme,
template_versions.job_id,
template_versions.created_by,
template_versions.external_auth_providers,
template_versions.message,
template_versions.archived,
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
COALESCE(visible_users.username, ''::text) AS created_by_username
FROM (public.template_versions
LEFT JOIN visible_users ON (template_versions.created_by = visible_users.id));
COMMENT ON VIEW template_version_with_user IS 'Joins in the username + avatar url of the created by user.';
-- Cleanup
DROP FUNCTION revert_migrate_external_auth_providers_to_jsonb;
@@ -0,0 +1,63 @@
-- We cannot alter the column type while a view depends on it, so we drop it and recreate it.
DROP VIEW template_version_with_user;
-- Turns the list of provider names into JSONB with the type `Array<{ id: string; optional?: boolean }>`
-- eg. `'{github,gitlab}'::text[]` would become `'[{"id": "github"}, {"id": "gitlab"}]'::jsonb`
CREATE OR REPLACE FUNCTION migrate_external_auth_providers_to_jsonb(text[])
RETURNS jsonb
LANGUAGE plpgsql
AS $$
DECLARE
result jsonb;
BEGIN
SELECT
jsonb_agg(jsonb_build_object('id', value::text)) INTO result
FROM
unnest($1) AS value;
RETURN result;
END;
$$;
-- Update the column type and migrate the values
ALTER TABLE template_versions
ALTER COLUMN external_auth_providers TYPE jsonb
USING migrate_external_auth_providers_to_jsonb(external_auth_providers);
-- Make the column non-nullable to make the types nicer on the Go side
UPDATE template_versions
SET external_auth_providers = '[]'::jsonb
WHERE external_auth_providers IS NULL;
ALTER TABLE template_versions
ALTER COLUMN external_auth_providers SET DEFAULT '[]'::jsonb;
ALTER TABLE template_versions
ALTER COLUMN external_auth_providers SET NOT NULL;
-- Recreate `template_version_with_user` as described in dump.sql
CREATE VIEW template_version_with_user AS
SELECT
template_versions.id,
template_versions.template_id,
template_versions.organization_id,
template_versions.created_at,
template_versions.updated_at,
template_versions.name,
template_versions.readme,
template_versions.job_id,
template_versions.created_by,
template_versions.external_auth_providers,
template_versions.message,
template_versions.archived,
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
COALESCE(visible_users.username, ''::text) AS created_by_username
FROM (public.template_versions
LEFT JOIN visible_users ON (template_versions.created_by = visible_users.id));
COMMENT ON VIEW template_version_with_user IS 'Joins in the username + avatar url of the created by user.';
-- Cleanup
DROP FUNCTION migrate_external_auth_providers_to_jsonb;
+15 -15
View File
@@ -2080,20 +2080,20 @@ type TemplateTable struct {
// Joins in the username + avatar url of the created by user.
type TemplateVersion struct {
ID uuid.UUID `db:"id" json:"id"`
TemplateID uuid.NullUUID `db:"template_id" json:"template_id"`
OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
Name string `db:"name" json:"name"`
Readme string `db:"readme" json:"readme"`
JobID uuid.UUID `db:"job_id" json:"job_id"`
CreatedBy uuid.UUID `db:"created_by" json:"created_by"`
ExternalAuthProviders []string `db:"external_auth_providers" json:"external_auth_providers"`
Message string `db:"message" json:"message"`
Archived bool `db:"archived" json:"archived"`
CreatedByAvatarURL string `db:"created_by_avatar_url" json:"created_by_avatar_url"`
CreatedByUsername string `db:"created_by_username" json:"created_by_username"`
ID uuid.UUID `db:"id" json:"id"`
TemplateID uuid.NullUUID `db:"template_id" json:"template_id"`
OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
Name string `db:"name" json:"name"`
Readme string `db:"readme" json:"readme"`
JobID uuid.UUID `db:"job_id" json:"job_id"`
CreatedBy uuid.UUID `db:"created_by" json:"created_by"`
ExternalAuthProviders json.RawMessage `db:"external_auth_providers" json:"external_auth_providers"`
Message string `db:"message" json:"message"`
Archived bool `db:"archived" json:"archived"`
CreatedByAvatarURL string `db:"created_by_avatar_url" json:"created_by_avatar_url"`
CreatedByUsername string `db:"created_by_username" json:"created_by_username"`
}
type TemplateVersionParameter struct {
@@ -2143,7 +2143,7 @@ type TemplateVersionTable struct {
JobID uuid.UUID `db:"job_id" json:"job_id"`
CreatedBy uuid.UUID `db:"created_by" json:"created_by"`
// IDs of External auth providers for a specific template version
ExternalAuthProviders []string `db:"external_auth_providers" json:"external_auth_providers"`
ExternalAuthProviders json.RawMessage `db:"external_auth_providers" json:"external_auth_providers"`
// Message describing the changes in this version of the template, similar to a Git commit message. Like a commit message, this should be a short, high-level description of the changes in this version of the template. This message is immutable and should not be updated after the fact.
Message string `db:"message" json:"message"`
Archived bool `db:"archived" json:"archived"`
+11 -11
View File
@@ -6870,7 +6870,7 @@ func (q *sqlQuerier) GetPreviousTemplateVersion(ctx context.Context, arg GetPrev
&i.Readme,
&i.JobID,
&i.CreatedBy,
pq.Array(&i.ExternalAuthProviders),
&i.ExternalAuthProviders,
&i.Message,
&i.Archived,
&i.CreatedByAvatarURL,
@@ -6901,7 +6901,7 @@ func (q *sqlQuerier) GetTemplateVersionByID(ctx context.Context, id uuid.UUID) (
&i.Readme,
&i.JobID,
&i.CreatedBy,
pq.Array(&i.ExternalAuthProviders),
&i.ExternalAuthProviders,
&i.Message,
&i.Archived,
&i.CreatedByAvatarURL,
@@ -6932,7 +6932,7 @@ func (q *sqlQuerier) GetTemplateVersionByJobID(ctx context.Context, jobID uuid.U
&i.Readme,
&i.JobID,
&i.CreatedBy,
pq.Array(&i.ExternalAuthProviders),
&i.ExternalAuthProviders,
&i.Message,
&i.Archived,
&i.CreatedByAvatarURL,
@@ -6969,7 +6969,7 @@ func (q *sqlQuerier) GetTemplateVersionByTemplateIDAndName(ctx context.Context,
&i.Readme,
&i.JobID,
&i.CreatedBy,
pq.Array(&i.ExternalAuthProviders),
&i.ExternalAuthProviders,
&i.Message,
&i.Archived,
&i.CreatedByAvatarURL,
@@ -7006,7 +7006,7 @@ func (q *sqlQuerier) GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UU
&i.Readme,
&i.JobID,
&i.CreatedBy,
pq.Array(&i.ExternalAuthProviders),
&i.ExternalAuthProviders,
&i.Message,
&i.Archived,
&i.CreatedByAvatarURL,
@@ -7100,7 +7100,7 @@ func (q *sqlQuerier) GetTemplateVersionsByTemplateID(ctx context.Context, arg Ge
&i.Readme,
&i.JobID,
&i.CreatedBy,
pq.Array(&i.ExternalAuthProviders),
&i.ExternalAuthProviders,
&i.Message,
&i.Archived,
&i.CreatedByAvatarURL,
@@ -7142,7 +7142,7 @@ func (q *sqlQuerier) GetTemplateVersionsCreatedAfter(ctx context.Context, create
&i.Readme,
&i.JobID,
&i.CreatedBy,
pq.Array(&i.ExternalAuthProviders),
&i.ExternalAuthProviders,
&i.Message,
&i.Archived,
&i.CreatedByAvatarURL,
@@ -7292,13 +7292,13 @@ WHERE
`
type UpdateTemplateVersionExternalAuthProvidersByJobIDParams struct {
JobID uuid.UUID `db:"job_id" json:"job_id"`
ExternalAuthProviders []string `db:"external_auth_providers" json:"external_auth_providers"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
JobID uuid.UUID `db:"job_id" json:"job_id"`
ExternalAuthProviders json.RawMessage `db:"external_auth_providers" json:"external_auth_providers"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
}
func (q *sqlQuerier) UpdateTemplateVersionExternalAuthProvidersByJobID(ctx context.Context, arg UpdateTemplateVersionExternalAuthProvidersByJobIDParams) error {
_, err := q.db.ExecContext(ctx, updateTemplateVersionExternalAuthProvidersByJobID, arg.JobID, pq.Array(arg.ExternalAuthProviders), arg.UpdatedAt)
_, err := q.db.ExecContext(ctx, updateTemplateVersionExternalAuthProvidersByJobID, arg.JobID, arg.ExternalAuthProviders, arg.UpdatedAt)
return err
}
+5
View File
@@ -64,6 +64,11 @@ func (t TemplateACL) Value() (driver.Value, error) {
return json.Marshal(t)
}
type ExternalAuthProvider struct {
ID string `json:"id"`
Optional bool `json:"optional,omitempty"`
}
type StringMap map[string]string
func (m *StringMap) Scan(src interface{}) error {
+42 -10
View File
@@ -501,10 +501,16 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo
return nil, failJob(fmt.Sprintf("get workspace build parameters: %s", err))
}
externalAuthProviders := []*sdkproto.ExternalAuthProvider{}
for _, p := range templateVersion.ExternalAuthProviders {
dbExternalAuthProviders := []database.ExternalAuthProvider{}
err = json.Unmarshal(templateVersion.ExternalAuthProviders, &dbExternalAuthProviders)
if err != nil {
return nil, xerrors.Errorf("failed to deserialize external_auth_providers value: %w", err)
}
externalAuthProviders := make([]*sdkproto.ExternalAuthProvider, 0, len(dbExternalAuthProviders))
for _, p := range dbExternalAuthProviders {
link, err := s.Database.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{
ProviderID: p,
ProviderID: p.ID,
UserID: owner.ID,
})
if errors.Is(err, sql.ErrNoRows) {
@@ -515,7 +521,7 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo
}
var config *externalauth.Config
for _, c := range s.ExternalAuthConfigs {
if c.ID != p {
if c.ID != p.ID {
continue
}
config = c
@@ -524,7 +530,7 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo
// We weren't able to find a matching config for the ID!
if config == nil {
s.Logger.Warn(ctx, "workspace build job is missing external auth provider",
slog.F("provider_id", p),
slog.F("provider_id", p.ID),
slog.F("template_version_id", templateVersion.ID),
slog.F("workspace_id", workspaceBuild.WorkspaceID))
continue
@@ -532,13 +538,13 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo
link, valid, err := config.RefreshToken(ctx, s.Database, link)
if err != nil {
return nil, failJob(fmt.Sprintf("refresh external auth link %q: %s", p, err))
return nil, failJob(fmt.Sprintf("refresh external auth link %q: %s", p.ID, err))
}
if !valid {
continue
}
externalAuthProviders = append(externalAuthProviders, &sdkproto.ExternalAuthProvider{
Id: p,
Id: p.ID,
AccessToken: link.OAuthAccessToken,
})
}
@@ -1133,23 +1139,49 @@ func (s *server) CompleteJob(ctx context.Context, completed *proto.CompletedJob)
for _, externalAuthProvider := range jobType.TemplateImport.ExternalAuthProviders {
contains := false
for _, configuredProvider := range s.ExternalAuthConfigs {
if configuredProvider.ID == externalAuthProvider {
if configuredProvider.ID == externalAuthProvider.Id {
contains = true
break
}
}
if !contains {
completedError = sql.NullString{
String: fmt.Sprintf("external auth provider %q is not configured", externalAuthProvider),
String: fmt.Sprintf("external auth provider %q is not configured", externalAuthProvider.Id),
Valid: true,
}
break
}
}
// Fallback to `ExternalAuthProvidersNames` if it was specified and `ExternalAuthProviders`
// was not. Gives us backwards compatibility with custom provisioners that haven't been
// updated to use the new field yet.
var externalAuthProviders []database.ExternalAuthProvider
if providersLen := len(jobType.TemplateImport.ExternalAuthProviders); providersLen > 0 {
externalAuthProviders = make([]database.ExternalAuthProvider, 0, providersLen)
for _, provider := range jobType.TemplateImport.ExternalAuthProviders {
externalAuthProviders = append(externalAuthProviders, database.ExternalAuthProvider{
ID: provider.Id,
Optional: provider.Optional,
})
}
} else if namesLen := len(jobType.TemplateImport.ExternalAuthProvidersNames); namesLen > 0 {
externalAuthProviders = make([]database.ExternalAuthProvider, 0, namesLen)
for _, providerID := range jobType.TemplateImport.ExternalAuthProvidersNames {
externalAuthProviders = append(externalAuthProviders, database.ExternalAuthProvider{
ID: providerID,
})
}
}
externalAuthProvidersMessage, err := json.Marshal(externalAuthProviders)
if err != nil {
return nil, xerrors.Errorf("failed to serialize external_auth_providers value: %w", err)
}
err = s.Database.UpdateTemplateVersionExternalAuthProvidersByJobID(ctx, database.UpdateTemplateVersionExternalAuthProvidersByJobIDParams{
JobID: jobID,
ExternalAuthProviders: jobType.TemplateImport.ExternalAuthProviders,
ExternalAuthProviders: json.RawMessage(externalAuthProvidersMessage),
UpdatedAt: dbtime.Now(),
})
if err != nil {
@@ -172,11 +172,14 @@ func TestAcquireJob(t *testing.T) {
// create an API key with an expiration within the bounds of the
// deployment config.
dv := &codersdk.DeploymentValues{MaxTokenLifetime: clibase.Duration(time.Hour)}
gitAuthProvider := "github"
gitAuthProvider := &sdkproto.ExternalAuthProviderResource{
Id: "github",
}
srv, db, ps, _ := setup(t, false, &overrides{
deploymentValues: dv,
externalAuthConfigs: []*externalauth.Config{{
ID: gitAuthProvider,
ID: gitAuthProvider.Id,
InstrumentedOAuth2Config: &testutil.OAuth2Config{},
}},
})
@@ -191,7 +194,7 @@ func TestAcquireJob(t *testing.T) {
OAuthAccessToken: "access-token",
})
dbgen.ExternalAuthLink(t, db, database.ExternalAuthLink{
ProviderID: gitAuthProvider,
ProviderID: gitAuthProvider.Id,
UserID: user.ID,
})
template := dbgen.Template(t, db, database.Template{
@@ -207,9 +210,14 @@ func TestAcquireJob(t *testing.T) {
},
JobID: uuid.New(),
})
err := db.UpdateTemplateVersionExternalAuthProvidersByJobID(ctx, database.UpdateTemplateVersionExternalAuthProvidersByJobIDParams{
externalAuthProviders, err := json.Marshal([]database.ExternalAuthProvider{{
ID: gitAuthProvider.Id,
Optional: gitAuthProvider.Optional,
}})
require.NoError(t, err)
err = db.UpdateTemplateVersionExternalAuthProvidersByJobID(ctx, database.UpdateTemplateVersionExternalAuthProvidersByJobIDParams{
JobID: version.JobID,
ExternalAuthProviders: []string{gitAuthProvider},
ExternalAuthProviders: json.RawMessage(externalAuthProviders),
UpdatedAt: dbtime.Now(),
})
require.NoError(t, err)
@@ -321,7 +329,7 @@ func TestAcquireJob(t *testing.T) {
},
},
ExternalAuthProviders: []*sdkproto.ExternalAuthProvider{{
Id: gitAuthProvider,
Id: gitAuthProvider.Id,
AccessToken: "access_token",
}},
Metadata: &sdkproto.Metadata{
@@ -949,8 +957,10 @@ func TestCompleteJob(t *testing.T) {
Name: "hello",
Type: "aws_instance",
}},
StopResources: []*sdkproto.Resource{},
ExternalAuthProviders: []string{"github"},
StopResources: []*sdkproto.Resource{},
ExternalAuthProviders: []*sdkproto.ExternalAuthProviderResource{{
Id: "github",
}},
},
},
})
@@ -1002,7 +1012,7 @@ func TestCompleteJob(t *testing.T) {
Type: "aws_instance",
}},
StopResources: []*sdkproto.Resource{},
ExternalAuthProviders: []string{"github"},
ExternalAuthProviders: []*sdkproto.ExternalAuthProviderResource{{Id: "github"}},
},
},
})
@@ -1776,7 +1786,7 @@ func setup(t *testing.T, ignoreLogErrors bool, ov *overrides) (proto.DRPCProvisi
Tags: database.StringMap{},
LastSeenAt: sql.NullTime{},
Version: buildinfo.Version(),
APIVersion: proto.VersionCurrent.String(),
APIVersion: proto.CurrentVersion.String(),
})
require.NoError(t, err)
+13 -3
View File
@@ -289,19 +289,28 @@ func (api *API) templateVersionExternalAuth(rw http.ResponseWriter, r *http.Requ
templateVersion = httpmw.TemplateVersionParam(r)
)
rawProviders := templateVersion.ExternalAuthProviders
var rawProviders []database.ExternalAuthProvider
err := json.Unmarshal(templateVersion.ExternalAuthProviders, &rawProviders)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error reading auth config from database",
Detail: err.Error(),
})
return
}
providers := make([]codersdk.TemplateVersionExternalAuth, 0)
for _, rawProvider := range rawProviders {
var config *externalauth.Config
for _, provider := range api.ExternalAuthConfigs {
if provider.ID == rawProvider {
if provider.ID == rawProvider.ID {
config = provider
break
}
}
if config == nil {
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
Message: fmt.Sprintf("The template version references a Git auth provider %q that no longer exists.", rawProvider),
Message: fmt.Sprintf("The template version references a Git auth provider %q that no longer exists.", rawProvider.ID),
Detail: "You'll need to update the template version to use a different provider.",
})
return
@@ -323,6 +332,7 @@ func (api *API) templateVersionExternalAuth(rw http.ResponseWriter, r *http.Requ
AuthenticateURL: redirectURL.String(),
DisplayName: config.DisplayName,
DisplayIcon: config.DisplayIcon,
Optional: rawProvider.Optional,
}
authLink, err := api.Database.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{
+2 -1
View File
@@ -347,7 +347,7 @@ func TestTemplateVersionsExternalAuth(t *testing.T) {
ProvisionPlan: []*proto.Response{{
Type: &proto.Response_Plan{
Plan: &proto.PlanComplete{
ExternalAuthProviders: []string{"github"},
ExternalAuthProviders: []*proto.ExternalAuthProviderResource{{Id: "github", Optional: true}},
},
},
}},
@@ -373,6 +373,7 @@ func TestTemplateVersionsExternalAuth(t *testing.T) {
require.NoError(t, err)
require.Len(t, providers, 1)
require.True(t, providers[0].Authenticated)
require.True(t, providers[0].Optional)
})
}