Skip to content

Commit 604cf5b

Browse files
committed
Add gitauth endpoint to query authenticated state
1 parent 3d67a0d commit 604cf5b

File tree

14 files changed

+241
-66
lines changed

14 files changed

+241
-66
lines changed

coderd/coderd.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@ func New(options *Options) *API {
479479
r.Get("/schema", api.templateVersionSchema)
480480
r.Get("/parameters", api.templateVersionParameters)
481481
r.Get("/rich-parameters", api.templateVersionRichParameters)
482+
r.Get("/gitauth", api.templateVersionGitAuth)
482483
r.Get("/variables", api.templateVersionVariables)
483484
r.Get("/resources", api.templateVersionResources)
484485
r.Get("/logs", api.templateVersionLogs)
@@ -795,12 +796,18 @@ func (api *API) CreateInMemoryProvisionerDaemon(ctx context.Context, debounce ti
795796
}
796797

797798
mux := drpcmux.New()
799+
800+
gitAuthProviders := make([]string, 0, len(api.GitAuthConfigs))
801+
for _, cfg := range api.GitAuthConfigs {
802+
gitAuthProviders = append(gitAuthProviders, cfg.ID)
803+
}
798804
err = proto.DRPCRegisterProvisionerDaemon(mux, &provisionerdserver.Server{
799805
AccessURL: api.AccessURL,
800806
ID: daemon.ID,
801807
Database: api.Database,
802808
Pubsub: api.Pubsub,
803809
Provisioners: daemon.Provisioners,
810+
GitAuthProviders: gitAuthProviders,
804811
Telemetry: api.Telemetry,
805812
Tags: tags,
806813
QuotaCommitter: &api.QuotaCommitter,

coderd/database/dbauthz/querier.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,11 +1121,11 @@ func (q *querier) InsertGitAuthLink(ctx context.Context, arg database.InsertGitA
11211121
return insert(q.log, q.auth, rbac.ResourceUserData.WithOwner(arg.UserID.String()).WithID(arg.UserID), q.db.InsertGitAuthLink)(ctx, arg)
11221122
}
11231123

1124-
func (q *querier) UpdateGitAuthLink(ctx context.Context, arg database.UpdateGitAuthLinkParams) error {
1124+
func (q *querier) UpdateGitAuthLink(ctx context.Context, arg database.UpdateGitAuthLinkParams) (database.GitAuthLink, error) {
11251125
fetch := func(ctx context.Context, arg database.UpdateGitAuthLinkParams) (database.GitAuthLink, error) {
11261126
return q.db.GetGitAuthLink(ctx, database.GetGitAuthLinkParams{UserID: arg.UserID, ProviderID: arg.ProviderID})
11271127
}
1128-
return update(q.log, q.auth, fetch, q.db.UpdateGitAuthLink)(ctx, arg)
1128+
return updateWithReturn(q.log, q.auth, fetch, q.db.UpdateGitAuthLink)(ctx, arg)
11291129
}
11301130

11311131
func (q *querier) UpdateUserLink(ctx context.Context, arg database.UpdateUserLinkParams) (database.UserLink, error) {

coderd/database/dbauthz/querier_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -883,7 +883,7 @@ func (s *MethodTestSuite) TestUser() {
883883
check.Args(database.UpdateGitAuthLinkParams{
884884
ProviderID: link.ProviderID,
885885
UserID: link.UserID,
886-
}).Asserts(link, rbac.ActionUpdate).Returns()
886+
}).Asserts(link, rbac.ActionUpdate).Returns(link)
887887
}))
888888
s.Run("UpdateUserLink", s.Subtest(func(db database.Store, check *expects) {
889889
link := dbgen.UserLink(s.T(), db, database.UserLink{})

coderd/database/dbfake/databasefake.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4294,9 +4294,9 @@ func (q *fakeQuerier) InsertGitAuthLink(_ context.Context, arg database.InsertGi
42944294
return gitAuthLink, nil
42954295
}
42964296

4297-
func (q *fakeQuerier) UpdateGitAuthLink(_ context.Context, arg database.UpdateGitAuthLinkParams) error {
4297+
func (q *fakeQuerier) UpdateGitAuthLink(_ context.Context, arg database.UpdateGitAuthLinkParams) (database.GitAuthLink, error) {
42984298
if err := validateDatabaseType(arg); err != nil {
4299-
return err
4299+
return database.GitAuthLink{}, err
43004300
}
43014301

43024302
q.mutex.Lock()
@@ -4313,8 +4313,10 @@ func (q *fakeQuerier) UpdateGitAuthLink(_ context.Context, arg database.UpdateGi
43134313
gitAuthLink.OAuthRefreshToken = arg.OAuthRefreshToken
43144314
gitAuthLink.OAuthExpiry = arg.OAuthExpiry
43154315
q.gitAuthLinks[index] = gitAuthLink
4316+
4317+
return gitAuthLink, nil
43164318
}
4317-
return nil
4319+
return database.GitAuthLink{}, sql.ErrNoRows
43184320
}
43194321

43204322
func (q *fakeQuerier) GetQuotaAllowanceForUser(_ context.Context, userID uuid.UUID) (int64, error) {

coderd/database/querier.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

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

coderd/database/queries/gitauth.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ INSERT INTO git_auth_links (
2020
$7
2121
) RETURNING *;
2222

23-
-- name: UpdateGitAuthLink :exec
23+
-- name: UpdateGitAuthLink :one
2424
UPDATE git_auth_links SET
2525
updated_at = $3,
2626
oauth_access_token = $4,
2727
oauth_refresh_token = $5,
2828
oauth_expiry = $6
29-
WHERE provider_id = $1 AND user_id = $2;
29+
WHERE provider_id = $1 AND user_id = $2 RETURNING *;

coderd/provisionerdserver/provisionerdserver.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,9 +812,15 @@ func (server *Server) CompleteJob(ctx context.Context, completed *proto.Complete
812812
}
813813
}
814814

815+
var completedError sql.NullString
816+
815817
for _, gitAuthProvider := range jobType.TemplateImport.GitAuthProviders {
816818
if !slice.Contains(server.GitAuthProviders, gitAuthProvider) {
817-
return nil, xerrors.Errorf("git auth provider %q is not configured", gitAuthProvider)
819+
completedError = sql.NullString{
820+
String: fmt.Sprintf("git auth provider %q is not configured", gitAuthProvider),
821+
Valid: true,
822+
}
823+
break
818824
}
819825
}
820826

@@ -834,6 +840,7 @@ func (server *Server) CompleteJob(ctx context.Context, completed *proto.Complete
834840
Time: database.Now(),
835841
Valid: true,
836842
},
843+
Error: completedError,
837844
})
838845
if err != nil {
839846
return nil, xerrors.Errorf("update provisioner job: %w", err)

coderd/provisionerdserver/provisionerdserver_test.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,7 @@ func TestCompleteJob(t *testing.T) {
756756
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
757757
})
758758
require.NoError(t, err)
759-
completeJob := func() error {
759+
completeJob := func() {
760760
_, err = srv.CompleteJob(ctx, &proto.CompletedJob{
761761
JobId: job.ID.String(),
762762
Type: &proto.CompletedJob_TemplateImport_{
@@ -770,13 +770,17 @@ func TestCompleteJob(t *testing.T) {
770770
},
771771
},
772772
})
773-
return err
773+
require.NoError(t, err)
774774
}
775-
err = completeJob()
776-
require.ErrorContains(t, err, `git auth provider "github" is not configured`)
775+
completeJob()
776+
job, err = srv.Database.GetProvisionerJobByID(ctx, job.ID)
777+
require.NoError(t, err)
778+
require.Contains(t, job.Error.String, `git auth provider "github" is not configured`)
777779
srv.GitAuthProviders = []string{"github"}
778-
err = completeJob()
780+
completeJob()
781+
job, err = srv.Database.GetProvisionerJobByID(ctx, job.ID)
779782
require.NoError(t, err)
783+
require.False(t, job.Error.Valid)
780784
})
781785
t.Run("WorkspaceBuild", func(t *testing.T) {
782786
t.Parallel()

coderd/templateversions.go

Lines changed: 103 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919

2020
"github.com/coder/coder/coderd/audit"
2121
"github.com/coder/coder/coderd/database"
22+
"github.com/coder/coder/coderd/gitauth"
2223
"github.com/coder/coder/coderd/httpapi"
2324
"github.com/coder/coder/coderd/httpmw"
2425
"github.com/coder/coder/coderd/parameter"
@@ -243,6 +244,99 @@ func (api *API) templateVersionRichParameters(rw http.ResponseWriter, r *http.Re
243244
httpapi.Write(ctx, rw, http.StatusOK, templateVersionParameters)
244245
}
245246

247+
// @Summary Get git auth by template version
248+
// @ID get-git-auth-by-template-version
249+
// @Security CoderSessionToken
250+
// @Produce json
251+
// @Tags Templates
252+
// @Param templateversion path string true "Template version ID" format(uuid)
253+
// @Success 200 {array} codersdk.GitAuth
254+
// @Router /templateversions/{templateversion}/gitauth [get]
255+
func (api *API) templateVersionGitAuth(rw http.ResponseWriter, r *http.Request) {
256+
ctx := r.Context()
257+
var (
258+
apiKey = httpmw.APIKey(r)
259+
templateVersion = httpmw.TemplateVersionParam(r)
260+
template = httpmw.TemplateParam(r)
261+
)
262+
263+
if !api.Authorize(r, rbac.ActionRead, templateVersion.RBACObject(template)) {
264+
httpapi.ResourceNotFound(rw)
265+
return
266+
}
267+
268+
rawProviders := templateVersion.GitAuthProviders
269+
providers := make([]codersdk.GitAuth, 0)
270+
for _, rawProvider := range rawProviders {
271+
var config *gitauth.Config
272+
for _, provider := range api.GitAuthConfigs {
273+
if provider.ID == rawProvider {
274+
config = provider
275+
break
276+
}
277+
}
278+
if config == nil {
279+
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
280+
Message: fmt.Sprintf("The template version references a Git auth provider %q that no longer exists.", rawProvider),
281+
Detail: "You'll need to update the template version to use a different provider.",
282+
})
283+
return
284+
}
285+
286+
// This is the URL that will redirect the user with a state token.
287+
redirectURL, err := api.AccessURL.Parse(fmt.Sprintf("/gitauth/%s", config.ID))
288+
if err != nil {
289+
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
290+
Message: "Failed to parse access URL.",
291+
Detail: err.Error(),
292+
})
293+
return
294+
}
295+
296+
provider := codersdk.GitAuth{
297+
ID: config.ID,
298+
Type: config.Type,
299+
AuthenticateURL: redirectURL.String(),
300+
}
301+
302+
authLink, err := api.Database.GetGitAuthLink(ctx, database.GetGitAuthLinkParams{
303+
ProviderID: config.ID,
304+
UserID: apiKey.UserID,
305+
})
306+
// If there isn't an auth link, then the user just isn't authenticated.
307+
if errors.Is(err, sql.ErrNoRows) {
308+
providers = append(providers, provider)
309+
continue
310+
}
311+
if err != nil {
312+
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
313+
Message: "Internal error fetching Git auth link.",
314+
Detail: err.Error(),
315+
})
316+
return
317+
}
318+
319+
_, updated, err := refreshGitToken(ctx, api.Database, apiKey.UserID, config, authLink)
320+
if err != nil {
321+
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
322+
Message: "Failed to refresh git auth token.",
323+
Detail: err.Error(),
324+
})
325+
return
326+
}
327+
// If the token couldn't be validated, then we assume the user isn't
328+
// authenticated and return early.
329+
if !updated {
330+
providers = append(providers, provider)
331+
continue
332+
}
333+
provider.Authenticated = true
334+
providers = append(providers, provider)
335+
}
336+
337+
httpapi.Write(ctx, rw, http.StatusOK, providers)
338+
}
339+
246340
// @Summary Get template variables by template version
247341
// @ID get-template-variables-by-template-version
248342
// @Security CoderSessionToken
@@ -1461,16 +1555,15 @@ func convertTemplateVersion(version database.TemplateVersion, job codersdk.Provi
14611555
}
14621556

14631557
return codersdk.TemplateVersion{
1464-
ID: version.ID,
1465-
TemplateID: &version.TemplateID.UUID,
1466-
OrganizationID: version.OrganizationID,
1467-
CreatedAt: version.CreatedAt,
1468-
UpdatedAt: version.UpdatedAt,
1469-
GitAuthProviders: version.GitAuthProviders,
1470-
Name: version.Name,
1471-
Job: job,
1472-
Readme: version.Readme,
1473-
CreatedBy: createdBy,
1558+
ID: version.ID,
1559+
TemplateID: &version.TemplateID.UUID,
1560+
OrganizationID: version.OrganizationID,
1561+
CreatedAt: version.CreatedAt,
1562+
UpdatedAt: version.UpdatedAt,
1563+
Name: version.Name,
1564+
Job: job,
1565+
Readme: version.Readme,
1566+
CreatedBy: createdBy,
14741567
}
14751568
}
14761569

0 commit comments

Comments
 (0)