feat: add support for coder_git_auth data source (#6334)

* Add git auth providers schema

* Pipe git auth providers to the schema

* Add git auth providers to the API

* Add gitauth endpoint to query authenticated state

* Add endpoint to query git state

* Use BroadcastChannel to automatically authenticate with Git

* Add error validation for submitting the create workspace form

* Fix panic on template dry-run

* Add tests for the template version Git auth endpoint

* Show error if no gitauth is configured

* Add gitauth to cliui

* Fix unused method receiver

* Fix linting errors

* Fix dbauthz querier test

* Fix make gen

* Add JavaScript test for git auth

* Fix bad error message

* Fix provisionerd test race

See https://github.com/coder/coder/actions/runs/4277960646/jobs/7447232814

* Fix requested changes

* Add comment to CreateWorkspacePageView
This commit is contained in:
Kyle Carberry
2023-02-27 10:18:19 -06:00
committed by GitHub
parent 3d8b77d6f1
commit 7f226d4f90
64 changed files with 2788 additions and 861 deletions
+24 -2
View File
@@ -889,6 +889,28 @@ func (q *querier) UpdateTemplateVersionDescriptionByJobID(ctx context.Context, a
return q.db.UpdateTemplateVersionDescriptionByJobID(ctx, arg)
}
func (q *querier) UpdateTemplateVersionGitAuthProvidersByJobID(ctx context.Context, arg database.UpdateTemplateVersionGitAuthProvidersByJobIDParams) error {
// An actor is allowed to update the template version git auth providers if they are authorized to update the template.
tv, err := q.db.GetTemplateVersionByJobID(ctx, arg.JobID)
if err != nil {
return err
}
var obj rbac.Objecter
if !tv.TemplateID.Valid {
obj = rbac.ResourceTemplate.InOrg(tv.OrganizationID)
} else {
tpl, err := q.db.GetTemplateByID(ctx, tv.TemplateID.UUID)
if err != nil {
return err
}
obj = tpl
}
if err := q.authorizeContext(ctx, rbac.ActionUpdate, obj); err != nil {
return err
}
return q.db.UpdateTemplateVersionGitAuthProvidersByJobID(ctx, arg)
}
func (q *querier) GetTemplateGroupRoles(ctx context.Context, id uuid.UUID) ([]database.TemplateGroup, error) {
// An actor is authorized to read template group roles if they are authorized to read the template.
template, err := q.db.GetTemplateByID(ctx, id)
@@ -1103,11 +1125,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) {
+19 -3
View File
@@ -736,6 +736,18 @@ func (s *MethodTestSuite) TestTemplate() {
Readme: "foo",
}).Asserts(t1, rbac.ActionUpdate).Returns()
}))
s.Run("UpdateTemplateVersionGitAuthProvidersByJobID", s.Subtest(func(db database.Store, check *expects) {
jobID := uuid.New()
t1 := dbgen.Template(s.T(), db, database.Template{})
_ = dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{
TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true},
JobID: jobID,
})
check.Args(database.UpdateTemplateVersionGitAuthProvidersByJobIDParams{
JobID: jobID,
GitAuthProviders: []string{},
}).Asserts(t1, rbac.ActionUpdate).Returns()
}))
}
func (s *MethodTestSuite) TestUser() {
@@ -881,9 +893,13 @@ func (s *MethodTestSuite) TestUser() {
s.Run("UpdateGitAuthLink", s.Subtest(func(db database.Store, check *expects) {
link := dbgen.GitAuthLink(s.T(), db, database.GitAuthLink{})
check.Args(database.UpdateGitAuthLinkParams{
ProviderID: link.ProviderID,
UserID: link.UserID,
}).Asserts(link, rbac.ActionUpdate).Returns()
ProviderID: link.ProviderID,
UserID: link.UserID,
OAuthAccessToken: link.OAuthAccessToken,
OAuthRefreshToken: link.OAuthRefreshToken,
OAuthExpiry: link.OAuthExpiry,
UpdatedAt: link.UpdatedAt,
}).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{})
+25 -3
View File
@@ -3277,6 +3277,26 @@ func (q *fakeQuerier) UpdateTemplateVersionDescriptionByJobID(_ context.Context,
return sql.ErrNoRows
}
func (q *fakeQuerier) UpdateTemplateVersionGitAuthProvidersByJobID(_ context.Context, arg database.UpdateTemplateVersionGitAuthProvidersByJobIDParams) error {
if err := validateDatabaseType(arg); err != nil {
return err
}
q.mutex.Lock()
defer q.mutex.Unlock()
for index, templateVersion := range q.templateVersions {
if templateVersion.JobID != arg.JobID {
continue
}
templateVersion.GitAuthProviders = arg.GitAuthProviders
templateVersion.UpdatedAt = arg.UpdatedAt
q.templateVersions[index] = templateVersion
return nil
}
return sql.ErrNoRows
}
func (q *fakeQuerier) UpdateWorkspaceAgentConnectionByID(_ context.Context, arg database.UpdateWorkspaceAgentConnectionByIDParams) error {
if err := validateDatabaseType(arg); err != nil {
return err
@@ -4291,9 +4311,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()
@@ -4310,8 +4330,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) {
+4 -1
View File
@@ -417,9 +417,12 @@ CREATE TABLE template_versions (
name character varying(64) NOT NULL,
readme character varying(1048576) NOT NULL,
job_id uuid NOT NULL,
created_by uuid NOT NULL
created_by uuid NOT NULL,
git_auth_providers text[]
);
COMMENT ON COLUMN template_versions.git_auth_providers IS 'IDs of Git auth providers for a specific template version';
CREATE TABLE templates (
id uuid NOT NULL,
created_at timestamp with time zone NOT NULL,
@@ -0,0 +1,2 @@
ALTER TABLE template_versions
DROP COLUMN git_auth_providers;
@@ -0,0 +1,4 @@
ALTER TABLE template_versions
ADD COLUMN git_auth_providers text[];
COMMENT ON COLUMN template_versions.git_auth_providers IS 'IDs of Git auth providers for a specific template version';
+2
View File
@@ -1433,6 +1433,8 @@ type TemplateVersion struct {
Readme string `db:"readme" json:"readme"`
JobID uuid.UUID `db:"job_id" json:"job_id"`
CreatedBy uuid.UUID `db:"created_by" json:"created_by"`
// IDs of Git auth providers for a specific template version
GitAuthProviders []string `db:"git_auth_providers" json:"git_auth_providers"`
}
type TemplateVersionParameter struct {
+2 -1
View File
@@ -176,7 +176,7 @@ type sqlcQuerier interface {
ParameterValue(ctx context.Context, id uuid.UUID) (ParameterValue, error)
ParameterValues(ctx context.Context, arg ParameterValuesParams) ([]ParameterValue, error)
UpdateAPIKeyByID(ctx context.Context, arg UpdateAPIKeyByIDParams) error
UpdateGitAuthLink(ctx context.Context, arg UpdateGitAuthLinkParams) error
UpdateGitAuthLink(ctx context.Context, arg UpdateGitAuthLinkParams) (GitAuthLink, error)
UpdateGitSSHKey(ctx context.Context, arg UpdateGitSSHKeyParams) (GitSSHKey, error)
UpdateGroupByID(ctx context.Context, arg UpdateGroupByIDParams) (Group, error)
UpdateMemberRoles(ctx context.Context, arg UpdateMemberRolesParams) (OrganizationMember, error)
@@ -190,6 +190,7 @@ type sqlcQuerier interface {
UpdateTemplateMetaByID(ctx context.Context, arg UpdateTemplateMetaByIDParams) (Template, error)
UpdateTemplateVersionByID(ctx context.Context, arg UpdateTemplateVersionByIDParams) error
UpdateTemplateVersionDescriptionByJobID(ctx context.Context, arg UpdateTemplateVersionDescriptionByJobIDParams) error
UpdateTemplateVersionGitAuthProvidersByJobID(ctx context.Context, arg UpdateTemplateVersionGitAuthProvidersByJobIDParams) error
UpdateUserDeletedByID(ctx context.Context, arg UpdateUserDeletedByIDParams) error
UpdateUserHashedPassword(ctx context.Context, arg UpdateUserHashedPasswordParams) error
UpdateUserLastSeenAt(ctx context.Context, arg UpdateUserLastSeenAtParams) (User, error)
+52 -13
View File
@@ -880,13 +880,13 @@ func (q *sqlQuerier) InsertGitAuthLink(ctx context.Context, arg InsertGitAuthLin
return i, err
}
const updateGitAuthLink = `-- name: UpdateGitAuthLink :exec
const updateGitAuthLink = `-- 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 provider_id, user_id, created_at, updated_at, oauth_access_token, oauth_refresh_token, oauth_expiry
`
type UpdateGitAuthLinkParams struct {
@@ -898,8 +898,8 @@ type UpdateGitAuthLinkParams struct {
OAuthExpiry time.Time `db:"oauth_expiry" json:"oauth_expiry"`
}
func (q *sqlQuerier) UpdateGitAuthLink(ctx context.Context, arg UpdateGitAuthLinkParams) error {
_, err := q.db.ExecContext(ctx, updateGitAuthLink,
func (q *sqlQuerier) UpdateGitAuthLink(ctx context.Context, arg UpdateGitAuthLinkParams) (GitAuthLink, error) {
row := q.db.QueryRowContext(ctx, updateGitAuthLink,
arg.ProviderID,
arg.UserID,
arg.UpdatedAt,
@@ -907,7 +907,17 @@ func (q *sqlQuerier) UpdateGitAuthLink(ctx context.Context, arg UpdateGitAuthLin
arg.OAuthRefreshToken,
arg.OAuthExpiry,
)
return err
var i GitAuthLink
err := row.Scan(
&i.ProviderID,
&i.UserID,
&i.CreatedAt,
&i.UpdatedAt,
&i.OAuthAccessToken,
&i.OAuthRefreshToken,
&i.OAuthExpiry,
)
return i, err
}
const deleteGitSSHKey = `-- name: DeleteGitSSHKey :exec
@@ -3715,7 +3725,7 @@ func (q *sqlQuerier) InsertTemplateVersionParameter(ctx context.Context, arg Ins
const getPreviousTemplateVersion = `-- name: GetPreviousTemplateVersion :one
SELECT
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers
FROM
template_versions
WHERE
@@ -3749,13 +3759,14 @@ func (q *sqlQuerier) GetPreviousTemplateVersion(ctx context.Context, arg GetPrev
&i.Readme,
&i.JobID,
&i.CreatedBy,
pq.Array(&i.GitAuthProviders),
)
return i, err
}
const getTemplateVersionByID = `-- name: GetTemplateVersionByID :one
SELECT
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers
FROM
template_versions
WHERE
@@ -3775,13 +3786,14 @@ func (q *sqlQuerier) GetTemplateVersionByID(ctx context.Context, id uuid.UUID) (
&i.Readme,
&i.JobID,
&i.CreatedBy,
pq.Array(&i.GitAuthProviders),
)
return i, err
}
const getTemplateVersionByJobID = `-- name: GetTemplateVersionByJobID :one
SELECT
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers
FROM
template_versions
WHERE
@@ -3801,13 +3813,14 @@ func (q *sqlQuerier) GetTemplateVersionByJobID(ctx context.Context, jobID uuid.U
&i.Readme,
&i.JobID,
&i.CreatedBy,
pq.Array(&i.GitAuthProviders),
)
return i, err
}
const getTemplateVersionByTemplateIDAndName = `-- name: GetTemplateVersionByTemplateIDAndName :one
SELECT
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers
FROM
template_versions
WHERE
@@ -3833,13 +3846,14 @@ func (q *sqlQuerier) GetTemplateVersionByTemplateIDAndName(ctx context.Context,
&i.Readme,
&i.JobID,
&i.CreatedBy,
pq.Array(&i.GitAuthProviders),
)
return i, err
}
const getTemplateVersionsByIDs = `-- name: GetTemplateVersionsByIDs :many
SELECT
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers
FROM
template_versions
WHERE
@@ -3865,6 +3879,7 @@ func (q *sqlQuerier) GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UU
&i.Readme,
&i.JobID,
&i.CreatedBy,
pq.Array(&i.GitAuthProviders),
); err != nil {
return nil, err
}
@@ -3881,7 +3896,7 @@ func (q *sqlQuerier) GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UU
const getTemplateVersionsByTemplateID = `-- name: GetTemplateVersionsByTemplateID :many
SELECT
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers
FROM
template_versions
WHERE
@@ -3945,6 +3960,7 @@ func (q *sqlQuerier) GetTemplateVersionsByTemplateID(ctx context.Context, arg Ge
&i.Readme,
&i.JobID,
&i.CreatedBy,
pq.Array(&i.GitAuthProviders),
); err != nil {
return nil, err
}
@@ -3960,7 +3976,7 @@ func (q *sqlQuerier) GetTemplateVersionsByTemplateID(ctx context.Context, arg Ge
}
const getTemplateVersionsCreatedAfter = `-- name: GetTemplateVersionsCreatedAfter :many
SELECT id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by FROM template_versions WHERE created_at > $1
SELECT id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers FROM template_versions WHERE created_at > $1
`
func (q *sqlQuerier) GetTemplateVersionsCreatedAfter(ctx context.Context, createdAt time.Time) ([]TemplateVersion, error) {
@@ -3982,6 +3998,7 @@ func (q *sqlQuerier) GetTemplateVersionsCreatedAfter(ctx context.Context, create
&i.Readme,
&i.JobID,
&i.CreatedBy,
pq.Array(&i.GitAuthProviders),
); err != nil {
return nil, err
}
@@ -4010,7 +4027,7 @@ INSERT INTO
created_by
)
VALUES
($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by
($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers
`
type InsertTemplateVersionParams struct {
@@ -4048,6 +4065,7 @@ func (q *sqlQuerier) InsertTemplateVersion(ctx context.Context, arg InsertTempla
&i.Readme,
&i.JobID,
&i.CreatedBy,
pq.Array(&i.GitAuthProviders),
)
return i, err
}
@@ -4094,6 +4112,27 @@ func (q *sqlQuerier) UpdateTemplateVersionDescriptionByJobID(ctx context.Context
return err
}
const updateTemplateVersionGitAuthProvidersByJobID = `-- name: UpdateTemplateVersionGitAuthProvidersByJobID :exec
UPDATE
template_versions
SET
git_auth_providers = $2,
updated_at = $3
WHERE
job_id = $1
`
type UpdateTemplateVersionGitAuthProvidersByJobIDParams struct {
JobID uuid.UUID `db:"job_id" json:"job_id"`
GitAuthProviders []string `db:"git_auth_providers" json:"git_auth_providers"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
}
func (q *sqlQuerier) UpdateTemplateVersionGitAuthProvidersByJobID(ctx context.Context, arg UpdateTemplateVersionGitAuthProvidersByJobIDParams) error {
_, err := q.db.ExecContext(ctx, updateTemplateVersionGitAuthProvidersByJobID, arg.JobID, pq.Array(arg.GitAuthProviders), arg.UpdatedAt)
return err
}
const getTemplateVersionVariables = `-- name: GetTemplateVersionVariables :many
SELECT template_version_id, name, description, type, value, default_value, required, sensitive FROM template_version_variables WHERE template_version_id = $1
`
+2 -2
View File
@@ -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 *;
@@ -102,6 +102,15 @@ SET
WHERE
job_id = $1;
-- name: UpdateTemplateVersionGitAuthProvidersByJobID :exec
UPDATE
template_versions
SET
git_auth_providers = $2,
updated_at = $3
WHERE
job_id = $1;
-- name: GetPreviousTemplateVersion :one
SELECT
*