Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add gitauth endpoint to query authenticated state
  • Loading branch information
kylecarbs committed Feb 23, 2023
commit 604cf5b83e1380aaff6d4bb4ce5c839a0f26c07d
7 changes: 7 additions & 0 deletions coderd/coderd.go
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@ func New(options *Options) *API {
r.Get("/schema", api.templateVersionSchema)
r.Get("/parameters", api.templateVersionParameters)
r.Get("/rich-parameters", api.templateVersionRichParameters)
r.Get("/gitauth", api.templateVersionGitAuth)
r.Get("/variables", api.templateVersionVariables)
r.Get("/resources", api.templateVersionResources)
r.Get("/logs", api.templateVersionLogs)
Expand Down Expand Up @@ -795,12 +796,18 @@ func (api *API) CreateInMemoryProvisionerDaemon(ctx context.Context, debounce ti
}

mux := drpcmux.New()

gitAuthProviders := make([]string, 0, len(api.GitAuthConfigs))
for _, cfg := range api.GitAuthConfigs {
gitAuthProviders = append(gitAuthProviders, cfg.ID)
}
err = proto.DRPCRegisterProvisionerDaemon(mux, &provisionerdserver.Server{
AccessURL: api.AccessURL,
ID: daemon.ID,
Database: api.Database,
Pubsub: api.Pubsub,
Provisioners: daemon.Provisioners,
GitAuthProviders: gitAuthProviders,
Telemetry: api.Telemetry,
Tags: tags,
QuotaCommitter: &api.QuotaCommitter,
Expand Down
4 changes: 2 additions & 2 deletions coderd/database/dbauthz/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -1121,11 +1121,11 @@ func (q *querier) InsertGitAuthLink(ctx context.Context, arg database.InsertGitA
return insert(q.log, q.auth, rbac.ResourceUserData.WithOwner(arg.UserID.String()).WithID(arg.UserID), q.db.InsertGitAuthLink)(ctx, arg)
}

func (q *querier) UpdateGitAuthLink(ctx context.Context, arg database.UpdateGitAuthLinkParams) error {
func (q *querier) UpdateGitAuthLink(ctx context.Context, arg database.UpdateGitAuthLinkParams) (database.GitAuthLink, error) {
fetch := func(ctx context.Context, arg database.UpdateGitAuthLinkParams) (database.GitAuthLink, error) {
return q.db.GetGitAuthLink(ctx, database.GetGitAuthLinkParams{UserID: arg.UserID, ProviderID: arg.ProviderID})
}
return update(q.log, q.auth, fetch, q.db.UpdateGitAuthLink)(ctx, arg)
return updateWithReturn(q.log, q.auth, fetch, q.db.UpdateGitAuthLink)(ctx, arg)
}

func (q *querier) UpdateUserLink(ctx context.Context, arg database.UpdateUserLinkParams) (database.UserLink, error) {
Expand Down
2 changes: 1 addition & 1 deletion coderd/database/dbauthz/querier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@ func (s *MethodTestSuite) TestUser() {
check.Args(database.UpdateGitAuthLinkParams{
ProviderID: link.ProviderID,
UserID: link.UserID,
}).Asserts(link, rbac.ActionUpdate).Returns()
}).Asserts(link, rbac.ActionUpdate).Returns(link)
}))
s.Run("UpdateUserLink", s.Subtest(func(db database.Store, check *expects) {
link := dbgen.UserLink(s.T(), db, database.UserLink{})
Expand Down
8 changes: 5 additions & 3 deletions coderd/database/dbfake/databasefake.go
Original file line number Diff line number Diff line change
Expand Up @@ -4294,9 +4294,9 @@ func (q *fakeQuerier) InsertGitAuthLink(_ context.Context, arg database.InsertGi
return gitAuthLink, nil
}

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

q.mutex.Lock()
Expand All @@ -4313,8 +4313,10 @@ func (q *fakeQuerier) UpdateGitAuthLink(_ context.Context, arg database.UpdateGi
gitAuthLink.OAuthRefreshToken = arg.OAuthRefreshToken
gitAuthLink.OAuthExpiry = arg.OAuthExpiry
q.gitAuthLinks[index] = gitAuthLink

return gitAuthLink, nil
}
return nil
return database.GitAuthLink{}, sql.ErrNoRows
}

func (q *fakeQuerier) GetQuotaAllowanceForUser(_ context.Context, userID uuid.UUID) (int64, error) {
Expand Down
2 changes: 1 addition & 1 deletion coderd/database/querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 15 additions & 5 deletions coderd/database/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions coderd/database/queries/gitauth.sql
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ INSERT INTO git_auth_links (
$7
) RETURNING *;

-- name: UpdateGitAuthLink :exec
-- name: UpdateGitAuthLink :one
UPDATE git_auth_links SET
updated_at = $3,
oauth_access_token = $4,
oauth_refresh_token = $5,
oauth_expiry = $6
WHERE provider_id = $1 AND user_id = $2;
WHERE provider_id = $1 AND user_id = $2 RETURNING *;
9 changes: 8 additions & 1 deletion coderd/provisionerdserver/provisionerdserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -812,9 +812,15 @@ func (server *Server) CompleteJob(ctx context.Context, completed *proto.Complete
}
}

var completedError sql.NullString

for _, gitAuthProvider := range jobType.TemplateImport.GitAuthProviders {
if !slice.Contains(server.GitAuthProviders, gitAuthProvider) {
return nil, xerrors.Errorf("git auth provider %q is not configured", gitAuthProvider)
completedError = sql.NullString{
String: fmt.Sprintf("git auth provider %q is not configured", gitAuthProvider),
Valid: true,
}
break
}
}

Expand All @@ -834,6 +840,7 @@ func (server *Server) CompleteJob(ctx context.Context, completed *proto.Complete
Time: database.Now(),
Valid: true,
},
Error: completedError,
})
if err != nil {
return nil, xerrors.Errorf("update provisioner job: %w", err)
Expand Down
14 changes: 9 additions & 5 deletions coderd/provisionerdserver/provisionerdserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,7 @@ func TestCompleteJob(t *testing.T) {
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
})
require.NoError(t, err)
completeJob := func() error {
completeJob := func() {
_, err = srv.CompleteJob(ctx, &proto.CompletedJob{
JobId: job.ID.String(),
Type: &proto.CompletedJob_TemplateImport_{
Expand All @@ -770,13 +770,17 @@ func TestCompleteJob(t *testing.T) {
},
},
})
return err
require.NoError(t, err)
}
err = completeJob()
require.ErrorContains(t, err, `git auth provider "github" is not configured`)
completeJob()
job, err = srv.Database.GetProvisionerJobByID(ctx, job.ID)
require.NoError(t, err)
require.Contains(t, job.Error.String, `git auth provider "github" is not configured`)
srv.GitAuthProviders = []string{"github"}
err = completeJob()
completeJob()
job, err = srv.Database.GetProvisionerJobByID(ctx, job.ID)
require.NoError(t, err)
require.False(t, job.Error.Valid)
})
t.Run("WorkspaceBuild", func(t *testing.T) {
t.Parallel()
Expand Down
113 changes: 103 additions & 10 deletions coderd/templateversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

"github.com/coder/coder/coderd/audit"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/gitauth"
"github.com/coder/coder/coderd/httpapi"
"github.com/coder/coder/coderd/httpmw"
"github.com/coder/coder/coderd/parameter"
Expand Down Expand Up @@ -243,6 +244,99 @@ 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
// @Security CoderSessionToken
// @Produce json
// @Tags Templates
// @Param templateversion path string true "Template version ID" format(uuid)
// @Success 200 {array} codersdk.GitAuth
// @Router /templateversions/{templateversion}/gitauth [get]
func (api *API) templateVersionGitAuth(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var (
apiKey = httpmw.APIKey(r)
templateVersion = httpmw.TemplateVersionParam(r)
template = httpmw.TemplateParam(r)
)

if !api.Authorize(r, rbac.ActionRead, templateVersion.RBACObject(template)) {
httpapi.ResourceNotFound(rw)
return
}

rawProviders := templateVersion.GitAuthProviders
providers := make([]codersdk.GitAuth, 0)
for _, rawProvider := range rawProviders {
var config *gitauth.Config
for _, provider := range api.GitAuthConfigs {
if provider.ID == rawProvider {
config = provider
break
}
}
if config == nil {
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
Message: fmt.Sprintf("The template version references a Git auth provider %q that no longer exists.", rawProvider),
Detail: "You'll need to update the template version to use a different provider.",
})
return
}

// This is the URL that will redirect the user with a state token.
redirectURL, err := api.AccessURL.Parse(fmt.Sprintf("/gitauth/%s", config.ID))
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Failed to parse access URL.",
Detail: err.Error(),
})
return
}

provider := codersdk.GitAuth{
ID: config.ID,
Type: config.Type,
AuthenticateURL: redirectURL.String(),
}

authLink, err := api.Database.GetGitAuthLink(ctx, database.GetGitAuthLinkParams{
ProviderID: config.ID,
UserID: apiKey.UserID,
})
// If there isn't an auth link, then the user just isn't authenticated.
if errors.Is(err, sql.ErrNoRows) {
providers = append(providers, provider)
continue
}
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching Git auth link.",
Detail: err.Error(),
})
return
}

_, updated, err := refreshGitToken(ctx, api.Database, apiKey.UserID, config, authLink)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Failed to refresh git auth token.",
Detail: err.Error(),
})
return
}
// If the token couldn't be validated, then we assume the user isn't
// authenticated and return early.
if !updated {
providers = append(providers, provider)
continue
}
provider.Authenticated = true
providers = append(providers, provider)
}

httpapi.Write(ctx, rw, http.StatusOK, providers)
}

// @Summary Get template variables by template version
// @ID get-template-variables-by-template-version
// @Security CoderSessionToken
Expand Down Expand Up @@ -1461,16 +1555,15 @@ func convertTemplateVersion(version database.TemplateVersion, job codersdk.Provi
}

return codersdk.TemplateVersion{
ID: version.ID,
TemplateID: &version.TemplateID.UUID,
OrganizationID: version.OrganizationID,
CreatedAt: version.CreatedAt,
UpdatedAt: version.UpdatedAt,
GitAuthProviders: version.GitAuthProviders,
Name: version.Name,
Job: job,
Readme: version.Readme,
CreatedBy: createdBy,
ID: version.ID,
TemplateID: &version.TemplateID.UUID,
OrganizationID: version.OrganizationID,
CreatedAt: version.CreatedAt,
UpdatedAt: version.UpdatedAt,
Name: version.Name,
Job: job,
Readme: version.Readme,
CreatedBy: createdBy,
}
}

Expand Down
19 changes: 19 additions & 0 deletions coderd/templateversions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,25 @@ func TestTemplateVersionParameters(t *testing.T) {
})
}

func TestTemplateVersionsGitAuth(t *testing.T) {
t.Parallel()
t.Run("WithoutAny", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)

ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()

_, err := client.TemplateVersionGitAuth(ctx, version.ID)
require.NoError(t, err)
})
// t.Run("", func(t *testing.T) {

// })
}

func TestTemplateVersionResources(t *testing.T) {
t.Parallel()
t.Run("ListRunning", func(t *testing.T) {
Expand Down
Loading