From 5596fb20b5fd1d1f3873f1a7259d0e2fc6890101 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 30 Sep 2023 14:30:01 -0500 Subject: [PATCH] chore: move `/gitauth` to `/externalauth` on the frontend (#9954) * chore: move `/gitauth` to `/externalauth` on the frontend This actually took a lot more jank than anticipated, so I wanted to split this up before adding the ability to embed new providers. * Rename FE * Fix em' up * Fix linting error * Fix e2e tests * chore: update helm golden files --- .vscode/settings.json | 1 + Makefile | 2 +- cli/create_test.go | 8 +- cli/server.go | 12 +- coderd/apidoc/docs.go | 376 +++++++++--------- coderd/apidoc/swagger.json | 356 ++++++++--------- coderd/coderd.go | 47 ++- coderd/coderdtest/coderdtest.go | 12 +- coderd/database/dbauthz/dbauthz.go | 2 +- coderd/{gitauth.go => externalauth.go} | 74 ++-- coderd/{gitauth => externalauth}/config.go | 60 +-- .../{gitauth => externalauth}/config_test.go | 41 +- coderd/{gitauth => externalauth}/oauth.go | 8 +- .../{gitauth_test.go => externalauth_test.go} | 84 ++-- coderd/gitauth/oauth_test.go | 9 - coderd/httpmw/externalauthparam.go | 40 ++ ...aram_test.go => externalauthparam_test.go} | 14 +- coderd/httpmw/gitauthparam.go | 40 -- .../patternmatcher/routepatterns_test.go | 4 +- .../provisionerdserver/provisionerdserver.go | 8 +- .../provisionerdserver_test.go | 10 +- coderd/templateversions.go | 18 +- coderd/templateversions_test.go | 10 +- coderd/tracing/httpmw.go | 2 +- coderd/tracing/httpmw_test.go | 2 +- coderd/workspaceagents.go | 48 +-- codersdk/{gitauth.go => externalauth.go} | 54 +-- codersdk/templateversions.go | 2 +- docs/api/git.md | 48 +-- docs/api/schemas.md | 214 +++++----- docs/api/templates.md | 8 +- provisioner/echo/serve.go | 8 +- provisioner/terraform/executor.go | 14 +- provisioner/terraform/resources.go | 12 +- provisioner/terraform/resources_test.go | 8 +- provisionerd/runner/runner.go | 2 +- provisionersdk/proto/provisioner.pb.go | 174 ++++---- provisionersdk/proto/provisioner.proto | 4 +- site/e2e/helpers.ts | 6 +- site/e2e/provisionerGenerated.ts | 8 +- .../{gitAuth.spec.ts => externalAuth.spec.ts} | 14 +- site/src/AppRouter.tsx | 9 +- site/src/api/api.ts | 22 +- site/src/api/queries/templates.ts | 10 +- site/src/api/typesGenerated.ts | 80 ++-- .../CreateWorkspacePage.test.tsx | 10 +- .../CreateWorkspacePage.tsx | 35 +- .../CreateWorkspacePageView.stories.tsx | 6 +- .../CreateWorkspacePageView.tsx | 62 +-- ...h.stories.tsx => ExternalAuth.stories.tsx} | 10 +- .../{GitAuth.tsx => ExternalAuth.tsx} | 22 +- .../ExternalAuthPage/ExternalAuthPage.tsx | 96 +++++ .../ExternalAuthPageView.stories.tsx} | 30 +- .../ExternalAuthPageView.tsx} | 84 ++-- site/src/pages/GitAuthPage/GitAuthPage.tsx | 89 ----- site/src/testHelpers/entities.ts | 6 +- site/src/testHelpers/handlers.ts | 2 +- site/src/utils/gitAuth.ts | 1 - site/src/xServices/auth/authXService.ts | 4 +- 59 files changed, 1231 insertions(+), 1211 deletions(-) rename coderd/{gitauth.go => externalauth.go} (73%) rename coderd/{gitauth => externalauth}/config.go (83%) rename coderd/{gitauth => externalauth}/config_test.go (91%) rename coderd/{gitauth => externalauth}/oauth.go (98%) rename coderd/{gitauth_test.go => externalauth_test.go} (84%) delete mode 100644 coderd/gitauth/oauth_test.go create mode 100644 coderd/httpmw/externalauthparam.go rename coderd/httpmw/{gitauthparam_test.go => externalauthparam_test.go} (72%) delete mode 100644 coderd/httpmw/gitauthparam.go rename codersdk/{gitauth.go => externalauth.go} (51%) rename site/e2e/tests/{gitAuth.spec.ts => externalAuth.spec.ts} (91%) rename site/src/pages/CreateWorkspacePage/{GitAuth.stories.tsx => ExternalAuth.stories.tsx} (83%) rename site/src/pages/CreateWorkspacePage/{GitAuth.tsx => ExternalAuth.tsx} (83%) create mode 100644 site/src/pages/ExternalAuthPage/ExternalAuthPage.tsx rename site/src/pages/{GitAuthPage/GitAuthPageView.stories.tsx => ExternalAuthPage/ExternalAuthPageView.stories.tsx} (82%) rename site/src/pages/{GitAuthPage/GitAuthPageView.tsx => ExternalAuthPage/ExternalAuthPageView.tsx} (72%) delete mode 100644 site/src/pages/GitAuthPage/GitAuthPage.tsx delete mode 100644 site/src/utils/gitAuth.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index b187ed265f..0664d7e81c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -39,6 +39,7 @@ "enterprisemeta", "errgroup", "eventsourcemock", + "externalauth", "Failf", "fatih", "Formik", diff --git a/Makefile b/Makefile index d382535030..64615132a5 100644 --- a/Makefile +++ b/Makefile @@ -542,7 +542,7 @@ site/src/api/typesGenerated.ts: scripts/apitypings/main.go $(shell find ./coders cd site pnpm run format:types ./src/api/typesGenerated.ts -site/e2e/provisionerGenerated.ts: provisionerd/proto/provisionerd.pb.go +site/e2e/provisionerGenerated.ts: provisionerd/proto/provisionerd.pb.go provisionersdk/proto/provisioner.pb.go cd site ../scripts/pnpm_install.sh pnpm run gen:provisioner diff --git a/cli/create_test.go b/cli/create_test.go index 6c516ae8d8..2cd4c9abaa 100644 --- a/cli/create_test.go +++ b/cli/create_test.go @@ -14,7 +14,7 @@ import ( "github.com/coder/coder/v2/cli/clitest" "github.com/coder/coder/v2/coderd/coderdtest" - "github.com/coder/coder/v2/coderd/gitauth" + "github.com/coder/coder/v2/coderd/externalauth" "github.com/coder/coder/v2/coderd/util/ptr" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/provisioner/echo" @@ -600,7 +600,7 @@ func TestCreateWithGitAuth(t *testing.T) { { Type: &proto.Response_Plan{ Plan: &proto.PlanComplete{ - GitAuthProviders: []string{"github"}, + ExternalAuthProviders: []string{"github"}, }, }, }, @@ -609,7 +609,7 @@ func TestCreateWithGitAuth(t *testing.T) { } client := coderdtest.New(t, &coderdtest.Options{ - ExternalAuthConfigs: []*gitauth.Config{{ + ExternalAuthConfigs: []*externalauth.Config{{ OAuth2Config: &testutil.OAuth2Config{}, ID: "github", Regex: regexp.MustCompile(`github\.com`), @@ -628,7 +628,7 @@ func TestCreateWithGitAuth(t *testing.T) { clitest.Start(t, inv) pty.ExpectMatch("You must authenticate with GitHub to create a workspace") - resp := coderdtest.RequestGitAuthCallback(t, "github", client) + resp := coderdtest.RequestExternalAuthCallback(t, "github", client) _ = resp.Body.Close() require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode) pty.ExpectMatch("Confirm create?") diff --git a/cli/server.go b/cli/server.go index 634bb059dd..b0ec9f999b 100644 --- a/cli/server.go +++ b/cli/server.go @@ -72,7 +72,7 @@ import ( "github.com/coder/coder/v2/coderd/database/migrations" "github.com/coder/coder/v2/coderd/database/pubsub" "github.com/coder/coder/v2/coderd/devtunnel" - "github.com/coder/coder/v2/coderd/gitauth" + "github.com/coder/coder/v2/coderd/externalauth" "github.com/coder/coder/v2/coderd/gitsshkey" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" @@ -574,16 +574,16 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. } vals.GitAuthProviders.Value = append(vals.GitAuthProviders.Value, gitAuthEnv...) - gitAuthConfigs, err := gitauth.ConvertConfig( + externalAuthConfigs, err := externalauth.ConvertConfig( vals.GitAuthProviders.Value, vals.AccessURL.Value(), ) if err != nil { - return xerrors.Errorf("convert git auth config: %w", err) + return xerrors.Errorf("convert external auth config: %w", err) } - for _, c := range gitAuthConfigs { + for _, c := range externalAuthConfigs { logger.Debug( - ctx, "loaded git auth config", + ctx, "loaded external auth config", slog.F("id", c.ID), ) } @@ -608,7 +608,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. Pubsub: pubsub.NewInMemory(), CacheDir: cacheDir, GoogleTokenValidator: googleTokenValidator, - ExternalAuthConfigs: gitAuthConfigs, + ExternalAuthConfigs: externalAuthConfigs, RealIPConfig: realIPConfig, SecureAuthCookie: vals.SecureAuthCookie.Value(), SSHKeygenAlgorithm: sshKeygenAlgorithm, diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 003baf1679..ab794794f6 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -602,6 +602,103 @@ const docTemplate = `{ } } }, + "/externalauth/{externalauth}": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Git" + ], + "summary": "Get external auth by ID", + "operationId": "get-external-auth-by-id", + "parameters": [ + { + "type": "string", + "format": "string", + "description": "Git Provider ID", + "name": "externalauth", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.ExternalAuth" + } + } + } + } + }, + "/externalauth/{externalauth}/device": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Git" + ], + "summary": "Get external auth device by ID.", + "operationId": "get-external-auth-device-by-id", + "parameters": [ + { + "type": "string", + "format": "string", + "description": "Git Provider ID", + "name": "externalauth", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.ExternalAuthDevice" + } + } + } + }, + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "tags": [ + "Git" + ], + "summary": "Post external auth device by ID", + "operationId": "post-external-auth-device-by-id", + "parameters": [ + { + "type": "string", + "format": "string", + "description": "External Provider ID", + "name": "externalauth", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, "/files": { "post": { "security": [ @@ -677,103 +774,6 @@ const docTemplate = `{ } } }, - "/gitauth/{gitauth}": { - "get": { - "security": [ - { - "CoderSessionToken": [] - } - ], - "produces": [ - "application/json" - ], - "tags": [ - "Git" - ], - "summary": "Get git auth by ID", - "operationId": "get-git-auth-by-id", - "parameters": [ - { - "type": "string", - "format": "string", - "description": "Git Provider ID", - "name": "gitauth", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/codersdk.GitAuth" - } - } - } - } - }, - "/gitauth/{gitauth}/device": { - "get": { - "security": [ - { - "CoderSessionToken": [] - } - ], - "produces": [ - "application/json" - ], - "tags": [ - "Git" - ], - "summary": "Get git auth device by ID.", - "operationId": "get-git-auth-device-by-id", - "parameters": [ - { - "type": "string", - "format": "string", - "description": "Git Provider ID", - "name": "gitauth", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/codersdk.GitAuthDevice" - } - } - } - }, - "post": { - "security": [ - { - "CoderSessionToken": [] - } - ], - "tags": [ - "Git" - ], - "summary": "Post git auth device by ID", - "operationId": "post-git-auth-device-by-id", - "parameters": [ - { - "type": "string", - "format": "string", - "description": "Git Provider ID", - "name": "gitauth", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "No Content" - } - } - } - }, "/groups/{group}": { "get": { "security": [ @@ -2768,7 +2768,7 @@ const docTemplate = `{ } } }, - "/templateversions/{templateversion}/gitauth": { + "/templateversions/{templateversion}/externalauth": { "get": { "security": [ { @@ -2781,8 +2781,8 @@ const docTemplate = `{ "tags": [ "Templates" ], - "summary": "Get git auth by template version", - "operationId": "get-git-auth-by-template-version", + "summary": "Get external auth by template version", + "operationId": "get-external-auth-by-template-version", "parameters": [ { "type": "string", @@ -8186,6 +8186,77 @@ const docTemplate = `{ "ExperimentDeploymentHealthPage" ] }, + "codersdk.ExternalAuth": { + "type": "object", + "properties": { + "app_install_url": { + "description": "AppInstallURL is the URL to install the app.", + "type": "string" + }, + "app_installable": { + "description": "AppInstallable is true if the request for app installs was successful.", + "type": "boolean" + }, + "authenticated": { + "type": "boolean" + }, + "device": { + "type": "boolean" + }, + "installations": { + "description": "AppInstallations are the installations that the user has access to.", + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.ExternalAuthAppInstallation" + } + }, + "type": { + "type": "string" + }, + "user": { + "description": "User is the user that authenticated with the provider.", + "allOf": [ + { + "$ref": "#/definitions/codersdk.ExternalAuthUser" + } + ] + } + } + }, + "codersdk.ExternalAuthAppInstallation": { + "type": "object", + "properties": { + "account": { + "$ref": "#/definitions/codersdk.ExternalAuthUser" + }, + "configure_url": { + "type": "string" + }, + "id": { + "type": "integer" + } + } + }, + "codersdk.ExternalAuthDevice": { + "type": "object", + "properties": { + "device_code": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "interval": { + "type": "integer" + }, + "user_code": { + "type": "string" + }, + "verification_uri": { + "type": "string" + } + } + }, "codersdk.ExternalAuthProvider": { "type": "string", "enum": [ @@ -8203,6 +8274,23 @@ const docTemplate = `{ "ExternalAuthProviderOpenIDConnect" ] }, + "codersdk.ExternalAuthUser": { + "type": "object", + "properties": { + "avatar_url": { + "type": "string" + }, + "login": { + "type": "string" + }, + "name": { + "type": "string" + }, + "profile_url": { + "type": "string" + } + } + }, "codersdk.Feature": { "type": "object", "properties": { @@ -8242,57 +8330,6 @@ const docTemplate = `{ } } }, - "codersdk.GitAuth": { - "type": "object", - "properties": { - "app_install_url": { - "description": "AppInstallURL is the URL to install the app.", - "type": "string" - }, - "app_installable": { - "description": "AppInstallable is true if the request for app installs was successful.", - "type": "boolean" - }, - "authenticated": { - "type": "boolean" - }, - "device": { - "type": "boolean" - }, - "installations": { - "description": "AppInstallations are the installations that the user has access to.", - "type": "array", - "items": { - "$ref": "#/definitions/codersdk.GitAuthAppInstallation" - } - }, - "type": { - "type": "string" - }, - "user": { - "description": "User is the user that authenticated with the provider.", - "allOf": [ - { - "$ref": "#/definitions/codersdk.GitAuthUser" - } - ] - } - } - }, - "codersdk.GitAuthAppInstallation": { - "type": "object", - "properties": { - "account": { - "$ref": "#/definitions/codersdk.GitAuthUser" - }, - "configure_url": { - "type": "string" - }, - "id": { - "type": "integer" - } - } - }, "codersdk.GitAuthConfig": { "type": "object", "properties": { @@ -8340,43 +8377,6 @@ const docTemplate = `{ } } }, - "codersdk.GitAuthDevice": { - "type": "object", - "properties": { - "device_code": { - "type": "string" - }, - "expires_in": { - "type": "integer" - }, - "interval": { - "type": "integer" - }, - "user_code": { - "type": "string" - }, - "verification_uri": { - "type": "string" - } - } - }, - "codersdk.GitAuthUser": { - "type": "object", - "properties": { - "avatar_url": { - "type": "string" - }, - "login": { - "type": "string" - }, - "name": { - "type": "string" - }, - "profile_url": { - "type": "string" - } - } - }, "codersdk.GitSSHKey": { "type": "object", "properties": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index ec02780589..7a7ee0a69e 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -512,6 +512,93 @@ } } }, + "/externalauth/{externalauth}": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Git"], + "summary": "Get external auth by ID", + "operationId": "get-external-auth-by-id", + "parameters": [ + { + "type": "string", + "format": "string", + "description": "Git Provider ID", + "name": "externalauth", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.ExternalAuth" + } + } + } + } + }, + "/externalauth/{externalauth}/device": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Git"], + "summary": "Get external auth device by ID.", + "operationId": "get-external-auth-device-by-id", + "parameters": [ + { + "type": "string", + "format": "string", + "description": "Git Provider ID", + "name": "externalauth", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.ExternalAuthDevice" + } + } + } + }, + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "tags": ["Git"], + "summary": "Post external auth device by ID", + "operationId": "post-external-auth-device-by-id", + "parameters": [ + { + "type": "string", + "format": "string", + "description": "External Provider ID", + "name": "externalauth", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, "/files": { "post": { "security": [ @@ -579,93 +666,6 @@ } } }, - "/gitauth/{gitauth}": { - "get": { - "security": [ - { - "CoderSessionToken": [] - } - ], - "produces": ["application/json"], - "tags": ["Git"], - "summary": "Get git auth by ID", - "operationId": "get-git-auth-by-id", - "parameters": [ - { - "type": "string", - "format": "string", - "description": "Git Provider ID", - "name": "gitauth", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/codersdk.GitAuth" - } - } - } - } - }, - "/gitauth/{gitauth}/device": { - "get": { - "security": [ - { - "CoderSessionToken": [] - } - ], - "produces": ["application/json"], - "tags": ["Git"], - "summary": "Get git auth device by ID.", - "operationId": "get-git-auth-device-by-id", - "parameters": [ - { - "type": "string", - "format": "string", - "description": "Git Provider ID", - "name": "gitauth", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/codersdk.GitAuthDevice" - } - } - } - }, - "post": { - "security": [ - { - "CoderSessionToken": [] - } - ], - "tags": ["Git"], - "summary": "Post git auth device by ID", - "operationId": "post-git-auth-device-by-id", - "parameters": [ - { - "type": "string", - "format": "string", - "description": "Git Provider ID", - "name": "gitauth", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "No Content" - } - } - } - }, "/groups/{group}": { "get": { "security": [ @@ -2430,7 +2430,7 @@ } } }, - "/templateversions/{templateversion}/gitauth": { + "/templateversions/{templateversion}/externalauth": { "get": { "security": [ { @@ -2439,8 +2439,8 @@ ], "produces": ["application/json"], "tags": ["Templates"], - "summary": "Get git auth by template version", - "operationId": "get-git-auth-by-template-version", + "summary": "Get external auth by template version", + "operationId": "get-external-auth-by-template-version", "parameters": [ { "type": "string", @@ -7334,6 +7334,77 @@ "ExperimentDeploymentHealthPage" ] }, + "codersdk.ExternalAuth": { + "type": "object", + "properties": { + "app_install_url": { + "description": "AppInstallURL is the URL to install the app.", + "type": "string" + }, + "app_installable": { + "description": "AppInstallable is true if the request for app installs was successful.", + "type": "boolean" + }, + "authenticated": { + "type": "boolean" + }, + "device": { + "type": "boolean" + }, + "installations": { + "description": "AppInstallations are the installations that the user has access to.", + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.ExternalAuthAppInstallation" + } + }, + "type": { + "type": "string" + }, + "user": { + "description": "User is the user that authenticated with the provider.", + "allOf": [ + { + "$ref": "#/definitions/codersdk.ExternalAuthUser" + } + ] + } + } + }, + "codersdk.ExternalAuthAppInstallation": { + "type": "object", + "properties": { + "account": { + "$ref": "#/definitions/codersdk.ExternalAuthUser" + }, + "configure_url": { + "type": "string" + }, + "id": { + "type": "integer" + } + } + }, + "codersdk.ExternalAuthDevice": { + "type": "object", + "properties": { + "device_code": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "interval": { + "type": "integer" + }, + "user_code": { + "type": "string" + }, + "verification_uri": { + "type": "string" + } + } + }, "codersdk.ExternalAuthProvider": { "type": "string", "enum": [ @@ -7351,6 +7422,23 @@ "ExternalAuthProviderOpenIDConnect" ] }, + "codersdk.ExternalAuthUser": { + "type": "object", + "properties": { + "avatar_url": { + "type": "string" + }, + "login": { + "type": "string" + }, + "name": { + "type": "string" + }, + "profile_url": { + "type": "string" + } + } + }, "codersdk.Feature": { "type": "object", "properties": { @@ -7390,57 +7478,6 @@ } } }, - "codersdk.GitAuth": { - "type": "object", - "properties": { - "app_install_url": { - "description": "AppInstallURL is the URL to install the app.", - "type": "string" - }, - "app_installable": { - "description": "AppInstallable is true if the request for app installs was successful.", - "type": "boolean" - }, - "authenticated": { - "type": "boolean" - }, - "device": { - "type": "boolean" - }, - "installations": { - "description": "AppInstallations are the installations that the user has access to.", - "type": "array", - "items": { - "$ref": "#/definitions/codersdk.GitAuthAppInstallation" - } - }, - "type": { - "type": "string" - }, - "user": { - "description": "User is the user that authenticated with the provider.", - "allOf": [ - { - "$ref": "#/definitions/codersdk.GitAuthUser" - } - ] - } - } - }, - "codersdk.GitAuthAppInstallation": { - "type": "object", - "properties": { - "account": { - "$ref": "#/definitions/codersdk.GitAuthUser" - }, - "configure_url": { - "type": "string" - }, - "id": { - "type": "integer" - } - } - }, "codersdk.GitAuthConfig": { "type": "object", "properties": { @@ -7488,43 +7525,6 @@ } } }, - "codersdk.GitAuthDevice": { - "type": "object", - "properties": { - "device_code": { - "type": "string" - }, - "expires_in": { - "type": "integer" - }, - "interval": { - "type": "integer" - }, - "user_code": { - "type": "string" - }, - "verification_uri": { - "type": "string" - } - } - }, - "codersdk.GitAuthUser": { - "type": "object", - "properties": { - "avatar_url": { - "type": "string" - }, - "login": { - "type": "string" - }, - "name": { - "type": "string" - }, - "profile_url": { - "type": "string" - } - } - }, "codersdk.GitSSHKey": { "type": "object", "properties": { diff --git a/coderd/coderd.go b/coderd/coderd.go index 6562044746..c02f9a8d3d 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -37,6 +37,7 @@ import ( // Used for swagger docs. _ "github.com/coder/coder/v2/coderd/apidoc" + "github.com/coder/coder/v2/coderd/externalauth" "cdr.dev/slog" "github.com/coder/coder/v2/buildinfo" @@ -47,7 +48,6 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/database/pubsub" - "github.com/coder/coder/v2/coderd/gitauth" "github.com/coder/coder/v2/coderd/gitsshkey" "github.com/coder/coder/v2/coderd/healthcheck" "github.com/coder/coder/v2/coderd/httpapi" @@ -115,7 +115,7 @@ type Options struct { SSHKeygenAlgorithm gitsshkey.Algorithm Telemetry telemetry.Reporter TracerProvider trace.TracerProvider - ExternalAuthConfigs []*gitauth.Config + ExternalAuthConfigs []*externalauth.Config RealIPConfig *httpmw.RealIPConfig TrialGenerator func(ctx context.Context, email string) error // TLSCertificates is used to mesh DERP servers securely. @@ -546,21 +546,24 @@ func New(options *Options) *API { }) // Register callback handlers for each OAuth2 provider. - r.Route("/gitauth", func(r chi.Router) { - for _, gitAuthConfig := range options.ExternalAuthConfigs { - // We don't need to register a callback handler for device auth. - if gitAuthConfig.DeviceAuth != nil { - continue + // We must support gitauth and externalauth for backwards compatibility. + for _, route := range []string{"gitauth", "externalauth"} { + r.Route("/"+route, func(r chi.Router) { + for _, externalAuthConfig := range options.ExternalAuthConfigs { + // We don't need to register a callback handler for device auth. + if externalAuthConfig.DeviceAuth != nil { + continue + } + r.Route(fmt.Sprintf("/%s/callback", externalAuthConfig.ID), func(r chi.Router) { + r.Use( + apiKeyMiddlewareRedirect, + httpmw.ExtractOAuth2(externalAuthConfig, options.HTTPClient, nil), + ) + r.Get("/", api.externalAuthCallback(externalAuthConfig)) + }) } - r.Route(fmt.Sprintf("/%s/callback", gitAuthConfig.ID), func(r chi.Router) { - r.Use( - apiKeyMiddlewareRedirect, - httpmw.ExtractOAuth2(gitAuthConfig, options.HTTPClient, nil), - ) - r.Get("/", api.gitAuthCallback(gitAuthConfig)) - }) - } - }) + }) + } r.Route("/api/v2", func(r chi.Router) { api.APIHandler = r @@ -613,14 +616,14 @@ func New(options *Options) *API { r.Get("/{fileID}", api.fileByID) r.Post("/", api.postFile) }) - r.Route("/gitauth/{gitauth}", func(r chi.Router) { + r.Route("/externalauth/{externalauth}", func(r chi.Router) { r.Use( apiKeyMiddleware, - httpmw.ExtractGitAuthParam(options.ExternalAuthConfigs), + httpmw.ExtractExternalAuthParam(options.ExternalAuthConfigs), ) - r.Get("/", api.gitAuthByID) - r.Post("/device", api.postGitAuthDeviceByID) - r.Get("/device", api.gitAuthDeviceByID) + r.Get("/", api.externalAuthByID) + r.Post("/device", api.postExternalAuthDeviceByID) + r.Get("/device", api.externalAuthDeviceByID) }) r.Route("/organizations", func(r chi.Router) { r.Use( @@ -686,7 +689,7 @@ func New(options *Options) *API { r.Get("/schema", templateVersionSchemaDeprecated) r.Get("/parameters", templateVersionParametersDeprecated) r.Get("/rich-parameters", api.templateVersionRichParameters) - r.Get("/gitauth", api.templateVersionGitAuth) + r.Get("/externalauth", api.templateVersionExternalAuth) r.Get("/variables", api.templateVersionVariables) r.Get("/resources", api.templateVersionResources) r.Get("/logs", api.templateVersionLogs) diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 9700311fe7..6cc0d5132e 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -59,7 +59,7 @@ import ( "github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/pubsub" - "github.com/coder/coder/v2/coderd/gitauth" + "github.com/coder/coder/v2/coderd/externalauth" "github.com/coder/coder/v2/coderd/gitsshkey" "github.com/coder/coder/v2/coderd/healthcheck" "github.com/coder/coder/v2/coderd/httpapi" @@ -105,7 +105,7 @@ type Options struct { AutobuildStats chan<- autobuild.Stats Auditor audit.Auditor TLSCertificates []tls.Certificate - ExternalAuthConfigs []*gitauth.Config + ExternalAuthConfigs []*externalauth.Config TrialGenerator func(context.Context, string) error TemplateScheduleStore schedule.TemplateScheduleStore Coordinator tailnet.Coordinator @@ -899,14 +899,14 @@ func MustWorkspace(t *testing.T, client *codersdk.Client, workspaceID uuid.UUID) return ws } -// RequestGitAuthCallback makes a request with the proper OAuth2 state cookie -// to the git auth callback endpoint. -func RequestGitAuthCallback(t *testing.T, providerID string, client *codersdk.Client) *http.Response { +// RequestExternalAuthCallback makes a request with the proper OAuth2 state cookie +// to the external auth callback endpoint. +func RequestExternalAuthCallback(t *testing.T, providerID string, client *codersdk.Client) *http.Response { client.HTTPClient.CheckRedirect = func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse } state := "somestate" - oauthURL, err := client.URL.Parse(fmt.Sprintf("/gitauth/%s/callback?code=asd&state=%s", providerID, state)) + oauthURL, err := client.URL.Parse(fmt.Sprintf("/externalauth/%s/callback?code=asd&state=%s", providerID, state)) require.NoError(t, err) req, err := http.NewRequestWithContext(context.Background(), "GET", oauthURL.String(), nil) require.NoError(t, err) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index bee782a1aa..c0a5cfcecf 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -2486,7 +2486,7 @@ func (q *querier) UpdateTemplateVersionDescriptionByJobID(ctx context.Context, a } func (q *querier) UpdateTemplateVersionExternalAuthProvidersByJobID(ctx context.Context, arg database.UpdateTemplateVersionExternalAuthProvidersByJobIDParams) error { - // An actor is allowed to update the template version git auth providers if they are authorized to update the template. + // An actor is allowed to update the template version external auth providers if they are authorized to update the template. tv, err := q.db.GetTemplateVersionByJobID(ctx, arg.JobID) if err != nil { return err diff --git a/coderd/gitauth.go b/coderd/externalauth.go similarity index 73% rename from coderd/gitauth.go rename to coderd/externalauth.go index 728f4d6613..f668d6b5a9 100644 --- a/coderd/gitauth.go +++ b/coderd/externalauth.go @@ -10,31 +10,31 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbtime" - "github.com/coder/coder/v2/coderd/gitauth" + "github.com/coder/coder/v2/coderd/externalauth" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/codersdk" ) -// @Summary Get git auth by ID -// @ID get-git-auth-by-id +// @Summary Get external auth by ID +// @ID get-external-auth-by-id // @Security CoderSessionToken // @Produce json // @Tags Git -// @Param gitauth path string true "Git Provider ID" format(string) -// @Success 200 {object} codersdk.GitAuth -// @Router /gitauth/{gitauth} [get] -func (api *API) gitAuthByID(w http.ResponseWriter, r *http.Request) { - config := httpmw.GitAuthParam(r) +// @Param externalauth path string true "Git Provider ID" format(string) +// @Success 200 {object} codersdk.ExternalAuth +// @Router /externalauth/{externalauth} [get] +func (api *API) externalAuthByID(w http.ResponseWriter, r *http.Request) { + config := httpmw.ExternalAuthParam(r) apiKey := httpmw.APIKey(r) ctx := r.Context() - res := codersdk.GitAuth{ + res := codersdk.ExternalAuth{ Authenticated: false, Device: config.DeviceAuth != nil, AppInstallURL: config.AppInstallURL, Type: config.Type.Pretty(), - AppInstallations: []codersdk.GitAuthAppInstallation{}, + AppInstallations: []codersdk.ExternalAuthAppInstallation{}, } link, err := api.Database.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{ @@ -44,7 +44,7 @@ func (api *API) gitAuthByID(w http.ResponseWriter, r *http.Request) { if err != nil { if !errors.Is(err, sql.ErrNoRows) { httpapi.Write(ctx, w, http.StatusInternalServerError, codersdk.Response{ - Message: "Failed to get git auth link.", + Message: "Failed to get external auth link.", Detail: err.Error(), }) return @@ -71,24 +71,24 @@ func (api *API) gitAuthByID(w http.ResponseWriter, r *http.Request) { return } if res.AppInstallations == nil { - res.AppInstallations = []codersdk.GitAuthAppInstallation{} + res.AppInstallations = []codersdk.ExternalAuthAppInstallation{} } httpapi.Write(ctx, w, http.StatusOK, res) } -// @Summary Post git auth device by ID -// @ID post-git-auth-device-by-id +// @Summary Post external auth device by ID +// @ID post-external-auth-device-by-id // @Security CoderSessionToken // @Tags Git -// @Param gitauth path string true "Git Provider ID" format(string) +// @Param externalauth path string true "External Provider ID" format(string) // @Success 204 -// @Router /gitauth/{gitauth}/device [post] -func (api *API) postGitAuthDeviceByID(rw http.ResponseWriter, r *http.Request) { +// @Router /externalauth/{externalauth}/device [post] +func (api *API) postExternalAuthDeviceByID(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() apiKey := httpmw.APIKey(r) - config := httpmw.GitAuthParam(r) + config := httpmw.ExternalAuthParam(r) - var req codersdk.GitAuthDeviceExchange + var req codersdk.ExternalAuthDeviceExchange if !httpapi.Read(ctx, rw, r, &req) { return } @@ -116,7 +116,7 @@ func (api *API) postGitAuthDeviceByID(rw http.ResponseWriter, r *http.Request) { if err != nil { if !errors.Is(err, sql.ErrNoRows) { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "Failed to get git auth link.", + Message: "Failed to get external auth link.", Detail: err.Error(), }) return @@ -133,7 +133,7 @@ func (api *API) postGitAuthDeviceByID(rw http.ResponseWriter, r *http.Request) { }) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "Failed to insert git auth link.", + Message: "Failed to insert external auth link.", Detail: err.Error(), }) return @@ -149,7 +149,7 @@ func (api *API) postGitAuthDeviceByID(rw http.ResponseWriter, r *http.Request) { }) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "Failed to update git auth link.", + Message: "Failed to update external auth link.", Detail: err.Error(), }) return @@ -158,16 +158,16 @@ func (api *API) postGitAuthDeviceByID(rw http.ResponseWriter, r *http.Request) { httpapi.Write(ctx, rw, http.StatusNoContent, nil) } -// @Summary Get git auth device by ID. -// @ID get-git-auth-device-by-id +// @Summary Get external auth device by ID. +// @ID get-external-auth-device-by-id // @Security CoderSessionToken // @Produce json // @Tags Git -// @Param gitauth path string true "Git Provider ID" format(string) -// @Success 200 {object} codersdk.GitAuthDevice -// @Router /gitauth/{gitauth}/device [get] -func (*API) gitAuthDeviceByID(rw http.ResponseWriter, r *http.Request) { - config := httpmw.GitAuthParam(r) +// @Param externalauth path string true "Git Provider ID" format(string) +// @Success 200 {object} codersdk.ExternalAuthDevice +// @Router /externalauth/{externalauth}/device [get] +func (*API) externalAuthDeviceByID(rw http.ResponseWriter, r *http.Request) { + config := httpmw.ExternalAuthParam(r) ctx := r.Context() if config.DeviceAuth == nil { @@ -189,7 +189,7 @@ func (*API) gitAuthDeviceByID(rw http.ResponseWriter, r *http.Request) { httpapi.Write(ctx, rw, http.StatusOK, deviceAuth) } -func (api *API) gitAuthCallback(gitAuthConfig *gitauth.Config) http.HandlerFunc { +func (api *API) externalAuthCallback(externalAuthConfig *externalauth.Config) http.HandlerFunc { return func(rw http.ResponseWriter, r *http.Request) { var ( ctx = r.Context() @@ -198,20 +198,20 @@ func (api *API) gitAuthCallback(gitAuthConfig *gitauth.Config) http.HandlerFunc ) _, err := api.Database.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{ - ProviderID: gitAuthConfig.ID, + ProviderID: externalAuthConfig.ID, UserID: apiKey.UserID, }) if err != nil { if !errors.Is(err, sql.ErrNoRows) { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "Failed to get git auth link.", + Message: "Failed to get external auth link.", Detail: err.Error(), }) return } _, err = api.Database.InsertExternalAuthLink(ctx, database.InsertExternalAuthLinkParams{ - ProviderID: gitAuthConfig.ID, + ProviderID: externalAuthConfig.ID, UserID: apiKey.UserID, CreatedAt: dbtime.Now(), UpdatedAt: dbtime.Now(), @@ -221,14 +221,14 @@ func (api *API) gitAuthCallback(gitAuthConfig *gitauth.Config) http.HandlerFunc }) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "Failed to insert git auth link.", + Message: "Failed to insert external auth link.", Detail: err.Error(), }) return } } else { _, err = api.Database.UpdateExternalAuthLink(ctx, database.UpdateExternalAuthLinkParams{ - ProviderID: gitAuthConfig.ID, + ProviderID: externalAuthConfig.ID, UserID: apiKey.UserID, UpdatedAt: dbtime.Now(), OAuthAccessToken: state.Token.AccessToken, @@ -237,7 +237,7 @@ func (api *API) gitAuthCallback(gitAuthConfig *gitauth.Config) http.HandlerFunc }) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "Failed to update git auth link.", + Message: "Failed to update external auth link.", Detail: err.Error(), }) return @@ -247,7 +247,7 @@ func (api *API) gitAuthCallback(gitAuthConfig *gitauth.Config) http.HandlerFunc redirect := state.Redirect if redirect == "" { // This is a nicely rendered screen on the frontend - redirect = fmt.Sprintf("/gitauth/%s", gitAuthConfig.ID) + redirect = fmt.Sprintf("/externalauth/%s", externalAuthConfig.ID) } http.Redirect(rw, r, redirect, http.StatusTemporaryRedirect) } diff --git a/coderd/gitauth/config.go b/coderd/externalauth/config.go similarity index 83% rename from coderd/gitauth/config.go rename to coderd/externalauth/config.go index 820721ad1b..51ef866354 100644 --- a/coderd/gitauth/config.go +++ b/coderd/externalauth/config.go @@ -1,4 +1,4 @@ -package gitauth +package externalauth import ( "context" @@ -65,35 +65,35 @@ type Config struct { // RefreshToken automatically refreshes the token if expired and permitted. // It returns the token and a bool indicating if the token is valid. -func (c *Config) RefreshToken(ctx context.Context, db database.Store, gitAuthLink database.ExternalAuthLink) (database.ExternalAuthLink, bool, error) { +func (c *Config) RefreshToken(ctx context.Context, db database.Store, externalAuthLink database.ExternalAuthLink) (database.ExternalAuthLink, bool, error) { // If the token is expired and refresh is disabled, we prompt // the user to authenticate again. if c.NoRefresh && // If the time is set to 0, then it should never expire. // This is true for github, which has no expiry. - !gitAuthLink.OAuthExpiry.IsZero() && - gitAuthLink.OAuthExpiry.Before(dbtime.Now()) { - return gitAuthLink, false, nil + !externalAuthLink.OAuthExpiry.IsZero() && + externalAuthLink.OAuthExpiry.Before(dbtime.Now()) { + return externalAuthLink, false, nil } // This is additional defensive programming. Because TokenSource is an interface, // we cannot be sure that the implementation will treat an 'IsZero' time // as "not-expired". The default implementation does, but a custom implementation // might not. Removing the refreshToken will guarantee a refresh will fail. - refreshToken := gitAuthLink.OAuthRefreshToken + refreshToken := externalAuthLink.OAuthRefreshToken if c.NoRefresh { refreshToken = "" } token, err := c.TokenSource(ctx, &oauth2.Token{ - AccessToken: gitAuthLink.OAuthAccessToken, + AccessToken: externalAuthLink.OAuthAccessToken, RefreshToken: refreshToken, - Expiry: gitAuthLink.OAuthExpiry, + Expiry: externalAuthLink.OAuthExpiry, }).Token() if err != nil { // Even if the token fails to be obtained, we still return false because // we aren't trying to surface an error, we're just trying to obtain a valid token. - return gitAuthLink, false, nil + return externalAuthLink, false, nil } r := retry.New(50*time.Millisecond, 200*time.Millisecond) // See the comment below why the retry and cancel is required. @@ -102,7 +102,7 @@ func (c *Config) RefreshToken(ctx context.Context, db database.Store, gitAuthLin validate: valid, _, err := c.ValidateToken(ctx, token.AccessToken) if err != nil { - return gitAuthLink, false, xerrors.Errorf("validate git auth token: %w", err) + return externalAuthLink, false, xerrors.Errorf("validate external auth token: %w", err) } if !valid { // A customer using GitHub in Australia reported that validating immediately @@ -116,29 +116,29 @@ validate: goto validate } // The token is no longer valid! - return gitAuthLink, false, nil + return externalAuthLink, false, nil } - if token.AccessToken != gitAuthLink.OAuthAccessToken { + if token.AccessToken != externalAuthLink.OAuthAccessToken { // Update it - gitAuthLink, err = db.UpdateExternalAuthLink(ctx, database.UpdateExternalAuthLinkParams{ + externalAuthLink, err = db.UpdateExternalAuthLink(ctx, database.UpdateExternalAuthLinkParams{ ProviderID: c.ID, - UserID: gitAuthLink.UserID, + UserID: externalAuthLink.UserID, UpdatedAt: dbtime.Now(), OAuthAccessToken: token.AccessToken, OAuthRefreshToken: token.RefreshToken, OAuthExpiry: token.Expiry, }) if err != nil { - return gitAuthLink, false, xerrors.Errorf("update git auth link: %w", err) + return externalAuthLink, false, xerrors.Errorf("update external auth link: %w", err) } } - return gitAuthLink, true, nil + return externalAuthLink, true, nil } // ValidateToken ensures the Git token provided is valid! // The user is optionally returned if the provider supports it. -func (c *Config) ValidateToken(ctx context.Context, token string) (bool, *codersdk.GitAuthUser, error) { +func (c *Config) ValidateToken(ctx context.Context, token string) (bool, *codersdk.ExternalAuthUser, error) { if c.ValidateURL == "" { // Default that the token is valid if no validation URL is provided. return true, nil, nil @@ -167,12 +167,12 @@ func (c *Config) ValidateToken(ctx context.Context, token string) (bool, *coders return false, nil, xerrors.Errorf("status %d: body: %s", res.StatusCode, data) } - var user *codersdk.GitAuthUser + var user *codersdk.ExternalAuthUser if c.Type == codersdk.ExternalAuthProviderGitHub { var ghUser github.User err = json.NewDecoder(res.Body).Decode(&ghUser) if err == nil { - user = &codersdk.GitAuthUser{ + user = &codersdk.ExternalAuthUser{ Login: ghUser.GetLogin(), AvatarURL: ghUser.GetAvatarURL(), ProfileURL: ghUser.GetHTMLURL(), @@ -194,7 +194,7 @@ type AppInstallation struct { // AppInstallations returns a list of app installations for the given token. // If the provider does not support app installations, it returns nil. -func (c *Config) AppInstallations(ctx context.Context, token string) ([]codersdk.GitAuthAppInstallation, bool, error) { +func (c *Config) AppInstallations(ctx context.Context, token string) ([]codersdk.ExternalAuthAppInstallation, bool, error) { if c.AppInstallationsURL == "" { return nil, false, nil } @@ -213,7 +213,7 @@ func (c *Config) AppInstallations(ctx context.Context, token string) ([]codersdk if res.StatusCode != http.StatusOK { return nil, false, nil } - installs := []codersdk.GitAuthAppInstallation{} + installs := []codersdk.ExternalAuthAppInstallation{} if c.Type == codersdk.ExternalAuthProviderGitHub { var ghInstalls struct { Installations []*github.Installation `json:"installations"` @@ -227,10 +227,10 @@ func (c *Config) AppInstallations(ctx context.Context, token string) ([]codersdk if account == nil { continue } - installs = append(installs, codersdk.GitAuthAppInstallation{ + installs = append(installs, codersdk.ExternalAuthAppInstallation{ ID: int(installation.GetID()), ConfigureURL: installation.GetHTMLURL(), - Account: codersdk.GitAuthUser{ + Account: codersdk.ExternalAuthUser{ Login: account.GetLogin(), AvatarURL: account.GetAvatarURL(), ProfileURL: account.GetHTMLURL(), @@ -266,30 +266,30 @@ func ConvertConfig(entries []codersdk.GitAuthConfig, accessURL *url.URL) ([]*Con entry.ID = string(typ) } if valid := httpapi.NameValid(entry.ID); valid != nil { - return nil, xerrors.Errorf("git auth provider %q doesn't have a valid id: %w", entry.ID, valid) + return nil, xerrors.Errorf("external auth provider %q doesn't have a valid id: %w", entry.ID, valid) } _, exists := ids[entry.ID] if exists { if entry.ID == string(typ) { - return nil, xerrors.Errorf("multiple %s git auth providers provided. you must specify a unique id for each", typ) + return nil, xerrors.Errorf("multiple %s external auth providers provided. you must specify a unique id for each", typ) } return nil, xerrors.Errorf("multiple git providers exist with the id %q. specify a unique id for each", entry.ID) } ids[entry.ID] = struct{}{} if entry.ClientID == "" { - return nil, xerrors.Errorf("%q git auth provider: client_id must be provided", entry.ID) + return nil, xerrors.Errorf("%q external auth provider: client_id must be provided", entry.ID) } - authRedirect, err := accessURL.Parse(fmt.Sprintf("/gitauth/%s/callback", entry.ID)) + authRedirect, err := accessURL.Parse(fmt.Sprintf("/externalauth/%s/callback", entry.ID)) if err != nil { - return nil, xerrors.Errorf("parse gitauth callback url: %w", err) + return nil, xerrors.Errorf("parse externalauth callback url: %w", err) } regex := regex[typ] if entry.Regex != "" { regex, err = regexp.Compile(entry.Regex) if err != nil { - return nil, xerrors.Errorf("compile regex for git auth provider %q: %w", entry.ID, entry.Regex) + return nil, xerrors.Errorf("compile regex for external auth provider %q: %w", entry.ID, entry.Regex) } } @@ -339,7 +339,7 @@ func ConvertConfig(entries []codersdk.GitAuthConfig, accessURL *url.URL) ([]*Con entry.DeviceCodeURL = deviceAuthURL[typ] } if entry.DeviceCodeURL == "" { - return nil, xerrors.Errorf("git auth provider %q: device auth url must be provided", entry.ID) + return nil, xerrors.Errorf("external auth provider %q: device auth url must be provided", entry.ID) } cfg.DeviceAuth = &DeviceAuth{ ClientID: entry.ClientID, diff --git a/coderd/gitauth/config_test.go b/coderd/externalauth/config_test.go similarity index 91% rename from coderd/gitauth/config_test.go rename to coderd/externalauth/config_test.go index 3fecc561af..4bd9e0b162 100644 --- a/coderd/gitauth/config_test.go +++ b/coderd/externalauth/config_test.go @@ -1,4 +1,4 @@ -package gitauth_test +package externalauth_test import ( "context" @@ -19,14 +19,13 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/database/dbfake" - "github.com/coder/coder/v2/coderd/gitauth" + "github.com/coder/coder/v2/coderd/externalauth" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/testutil" ) func TestRefreshToken(t *testing.T) { t.Parallel() - const providerID = "test-idp" expired := time.Now().Add(time.Hour * -1) t.Run("NoRefreshExpired", func(t *testing.T) { @@ -44,7 +43,7 @@ func TestRefreshToken(t *testing.T) { return nil, xerrors.New("should not be called") }), }, - GitConfigOpt: func(cfg *gitauth.Config) { + GitConfigOpt: func(cfg *externalauth.Config) { cfg.NoRefresh = true }, }) @@ -75,7 +74,7 @@ func TestRefreshToken(t *testing.T) { return jwt.MapClaims{}, nil }), }, - GitConfigOpt: func(cfg *gitauth.Config) { + GitConfigOpt: func(cfg *externalauth.Config) { cfg.NoRefresh = true }, }) @@ -92,7 +91,7 @@ func TestRefreshToken(t *testing.T) { t.Run("FalseIfTokenSourceFails", func(t *testing.T) { t.Parallel() - config := &gitauth.Config{ + config := &externalauth.Config{ OAuth2Config: &testutil.OAuth2Config{ TokenSourceFunc: func() (*oauth2.Token, error) { return nil, xerrors.New("failure") @@ -118,7 +117,7 @@ func TestRefreshToken(t *testing.T) { return jwt.MapClaims{}, xerrors.New(staticError) }), }, - GitConfigOpt: func(cfg *gitauth.Config) { + GitConfigOpt: func(cfg *externalauth.Config) { }, }) @@ -143,7 +142,7 @@ func TestRefreshToken(t *testing.T) { return jwt.MapClaims{}, oidctest.StatusError(http.StatusUnauthorized, xerrors.New(staticError)) }), }, - GitConfigOpt: func(cfg *gitauth.Config) { + GitConfigOpt: func(cfg *externalauth.Config) { }, }) @@ -176,7 +175,7 @@ func TestRefreshToken(t *testing.T) { return jwt.MapClaims{}, oidctest.StatusError(http.StatusUnauthorized, xerrors.New(staticError)) }), }, - GitConfigOpt: func(cfg *gitauth.Config) { + GitConfigOpt: func(cfg *externalauth.Config) { cfg.Type = codersdk.ExternalAuthProviderGitHub }, }) @@ -206,7 +205,7 @@ func TestRefreshToken(t *testing.T) { return jwt.MapClaims{}, nil }), }, - GitConfigOpt: func(cfg *gitauth.Config) { + GitConfigOpt: func(cfg *externalauth.Config) { cfg.Type = codersdk.ExternalAuthProviderGitHub }, }) @@ -237,7 +236,7 @@ func TestRefreshToken(t *testing.T) { return jwt.MapClaims{}, nil }), }, - GitConfigOpt: func(cfg *gitauth.Config) { + GitConfigOpt: func(cfg *externalauth.Config) { cfg.Type = codersdk.ExternalAuthProviderGitHub }, DB: db, @@ -268,7 +267,7 @@ func TestConvertYAML(t *testing.T) { for _, tc := range []struct { Name string Input []codersdk.GitAuthConfig - Output []*gitauth.Config + Output []*externalauth.Config Error string }{{ Name: "InvalidType", @@ -298,7 +297,7 @@ func TestConvertYAML(t *testing.T) { }, { Type: string(codersdk.ExternalAuthProviderGitHub), }}, - Error: "multiple github git auth providers provided", + Error: "multiple github external auth providers provided", }, { Name: "InvalidRegex", Input: []codersdk.GitAuthConfig{{ @@ -307,7 +306,7 @@ func TestConvertYAML(t *testing.T) { ClientSecret: "example", Regex: `\K`, }}, - Error: "compile regex for git auth provider", + Error: "compile regex for external auth provider", }, { Name: "NoDeviceURL", Input: []codersdk.GitAuthConfig{{ @@ -321,7 +320,7 @@ func TestConvertYAML(t *testing.T) { tc := tc t.Run(tc.Name, func(t *testing.T) { t.Parallel() - output, err := gitauth.ConvertConfig(tc.Input, &url.URL{}) + output, err := externalauth.ConvertConfig(tc.Input, &url.URL{}) if tc.Error != "" { require.Error(t, err) require.Contains(t, err.Error(), tc.Error) @@ -333,7 +332,7 @@ func TestConvertYAML(t *testing.T) { t.Run("CustomScopesAndEndpoint", func(t *testing.T) { t.Parallel() - config, err := gitauth.ConvertConfig([]codersdk.GitAuthConfig{{ + config, err := externalauth.ConvertConfig([]codersdk.GitAuthConfig{{ Type: string(codersdk.ExternalAuthProviderGitLab), ClientID: "id", ClientSecret: "secret", @@ -342,24 +341,24 @@ func TestConvertYAML(t *testing.T) { Scopes: []string{"read"}, }}, &url.URL{}) require.NoError(t, err) - require.Equal(t, "https://auth.com?client_id=id&redirect_uri=%2Fgitauth%2Fgitlab%2Fcallback&response_type=code&scope=read", config[0].AuthCodeURL("")) + require.Equal(t, "https://auth.com?client_id=id&redirect_uri=%2Fexternalauth%2Fgitlab%2Fcallback&response_type=code&scope=read", config[0].AuthCodeURL("")) }) } type testConfig struct { FakeIDPOpts []oidctest.FakeIDPOpt CoderOIDCConfigOpts []func(cfg *coderd.OIDCConfig) - GitConfigOpt func(cfg *gitauth.Config) + GitConfigOpt func(cfg *externalauth.Config) // If DB is passed in, the link will be inserted into the DB. DB database.Store } -// setupTest will configure a fake IDP and a gitauth.Config for testing. +// setupTest will configure a fake IDP and a externalauth.Config for testing. // The Fake's userinfo endpoint is used for validating tokens. // No http servers are started so use the fake IDP's HTTPClient to make requests. // The returned token is a fully valid token for the IDP. Feel free to manipulate it // to test different scenarios. -func setupOauth2Test(t *testing.T, settings testConfig) (*oidctest.FakeIDP, *gitauth.Config, database.ExternalAuthLink) { +func setupOauth2Test(t *testing.T, settings testConfig) (*oidctest.FakeIDP, *externalauth.Config, database.ExternalAuthLink) { t.Helper() const providerID = "test-idp" @@ -367,7 +366,7 @@ func setupOauth2Test(t *testing.T, settings testConfig) (*oidctest.FakeIDP, *git append([]oidctest.FakeIDPOpt{}, settings.FakeIDPOpts...)..., ) - config := &gitauth.Config{ + config := &externalauth.Config{ OAuth2Config: fake.OIDCConfig(t, nil, settings.CoderOIDCConfigOpts...), ID: providerID, ValidateURL: fake.WellknownConfig().UserInfoURL, diff --git a/coderd/gitauth/oauth.go b/coderd/externalauth/oauth.go similarity index 98% rename from coderd/gitauth/oauth.go rename to coderd/externalauth/oauth.go index 24b0416d20..0f679e8fe0 100644 --- a/coderd/gitauth/oauth.go +++ b/coderd/externalauth/oauth.go @@ -1,4 +1,4 @@ -package gitauth +package externalauth import ( "context" @@ -107,7 +107,7 @@ type DeviceAuth struct { // AuthorizeDevice begins the device authorization flow. // See: https://tools.ietf.org/html/rfc8628#section-3.1 -func (c *DeviceAuth) AuthorizeDevice(ctx context.Context) (*codersdk.GitAuthDevice, error) { +func (c *DeviceAuth) AuthorizeDevice(ctx context.Context) (*codersdk.ExternalAuthDevice, error) { if c.CodeURL == "" { return nil, xerrors.New("oauth2: device code URL not set") } @@ -126,7 +126,7 @@ func (c *DeviceAuth) AuthorizeDevice(ctx context.Context) (*codersdk.GitAuthDevi } defer resp.Body.Close() var r struct { - codersdk.GitAuthDevice + codersdk.ExternalAuthDevice ErrorDescription string `json:"error_description"` } err = json.NewDecoder(resp.Body).Decode(&r) @@ -136,7 +136,7 @@ func (c *DeviceAuth) AuthorizeDevice(ctx context.Context) (*codersdk.GitAuthDevi if r.ErrorDescription != "" { return nil, xerrors.New(r.ErrorDescription) } - return &r.GitAuthDevice, nil + return &r.ExternalAuthDevice, nil } type ExchangeDeviceCodeResponse struct { diff --git a/coderd/gitauth_test.go b/coderd/externalauth_test.go similarity index 84% rename from coderd/gitauth_test.go rename to coderd/externalauth_test.go index 985a823af4..b5090b6058 100644 --- a/coderd/gitauth_test.go +++ b/coderd/externalauth_test.go @@ -18,7 +18,7 @@ import ( "github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/database/dbtime" - "github.com/coder/coder/v2/coderd/gitauth" + "github.com/coder/coder/v2/coderd/externalauth" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/codersdk/agentsdk" @@ -26,19 +26,19 @@ import ( "github.com/coder/coder/v2/testutil" ) -func TestGitAuthByID(t *testing.T) { +func TestExternalAuthByID(t *testing.T) { t.Parallel() t.Run("Unauthenticated", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{ - ExternalAuthConfigs: []*gitauth.Config{{ + ExternalAuthConfigs: []*externalauth.Config{{ ID: "test", OAuth2Config: &testutil.OAuth2Config{}, Type: codersdk.ExternalAuthProviderGitHub, }}, }) coderdtest.CreateFirstUser(t, client) - auth, err := client.GitAuthByID(context.Background(), "test") + auth, err := client.ExternalAuthByID(context.Background(), "test") require.NoError(t, err) require.False(t, auth.Authenticated) }) @@ -47,7 +47,7 @@ func TestGitAuthByID(t *testing.T) { // still return that the provider is authenticated. t.Parallel() client := coderdtest.New(t, &coderdtest.Options{ - ExternalAuthConfigs: []*gitauth.Config{{ + ExternalAuthConfigs: []*externalauth.Config{{ ID: "test", OAuth2Config: &testutil.OAuth2Config{}, // AzureDevops doesn't have a user endpoint! @@ -55,9 +55,9 @@ func TestGitAuthByID(t *testing.T) { }}, }) coderdtest.CreateFirstUser(t, client) - resp := coderdtest.RequestGitAuthCallback(t, "test", client) + resp := coderdtest.RequestExternalAuthCallback(t, "test", client) _ = resp.Body.Close() - auth, err := client.GitAuthByID(context.Background(), "test") + auth, err := client.ExternalAuthByID(context.Background(), "test") require.NoError(t, err) require.True(t, auth.Authenticated) }) @@ -71,7 +71,7 @@ func TestGitAuthByID(t *testing.T) { })) defer validateSrv.Close() client := coderdtest.New(t, &coderdtest.Options{ - ExternalAuthConfigs: []*gitauth.Config{{ + ExternalAuthConfigs: []*externalauth.Config{{ ID: "test", ValidateURL: validateSrv.URL, OAuth2Config: &testutil.OAuth2Config{}, @@ -79,9 +79,9 @@ func TestGitAuthByID(t *testing.T) { }}, }) coderdtest.CreateFirstUser(t, client) - resp := coderdtest.RequestGitAuthCallback(t, "test", client) + resp := coderdtest.RequestExternalAuthCallback(t, "test", client) _ = resp.Body.Close() - auth, err := client.GitAuthByID(context.Background(), "test") + auth, err := client.ExternalAuthByID(context.Background(), "test") require.NoError(t, err) require.True(t, auth.Authenticated) require.NotNil(t, auth.User) @@ -111,7 +111,7 @@ func TestGitAuthByID(t *testing.T) { })) defer srv.Close() client := coderdtest.New(t, &coderdtest.Options{ - ExternalAuthConfigs: []*gitauth.Config{{ + ExternalAuthConfigs: []*externalauth.Config{{ ID: "test", ValidateURL: srv.URL + "/user", AppInstallationsURL: srv.URL + "/installs", @@ -120,9 +120,9 @@ func TestGitAuthByID(t *testing.T) { }}, }) coderdtest.CreateFirstUser(t, client) - resp := coderdtest.RequestGitAuthCallback(t, "test", client) + resp := coderdtest.RequestExternalAuthCallback(t, "test", client) _ = resp.Body.Close() - auth, err := client.GitAuthByID(context.Background(), "test") + auth, err := client.ExternalAuthByID(context.Background(), "test") require.NoError(t, err) require.True(t, auth.Authenticated) require.NotNil(t, auth.User) @@ -137,12 +137,12 @@ func TestGitAuthDevice(t *testing.T) { t.Run("NotSupported", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{ - ExternalAuthConfigs: []*gitauth.Config{{ + ExternalAuthConfigs: []*externalauth.Config{{ ID: "test", }}, }) coderdtest.CreateFirstUser(t, client) - _, err := client.GitAuthDeviceByID(context.Background(), "test") + _, err := client.ExternalAuthDeviceByID(context.Background(), "test") var sdkErr *codersdk.Error require.ErrorAs(t, err, &sdkErr) require.Equal(t, http.StatusBadRequest, sdkErr.StatusCode()) @@ -150,15 +150,15 @@ func TestGitAuthDevice(t *testing.T) { t.Run("FetchCode", func(t *testing.T) { t.Parallel() srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - httpapi.Write(r.Context(), w, http.StatusOK, codersdk.GitAuthDevice{ + httpapi.Write(r.Context(), w, http.StatusOK, codersdk.ExternalAuthDevice{ UserCode: "hey", }) })) defer srv.Close() client := coderdtest.New(t, &coderdtest.Options{ - ExternalAuthConfigs: []*gitauth.Config{{ + ExternalAuthConfigs: []*externalauth.Config{{ ID: "test", - DeviceAuth: &gitauth.DeviceAuth{ + DeviceAuth: &externalauth.DeviceAuth{ ClientID: "test", CodeURL: srv.URL, Scopes: []string{"repo"}, @@ -166,13 +166,13 @@ func TestGitAuthDevice(t *testing.T) { }}, }) coderdtest.CreateFirstUser(t, client) - device, err := client.GitAuthDeviceByID(context.Background(), "test") + device, err := client.ExternalAuthDeviceByID(context.Background(), "test") require.NoError(t, err) require.Equal(t, "hey", device.UserCode) }) t.Run("ExchangeCode", func(t *testing.T) { t.Parallel() - resp := gitauth.ExchangeDeviceCodeResponse{ + resp := externalauth.ExchangeDeviceCodeResponse{ Error: "authorization_pending", } srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -180,9 +180,9 @@ func TestGitAuthDevice(t *testing.T) { })) defer srv.Close() client := coderdtest.New(t, &coderdtest.Options{ - ExternalAuthConfigs: []*gitauth.Config{{ + ExternalAuthConfigs: []*externalauth.Config{{ ID: "test", - DeviceAuth: &gitauth.DeviceAuth{ + DeviceAuth: &externalauth.DeviceAuth{ ClientID: "test", TokenURL: srv.URL, Scopes: []string{"repo"}, @@ -190,7 +190,7 @@ func TestGitAuthDevice(t *testing.T) { }}, }) coderdtest.CreateFirstUser(t, client) - err := client.GitAuthDeviceExchange(context.Background(), "test", codersdk.GitAuthDeviceExchange{ + err := client.ExternalAuthDeviceExchange(context.Background(), "test", codersdk.ExternalAuthDeviceExchange{ DeviceCode: "hey", }) var sdkErr *codersdk.Error @@ -198,16 +198,16 @@ func TestGitAuthDevice(t *testing.T) { require.Equal(t, http.StatusBadRequest, sdkErr.StatusCode()) require.Equal(t, "authorization_pending", sdkErr.Detail) - resp = gitauth.ExchangeDeviceCodeResponse{ + resp = externalauth.ExchangeDeviceCodeResponse{ AccessToken: "hey", } - err = client.GitAuthDeviceExchange(context.Background(), "test", codersdk.GitAuthDeviceExchange{ + err = client.ExternalAuthDeviceExchange(context.Background(), "test", codersdk.ExternalAuthDeviceExchange{ DeviceCode: "hey", }) require.NoError(t, err) - auth, err := client.GitAuthByID(context.Background(), "test") + auth, err := client.ExternalAuthByID(context.Background(), "test") require.NoError(t, err) require.True(t, auth.Authenticated) }) @@ -220,7 +220,7 @@ func TestGitAuthCallback(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{ IncludeProvisionerDaemon: true, - ExternalAuthConfigs: []*gitauth.Config{}, + ExternalAuthConfigs: []*externalauth.Config{}, }) user := coderdtest.CreateFirstUser(t, client) authToken := uuid.NewString() @@ -245,7 +245,7 @@ func TestGitAuthCallback(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{ IncludeProvisionerDaemon: true, - ExternalAuthConfigs: []*gitauth.Config{{ + ExternalAuthConfigs: []*externalauth.Config{{ OAuth2Config: &testutil.OAuth2Config{}, ID: "github", Regex: regexp.MustCompile(`github\.com`), @@ -268,27 +268,27 @@ func TestGitAuthCallback(t *testing.T) { agentClient.SetSessionToken(authToken) token, err := agentClient.GitAuth(context.Background(), "github.com/asd/asd", false) require.NoError(t, err) - require.True(t, strings.HasSuffix(token.URL, fmt.Sprintf("/gitauth/%s", "github"))) + require.True(t, strings.HasSuffix(token.URL, fmt.Sprintf("/externalauth/%s", "github"))) }) t.Run("UnauthorizedCallback", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{ IncludeProvisionerDaemon: true, - ExternalAuthConfigs: []*gitauth.Config{{ + ExternalAuthConfigs: []*externalauth.Config{{ OAuth2Config: &testutil.OAuth2Config{}, ID: "github", Regex: regexp.MustCompile(`github\.com`), Type: codersdk.ExternalAuthProviderGitHub, }}, }) - resp := coderdtest.RequestGitAuthCallback(t, "github", client) + resp := coderdtest.RequestExternalAuthCallback(t, "github", client) require.Equal(t, http.StatusSeeOther, resp.StatusCode) }) t.Run("AuthorizedCallback", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{ IncludeProvisionerDaemon: true, - ExternalAuthConfigs: []*gitauth.Config{{ + ExternalAuthConfigs: []*externalauth.Config{{ OAuth2Config: &testutil.OAuth2Config{}, ID: "github", Regex: regexp.MustCompile(`github\.com`), @@ -296,14 +296,14 @@ func TestGitAuthCallback(t *testing.T) { }}, }) _ = coderdtest.CreateFirstUser(t, client) - resp := coderdtest.RequestGitAuthCallback(t, "github", client) + resp := coderdtest.RequestExternalAuthCallback(t, "github", client) require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode) location, err := resp.Location() require.NoError(t, err) - require.Equal(t, "/gitauth/github", location.Path) + require.Equal(t, "/externalauth/github", location.Path) // Callback again to simulate updating the token. - resp = coderdtest.RequestGitAuthCallback(t, "github", client) + resp = coderdtest.RequestExternalAuthCallback(t, "github", client) require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode) }) t.Run("ValidateURL", func(t *testing.T) { @@ -314,7 +314,7 @@ func TestGitAuthCallback(t *testing.T) { defer srv.Close() client := coderdtest.New(t, &coderdtest.Options{ IncludeProvisionerDaemon: true, - ExternalAuthConfigs: []*gitauth.Config{{ + ExternalAuthConfigs: []*externalauth.Config{{ ValidateURL: srv.URL, OAuth2Config: &testutil.OAuth2Config{}, ID: "github", @@ -337,7 +337,7 @@ func TestGitAuthCallback(t *testing.T) { agentClient := agentsdk.New(client.URL) agentClient.SetSessionToken(authToken) - resp := coderdtest.RequestGitAuthCallback(t, "github", client) + resp := coderdtest.RequestExternalAuthCallback(t, "github", client) require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode) // If the validation URL says unauthorized, the callback @@ -359,14 +359,14 @@ func TestGitAuthCallback(t *testing.T) { var apiError *codersdk.Error require.ErrorAs(t, err, &apiError) require.Equal(t, http.StatusInternalServerError, apiError.StatusCode()) - require.Equal(t, "validate git auth token: status 403: body: Something went wrong!", apiError.Detail) + require.Equal(t, "validate external auth token: status 403: body: Something went wrong!", apiError.Detail) }) t.Run("ExpiredNoRefresh", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{ IncludeProvisionerDaemon: true, - ExternalAuthConfigs: []*gitauth.Config{{ + ExternalAuthConfigs: []*externalauth.Config{{ OAuth2Config: &testutil.OAuth2Config{ Token: &oauth2.Token{ AccessToken: "token", @@ -402,7 +402,7 @@ func TestGitAuthCallback(t *testing.T) { // In the configuration, we set our OAuth provider // to return an expired token. Coder consumes this // and stores it. - resp := coderdtest.RequestGitAuthCallback(t, "github", client) + resp := coderdtest.RequestExternalAuthCallback(t, "github", client) require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode) // Because the token is expired and `NoRefresh` is specified, @@ -416,7 +416,7 @@ func TestGitAuthCallback(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{ IncludeProvisionerDaemon: true, - ExternalAuthConfigs: []*gitauth.Config{{ + ExternalAuthConfigs: []*externalauth.Config{{ OAuth2Config: &testutil.OAuth2Config{}, ID: "github", Regex: regexp.MustCompile(`github\.com`), @@ -452,7 +452,7 @@ func TestGitAuthCallback(t *testing.T) { time.Sleep(250 * time.Millisecond) - resp := coderdtest.RequestGitAuthCallback(t, "github", client) + resp := coderdtest.RequestExternalAuthCallback(t, "github", client) require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode) token = <-tokenChan require.Equal(t, "access_token", token.Username) diff --git a/coderd/gitauth/oauth_test.go b/coderd/gitauth/oauth_test.go deleted file mode 100644 index b85baeb935..0000000000 --- a/coderd/gitauth/oauth_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package gitauth_test - -import ( - "testing" -) - -func TestOAuthJWTConfig(t *testing.T) { - t.Parallel() -} diff --git a/coderd/httpmw/externalauthparam.go b/coderd/httpmw/externalauthparam.go new file mode 100644 index 0000000000..91c3e22f22 --- /dev/null +++ b/coderd/httpmw/externalauthparam.go @@ -0,0 +1,40 @@ +package httpmw + +import ( + "context" + "net/http" + + "github.com/go-chi/chi/v5" + + "github.com/coder/coder/v2/coderd/externalauth" + "github.com/coder/coder/v2/coderd/httpapi" +) + +type externalAuthParamContextKey struct{} + +func ExternalAuthParam(r *http.Request) *externalauth.Config { + config, ok := r.Context().Value(externalAuthParamContextKey{}).(*externalauth.Config) + if !ok { + panic("developer error: external auth param middleware not provided") + } + return config +} + +func ExtractExternalAuthParam(configs []*externalauth.Config) func(next http.Handler) http.Handler { + configByID := make(map[string]*externalauth.Config) + for _, c := range configs { + configByID[c.ID] = c + } + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + config, ok := configByID[chi.URLParam(r, "externalauth")] + if !ok { + httpapi.ResourceNotFound(w) + return + } + + r = r.WithContext(context.WithValue(r.Context(), externalAuthParamContextKey{}, config)) + next.ServeHTTP(w, r) + }) + } +} diff --git a/coderd/httpmw/gitauthparam_test.go b/coderd/httpmw/externalauthparam_test.go similarity index 72% rename from coderd/httpmw/gitauthparam_test.go rename to coderd/httpmw/externalauthparam_test.go index 665e438a23..4081e9f426 100644 --- a/coderd/httpmw/gitauthparam_test.go +++ b/coderd/httpmw/externalauthparam_test.go @@ -9,25 +9,25 @@ import ( "github.com/go-chi/chi/v5" "github.com/stretchr/testify/require" - "github.com/coder/coder/v2/coderd/gitauth" + "github.com/coder/coder/v2/coderd/externalauth" "github.com/coder/coder/v2/coderd/httpmw" ) //nolint:bodyclose -func TestGitAuthParam(t *testing.T) { +func TestExternalAuthParam(t *testing.T) { t.Parallel() t.Run("Found", func(t *testing.T) { t.Parallel() routeCtx := chi.NewRouteContext() - routeCtx.URLParams.Add("gitauth", "my-id") + routeCtx.URLParams.Add("externalauth", "my-id") r := httptest.NewRequest(http.MethodGet, "/", nil) r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, routeCtx)) res := httptest.NewRecorder() - httpmw.ExtractGitAuthParam([]*gitauth.Config{{ + httpmw.ExtractExternalAuthParam([]*externalauth.Config{{ ID: "my-id", }})(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, "my-id", httpmw.GitAuthParam(r).ID) + require.Equal(t, "my-id", httpmw.ExternalAuthParam(r).ID) w.WriteHeader(http.StatusOK) })).ServeHTTP(res, r) @@ -37,12 +37,12 @@ func TestGitAuthParam(t *testing.T) { t.Run("NotFound", func(t *testing.T) { t.Parallel() routeCtx := chi.NewRouteContext() - routeCtx.URLParams.Add("gitauth", "my-id") + routeCtx.URLParams.Add("externalauth", "my-id") r := httptest.NewRequest(http.MethodGet, "/", nil) r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, routeCtx)) res := httptest.NewRecorder() - httpmw.ExtractGitAuthParam([]*gitauth.Config{})(nil).ServeHTTP(res, r) + httpmw.ExtractExternalAuthParam([]*externalauth.Config{})(nil).ServeHTTP(res, r) require.Equal(t, http.StatusNotFound, res.Result().StatusCode) }) diff --git a/coderd/httpmw/gitauthparam.go b/coderd/httpmw/gitauthparam.go deleted file mode 100644 index 240732275b..0000000000 --- a/coderd/httpmw/gitauthparam.go +++ /dev/null @@ -1,40 +0,0 @@ -package httpmw - -import ( - "context" - "net/http" - - "github.com/go-chi/chi/v5" - - "github.com/coder/coder/v2/coderd/gitauth" - "github.com/coder/coder/v2/coderd/httpapi" -) - -type gitAuthParamContextKey struct{} - -func GitAuthParam(r *http.Request) *gitauth.Config { - config, ok := r.Context().Value(gitAuthParamContextKey{}).(*gitauth.Config) - if !ok { - panic("developer error: gitauth param middleware not provided") - } - return config -} - -func ExtractGitAuthParam(configs []*gitauth.Config) func(next http.Handler) http.Handler { - configByID := make(map[string]*gitauth.Config) - for _, c := range configs { - configByID[c.ID] = c - } - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - config, ok := configByID[chi.URLParam(r, "gitauth")] - if !ok { - httpapi.ResourceNotFound(w) - return - } - - r = r.WithContext(context.WithValue(r.Context(), gitAuthParamContextKey{}, config)) - next.ServeHTTP(w, r) - }) - } -} diff --git a/coderd/httpmw/patternmatcher/routepatterns_test.go b/coderd/httpmw/patternmatcher/routepatterns_test.go index dc7f779136..880fa88e71 100644 --- a/coderd/httpmw/patternmatcher/routepatterns_test.go +++ b/coderd/httpmw/patternmatcher/routepatterns_test.go @@ -65,9 +65,9 @@ func Test_RoutePatterns(t *testing.T) { "/api/**", "/@*/*/apps/**", "/%40*/*/apps/**", - "/gitauth/*/callback", + "/externalauth/*/callback", }, - output: "^(/api/?|/api/.+/?|/@[^/]+/[^/]+/apps/.+/?|/%40[^/]+/[^/]+/apps/.+/?|/gitauth/[^/]+/callback/?)$", + output: "^(/api/?|/api/.+/?|/@[^/]+/[^/]+/apps/.+/?|/%40[^/]+/[^/]+/apps/.+/?|/externalauth/[^/]+/callback/?)$", }, { name: "Slash", diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index 2c063660db..bbda529af6 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -31,7 +31,7 @@ import ( "github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/database/pubsub" - "github.com/coder/coder/v2/coderd/gitauth" + "github.com/coder/coder/v2/coderd/externalauth" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/coderd/schedule" "github.com/coder/coder/v2/coderd/telemetry" @@ -49,7 +49,7 @@ const DefaultAcquireJobLongPollDur = time.Second * 5 type Options struct { OIDCConfig httpmw.OAuth2Config - ExternalAuthConfigs []*gitauth.Config + ExternalAuthConfigs []*externalauth.Config // TimeNowFn is only used in tests TimeNowFn func() time.Time @@ -62,7 +62,7 @@ type server struct { ID uuid.UUID Logger slog.Logger Provisioners []database.ProvisionerType - ExternalAuthConfigs []*gitauth.Config + ExternalAuthConfigs []*externalauth.Config Tags Tags Database database.Store Pubsub pubsub.Pubsub @@ -416,7 +416,7 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo if err != nil { return nil, failJob(fmt.Sprintf("acquire external auth link: %s", err)) } - var config *gitauth.Config + var config *externalauth.Config for _, c := range s.ExternalAuthConfigs { if c.ID != p { continue diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index 7b380b6426..4b9ccd4e9a 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -31,7 +31,7 @@ import ( "github.com/coder/coder/v2/coderd/database/dbgen" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/database/pubsub" - "github.com/coder/coder/v2/coderd/gitauth" + "github.com/coder/coder/v2/coderd/externalauth" "github.com/coder/coder/v2/coderd/provisionerdserver" "github.com/coder/coder/v2/coderd/schedule" "github.com/coder/coder/v2/coderd/schedule/cron" @@ -143,7 +143,7 @@ func TestAcquireJob(t *testing.T) { gitAuthProvider := "github" srv, db, ps := setup(t, false, &overrides{ deploymentValues: dv, - externalAuthConfigs: []*gitauth.Config{{ + externalAuthConfigs: []*externalauth.Config{{ ID: gitAuthProvider, OAuth2Config: &testutil.OAuth2Config{}, }}, @@ -941,7 +941,7 @@ func TestCompleteJob(t *testing.T) { srvID := uuid.New() srv, db, _ := setup(t, false, &overrides{ id: &srvID, - externalAuthConfigs: []*gitauth.Config{{ + externalAuthConfigs: []*externalauth.Config{{ ID: "github", }}, }) @@ -1675,7 +1675,7 @@ func TestInsertWorkspaceResource(t *testing.T) { type overrides struct { deploymentValues *codersdk.DeploymentValues - externalAuthConfigs []*gitauth.Config + externalAuthConfigs []*externalauth.Config id *uuid.UUID templateScheduleStore *atomic.Pointer[schedule.TemplateScheduleStore] userQuietHoursScheduleStore *atomic.Pointer[schedule.UserQuietHoursScheduleStore] @@ -1691,7 +1691,7 @@ func setup(t *testing.T, ignoreLogErrors bool, ov *overrides) (proto.DRPCProvisi db := dbfake.New() ps := pubsub.NewInMemory() deploymentValues := &codersdk.DeploymentValues{} - var externalAuthConfigs []*gitauth.Config + var externalAuthConfigs []*externalauth.Config srvID := uuid.New() tss := testTemplateScheduleStore() uqhss := testUserQuietHoursScheduleStore() diff --git a/coderd/templateversions.go b/coderd/templateversions.go index a797d16979..cbc9bb0605 100644 --- a/coderd/templateversions.go +++ b/coderd/templateversions.go @@ -22,7 +22,7 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/database/provisionerjobs" - "github.com/coder/coder/v2/coderd/gitauth" + "github.com/coder/coder/v2/coderd/externalauth" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/coderd/parameter" @@ -273,15 +273,15 @@ func (api *API) templateVersionRichParameters(rw http.ResponseWriter, r *http.Re httpapi.Write(ctx, rw, http.StatusOK, templateVersionParameters) } -// @Summary Get git auth by template version -// @ID get-git-auth-by-template-version +// @Summary Get external auth by template version +// @ID get-external-auth-by-template-version // @Security CoderSessionToken // @Produce json // @Tags Templates // @Param templateversion path string true "Template version ID" format(uuid) // @Success 200 {array} codersdk.TemplateVersionExternalAuth -// @Router /templateversions/{templateversion}/gitauth [get] -func (api *API) templateVersionGitAuth(rw http.ResponseWriter, r *http.Request) { +// @Router /templateversions/{templateversion}/externalauth [get] +func (api *API) templateVersionExternalAuth(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() var ( apiKey = httpmw.APIKey(r) @@ -291,7 +291,7 @@ func (api *API) templateVersionGitAuth(rw http.ResponseWriter, r *http.Request) rawProviders := templateVersion.ExternalAuthProviders providers := make([]codersdk.TemplateVersionExternalAuth, 0) for _, rawProvider := range rawProviders { - var config *gitauth.Config + var config *externalauth.Config for _, provider := range api.ExternalAuthConfigs { if provider.ID == rawProvider { config = provider @@ -307,7 +307,7 @@ func (api *API) templateVersionGitAuth(rw http.ResponseWriter, r *http.Request) } // This is the URL that will redirect the user with a state token. - redirectURL, err := api.AccessURL.Parse(fmt.Sprintf("/gitauth/%s", config.ID)) + redirectURL, err := api.AccessURL.Parse(fmt.Sprintf("/externalauth/%s", config.ID)) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ Message: "Failed to parse access URL.", @@ -333,7 +333,7 @@ func (api *API) templateVersionGitAuth(rw http.ResponseWriter, r *http.Request) } if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching git auth link.", + Message: "Internal error fetching external auth link.", Detail: err.Error(), }) return @@ -342,7 +342,7 @@ func (api *API) templateVersionGitAuth(rw http.ResponseWriter, r *http.Request) _, updated, err := config.RefreshToken(ctx, api.Database, authLink) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Failed to refresh git auth token.", + Message: "Failed to refresh external auth token.", Detail: err.Error(), }) return diff --git a/coderd/templateversions_test.go b/coderd/templateversions_test.go index 1218356703..7f9c7f54dc 100644 --- a/coderd/templateversions_test.go +++ b/coderd/templateversions_test.go @@ -16,7 +16,7 @@ import ( "github.com/coder/coder/v2/coderd/audit" "github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/gitauth" + "github.com/coder/coder/v2/coderd/externalauth" "github.com/coder/coder/v2/coderd/provisionerdserver" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/codersdk" @@ -319,7 +319,7 @@ func TestPatchCancelTemplateVersion(t *testing.T) { }) } -func TestTemplateVersionsGitAuth(t *testing.T) { +func TestTemplateVersionsExternalAuth(t *testing.T) { t.Parallel() t.Run("Empty", func(t *testing.T) { t.Parallel() @@ -338,7 +338,7 @@ func TestTemplateVersionsGitAuth(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{ IncludeProvisionerDaemon: true, - ExternalAuthConfigs: []*gitauth.Config{{ + ExternalAuthConfigs: []*externalauth.Config{{ OAuth2Config: &testutil.OAuth2Config{}, ID: "github", Regex: regexp.MustCompile(`github\.com`), @@ -351,7 +351,7 @@ func TestTemplateVersionsGitAuth(t *testing.T) { ProvisionPlan: []*proto.Response{{ Type: &proto.Response_Plan{ Plan: &proto.PlanComplete{ - GitAuthProviders: []string{"github"}, + ExternalAuthProviders: []string{"github"}, }, }, }}, @@ -368,7 +368,7 @@ func TestTemplateVersionsGitAuth(t *testing.T) { require.False(t, providers[0].Authenticated) // Perform the Git auth callback to authenticate the user... - resp := coderdtest.RequestGitAuthCallback(t, "github", client) + resp := coderdtest.RequestExternalAuthCallback(t, "github", client) _ = resp.Body.Close() require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode) diff --git a/coderd/tracing/httpmw.go b/coderd/tracing/httpmw.go index 653a743862..994c16f41a 100644 --- a/coderd/tracing/httpmw.go +++ b/coderd/tracing/httpmw.go @@ -26,7 +26,7 @@ func Middleware(tracerProvider trace.TracerProvider) func(http.Handler) http.Han "/api/**", "/@*/*/apps/**", "/%40*/*/apps/**", - "/gitauth/*/callback", + "/externalauth/*/callback", }.MustCompile() var tracer trace.Tracer diff --git a/coderd/tracing/httpmw_test.go b/coderd/tracing/httpmw_test.go index e866acd513..ca759513ec 100644 --- a/coderd/tracing/httpmw_test.go +++ b/coderd/tracing/httpmw_test.go @@ -59,7 +59,7 @@ func Test_Middleware(t *testing.T) { {"/%40hi/hi/apps/hi", true}, {"/%40hi/hi/apps/hi/hi", true}, {"/%40hi/hi/apps/hi/hi", true}, - {"/gitauth/hi/callback", true}, + {"/externalauth/hi/callback", true}, // Other routes that should not be collected. {"/index.html", false}, diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index cef3910581..b7b258b4f8 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -34,7 +34,7 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/database/dbtime" - "github.com/coder/coder/v2/coderd/gitauth" + "github.com/coder/coder/v2/coderd/externalauth" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/coderd/rbac" @@ -2178,25 +2178,25 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request) // new token to be issued! listen := r.URL.Query().Has("listen") - var gitAuthConfig *gitauth.Config + var externalAuthConfig *externalauth.Config for _, gitAuth := range api.ExternalAuthConfigs { matches := gitAuth.Regex.MatchString(gitURL) if !matches { continue } - gitAuthConfig = gitAuth + externalAuthConfig = gitAuth } - if gitAuthConfig == nil { - detail := "No git providers are configured." + if externalAuthConfig == nil { + detail := "No external auth providers are configured." if len(api.ExternalAuthConfigs) > 0 { regexURLs := make([]string, 0, len(api.ExternalAuthConfigs)) - for _, gitAuth := range api.ExternalAuthConfigs { - regexURLs = append(regexURLs, fmt.Sprintf("%s=%q", gitAuth.ID, gitAuth.Regex.String())) + for _, extAuth := range api.ExternalAuthConfigs { + regexURLs = append(regexURLs, fmt.Sprintf("%s=%q", extAuth.ID, extAuth.Regex.String())) } - detail = fmt.Sprintf("The configured git provider have regex filters that do not match the git url. Provider url regexs: %s", strings.Join(regexURLs, ",")) + detail = fmt.Sprintf("The configured external auth provider have regex filters that do not match the git url. Provider url regexs: %s", strings.Join(regexURLs, ",")) } httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{ - Message: fmt.Sprintf("No matching git provider found in Coder for the url %q.", gitURL), + Message: fmt.Sprintf("No matching external auth provider found in Coder for the url %q.", gitURL), Detail: detail, }) return @@ -2239,8 +2239,8 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request) return case <-ticker.C: } - gitAuthLink, err := api.Database.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{ - ProviderID: gitAuthConfig.ID, + externalAuthLink, err := api.Database.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{ + ProviderID: externalAuthConfig.ID, UserID: workspace.OwnerID, }) if err != nil { @@ -2248,7 +2248,7 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request) continue } httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Failed to get git auth link.", + Message: "Failed to get external auth link.", Detail: err.Error(), }) return @@ -2258,27 +2258,27 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request) // to expire. // See // https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app. - if gitAuthLink.OAuthExpiry.Before(dbtime.Now()) && !gitAuthLink.OAuthExpiry.IsZero() { + if externalAuthLink.OAuthExpiry.Before(dbtime.Now()) && !externalAuthLink.OAuthExpiry.IsZero() { continue } - valid, _, err := gitAuthConfig.ValidateToken(ctx, gitAuthLink.OAuthAccessToken) + valid, _, err := externalAuthConfig.ValidateToken(ctx, externalAuthLink.OAuthAccessToken) if err != nil { - api.Logger.Warn(ctx, "failed to validate git auth token", + api.Logger.Warn(ctx, "failed to validate external auth token", slog.F("workspace_owner_id", workspace.OwnerID.String()), - slog.F("validate_url", gitAuthConfig.ValidateURL), + slog.F("validate_url", externalAuthConfig.ValidateURL), slog.Error(err), ) } if !valid { continue } - httpapi.Write(ctx, rw, http.StatusOK, formatGitAuthAccessToken(gitAuthConfig.Type, gitAuthLink.OAuthAccessToken)) + httpapi.Write(ctx, rw, http.StatusOK, formatGitAuthAccessToken(externalAuthConfig.Type, externalAuthLink.OAuthAccessToken)) return } } // This is the URL that will redirect the user with a state token. - redirectURL, err := api.AccessURL.Parse(fmt.Sprintf("/gitauth/%s", gitAuthConfig.ID)) + redirectURL, err := api.AccessURL.Parse(fmt.Sprintf("/externalauth/%s", externalAuthConfig.ID)) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ Message: "Failed to parse access URL.", @@ -2287,14 +2287,14 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request) return } - gitAuthLink, err := api.Database.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{ - ProviderID: gitAuthConfig.ID, + externalAuthLink, err := api.Database.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{ + ProviderID: externalAuthConfig.ID, UserID: workspace.OwnerID, }) if err != nil { if !errors.Is(err, sql.ErrNoRows) { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Failed to get git auth link.", + Message: "Failed to get external auth link.", Detail: err.Error(), }) return @@ -2306,10 +2306,10 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request) return } - gitAuthLink, updated, err := gitAuthConfig.RefreshToken(ctx, api.Database, gitAuthLink) + externalAuthLink, updated, err := externalAuthConfig.RefreshToken(ctx, api.Database, externalAuthLink) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Failed to refresh git auth token.", + Message: "Failed to refresh external auth token.", Detail: err.Error(), }) return @@ -2320,7 +2320,7 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request) }) return } - httpapi.Write(ctx, rw, http.StatusOK, formatGitAuthAccessToken(gitAuthConfig.Type, gitAuthLink.OAuthAccessToken)) + httpapi.Write(ctx, rw, http.StatusOK, formatGitAuthAccessToken(externalAuthConfig.Type, externalAuthLink.OAuthAccessToken)) } // Provider types have different username/password formats. diff --git a/codersdk/gitauth.go b/codersdk/externalauth.go similarity index 51% rename from codersdk/gitauth.go rename to codersdk/externalauth.go index c825977120..5350dc3a6b 100644 --- a/codersdk/gitauth.go +++ b/codersdk/externalauth.go @@ -7,37 +7,37 @@ import ( "net/http" ) -type GitAuth struct { +type ExternalAuth struct { Authenticated bool `json:"authenticated"` Device bool `json:"device"` Type string `json:"type"` // User is the user that authenticated with the provider. - User *GitAuthUser `json:"user"` + User *ExternalAuthUser `json:"user"` // AppInstallable is true if the request for app installs was successful. AppInstallable bool `json:"app_installable"` // AppInstallations are the installations that the user has access to. - AppInstallations []GitAuthAppInstallation `json:"installations"` + AppInstallations []ExternalAuthAppInstallation `json:"installations"` // AppInstallURL is the URL to install the app. AppInstallURL string `json:"app_install_url"` } -type GitAuthAppInstallation struct { - ID int `json:"id"` - Account GitAuthUser `json:"account"` - ConfigureURL string `json:"configure_url"` +type ExternalAuthAppInstallation struct { + ID int `json:"id"` + Account ExternalAuthUser `json:"account"` + ConfigureURL string `json:"configure_url"` } -type GitAuthUser struct { +type ExternalAuthUser struct { Login string `json:"login"` AvatarURL string `json:"avatar_url"` ProfileURL string `json:"profile_url"` Name string `json:"name"` } -// GitAuthDevice is the response from the device authorization endpoint. +// ExternalAuthDevice is the response from the device authorization endpoint. // See: https://tools.ietf.org/html/rfc8628#section-3.2 -type GitAuthDevice struct { +type ExternalAuthDevice struct { DeviceCode string `json:"device_code"` UserCode string `json:"user_code"` VerificationURI string `json:"verification_uri"` @@ -45,26 +45,26 @@ type GitAuthDevice struct { Interval int `json:"interval"` } -type GitAuthDeviceExchange struct { +type ExternalAuthDeviceExchange struct { DeviceCode string `json:"device_code"` } -func (c *Client) GitAuthDeviceByID(ctx context.Context, provider string) (GitAuthDevice, error) { - res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/gitauth/%s/device", provider), nil) +func (c *Client) ExternalAuthDeviceByID(ctx context.Context, provider string) (ExternalAuthDevice, error) { + res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/externalauth/%s/device", provider), nil) if err != nil { - return GitAuthDevice{}, err + return ExternalAuthDevice{}, err } defer res.Body.Close() if res.StatusCode != http.StatusOK { - return GitAuthDevice{}, ReadBodyAsError(res) + return ExternalAuthDevice{}, ReadBodyAsError(res) } - var gitauth GitAuthDevice - return gitauth, json.NewDecoder(res.Body).Decode(&gitauth) + var extAuth ExternalAuthDevice + return extAuth, json.NewDecoder(res.Body).Decode(&extAuth) } -// ExchangeGitAuth exchanges a device code for a git auth token. -func (c *Client) GitAuthDeviceExchange(ctx context.Context, provider string, req GitAuthDeviceExchange) error { - res, err := c.Request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/gitauth/%s/device", provider), req) +// ExchangeGitAuth exchanges a device code for an external auth token. +func (c *Client) ExternalAuthDeviceExchange(ctx context.Context, provider string, req ExternalAuthDeviceExchange) error { + res, err := c.Request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/externalauth/%s/device", provider), req) if err != nil { return err } @@ -75,16 +75,16 @@ func (c *Client) GitAuthDeviceExchange(ctx context.Context, provider string, req return nil } -// GitAuthByID returns the git auth for the given provider by ID. -func (c *Client) GitAuthByID(ctx context.Context, provider string) (GitAuth, error) { - res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/gitauth/%s", provider), nil) +// ExternalAuthByID returns the external auth for the given provider by ID. +func (c *Client) ExternalAuthByID(ctx context.Context, provider string) (ExternalAuth, error) { + res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/externalauth/%s", provider), nil) if err != nil { - return GitAuth{}, err + return ExternalAuth{}, err } defer res.Body.Close() if res.StatusCode != http.StatusOK { - return GitAuth{}, ReadBodyAsError(res) + return ExternalAuth{}, ReadBodyAsError(res) } - var gitauth GitAuth - return gitauth, json.NewDecoder(res.Body).Decode(&gitauth) + var extAuth ExternalAuth + return extAuth, json.NewDecoder(res.Body).Decode(&extAuth) } diff --git a/codersdk/templateversions.go b/codersdk/templateversions.go index 3e3a1363bc..fb1f0b21fe 100644 --- a/codersdk/templateversions.go +++ b/codersdk/templateversions.go @@ -134,7 +134,7 @@ func (c *Client) TemplateVersionRichParameters(ctx context.Context, version uuid // TemplateVersionExternalAuth returns authentication providers for the requested template version. func (c *Client) TemplateVersionExternalAuth(ctx context.Context, version uuid.UUID) ([]TemplateVersionExternalAuth, error) { - res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/templateversions/%s/gitauth", version), nil) + res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/templateversions/%s/externalauth", version), nil) if err != nil { return nil, err } diff --git a/docs/api/git.md b/docs/api/git.md index 0f55fdfba9..bcc8889006 100644 --- a/docs/api/git.md +++ b/docs/api/git.md @@ -1,23 +1,23 @@ # Git -## Get git auth by ID +## Get external auth by ID ### Code samples ```shell # Example request using curl -curl -X GET http://coder-server:8080/api/v2/gitauth/{gitauth} \ +curl -X GET http://coder-server:8080/api/v2/externalauth/{externalauth} \ -H 'Accept: application/json' \ -H 'Coder-Session-Token: API_KEY' ``` -`GET /gitauth/{gitauth}` +`GET /externalauth/{externalauth}` ### Parameters -| Name | In | Type | Required | Description | -| --------- | ---- | -------------- | -------- | --------------- | -| `gitauth` | path | string(string) | true | Git Provider ID | +| Name | In | Type | Required | Description | +| -------------- | ---- | -------------- | -------- | --------------- | +| `externalauth` | path | string(string) | true | Git Provider ID | ### Example responses @@ -53,30 +53,30 @@ curl -X GET http://coder-server:8080/api/v2/gitauth/{gitauth} \ ### Responses -| Status | Meaning | Description | Schema | -| ------ | ------------------------------------------------------- | ----------- | ---------------------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.GitAuth](schemas.md#codersdkgitauth) | +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------------- | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.ExternalAuth](schemas.md#codersdkexternalauth) | To perform this operation, you must be authenticated. [Learn more](authentication.md). -## Get git auth device by ID. +## Get external auth device by ID. ### Code samples ```shell # Example request using curl -curl -X GET http://coder-server:8080/api/v2/gitauth/{gitauth}/device \ +curl -X GET http://coder-server:8080/api/v2/externalauth/{externalauth}/device \ -H 'Accept: application/json' \ -H 'Coder-Session-Token: API_KEY' ``` -`GET /gitauth/{gitauth}/device` +`GET /externalauth/{externalauth}/device` ### Parameters -| Name | In | Type | Required | Description | -| --------- | ---- | -------------- | -------- | --------------- | -| `gitauth` | path | string(string) | true | Git Provider ID | +| Name | In | Type | Required | Description | +| -------------- | ---- | -------------- | -------- | --------------- | +| `externalauth` | path | string(string) | true | Git Provider ID | ### Example responses @@ -94,29 +94,29 @@ curl -X GET http://coder-server:8080/api/v2/gitauth/{gitauth}/device \ ### Responses -| Status | Meaning | Description | Schema | -| ------ | ------------------------------------------------------- | ----------- | ---------------------------------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.GitAuthDevice](schemas.md#codersdkgitauthdevice) | +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------------------------- | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.ExternalAuthDevice](schemas.md#codersdkexternalauthdevice) | To perform this operation, you must be authenticated. [Learn more](authentication.md). -## Post git auth device by ID +## Post external auth device by ID ### Code samples ```shell # Example request using curl -curl -X POST http://coder-server:8080/api/v2/gitauth/{gitauth}/device \ +curl -X POST http://coder-server:8080/api/v2/externalauth/{externalauth}/device \ -H 'Coder-Session-Token: API_KEY' ``` -`POST /gitauth/{gitauth}/device` +`POST /externalauth/{externalauth}/device` ### Parameters -| Name | In | Type | Required | Description | -| --------- | ---- | -------------- | -------- | --------------- | -| `gitauth` | path | string(string) | true | Git Provider ID | +| Name | In | Type | Required | Description | +| -------------- | ---- | -------------- | -------- | -------------------- | +| `externalauth` | path | string(string) | true | External Provider ID | ### Responses diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 4e4a1dede6..00b61e6202 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -2752,6 +2752,93 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `template_autostop_requirement` | | `deployment_health_page` | +## codersdk.ExternalAuth + +```json +{ + "app_install_url": "string", + "app_installable": true, + "authenticated": true, + "device": true, + "installations": [ + { + "account": { + "avatar_url": "string", + "login": "string", + "name": "string", + "profile_url": "string" + }, + "configure_url": "string", + "id": 0 + } + ], + "type": "string", + "user": { + "avatar_url": "string", + "login": "string", + "name": "string", + "profile_url": "string" + } +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +| ----------------- | ------------------------------------------------------------------------------------- | -------- | ------------ | ----------------------------------------------------------------------- | +| `app_install_url` | string | false | | App install URL is the URL to install the app. | +| `app_installable` | boolean | false | | App installable is true if the request for app installs was successful. | +| `authenticated` | boolean | false | | | +| `device` | boolean | false | | | +| `installations` | array of [codersdk.ExternalAuthAppInstallation](#codersdkexternalauthappinstallation) | false | | Installations are the installations that the user has access to. | +| `type` | string | false | | | +| `user` | [codersdk.ExternalAuthUser](#codersdkexternalauthuser) | false | | User is the user that authenticated with the provider. | + +## codersdk.ExternalAuthAppInstallation + +```json +{ + "account": { + "avatar_url": "string", + "login": "string", + "name": "string", + "profile_url": "string" + }, + "configure_url": "string", + "id": 0 +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +| --------------- | ------------------------------------------------------ | -------- | ------------ | ----------- | +| `account` | [codersdk.ExternalAuthUser](#codersdkexternalauthuser) | false | | | +| `configure_url` | string | false | | | +| `id` | integer | false | | | + +## codersdk.ExternalAuthDevice + +```json +{ + "device_code": "string", + "expires_in": 0, + "interval": 0, + "user_code": "string", + "verification_uri": "string" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +| ------------------ | ------- | -------- | ------------ | ----------- | +| `device_code` | string | false | | | +| `expires_in` | integer | false | | | +| `interval` | integer | false | | | +| `user_code` | string | false | | | +| `verification_uri` | string | false | | | + ## codersdk.ExternalAuthProvider ```json @@ -2770,6 +2857,26 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `bitbucket` | | `openid-connect` | +## codersdk.ExternalAuthUser + +```json +{ + "avatar_url": "string", + "login": "string", + "name": "string", + "profile_url": "string" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +| ------------- | ------ | -------- | ------------ | ----------- | +| `avatar_url` | string | false | | | +| `login` | string | false | | | +| `name` | string | false | | | +| `profile_url` | string | false | | | + ## codersdk.Feature ```json @@ -2838,71 +2945,6 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `count` | integer | false | | | | `users` | array of [codersdk.User](#codersdkuser) | false | | | -## codersdk.GitAuth - -```json -{ - "app_install_url": "string", - "app_installable": true, - "authenticated": true, - "device": true, - "installations": [ - { - "account": { - "avatar_url": "string", - "login": "string", - "name": "string", - "profile_url": "string" - }, - "configure_url": "string", - "id": 0 - } - ], - "type": "string", - "user": { - "avatar_url": "string", - "login": "string", - "name": "string", - "profile_url": "string" - } -} -``` - -### Properties - -| Name | Type | Required | Restrictions | Description | -| ----------------- | --------------------------------------------------------------------------- | -------- | ------------ | ----------------------------------------------------------------------- | -| `app_install_url` | string | false | | App install URL is the URL to install the app. | -| `app_installable` | boolean | false | | App installable is true if the request for app installs was successful. | -| `authenticated` | boolean | false | | | -| `device` | boolean | false | | | -| `installations` | array of [codersdk.GitAuthAppInstallation](#codersdkgitauthappinstallation) | false | | Installations are the installations that the user has access to. | -| `type` | string | false | | | -| `user` | [codersdk.GitAuthUser](#codersdkgitauthuser) | false | | User is the user that authenticated with the provider. | - -## codersdk.GitAuthAppInstallation - -```json -{ - "account": { - "avatar_url": "string", - "login": "string", - "name": "string", - "profile_url": "string" - }, - "configure_url": "string", - "id": 0 -} -``` - -### Properties - -| Name | Type | Required | Restrictions | Description | -| --------------- | -------------------------------------------- | -------- | ------------ | ----------- | -| `account` | [codersdk.GitAuthUser](#codersdkgitauthuser) | false | | | -| `configure_url` | string | false | | | -| `id` | integer | false | | | - ## codersdk.GitAuthConfig ```json @@ -2941,48 +2983,6 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `type` | string | false | | | | `validate_url` | string | false | | | -## codersdk.GitAuthDevice - -```json -{ - "device_code": "string", - "expires_in": 0, - "interval": 0, - "user_code": "string", - "verification_uri": "string" -} -``` - -### Properties - -| Name | Type | Required | Restrictions | Description | -| ------------------ | ------- | -------- | ------------ | ----------- | -| `device_code` | string | false | | | -| `expires_in` | integer | false | | | -| `interval` | integer | false | | | -| `user_code` | string | false | | | -| `verification_uri` | string | false | | | - -## codersdk.GitAuthUser - -```json -{ - "avatar_url": "string", - "login": "string", - "name": "string", - "profile_url": "string" -} -``` - -### Properties - -| Name | Type | Required | Restrictions | Description | -| ------------- | ------ | -------- | ------------ | ----------- | -| `avatar_url` | string | false | | | -| `login` | string | false | | | -| `name` | string | false | | | -| `profile_url` | string | false | | | - ## codersdk.GitSSHKey ```json diff --git a/docs/api/templates.md b/docs/api/templates.md index f4084144e0..fe9d76633e 100644 --- a/docs/api/templates.md +++ b/docs/api/templates.md @@ -1800,18 +1800,18 @@ Status Code **200** To perform this operation, you must be authenticated. [Learn more](authentication.md). -## Get git auth by template version +## Get external auth by template version ### Code samples ```shell # Example request using curl -curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/gitauth \ +curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/externalauth \ -H 'Accept: application/json' \ -H 'Coder-Session-Token: API_KEY' ``` -`GET /templateversions/{templateversion}/gitauth` +`GET /templateversions/{templateversion}/externalauth` ### Parameters @@ -1840,7 +1840,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/g | ------ | ------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------- | | 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | array of [codersdk.TemplateVersionExternalAuth](schemas.md#codersdktemplateversionexternalauth) | -

Response Schema

+

Response Schema

Status Code **200** diff --git a/provisioner/echo/serve.go b/provisioner/echo/serve.go index 9e22157bc3..6ab89c13a6 100644 --- a/provisioner/echo/serve.go +++ b/provisioner/echo/serve.go @@ -225,10 +225,10 @@ func Tar(responses *Responses) ([]byte, error) { } responses.ProvisionPlan = append(responses.ProvisionPlan, &proto.Response{ Type: &proto.Response_Plan{Plan: &proto.PlanComplete{ - Error: resp.GetApply().GetError(), - Resources: resp.GetApply().GetResources(), - Parameters: resp.GetApply().GetParameters(), - GitAuthProviders: resp.GetApply().GetGitAuthProviders(), + Error: resp.GetApply().GetError(), + Resources: resp.GetApply().GetResources(), + Parameters: resp.GetApply().GetParameters(), + ExternalAuthProviders: resp.GetApply().GetExternalAuthProviders(), }}, }) } diff --git a/provisioner/terraform/executor.go b/provisioner/terraform/executor.go index d523eeca19..3917e4ca15 100644 --- a/provisioner/terraform/executor.go +++ b/provisioner/terraform/executor.go @@ -264,9 +264,9 @@ func (e *executor) plan(ctx, killCtx context.Context, env, vars []string, logr l return nil, err } return &proto.PlanComplete{ - Parameters: state.Parameters, - Resources: state.Resources, - GitAuthProviders: state.GitAuthProviders, + Parameters: state.Parameters, + Resources: state.Resources, + ExternalAuthProviders: state.ExternalAuthProviders, }, nil } @@ -404,10 +404,10 @@ func (e *executor) apply( return nil, xerrors.Errorf("read statefile %q: %w", statefilePath, err) } return &proto.ApplyComplete{ - Parameters: state.Parameters, - Resources: state.Resources, - GitAuthProviders: state.GitAuthProviders, - State: stateContent, + Parameters: state.Parameters, + Resources: state.Resources, + ExternalAuthProviders: state.ExternalAuthProviders, + State: stateContent, }, nil } diff --git a/provisioner/terraform/resources.go b/provisioner/terraform/resources.go index 4cdd168907..36d494711d 100644 --- a/provisioner/terraform/resources.go +++ b/provisioner/terraform/resources.go @@ -114,9 +114,9 @@ type resourceMetadataItem struct { } type State struct { - Resources []*proto.Resource - Parameters []*proto.RichParameter - GitAuthProviders []string + Resources []*proto.Resource + Parameters []*proto.RichParameter + ExternalAuthProviders []string } // ConvertState consumes Terraform state and a GraphViz representation @@ -680,9 +680,9 @@ func ConvertState(modules []*tfjson.StateModule, rawGraph string) (*State, error } return &State{ - Resources: resources, - Parameters: parameters, - GitAuthProviders: gitAuthProviders, + Resources: resources, + Parameters: parameters, + ExternalAuthProviders: gitAuthProviders, }, nil } diff --git a/provisioner/terraform/resources_test.go b/provisioner/terraform/resources_test.go index cb3c4237c1..83aaabf21a 100644 --- a/provisioner/terraform/resources_test.go +++ b/provisioner/terraform/resources_test.go @@ -546,7 +546,7 @@ func TestConvertResources(t *testing.T) { state, err := terraform.ConvertState(modules, string(tfPlanGraph)) require.NoError(t, err) sortResources(state.Resources) - sort.Strings(state.GitAuthProviders) + sort.Strings(state.ExternalAuthProviders) expectedNoMetadata := make([]*proto.Resource, 0) for _, resource := range expected.resources { @@ -584,7 +584,7 @@ func TestConvertResources(t *testing.T) { require.Equal(t, string(parametersWant), string(parametersGot)) require.Equal(t, expectedNoMetadataMap, resourcesMap) - require.ElementsMatch(t, expected.gitAuthProviders, state.GitAuthProviders) + require.ElementsMatch(t, expected.gitAuthProviders, state.ExternalAuthProviders) }) t.Run("Provision", func(t *testing.T) { @@ -600,7 +600,7 @@ func TestConvertResources(t *testing.T) { state, err := terraform.ConvertState([]*tfjson.StateModule{tfState.Values.RootModule}, string(tfStateGraph)) require.NoError(t, err) sortResources(state.Resources) - sort.Strings(state.GitAuthProviders) + sort.Strings(state.ExternalAuthProviders) for _, resource := range state.Resources { for _, agent := range resource.Agents { agent.Id = "" @@ -627,7 +627,7 @@ func TestConvertResources(t *testing.T) { require.NoError(t, err) require.Equal(t, expectedMap, resourcesMap) - require.ElementsMatch(t, expected.gitAuthProviders, state.GitAuthProviders) + require.ElementsMatch(t, expected.gitAuthProviders, state.ExternalAuthProviders) }) }) } diff --git a/provisionerd/runner/runner.go b/provisionerd/runner/runner.go index 7fe2c5a521..0a529e20da 100644 --- a/provisionerd/runner/runner.go +++ b/provisionerd/runner/runner.go @@ -720,7 +720,7 @@ func (r *Runner) runTemplateImportProvisionWithRichParameters( return &templateImportProvision{ Resources: c.Resources, Parameters: c.Parameters, - ExternalAuthProviders: c.GitAuthProviders, + ExternalAuthProviders: c.ExternalAuthProviders, }, nil default: return nil, xerrors.Errorf("invalid message type %q received from provisioner", diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index 7ec9944717..271801463d 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -1867,10 +1867,10 @@ type PlanComplete struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` - Resources []*Resource `protobuf:"bytes,2,rep,name=resources,proto3" json:"resources,omitempty"` - Parameters []*RichParameter `protobuf:"bytes,3,rep,name=parameters,proto3" json:"parameters,omitempty"` - GitAuthProviders []string `protobuf:"bytes,4,rep,name=git_auth_providers,json=gitAuthProviders,proto3" json:"git_auth_providers,omitempty"` + Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` + Resources []*Resource `protobuf:"bytes,2,rep,name=resources,proto3" json:"resources,omitempty"` + Parameters []*RichParameter `protobuf:"bytes,3,rep,name=parameters,proto3" json:"parameters,omitempty"` + ExternalAuthProviders []string `protobuf:"bytes,4,rep,name=external_auth_providers,json=externalAuthProviders,proto3" json:"external_auth_providers,omitempty"` } func (x *PlanComplete) Reset() { @@ -1926,9 +1926,9 @@ func (x *PlanComplete) GetParameters() []*RichParameter { return nil } -func (x *PlanComplete) GetGitAuthProviders() []string { +func (x *PlanComplete) GetExternalAuthProviders() []string { if x != nil { - return x.GitAuthProviders + return x.ExternalAuthProviders } return nil } @@ -1988,11 +1988,11 @@ type ApplyComplete struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - State []byte `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"` - Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` - Resources []*Resource `protobuf:"bytes,3,rep,name=resources,proto3" json:"resources,omitempty"` - Parameters []*RichParameter `protobuf:"bytes,4,rep,name=parameters,proto3" json:"parameters,omitempty"` - GitAuthProviders []string `protobuf:"bytes,5,rep,name=git_auth_providers,json=gitAuthProviders,proto3" json:"git_auth_providers,omitempty"` + State []byte `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` + Resources []*Resource `protobuf:"bytes,3,rep,name=resources,proto3" json:"resources,omitempty"` + Parameters []*RichParameter `protobuf:"bytes,4,rep,name=parameters,proto3" json:"parameters,omitempty"` + ExternalAuthProviders []string `protobuf:"bytes,5,rep,name=external_auth_providers,json=externalAuthProviders,proto3" json:"external_auth_providers,omitempty"` } func (x *ApplyComplete) Reset() { @@ -2055,9 +2055,9 @@ func (x *ApplyComplete) GetParameters() []*RichParameter { return nil } -func (x *ApplyComplete) GetGitAuthProviders() []string { +func (x *ApplyComplete) GetExternalAuthProviders() []string { if x != nil { - return x.GitAuthProviders + return x.ExternalAuthProviders } return nil } @@ -2778,7 +2778,7 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, - 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x22, 0xc3, 0x01, 0x0a, 0x0c, 0x50, + 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x22, 0xcd, 0x01, 0x0a, 0x0c, 0x50, 0x6c, 0x61, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, @@ -2788,78 +2788,80 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x67, 0x69, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, - 0x67, 0x69, 0x74, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, - 0x22, 0x41, 0x0a, 0x0c, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x22, 0xda, 0x01, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x43, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, - 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, - 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x67, 0x69, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, - 0x67, 0x69, 0x74, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, - 0x22, 0x0f, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x22, 0x8c, 0x02, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, - 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x48, 0x00, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x31, 0x0a, 0x05, - 0x70, 0x61, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x12, - 0x2e, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x6c, 0x61, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, - 0x31, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x70, 0x70, - 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x61, 0x70, 0x70, - 0x6c, 0x79, 0x12, 0x34, 0x0a, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, - 0x52, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x22, 0xd1, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, - 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, 0x03, - 0x6c, 0x6f, 0x67, 0x12, 0x32, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, - 0x52, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, - 0x48, 0x00, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x32, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x6c, - 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x42, 0x06, 0x0a, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x2a, 0x3f, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, - 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x44, - 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x02, - 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52, 0x4e, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, - 0x52, 0x4f, 0x52, 0x10, 0x04, 0x2a, 0x3b, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, - 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, 0x4e, 0x45, - 0x52, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, - 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, - 0x10, 0x02, 0x2a, 0x37, 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54, 0x41, - 0x52, 0x54, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x01, 0x12, 0x0b, - 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4f, 0x59, 0x10, 0x02, 0x32, 0x49, 0x0a, 0x0b, 0x50, - 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x12, 0x3a, 0x0a, 0x07, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, - 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x73, - 0x64, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x72, 0x73, 0x12, 0x36, 0x0a, 0x17, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, + 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, + 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x22, 0x41, 0x0a, 0x0c, 0x41, 0x70, + 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xe4, 0x01, + 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x33, 0x0a, 0x09, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x12, 0x3a, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x36, 0x0a, 0x17, + 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x15, 0x65, + 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x73, 0x22, 0x0f, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8c, 0x02, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x2d, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x12, 0x31, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, + 0x72, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x70, 0x61, + 0x72, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x04, 0x70, + 0x6c, 0x61, 0x6e, 0x12, 0x31, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, + 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x34, 0x0a, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x06, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x22, 0xd1, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x24, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, + 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x32, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x70, + 0x6c, 0x61, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x43, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x32, 0x0a, 0x05, + 0x61, 0x70, 0x70, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x43, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, + 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x2a, 0x3f, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, + 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x00, 0x12, + 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, + 0x46, 0x4f, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52, 0x4e, 0x10, 0x03, 0x12, 0x09, + 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x04, 0x2a, 0x3b, 0x0a, 0x0f, 0x41, 0x70, 0x70, + 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, + 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x41, 0x55, 0x54, 0x48, 0x45, + 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x55, + 0x42, 0x4c, 0x49, 0x43, 0x10, 0x02, 0x2a, 0x37, 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, + 0x05, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x54, 0x4f, 0x50, + 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4f, 0x59, 0x10, 0x02, 0x32, + 0x49, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x12, 0x3a, + 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index 24e0c87301..1682d75f60 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -245,7 +245,7 @@ message PlanComplete { string error = 1; repeated Resource resources = 2; repeated RichParameter parameters = 3; - repeated string git_auth_providers = 4; + repeated string external_auth_providers = 4; } // ApplyRequest asks the provisioner to apply the changes. Apply MUST be preceded by a successful plan request/response @@ -260,7 +260,7 @@ message ApplyComplete { string error = 2; repeated Resource resources = 3; repeated RichParameter parameters = 4; - repeated string git_auth_providers = 5; + repeated string external_auth_providers = 5; } // CancelRequest requests that the previous request be canceled gracefully. diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index 548ac91686..1e54d84b80 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -426,7 +426,7 @@ const createTemplateVersionTar = async ( error: response.apply?.error ?? "", resources: response.apply?.resources ?? [], parameters: response.apply?.parameters ?? [], - gitAuthProviders: response.apply?.gitAuthProviders ?? [], + externalAuthProviders: response.apply?.externalAuthProviders ?? [], }, }; }); @@ -508,7 +508,7 @@ const createTemplateVersionTar = async ( state: new Uint8Array(), resources: [], parameters: [], - gitAuthProviders: [], + externalAuthProviders: [], ...response.apply, } as ApplyComplete; response.apply.resources = response.apply.resources?.map(fillResource); @@ -523,7 +523,7 @@ const createTemplateVersionTar = async ( error: "", resources: [], parameters: [], - gitAuthProviders: [], + externalAuthProviders: [], ...response.plan, } as PlanComplete; response.plan.resources = response.plan.resources?.map(fillResource); diff --git a/site/e2e/provisionerGenerated.ts b/site/e2e/provisionerGenerated.ts index 1ade0a9e6b..5ad3fb645a 100644 --- a/site/e2e/provisionerGenerated.ts +++ b/site/e2e/provisionerGenerated.ts @@ -249,7 +249,7 @@ export interface PlanComplete { error: string; resources: Resource[]; parameters: RichParameter[]; - gitAuthProviders: string[]; + externalAuthProviders: string[]; } /** @@ -266,7 +266,7 @@ export interface ApplyComplete { error: string; resources: Resource[]; parameters: RichParameter[]; - gitAuthProviders: string[]; + externalAuthProviders: string[]; } /** CancelRequest requests that the previous request be canceled gracefully. */ @@ -859,7 +859,7 @@ export const PlanComplete = { for (const v of message.parameters) { RichParameter.encode(v!, writer.uint32(26).fork()).ldelim(); } - for (const v of message.gitAuthProviders) { + for (const v of message.externalAuthProviders) { writer.uint32(34).string(v!); } return writer; @@ -895,7 +895,7 @@ export const ApplyComplete = { for (const v of message.parameters) { RichParameter.encode(v!, writer.uint32(34).fork()).ldelim(); } - for (const v of message.gitAuthProviders) { + for (const v of message.externalAuthProviders) { writer.uint32(42).string(v!); } return writer; diff --git a/site/e2e/tests/gitAuth.spec.ts b/site/e2e/tests/externalAuth.spec.ts similarity index 91% rename from site/e2e/tests/gitAuth.spec.ts rename to site/e2e/tests/externalAuth.spec.ts index 1206561538..a0e55e24d8 100644 --- a/site/e2e/tests/gitAuth.spec.ts +++ b/site/e2e/tests/externalAuth.spec.ts @@ -1,15 +1,15 @@ import { test } from "@playwright/test"; import { gitAuth } from "../constants"; import { Endpoints } from "@octokit/types"; -import { GitAuthDevice } from "api/typesGenerated"; +import { ExternalAuthDevice } from "api/typesGenerated"; import { Awaiter, createServer } from "../helpers"; import { beforeCoderTest } from "../hooks"; test.beforeEach(async ({ page }) => await beforeCoderTest(page)); // Ensures that a Git auth provider with the device flow functions and completes! -test("git auth device", async ({ page }) => { - const device: GitAuthDevice = { +test("external auth device", async ({ page }) => { + const device: ExternalAuthDevice = { device_code: "1234", user_code: "1234-5678", expires_in: 900, @@ -46,7 +46,7 @@ test("git auth device", async ({ page }) => { sentPending.done(); }); - await page.goto(`/gitauth/${gitAuth.deviceProvider}`, { + await page.goto(`/externalauth/${gitAuth.deviceProvider}`, { waitUntil: "domcontentloaded", }); await page.getByText(device.user_code).isVisible(); @@ -57,7 +57,7 @@ test("git auth device", async ({ page }) => { await page.waitForSelector("text=1 organization authorized"); }); -test("git auth web", async ({ baseURL, page }) => { +test("external auth web", async ({ baseURL, page }) => { const srv = await createServer(gitAuth.webPort); // The GitHub validate endpoint returns the currently authenticated user! srv.use(gitAuth.validatePath, (req, res) => { @@ -70,11 +70,11 @@ test("git auth web", async ({ baseURL, page }) => { }); srv.use(gitAuth.authPath, (req, res) => { res.redirect( - `${baseURL}/gitauth/${gitAuth.webProvider}/callback?code=1234&state=` + + `${baseURL}/externalauth/${gitAuth.webProvider}/callback?code=1234&state=` + req.query.state, ); }); - await page.goto(`/gitauth/${gitAuth.webProvider}`, { + await page.goto(`/externalauth/${gitAuth.webProvider}`, { waitUntil: "domcontentloaded", }); // This endpoint doesn't have the installations URL set intentionally! diff --git a/site/src/AppRouter.tsx b/site/src/AppRouter.tsx index badbbc0aa6..84cbd85472 100644 --- a/site/src/AppRouter.tsx +++ b/site/src/AppRouter.tsx @@ -122,7 +122,9 @@ const NetworkSettingsPage = lazy( "./pages/DeploySettingsPage/NetworkSettingsPage/NetworkSettingsPage" ), ); -const GitAuthPage = lazy(() => import("./pages/GitAuthPage/GitAuthPage")); +const ExternalAuthPage = lazy( + () => import("./pages/ExternalAuthPage/ExternalAuthPage"), +); const TemplateVersionPage = lazy( () => import("./pages/TemplateVersionPage/TemplateVersionPage"), ); @@ -207,7 +209,10 @@ export const AppRouter: FC = () => { } /> - } /> + } + /> } /> diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 2670bebdb3..9828ab7884 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -331,11 +331,11 @@ export const createTemplateVersion = async ( return response.data; }; -export const getTemplateVersionGitAuth = async ( +export const getTemplateVersionExternalAuth = async ( versionId: string, ): Promise => { const response = await axios.get( - `/api/v2/templateversions/${versionId}/gitauth`, + `/api/v2/templateversions/${versionId}/externalauth`, ); return response.data; }; @@ -855,25 +855,25 @@ export const getExperiments = async (): Promise => { } }; -export const getGitAuthProvider = async ( +export const getExternalAuthProvider = async ( provider: string, -): Promise => { - const resp = await axios.get(`/api/v2/gitauth/${provider}`); +): Promise => { + const resp = await axios.get(`/api/v2/externalauth/${provider}`); return resp.data; }; -export const getGitAuthDevice = async ( +export const getExternalAuthDevice = async ( provider: string, -): Promise => { - const resp = await axios.get(`/api/v2/gitauth/${provider}/device`); +): Promise => { + const resp = await axios.get(`/api/v2/externalauth/${provider}/device`); return resp.data; }; -export const exchangeGitAuthDevice = async ( +export const exchangeExternalAuthDevice = async ( provider: string, - req: TypesGen.GitAuthDeviceExchange, + req: TypesGen.ExternalAuthDeviceExchange, ): Promise => { - const resp = await axios.post(`/api/v2/gitauth/${provider}/device`, req); + const resp = await axios.post(`/api/v2/externalauth/${provider}/device`, req); return resp.data; }; diff --git a/site/src/api/queries/templates.ts b/site/src/api/queries/templates.ts index b01cb2d31a..15fc52db1e 100644 --- a/site/src/api/queries/templates.ts +++ b/site/src/api/queries/templates.ts @@ -121,15 +121,15 @@ export const updateActiveTemplateVersion = ( }; }; -export const templateVersionGitAuthKey = (versionId: string) => [ +export const templateVersionExternalAuthKey = (versionId: string) => [ "templateVersion", versionId, - "gitAuth", + "externalAuth", ]; -export const templateVersionGitAuth = (versionId: string) => { +export const templateVersionExternalAuth = (versionId: string) => { return { - queryKey: templateVersionGitAuthKey(versionId), - queryFn: () => API.getTemplateVersionGitAuth(versionId), + queryKey: templateVersionExternalAuthKey(versionId), + queryFn: () => API.getTemplateVersionExternalAuth(versionId), }; }; diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index cd70732f87..0b7f0c4cde 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -422,6 +422,46 @@ export interface Entitlements { // From codersdk/deployment.go export type Experiments = Experiment[]; +// From codersdk/externalauth.go +export interface ExternalAuth { + readonly authenticated: boolean; + readonly device: boolean; + readonly type: string; + readonly user?: ExternalAuthUser; + readonly app_installable: boolean; + readonly installations: ExternalAuthAppInstallation[]; + readonly app_install_url: string; +} + +// From codersdk/externalauth.go +export interface ExternalAuthAppInstallation { + readonly id: number; + readonly account: ExternalAuthUser; + readonly configure_url: string; +} + +// From codersdk/externalauth.go +export interface ExternalAuthDevice { + readonly device_code: string; + readonly user_code: string; + readonly verification_uri: string; + readonly expires_in: number; + readonly interval: number; +} + +// From codersdk/externalauth.go +export interface ExternalAuthDeviceExchange { + readonly device_code: string; +} + +// From codersdk/externalauth.go +export interface ExternalAuthUser { + readonly login: string; + readonly avatar_url: string; + readonly profile_url: string; + readonly name: string; +} + // From codersdk/deployment.go export interface Feature { readonly entitlement: Entitlement; @@ -441,24 +481,6 @@ export interface GetUsersResponse { readonly count: number; } -// From codersdk/gitauth.go -export interface GitAuth { - readonly authenticated: boolean; - readonly device: boolean; - readonly type: string; - readonly user?: GitAuthUser; - readonly app_installable: boolean; - readonly installations: GitAuthAppInstallation[]; - readonly app_install_url: string; -} - -// From codersdk/gitauth.go -export interface GitAuthAppInstallation { - readonly id: number; - readonly account: GitAuthUser; - readonly configure_url: string; -} - // From codersdk/deployment.go export interface GitAuthConfig { readonly id: string; @@ -476,28 +498,6 @@ export interface GitAuthConfig { readonly device_code_url: string; } -// From codersdk/gitauth.go -export interface GitAuthDevice { - readonly device_code: string; - readonly user_code: string; - readonly verification_uri: string; - readonly expires_in: number; - readonly interval: number; -} - -// From codersdk/gitauth.go -export interface GitAuthDeviceExchange { - readonly device_code: string; -} - -// From codersdk/gitauth.go -export interface GitAuthUser { - readonly login: string; - readonly avatar_url: string; - readonly profile_url: string; - readonly name: string; -} - // From codersdk/gitsshkey.go export interface GitSSHKey { readonly user_id: string; diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.test.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.test.tsx index 0e153b3136..37cfbd791c 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.test.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.test.tsx @@ -156,7 +156,7 @@ describe("CreateWorkspacePage", () => { expect(validationError).toBeInTheDocument(); }); - it("gitauth authenticates and succeeds", async () => { + it("external auth authenticates and succeeds", async () => { jest .spyOn(API, "getWorkspaceQuota") .mockResolvedValueOnce(MockWorkspaceQuota); @@ -165,7 +165,7 @@ describe("CreateWorkspacePage", () => { .mockResolvedValueOnce({ users: [MockUser], count: 1 }); jest.spyOn(API, "createWorkspace").mockResolvedValueOnce(MockWorkspace); jest - .spyOn(API, "getTemplateVersionGitAuth") + .spyOn(API, "getTemplateVersionExternalAuth") .mockResolvedValue([MockTemplateVersionExternalAuthGithub]); renderCreateWorkspacePage(); @@ -181,7 +181,7 @@ describe("CreateWorkspacePage", () => { await userEvent.click(githubButton); jest - .spyOn(API, "getTemplateVersionGitAuth") + .spyOn(API, "getTemplateVersionExternalAuth") .mockResolvedValue([MockTemplateVersionExternalAuthGithubAuthenticated]); await screen.findByText("Authenticated with GitHub"); @@ -200,9 +200,9 @@ describe("CreateWorkspacePage", () => { ); }); - it("gitauth: errors if unauthenticated and submits", async () => { + it("external auth: errors if unauthenticated and submits", async () => { jest - .spyOn(API, "getTemplateVersionGitAuth") + .spyOn(API, "getTemplateVersionExternalAuth") .mockResolvedValueOnce([MockTemplateVersionExternalAuthGithub]); renderCreateWorkspacePage(); diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx index f7739a2acb..91698fdc20 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx @@ -24,9 +24,9 @@ import { NumberDictionary, } from "unique-names-generator"; import { useQuery } from "@tanstack/react-query"; -import { templateVersionGitAuth } from "api/queries/templates"; +import { templateVersionExternalAuth } from "api/queries/templates"; -export type GitAuthPollingState = "idle" | "polling" | "abandoned"; +export type ExternalAuthPollingState = "idle" | "polling" | "abandoned"; const CreateWorkspacePage: FC = () => { const organizationId = useOrganizationId(); @@ -58,43 +58,44 @@ const CreateWorkspacePage: FC = () => { ? "Creating workspace..." : "Create workspace"; - const [gitAuthPollingState, setGitAuthPollingState] = - useState("idle"); + const [externalAuthPollingState, setExternalAuthPollingState] = + useState("idle"); - const startPollingGitAuth = useCallback(() => { - setGitAuthPollingState("polling"); + const startPollingExternalAuth = useCallback(() => { + setExternalAuthPollingState("polling"); }, []); - const { data: gitAuth, error } = useQuery( + const { data: externalAuth, error } = useQuery( versionId ? { - ...templateVersionGitAuth(versionId), - refetchInterval: gitAuthPollingState === "polling" ? 1000 : false, + ...templateVersionExternalAuth(versionId), + refetchInterval: + externalAuthPollingState === "polling" ? 1000 : false, } : { enabled: false }, ); - const allSignedIn = gitAuth?.every((it) => it.authenticated); + const allSignedIn = externalAuth?.every((it) => it.authenticated); useEffect(() => { if (allSignedIn) { - setGitAuthPollingState("idle"); + setExternalAuthPollingState("idle"); return; } - if (gitAuthPollingState !== "polling") { + if (externalAuthPollingState !== "polling") { return; } // Poll for a maximum of one minute const quitPolling = setTimeout( - () => setGitAuthPollingState("abandoned"), + () => setExternalAuthPollingState("abandoned"), 60_000, ); return () => { clearTimeout(quitPolling); }; - }, [gitAuthPollingState, allSignedIn]); + }, [externalAuthPollingState, allSignedIn]); return ( <> @@ -116,9 +117,9 @@ const CreateWorkspacePage: FC = () => { error={error} template={template!} versionId={versionId} - gitAuth={gitAuth ?? []} - gitAuthPollingState={gitAuthPollingState} - startPollingGitAuth={startPollingGitAuth} + externalAuth={externalAuth ?? []} + externalAuthPollingState={externalAuthPollingState} + startPollingExternalAuth={startPollingExternalAuth} permissions={permissions as CreateWSPermissions} parameters={parameters!} creatingWorkspace={createWorkspaceState.matches("creatingWorkspace")} diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx index f8b25451e8..5a0478ca4d 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx @@ -18,7 +18,7 @@ const meta: Meta = { defaultBuildParameters: [], template: MockTemplate, parameters: [], - gitAuth: [], + externalAuth: [], permissions: { createWorkspaceForUser: true, }, @@ -86,9 +86,9 @@ export const Parameters: Story = { }, }; -export const GitAuth: Story = { +export const ExternalAuth: Story = { args: { - gitAuth: [ + externalAuth: [ { id: "github", type: "github", diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx index aea3832f65..2776a43ef3 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx @@ -27,10 +27,10 @@ import { MutableTemplateParametersSection, } from "components/TemplateParameters/TemplateParameters"; import { CreateWSPermissions } from "xServices/createWorkspace/createWorkspaceXService"; -import { GitAuth } from "./GitAuth"; +import { ExternalAuth } from "./ExternalAuth"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Stack } from "components/Stack/Stack"; -import { type GitAuthPollingState } from "./CreateWorkspacePage"; +import { type ExternalAuthPollingState } from "./CreateWorkspacePage"; export interface CreateWorkspacePageViewProps { error: unknown; @@ -38,9 +38,9 @@ export interface CreateWorkspacePageViewProps { defaultOwner: TypesGen.User; template: TypesGen.Template; versionId?: string; - gitAuth: TypesGen.TemplateVersionExternalAuth[]; - gitAuthPollingState: GitAuthPollingState; - startPollingGitAuth: () => void; + externalAuth: TypesGen.TemplateVersionExternalAuth[]; + externalAuthPollingState: ExternalAuthPollingState; + startPollingExternalAuth: () => void; parameters: TypesGen.TemplateVersionParameter[]; defaultBuildParameters: TypesGen.WorkspaceBuildParameter[]; permissions: CreateWSPermissions; @@ -58,9 +58,9 @@ export const CreateWorkspacePageView: FC = ({ defaultOwner, template, versionId, - gitAuth, - gitAuthPollingState, - startPollingGitAuth, + externalAuth, + externalAuthPollingState, + startPollingExternalAuth, parameters, defaultBuildParameters, permissions, @@ -70,7 +70,8 @@ export const CreateWorkspacePageView: FC = ({ }) => { const styles = useStyles(); const [owner, setOwner] = useState(defaultOwner); - const { verifyGitAuth, gitAuthErrors } = useGitAuthVerification(gitAuth); + const { verifyExternalAuth, externalAuthErrors } = + useExternalAuthVerification(externalAuth); const form: FormikContextType = useFormik({ initialValues: { @@ -87,7 +88,7 @@ export const CreateWorkspacePageView: FC = ({ }), enableReinitialize: true, onSubmit: (request) => { - if (!verifyGitAuth()) { + if (!verifyExternalAuth()) { form.setSubmitting(false); return; } @@ -160,21 +161,21 @@ export const CreateWorkspacePageView: FC = ({ )} - {gitAuth && gitAuth.length > 0 && ( + {externalAuth && externalAuth.length > 0 && ( - {gitAuth.map((auth) => ( - ( + ))} @@ -231,23 +232,24 @@ export const CreateWorkspacePageView: FC = ({ ); }; -type GitAuthErrors = Record; +type ExternalAuthErrors = Record; -const useGitAuthVerification = ( - gitAuth: TypesGen.TemplateVersionExternalAuth[], +const useExternalAuthVerification = ( + externalAuth: TypesGen.TemplateVersionExternalAuth[], ) => { - const [gitAuthErrors, setGitAuthErrors] = useState({}); + const [externalAuthErrors, setExternalAuthErrors] = + useState({}); - // Clear errors when gitAuth is refreshed + // Clear errors when externalAuth is refreshed useEffect(() => { - setGitAuthErrors({}); - }, [gitAuth]); + setExternalAuthErrors({}); + }, [externalAuth]); - const verifyGitAuth = () => { - const errors: GitAuthErrors = {}; + const verifyExternalAuth = () => { + const errors: ExternalAuthErrors = {}; - for (let i = 0; i < gitAuth.length; i++) { - const auth = gitAuth.at(i); + for (let i = 0; i < externalAuth.length; i++) { + const auth = externalAuth.at(i); if (!auth) { continue; } @@ -256,14 +258,14 @@ const useGitAuthVerification = ( } } - setGitAuthErrors(errors); + setExternalAuthErrors(errors); const isValid = Object.keys(errors).length === 0; return isValid; }; return { - gitAuthErrors, - verifyGitAuth, + externalAuthErrors, + verifyExternalAuth, }; }; diff --git a/site/src/pages/CreateWorkspacePage/GitAuth.stories.tsx b/site/src/pages/CreateWorkspacePage/ExternalAuth.stories.tsx similarity index 83% rename from site/src/pages/CreateWorkspacePage/GitAuth.stories.tsx rename to site/src/pages/CreateWorkspacePage/ExternalAuth.stories.tsx index bd6f8cf813..9c65abc5a0 100644 --- a/site/src/pages/CreateWorkspacePage/GitAuth.stories.tsx +++ b/site/src/pages/CreateWorkspacePage/ExternalAuth.stories.tsx @@ -1,13 +1,13 @@ -import { GitAuth } from "./GitAuth"; +import { ExternalAuth } from "./ExternalAuth"; import type { Meta, StoryObj } from "@storybook/react"; -const meta: Meta = { - title: "components/GitAuth", - component: GitAuth, +const meta: Meta = { + title: "components/ExternalAuth", + component: ExternalAuth, }; export default meta; -type Story = StoryObj; +type Story = StoryObj; export const GithubNotAuthenticated: Story = { args: { diff --git a/site/src/pages/CreateWorkspacePage/GitAuth.tsx b/site/src/pages/CreateWorkspacePage/ExternalAuth.tsx similarity index 83% rename from site/src/pages/CreateWorkspacePage/GitAuth.tsx rename to site/src/pages/CreateWorkspacePage/ExternalAuth.tsx index e7ab032153..4c685089b7 100644 --- a/site/src/pages/CreateWorkspacePage/GitAuth.tsx +++ b/site/src/pages/CreateWorkspacePage/ExternalAuth.tsx @@ -9,27 +9,27 @@ import { BitbucketIcon } from "components/Icons/BitbucketIcon"; import { GitlabIcon } from "components/Icons/GitlabIcon"; import { FC } from "react"; import { makeStyles } from "@mui/styles"; -import { type GitAuthPollingState } from "./CreateWorkspacePage"; +import { type ExternalAuthPollingState } from "./CreateWorkspacePage"; import { Stack } from "components/Stack/Stack"; import ReplayIcon from "@mui/icons-material/Replay"; import { LoadingButton } from "components/LoadingButton/LoadingButton"; -export interface GitAuthProps { +export interface ExternalAuthProps { type: TypesGen.ExternalAuthProvider; authenticated: boolean; authenticateURL: string; - gitAuthPollingState: GitAuthPollingState; - startPollingGitAuth: () => void; + externalAuthPollingState: ExternalAuthPollingState; + startPollingExternalAuth: () => void; error?: string; } -export const GitAuth: FC = (props) => { +export const ExternalAuth: FC = (props) => { const { type, authenticated, authenticateURL, - gitAuthPollingState, - startPollingGitAuth, + externalAuthPollingState, + startPollingExternalAuth, error, } = props; @@ -66,7 +66,7 @@ export const GitAuth: FC = (props) => { > = (props) => { return; } window.open(authenticateURL, "_blank", "width=900,height=600"); - startPollingGitAuth(); + startPollingExternalAuth(); }} > {authenticated @@ -90,8 +90,8 @@ export const GitAuth: FC = (props) => { : `Login with ${prettyName}`} - {gitAuthPollingState === "abandoned" && ( - )} diff --git a/site/src/pages/ExternalAuthPage/ExternalAuthPage.tsx b/site/src/pages/ExternalAuthPage/ExternalAuthPage.tsx new file mode 100644 index 0000000000..04300803aa --- /dev/null +++ b/site/src/pages/ExternalAuthPage/ExternalAuthPage.tsx @@ -0,0 +1,96 @@ +import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { + exchangeExternalAuthDevice, + getExternalAuthDevice, + getExternalAuthProvider, +} from "api/api"; +import { usePermissions } from "hooks"; +import { type FC } from "react"; +import { useParams } from "react-router-dom"; +import ExternalAuthPageView from "./ExternalAuthPageView"; +import { ApiErrorResponse } from "api/errors"; +import { isAxiosError } from "axios"; + +const ExternalAuthPage: FC = () => { + const { provider } = useParams(); + if (!provider) { + throw new Error("provider must exist"); + } + const permissions = usePermissions(); + const queryClient = useQueryClient(); + const getExternalAuthProviderQuery = useQuery({ + queryKey: ["externalauth", provider], + queryFn: () => getExternalAuthProvider(provider), + refetchOnWindowFocus: true, + }); + + const getExternalAuthDeviceQuery = useQuery({ + enabled: + Boolean(!getExternalAuthProviderQuery.data?.authenticated) && + Boolean(getExternalAuthProviderQuery.data?.device), + queryFn: () => getExternalAuthDevice(provider), + queryKey: ["externalauth", provider, "device"], + refetchOnMount: false, + }); + const exchangeExternalAuthDeviceQuery = useQuery({ + queryFn: () => + exchangeExternalAuthDevice(provider, { + device_code: getExternalAuthDeviceQuery.data?.device_code || "", + }), + queryKey: [ + "externalauth", + provider, + getExternalAuthDeviceQuery.data?.device_code, + ], + enabled: Boolean(getExternalAuthDeviceQuery.data), + onSuccess: () => { + // Force a refresh of the Git auth status. + queryClient.invalidateQueries(["externalauth", provider]).catch((ex) => { + console.error("invalidate queries", ex); + }); + }, + retry: true, + retryDelay: (getExternalAuthDeviceQuery.data?.interval || 5) * 1000, + refetchOnWindowFocus: (query) => + query.state.status === "success" ? false : "always", + }); + + if ( + getExternalAuthProviderQuery.isLoading || + !getExternalAuthProviderQuery.data + ) { + return null; + } + + let deviceExchangeError: ApiErrorResponse | undefined; + if (isAxiosError(exchangeExternalAuthDeviceQuery.failureReason)) { + deviceExchangeError = + exchangeExternalAuthDeviceQuery.failureReason.response?.data; + } + + if ( + !getExternalAuthProviderQuery.data.authenticated && + !getExternalAuthProviderQuery.data.device + ) { + window.location.href = `/externalauth/${provider}/callback`; + + return null; + } + + return ( + { + queryClient.setQueryData(["externalauth", provider], { + ...getExternalAuthProviderQuery.data, + authenticated: false, + }); + }} + viewExternalAuthConfig={permissions.viewExternalAuthConfig} + deviceExchangeError={deviceExchangeError} + externalAuthDevice={getExternalAuthDeviceQuery.data} + /> + ); +}; + +export default ExternalAuthPage; diff --git a/site/src/pages/GitAuthPage/GitAuthPageView.stories.tsx b/site/src/pages/ExternalAuthPage/ExternalAuthPageView.stories.tsx similarity index 82% rename from site/src/pages/GitAuthPage/GitAuthPageView.stories.tsx rename to site/src/pages/ExternalAuthPage/ExternalAuthPageView.stories.tsx index 99593c98d2..2d975245d5 100644 --- a/site/src/pages/GitAuthPage/GitAuthPageView.stories.tsx +++ b/site/src/pages/ExternalAuthPage/ExternalAuthPageView.stories.tsx @@ -1,18 +1,20 @@ import { Meta, StoryFn } from "@storybook/react"; -import GitAuthPageView, { GitAuthPageViewProps } from "./GitAuthPageView"; +import ExternalAuthPageView, { + ExternalAuthPageViewProps, +} from "./ExternalAuthPageView"; export default { - title: "pages/GitAuthPageView", - component: GitAuthPageView, -} as Meta; + title: "pages/ExternalAuthPageView", + component: ExternalAuthPageView, +} as Meta; -const Template: StoryFn = (args) => ( - +const Template: StoryFn = (args) => ( + ); export const WebAuthenticated = Template.bind({}); WebAuthenticated.args = { - gitAuth: { + externalAuth: { type: "BitBucket", authenticated: true, device: false, @@ -30,7 +32,7 @@ WebAuthenticated.args = { export const DeviceUnauthenticated = Template.bind({}); DeviceUnauthenticated.args = { - gitAuth: { + externalAuth: { type: "GitHub", authenticated: false, device: true, @@ -38,7 +40,7 @@ DeviceUnauthenticated.args = { app_install_url: "", app_installable: false, }, - gitAuthDevice: { + externalAuthDevice: { device_code: "1234-5678", expires_in: 900, interval: 5, @@ -49,7 +51,7 @@ DeviceUnauthenticated.args = { export const DeviceUnauthenticatedError = Template.bind({}); DeviceUnauthenticatedError.args = { - gitAuth: { + externalAuth: { type: "GitHub", authenticated: false, device: true, @@ -57,7 +59,7 @@ DeviceUnauthenticatedError.args = { app_install_url: "", app_installable: false, }, - gitAuthDevice: { + externalAuthDevice: { device_code: "1234-5678", expires_in: 900, interval: 5, @@ -72,8 +74,8 @@ DeviceUnauthenticatedError.args = { export const DeviceAuthenticatedNotInstalled = Template.bind({}); DeviceAuthenticatedNotInstalled.args = { - viewGitAuthConfig: true, - gitAuth: { + viewExternalAuthConfig: true, + externalAuth: { type: "GitHub", authenticated: true, device: true, @@ -91,7 +93,7 @@ DeviceAuthenticatedNotInstalled.args = { export const DeviceAuthenticatedInstalled = Template.bind({}); DeviceAuthenticatedInstalled.args = { - gitAuth: { + externalAuth: { type: "GitHub", authenticated: true, device: true, diff --git a/site/src/pages/GitAuthPage/GitAuthPageView.tsx b/site/src/pages/ExternalAuthPage/ExternalAuthPageView.tsx similarity index 72% rename from site/src/pages/GitAuthPage/GitAuthPageView.tsx rename to site/src/pages/ExternalAuthPage/ExternalAuthPageView.tsx index 23ec8fd98e..3984f35e37 100644 --- a/site/src/pages/GitAuthPage/GitAuthPageView.tsx +++ b/site/src/pages/ExternalAuthPage/ExternalAuthPageView.tsx @@ -5,7 +5,7 @@ import Link from "@mui/material/Link"; import Tooltip from "@mui/material/Tooltip"; import { makeStyles } from "@mui/styles"; import { ApiErrorResponse } from "api/errors"; -import { GitAuth, GitAuthDevice } from "api/typesGenerated"; +import { ExternalAuth, ExternalAuthDevice } from "api/typesGenerated"; import { Alert } from "components/Alert/Alert"; import { Avatar } from "components/Avatar/Avatar"; import { CopyButton } from "components/CopyButton/CopyButton"; @@ -13,47 +13,53 @@ import { SignInLayout } from "components/SignInLayout/SignInLayout"; import { Welcome } from "components/Welcome/Welcome"; import { type FC } from "react"; -export interface GitAuthPageViewProps { - gitAuth: GitAuth; - viewGitAuthConfig: boolean; +export interface ExternalAuthPageViewProps { + externalAuth: ExternalAuth; + viewExternalAuthConfig: boolean; - gitAuthDevice?: GitAuthDevice; + externalAuthDevice?: ExternalAuthDevice; deviceExchangeError?: ApiErrorResponse; onReauthenticate: () => void; } -const GitAuthPageView: FC = ({ +const ExternalAuthPageView: FC = ({ deviceExchangeError, - gitAuth, - gitAuthDevice, + externalAuth, + externalAuthDevice, onReauthenticate, - viewGitAuthConfig, + viewExternalAuthConfig, }) => { const styles = useStyles(); - if (!gitAuth.authenticated) { + if (!externalAuth.authenticated) { return ( - + - {gitAuth.device && ( + {externalAuth.device && ( )} ); } - const hasInstallations = gitAuth.installations.length > 0; + const hasInstallations = externalAuth.installations.length > 0; // We only want to wrap this with a link if an install URL is available! - let installTheApp: JSX.Element = <>{`install the ${gitAuth.type} App`}; - if (gitAuth.app_install_url) { + let installTheApp: JSX.Element = ( + <>{`install the ${externalAuth.type} App`} + ); + if (externalAuth.app_install_url) { installTheApp = ( - + {installTheApp} ); @@ -61,16 +67,17 @@ const GitAuthPageView: FC = ({ return ( - +

- Hey @{gitAuth.user?.login}! 👋{" "} - {(!gitAuth.app_installable || gitAuth.installations.length > 0) && + Hey @{externalAuth.user?.login}! 👋{" "} + {(!externalAuth.app_installable || + externalAuth.installations.length > 0) && "You are now authenticated with Git. Feel free to close this window!"}

- {gitAuth.installations.length > 0 && ( + {externalAuth.installations.length > 0 && (
- {gitAuth.installations.map((install) => { + {externalAuth.installations.map((install) => { if (!install.account) { return; } @@ -93,32 +100,33 @@ const GitAuthPageView: FC = ({ ); })}   - {gitAuth.installations.length} organization - {gitAuth.installations.length !== 1 && "s are"} authorized + {externalAuth.installations.length} organization + {externalAuth.installations.length !== 1 && "s are"} authorized
)}
- {!hasInstallations && gitAuth.app_installable && ( + {!hasInstallations && externalAuth.app_installable && ( You must {installTheApp} to clone private repositories. Accounts will appear here once authorized. )} - {viewGitAuthConfig && - gitAuth.app_install_url && - gitAuth.app_installable && ( + {viewExternalAuthConfig && + externalAuth.app_install_url && + externalAuth.app_installable && ( - {gitAuth.installations.length > 0 + {externalAuth.installations.length > 0 ? "Configure" - : "Install"} the {gitAuth.type} App + : "Install"}{" "} + the {externalAuth.type} App )} = ({ }; const GitDeviceAuth: FC<{ - gitAuthDevice?: GitAuthDevice; + externalAuthDevice?: ExternalAuthDevice; deviceExchangeError?: ApiErrorResponse; -}> = ({ gitAuthDevice, deviceExchangeError }) => { +}> = ({ externalAuthDevice, deviceExchangeError }) => { const styles = useStyles(); let status = ( @@ -175,7 +183,7 @@ const GitDeviceAuth: FC<{ } } - if (!gitAuthDevice) { + if (!externalAuthDevice) { return ; } @@ -184,8 +192,8 @@ const GitDeviceAuth: FC<{

Copy your one-time code: 

- {gitAuthDevice.user_code} {" "} - + {externalAuthDevice.user_code} +  

Then open the link below and paste it: @@ -193,7 +201,7 @@ const GitDeviceAuth: FC<{
@@ -207,7 +215,7 @@ const GitDeviceAuth: FC<{ ); }; -export default GitAuthPageView; +export default ExternalAuthPageView; const useStyles = makeStyles((theme) => ({ text: { diff --git a/site/src/pages/GitAuthPage/GitAuthPage.tsx b/site/src/pages/GitAuthPage/GitAuthPage.tsx deleted file mode 100644 index f0ebfa22f3..0000000000 --- a/site/src/pages/GitAuthPage/GitAuthPage.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { useQuery, useQueryClient } from "@tanstack/react-query"; -import { - exchangeGitAuthDevice, - getGitAuthDevice, - getGitAuthProvider, -} from "api/api"; -import { usePermissions } from "hooks"; -import { type FC } from "react"; -import { useParams } from "react-router-dom"; -import GitAuthPageView from "./GitAuthPageView"; -import { ApiErrorResponse } from "api/errors"; -import { isAxiosError } from "axios"; - -const GitAuthPage: FC = () => { - const { provider } = useParams(); - if (!provider) { - throw new Error("provider must exist"); - } - const permissions = usePermissions(); - const queryClient = useQueryClient(); - const getGitAuthProviderQuery = useQuery({ - queryKey: ["gitauth", provider], - queryFn: () => getGitAuthProvider(provider), - refetchOnWindowFocus: true, - }); - - const getGitAuthDeviceQuery = useQuery({ - enabled: - Boolean(!getGitAuthProviderQuery.data?.authenticated) && - Boolean(getGitAuthProviderQuery.data?.device), - queryFn: () => getGitAuthDevice(provider), - queryKey: ["gitauth", provider, "device"], - refetchOnMount: false, - }); - const exchangeGitAuthDeviceQuery = useQuery({ - queryFn: () => - exchangeGitAuthDevice(provider, { - device_code: getGitAuthDeviceQuery.data?.device_code || "", - }), - queryKey: ["gitauth", provider, getGitAuthDeviceQuery.data?.device_code], - enabled: Boolean(getGitAuthDeviceQuery.data), - onSuccess: () => { - // Force a refresh of the Git auth status. - queryClient.invalidateQueries(["gitauth", provider]).catch((ex) => { - console.error("invalidate queries", ex); - }); - }, - retry: true, - retryDelay: (getGitAuthDeviceQuery.data?.interval || 5) * 1000, - refetchOnWindowFocus: (query) => - query.state.status === "success" ? false : "always", - }); - - if (getGitAuthProviderQuery.isLoading || !getGitAuthProviderQuery.data) { - return null; - } - - let deviceExchangeError: ApiErrorResponse | undefined; - if (isAxiosError(exchangeGitAuthDeviceQuery.failureReason)) { - deviceExchangeError = - exchangeGitAuthDeviceQuery.failureReason.response?.data; - } - - if ( - !getGitAuthProviderQuery.data.authenticated && - !getGitAuthProviderQuery.data.device - ) { - window.location.href = `/gitauth/${provider}/callback`; - - return null; - } - - return ( - { - queryClient.setQueryData(["gitauth", provider], { - ...getGitAuthProviderQuery.data, - authenticated: false, - }); - }} - viewGitAuthConfig={permissions.viewGitAuthConfig} - deviceExchangeError={deviceExchangeError} - gitAuthDevice={getGitAuthDeviceQuery.data} - /> - ); -}; - -export default GitAuthPage; diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 1a72a34a64..d44ed976f1 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -2140,7 +2140,7 @@ export const MockPermissions: Permissions = { viewDeploymentValues: true, viewUpdateCheck: true, viewDeploymentStats: true, - viewGitAuthConfig: true, + viewExternalAuthConfig: true, editWorkspaceProxies: true, }; @@ -2188,7 +2188,7 @@ export const MockTemplateVersionExternalAuthGithub: TypesGen.TemplateVersionExte { id: "github", type: "github", - authenticate_url: "https://example.com/gitauth/github", + authenticate_url: "https://example.com/externalauth/github", authenticated: false, }; @@ -2196,7 +2196,7 @@ export const MockTemplateVersionExternalAuthGithubAuthenticated: TypesGen.Templa { id: "github", type: "github", - authenticate_url: "https://example.com/gitauth/github", + authenticate_url: "https://example.com/externalauth/github", authenticated: true, }; diff --git a/site/src/testHelpers/handlers.ts b/site/src/testHelpers/handlers.ts index c1deb90054..abce3fd217 100644 --- a/site/src/testHelpers/handlers.ts +++ b/site/src/testHelpers/handlers.ts @@ -112,7 +112,7 @@ export const handlers = [ }, ), rest.get( - "/api/v2/templateversions/:templateVersionId/gitauth", + "/api/v2/templateversions/:templateVersionId/externalauth", async (req, res, ctx) => { return res(ctx.status(200), ctx.json([])); }, diff --git a/site/src/utils/gitAuth.ts b/site/src/utils/gitAuth.ts deleted file mode 100644 index 66b6ac9bc3..0000000000 --- a/site/src/utils/gitAuth.ts +++ /dev/null @@ -1 +0,0 @@ -export const REFRESH_GITAUTH_BROADCAST_CHANNEL = "gitauth_refresh"; diff --git a/site/src/xServices/auth/authXService.ts b/site/src/xServices/auth/authXService.ts index 295954402a..ee4bda58de 100644 --- a/site/src/xServices/auth/authXService.ts +++ b/site/src/xServices/auth/authXService.ts @@ -18,7 +18,7 @@ export const checks = { viewDeploymentValues: "viewDeploymentValues", createGroup: "createGroup", viewUpdateCheck: "viewUpdateCheck", - viewGitAuthConfig: "viewGitAuthConfig", + viewExternalAuthConfig: "viewExternalAuthConfig", viewDeploymentStats: "viewDeploymentStats", editWorkspaceProxies: "editWorkspaceProxies", } as const; @@ -84,7 +84,7 @@ export const permissionsToCheck = { }, action: "read", }, - [checks.viewGitAuthConfig]: { + [checks.viewExternalAuthConfig]: { object: { resource_type: "deployment_config", },