Skip to content

Commit 475c365

Browse files
authored
feat: add support for optional external auth providers (coder#12021)
1 parent 78c9f82 commit 475c365

39 files changed

+1495
-727
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ coderd/apidoc/swagger.json linguist-generated=true
66
coderd/database/dump.sql linguist-generated=true
77
peerbroker/proto/*.go linguist-generated=true
88
provisionerd/proto/*.go linguist-generated=true
9+
provisionerd/proto/version.go linguist-generated=false
910
provisionersdk/proto/*.go linguist-generated=true
1011
*.tfplan.json linguist-generated=true
1112
*.tfstate.json linguist-generated=true
1213
*.tfstate.dot linguist-generated=true
1314
*.tfplan.dot linguist-generated=true
15+
site/e2e/provisionerGenerated.ts linguist-generated=true
1416
site/src/api/typesGenerated.ts linguist-generated=true
1517
site/src/pages/SetupPage/countries.tsx linguist-generated=true

cli/create_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,7 @@ func TestCreateWithGitAuth(t *testing.T) {
803803
{
804804
Type: &proto.Response_Plan{
805805
Plan: &proto.PlanComplete{
806-
ExternalAuthProviders: []string{"github"},
806+
ExternalAuthProviders: []*proto.ExternalAuthProviderResource{{Id: "github"}},
807807
},
808808
},
809809
},

coderd/apidoc/docs.go

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/coderd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1247,7 +1247,7 @@ func (api *API) CreateInMemoryProvisionerDaemon(dialCtx context.Context, name st
12471247
Tags: provisionersdk.MutateTags(uuid.Nil, nil),
12481248
LastSeenAt: sql.NullTime{Time: dbtime.Now(), Valid: true},
12491249
Version: buildinfo.Version(),
1250-
APIVersion: proto.VersionCurrent.String(),
1250+
APIVersion: proto.CurrentVersion.String(),
12511251
})
12521252
if err != nil {
12531253
return nil, xerrors.Errorf("failed to create in-memory provisioner daemon: %w", err)

coderd/database/dbauthz/dbauthz_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -928,8 +928,7 @@ func (s *MethodTestSuite) TestTemplate() {
928928
JobID: jobID,
929929
})
930930
check.Args(database.UpdateTemplateVersionExternalAuthProvidersByJobIDParams{
931-
JobID: jobID,
932-
ExternalAuthProviders: []string{},
931+
JobID: jobID,
933932
}).Asserts(t1, rbac.ActionUpdate).Returns()
934933
}))
935934
s.Run("GetTemplateInsights", s.Subtest(func(db database.Store, check *expects) {

coderd/database/dbpurge/dbpurge_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
219219
CreatedAt: now.Add(-14 * 24 * time.Hour),
220220
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-7 * 24 * time.Hour).Add(time.Minute)},
221221
Version: "1.0.0",
222-
APIVersion: proto.VersionCurrent.String(),
222+
APIVersion: proto.CurrentVersion.String(),
223223
})
224224
require.NoError(t, err)
225225
_, err = db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
@@ -230,7 +230,7 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
230230
CreatedAt: now.Add(-8 * 24 * time.Hour),
231231
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-8 * 24 * time.Hour).Add(time.Hour)},
232232
Version: "1.0.0",
233-
APIVersion: proto.VersionCurrent.String(),
233+
APIVersion: proto.CurrentVersion.String(),
234234
})
235235
require.NoError(t, err)
236236
_, err = db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
@@ -243,7 +243,7 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
243243
},
244244
CreatedAt: now.Add(-9 * 24 * time.Hour),
245245
Version: "1.0.0",
246-
APIVersion: proto.VersionCurrent.String(),
246+
APIVersion: proto.CurrentVersion.String(),
247247
})
248248
require.NoError(t, err)
249249
_, err = db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
@@ -257,7 +257,7 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
257257
CreatedAt: now.Add(-6 * 24 * time.Hour),
258258
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-6 * 24 * time.Hour)},
259259
Version: "1.0.0",
260-
APIVersion: proto.VersionCurrent.String(),
260+
APIVersion: proto.CurrentVersion.String(),
261261
})
262262
require.NoError(t, err)
263263

coderd/database/dump.sql

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
-- We cannot alter the column type while a view depends on it, so we drop it and recreate it.
2+
DROP VIEW template_version_with_user;
3+
4+
5+
-- Does the opposite of `migrate_external_auth_providers_to_jsonb`
6+
-- eg. `'[{"id": "github"}, {"id": "gitlab"}]'::jsonb` would become `'{github,gitlab}'::text[]`
7+
CREATE OR REPLACE FUNCTION revert_migrate_external_auth_providers_to_jsonb(jsonb)
8+
RETURNS text[]
9+
LANGUAGE plpgsql
10+
AS $$
11+
DECLARE
12+
result text[];
13+
BEGIN
14+
SELECT
15+
array_agg(id::text) INTO result
16+
FROM (
17+
SELECT
18+
jsonb_array_elements($1) ->> 'id' AS id) AS external_auth_provider_ids;
19+
RETURN result;
20+
END;
21+
$$;
22+
23+
24+
-- Remove the non-null constraint and default
25+
ALTER TABLE template_versions
26+
ALTER COLUMN external_auth_providers DROP DEFAULT;
27+
ALTER TABLE template_versions
28+
ALTER COLUMN external_auth_providers DROP NOT NULL;
29+
30+
31+
-- Update the column type and migrate the values
32+
ALTER TABLE template_versions
33+
ALTER COLUMN external_auth_providers TYPE text[]
34+
USING revert_migrate_external_auth_providers_to_jsonb(external_auth_providers);
35+
36+
37+
-- Recreate `template_version_with_user` as described in dump.sql
38+
CREATE VIEW template_version_with_user AS
39+
SELECT
40+
template_versions.id,
41+
template_versions.template_id,
42+
template_versions.organization_id,
43+
template_versions.created_at,
44+
template_versions.updated_at,
45+
template_versions.name,
46+
template_versions.readme,
47+
template_versions.job_id,
48+
template_versions.created_by,
49+
template_versions.external_auth_providers,
50+
template_versions.message,
51+
template_versions.archived,
52+
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
53+
COALESCE(visible_users.username, ''::text) AS created_by_username
54+
FROM (public.template_versions
55+
LEFT JOIN visible_users ON (template_versions.created_by = visible_users.id));
56+
57+
COMMENT ON VIEW template_version_with_user IS 'Joins in the username + avatar url of the created by user.';
58+
59+
60+
-- Cleanup
61+
DROP FUNCTION revert_migrate_external_auth_providers_to_jsonb;
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
-- We cannot alter the column type while a view depends on it, so we drop it and recreate it.
2+
DROP VIEW template_version_with_user;
3+
4+
5+
-- Turns the list of provider names into JSONB with the type `Array<{ id: string; optional?: boolean }>`
6+
-- eg. `'{github,gitlab}'::text[]` would become `'[{"id": "github"}, {"id": "gitlab"}]'::jsonb`
7+
CREATE OR REPLACE FUNCTION migrate_external_auth_providers_to_jsonb(text[])
8+
RETURNS jsonb
9+
LANGUAGE plpgsql
10+
AS $$
11+
DECLARE
12+
result jsonb;
13+
BEGIN
14+
SELECT
15+
jsonb_agg(jsonb_build_object('id', value::text)) INTO result
16+
FROM
17+
unnest($1) AS value;
18+
RETURN result;
19+
END;
20+
$$;
21+
22+
23+
-- Update the column type and migrate the values
24+
ALTER TABLE template_versions
25+
ALTER COLUMN external_auth_providers TYPE jsonb
26+
USING migrate_external_auth_providers_to_jsonb(external_auth_providers);
27+
28+
29+
-- Make the column non-nullable to make the types nicer on the Go side
30+
UPDATE template_versions
31+
SET external_auth_providers = '[]'::jsonb
32+
WHERE external_auth_providers IS NULL;
33+
ALTER TABLE template_versions
34+
ALTER COLUMN external_auth_providers SET DEFAULT '[]'::jsonb;
35+
ALTER TABLE template_versions
36+
ALTER COLUMN external_auth_providers SET NOT NULL;
37+
38+
39+
-- Recreate `template_version_with_user` as described in dump.sql
40+
CREATE VIEW template_version_with_user AS
41+
SELECT
42+
template_versions.id,
43+
template_versions.template_id,
44+
template_versions.organization_id,
45+
template_versions.created_at,
46+
template_versions.updated_at,
47+
template_versions.name,
48+
template_versions.readme,
49+
template_versions.job_id,
50+
template_versions.created_by,
51+
template_versions.external_auth_providers,
52+
template_versions.message,
53+
template_versions.archived,
54+
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
55+
COALESCE(visible_users.username, ''::text) AS created_by_username
56+
FROM (public.template_versions
57+
LEFT JOIN visible_users ON (template_versions.created_by = visible_users.id));
58+
59+
COMMENT ON VIEW template_version_with_user IS 'Joins in the username + avatar url of the created by user.';
60+
61+
62+
-- Cleanup
63+
DROP FUNCTION migrate_external_auth_providers_to_jsonb;

coderd/database/models.go

Lines changed: 15 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

Lines changed: 11 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ func (t TemplateACL) Value() (driver.Value, error) {
6464
return json.Marshal(t)
6565
}
6666

67+
type ExternalAuthProvider struct {
68+
ID string `json:"id"`
69+
Optional bool `json:"optional,omitempty"`
70+
}
71+
6772
type StringMap map[string]string
6873

6974
func (m *StringMap) Scan(src interface{}) error {

0 commit comments

Comments
 (0)