feat: add template setting to require active template version (#10277)

This commit is contained in:
Jon Ayers
2023-10-18 17:07:21 -05:00
committed by GitHub
parent 1ad998ee3a
commit 997493d4ae
47 changed files with 802 additions and 70 deletions

View File

@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"sync/atomic"
"time"
"github.com/google/uuid"
@ -101,9 +102,10 @@ type querier struct {
db database.Store
auth rbac.Authorizer
log slog.Logger
acs *atomic.Pointer[AccessControlStore]
}
func New(db database.Store, authorizer rbac.Authorizer, logger slog.Logger) database.Store {
func New(db database.Store, authorizer rbac.Authorizer, logger slog.Logger, acs *atomic.Pointer[AccessControlStore]) database.Store {
// If the underlying db store is already a querier, return it.
// Do not double wrap.
if slices.Contains(db.Wrappers(), wrapname) {
@ -113,6 +115,7 @@ func New(db database.Store, authorizer rbac.Authorizer, logger slog.Logger) data
db: db,
auth: authorizer,
log: logger,
acs: acs,
}
}
@ -507,7 +510,7 @@ func (q *querier) Ping(ctx context.Context) (time.Duration, error) {
func (q *querier) InTx(function func(querier database.Store) error, txOpts *sql.TxOptions) error {
return q.db.InTx(func(tx database.Store) error {
// Wrap the transaction store in a querier.
wrapped := New(tx, q.auth, q.log)
wrapped := New(tx, q.auth, q.log, q.acs)
return function(wrapped)
}, txOpts)
}
@ -2200,7 +2203,7 @@ func (q *querier) InsertWorkspaceAppStats(ctx context.Context, arg database.Inse
func (q *querier) InsertWorkspaceBuild(ctx context.Context, arg database.InsertWorkspaceBuildParams) error {
w, err := q.db.GetWorkspaceByID(ctx, arg.WorkspaceID)
if err != nil {
return err
return xerrors.Errorf("get workspace by id: %w", err)
}
var action rbac.Action = rbac.ActionUpdate
@ -2209,7 +2212,28 @@ func (q *querier) InsertWorkspaceBuild(ctx context.Context, arg database.InsertW
}
if err = q.authorizeContext(ctx, action, w.WorkspaceBuildRBAC(arg.Transition)); err != nil {
return err
return xerrors.Errorf("authorize context: %w", err)
}
// If we're starting a workspace we need to check the template.
if arg.Transition == database.WorkspaceTransitionStart {
t, err := q.db.GetTemplateByID(ctx, w.TemplateID)
if err != nil {
return xerrors.Errorf("get template by id: %w", err)
}
accessControl := (*q.acs.Load()).GetTemplateAccessControl(t)
// If the template requires the active version we need to check if
// the user is a template admin. If they aren't and are attempting
// to use a non-active version then we must fail the request.
if accessControl.RequireActiveVersion {
if arg.TemplateVersionID != t.ActiveVersionID {
if err = q.authorizeContext(ctx, rbac.ActionUpdate, t); err != nil {
return xerrors.Errorf("cannot use non-active version: %w", err)
}
}
}
}
return q.db.InsertWorkspaceBuild(ctx, arg)
@ -2442,6 +2466,13 @@ func (q *querier) UpdateTemplateACLByID(ctx context.Context, arg database.Update
return fetchAndExec(q.log, q.auth, rbac.ActionCreate, fetch, q.db.UpdateTemplateACLByID)(ctx, arg)
}
func (q *querier) UpdateTemplateAccessControlByID(ctx context.Context, arg database.UpdateTemplateAccessControlByIDParams) error {
fetch := func(ctx context.Context, arg database.UpdateTemplateAccessControlByIDParams) (database.Template, error) {
return q.db.GetTemplateByID(ctx, arg.ID)
}
return update(q.log, q.auth, fetch, q.db.UpdateTemplateAccessControlByID)(ctx, arg)
}
func (q *querier) UpdateTemplateActiveVersionByID(ctx context.Context, arg database.UpdateTemplateActiveVersionByIDParams) error {
fetch := func(ctx context.Context, arg database.UpdateTemplateActiveVersionByIDParams) (database.Template, error) {
return q.db.GetTemplateByID(ctx, arg.ID)