diff --git a/cli/server/config.go b/cli/server/config.go index 414ebd2a9..b1dea701f 100644 --- a/cli/server/config.go +++ b/cli/server/config.go @@ -90,10 +90,8 @@ func getSanitizedMachineName() (string, error) { // ProvideDatabaseConfig loads the database config from the main config. func ProvideDatabaseConfig(config *types.Config) database.Config { return database.Config{ - Driver: config.Database.Driver, - Datasource: config.Database.Datasource, - Secret: config.Database.Secret, - EncryptMixedContent: config.Database.EncryptMixedContent, + Driver: config.Database.Driver, + Datasource: config.Database.Datasource, } } diff --git a/cmd/gitness/wire.go b/cmd/gitness/wire.go index f610c1a4d..ed157dbc2 100644 --- a/cmd/gitness/wire.go +++ b/cmd/gitness/wire.go @@ -11,6 +11,7 @@ import ( "context" cliserver "github.com/harness/gitness/cli/server" + "github.com/harness/gitness/encrypt" "github.com/harness/gitness/events" "github.com/harness/gitness/gitrpc" gitrpcserver "github.com/harness/gitness/gitrpc/server" @@ -82,6 +83,7 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e gitrpc.WireSet, store.WireSet, check.WireSet, + encrypt.WireSet, cliserver.ProvideEventsConfig, events.WireSet, cliserver.ProvideWebhookConfig, diff --git a/cmd/gitness/wire_gen.go b/cmd/gitness/wire_gen.go index a9d129906..4329e3130 100644 --- a/cmd/gitness/wire_gen.go +++ b/cmd/gitness/wire_gen.go @@ -10,6 +10,7 @@ import ( "context" "github.com/harness/gitness/cli/server" + "github.com/harness/gitness/encrypt" "github.com/harness/gitness/events" "github.com/harness/gitness/gitrpc" server3 "github.com/harness/gitness/gitrpc/server" @@ -94,7 +95,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro secretStore := database.ProvideSecretStore(db) spaceController := space.ProvideController(db, provider, pathUID, authorizer, pathStore, pipelineStore, secretStore, spaceStore, repoStore, principalStore, repoController, membershipStore) pipelineController := pipeline.ProvideController(db, pathUID, pathStore, repoStore, authorizer, pipelineStore, spaceStore) - encrypter, err := database.ProvideEncryptor(databaseConfig) + encrypter, err := encrypt.ProvideEncrypter(config) if err != nil { return nil, err } diff --git a/encrypt/aesgcm.go b/encrypt/aesgcm.go index a7340d462..4a01fbba2 100644 --- a/encrypt/aesgcm.go +++ b/encrypt/aesgcm.go @@ -5,6 +5,7 @@ package encrypt import ( + "crypto/aes" "crypto/cipher" "crypto/rand" "errors" @@ -68,3 +69,16 @@ func (e *Aesgcm) Decrypt(ciphertext []byte) (string, error) { } return string(plaintext), err } + +// New provides a new aesgcm encrypter +func New(key string, compat bool) (Encrypter, error) { + if len(key) != 32 { + return nil, errKeySize + } + b := []byte(key) + block, err := aes.NewCipher(b) + if err != nil { + return nil, err + } + return &Aesgcm{block: block, Compat: compat}, nil +} diff --git a/encrypt/encrypt.go b/encrypt/encrypt.go index 403c866d5..adfb42454 100644 --- a/encrypt/encrypt.go +++ b/encrypt/encrypt.go @@ -5,33 +5,16 @@ package encrypt import ( - "crypto/aes" "errors" ) // indicates key size is too small. var errKeySize = errors.New("encryption key must be 32 bytes") -// Encrypter provides database field encryption and decryption. +// Encrypter provides field encryption and decryption. // Encrypted values are currently limited to strings, which is // reflected in the interface design. type Encrypter interface { Encrypt(plaintext string) ([]byte, error) Decrypt(ciphertext []byte) (string, error) } - -// New provides a new database field encrypter. -func New(key string) (Encrypter, error) { - if key == "" { - return &none{}, nil - } - if len(key) != 32 { - return nil, errKeySize - } - b := []byte(key) - block, err := aes.NewCipher(b) - if err != nil { - return nil, err - } - return &Aesgcm{block: block}, nil -} diff --git a/encrypt/wire.go b/encrypt/wire.go new file mode 100644 index 000000000..61888a2e1 --- /dev/null +++ b/encrypt/wire.go @@ -0,0 +1,19 @@ +package encrypt + +import ( + "github.com/harness/gitness/types" + + "github.com/google/wire" +) + +// WireSet provides a wire set for this package. +var WireSet = wire.NewSet( + ProvideEncrypter, +) + +func ProvideEncrypter(config *types.Config) (Encrypter, error) { + if config.Encrypter.Secret == "" { + return &none{}, nil + } + return New(config.Encrypter.Secret, config.Encrypter.EncryptMixedContent) +} diff --git a/internal/api/controller/execution/list.go b/internal/api/controller/execution/list.go index e0a6d6587..a5ba72f6b 100644 --- a/internal/api/controller/execution/list.go +++ b/internal/api/controller/execution/list.go @@ -39,18 +39,17 @@ func (c *Controller) List( var executions []*types.Execution err = dbtx.New(c.db).WithTx(ctx, func(ctx context.Context) (err error) { - var dbErr error - count, dbErr = c.executionStore.Count(ctx, pipeline.ID) - if dbErr != nil { + count, err = c.executionStore.Count(ctx, pipeline.ID) + if err != nil { return fmt.Errorf("failed to count child executions: %w", err) } - executions, dbErr = c.executionStore.List(ctx, pipeline.ID, pagination) - if dbErr != nil { + executions, err = c.executionStore.List(ctx, pipeline.ID, pagination) + if err != nil { return fmt.Errorf("failed to list child executions: %w", err) } - return dbErr + return }, dbtx.TxDefaultReadOnly) if err != nil { return executions, count, fmt.Errorf("failed to fetch list: %w", err) diff --git a/internal/api/controller/secret/create.go b/internal/api/controller/secret/create.go index 63b4ee881..18b1f6288 100644 --- a/internal/api/controller/secret/create.go +++ b/internal/api/controller/secret/create.go @@ -15,7 +15,6 @@ import ( apiauth "github.com/harness/gitness/internal/api/auth" "github.com/harness/gitness/internal/api/usererror" "github.com/harness/gitness/internal/auth" - "github.com/harness/gitness/store/database/dbtx" "github.com/harness/gitness/types" "github.com/harness/gitness/types/check" "github.com/harness/gitness/types/enum" @@ -50,33 +49,24 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, in *Crea } var secret *types.Secret - err = dbtx.New(c.db).WithTx(ctx, func(ctx context.Context) error { - // lock parent space path to ensure it doesn't get updated while we setup new pipeline - _, err := c.pathStore.FindPrimaryWithLock(ctx, enum.PathTargetTypeSpace, parentSpace.ID) - if err != nil { - return usererror.BadRequest("Parent not found") - } - - now := time.Now().UnixMilli() - secret = &types.Secret{ - Description: in.Description, - Data: in.Data, - SpaceID: parentSpace.ID, - UID: in.UID, - Created: now, - Updated: now, - Version: 0, - } - secret, err = enc(c.encrypter, secret) - if err != nil { - return fmt.Errorf("could not encrypt secret: %w", err) - } - err = c.secretStore.Create(ctx, secret) - if err != nil { - return fmt.Errorf("secret creation failed: %w", err) - } - return nil - }) + now := time.Now().UnixMilli() + secret = &types.Secret{ + Description: in.Description, + Data: in.Data, + SpaceID: parentSpace.ID, + UID: in.UID, + Created: now, + Updated: now, + Version: 0, + } + secret, err = enc(c.encrypter, secret) + if err != nil { + return nil, fmt.Errorf("could not encrypt secret: %w", err) + } + err = c.secretStore.Create(ctx, secret) + if err != nil { + return nil, fmt.Errorf("secret creation failed: %w", err) + } if err != nil { return nil, err } diff --git a/internal/api/controller/secret/update.go b/internal/api/controller/secret/update.go index 2ec2de78b..c3be74121 100644 --- a/internal/api/controller/secret/update.go +++ b/internal/api/controller/secret/update.go @@ -50,7 +50,7 @@ func (c *Controller) Update( if in.Data != "" { data, err := c.encrypter.Encrypt(original.Data) if err != nil { - return err + return fmt.Errorf("could not encrypt secret: %w", err) } original.Data = string(data) } diff --git a/internal/api/controller/space/list_pipelines.go b/internal/api/controller/space/list_pipelines.go index e80bc3586..87d999bb4 100644 --- a/internal/api/controller/space/list_pipelines.go +++ b/internal/api/controller/space/list_pipelines.go @@ -19,14 +19,14 @@ func (c *Controller) ListPipelines( ctx context.Context, session *auth.Session, spaceRef string, - pagination types.Pagination, + filter types.ListQueryFilter, ) ([]*types.Pipeline, int64, error) { space, err := c.spaceStore.FindByRef(ctx, spaceRef) if err != nil { return nil, 0, fmt.Errorf("failed to find parent space: %w", err) } - err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceView, true) + err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionPipelineView, false) if err != nil { return nil, 0, fmt.Errorf("could not authorize: %w", err) } @@ -35,16 +35,14 @@ func (c *Controller) ListPipelines( var pipelines []*types.Pipeline err = dbtx.New(c.db).WithTx(ctx, func(ctx context.Context) (err error) { - count, err = c.pipelineStore.Count(ctx, space.ID, pagination) + count, err = c.pipelineStore.Count(ctx, space.ID, filter) if err != nil { - err = fmt.Errorf("failed to count child executions: %w", err) - return + return fmt.Errorf("failed to count child executions: %w", err) } - pipelines, err = c.pipelineStore.List(ctx, space.ID, pagination) + pipelines, err = c.pipelineStore.List(ctx, space.ID, filter) if err != nil { - err = fmt.Errorf("failed to count child executions: %w", err) - return + return fmt.Errorf("failed to count child executions: %w", err) } return }, dbtx.TxDefaultReadOnly) diff --git a/internal/api/controller/space/list_secrets.go b/internal/api/controller/space/list_secrets.go index 7db2fda4f..1c091d639 100644 --- a/internal/api/controller/space/list_secrets.go +++ b/internal/api/controller/space/list_secrets.go @@ -19,14 +19,14 @@ func (c *Controller) ListSecrets( ctx context.Context, session *auth.Session, spaceRef string, - pagination types.Pagination, + filter types.ListQueryFilter, ) ([]*types.Secret, int64, error) { space, err := c.spaceStore.FindByRef(ctx, spaceRef) if err != nil { return nil, 0, fmt.Errorf("failed to find parent space: %w", err) } - err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceView, true) + err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSecretView, false) if err != nil { return nil, 0, fmt.Errorf("could not authorize: %w", err) } @@ -35,16 +35,14 @@ func (c *Controller) ListSecrets( var secrets []*types.Secret err = dbtx.New(c.db).WithTx(ctx, func(ctx context.Context) (err error) { - count, err = c.secretStore.Count(ctx, space.ID, pagination) + count, err = c.secretStore.Count(ctx, space.ID, filter) if err != nil { - err = fmt.Errorf("failed to count child executions: %w", err) - return + return fmt.Errorf("failed to count child executions: %w", err) } - secrets, err = c.secretStore.List(ctx, space.ID, pagination) + secrets, err = c.secretStore.List(ctx, space.ID, filter) if err != nil { - err = fmt.Errorf("failed to list child executions: %w", err) - return + return fmt.Errorf("failed to list child executions: %w", err) } return }, dbtx.TxDefaultReadOnly) diff --git a/internal/api/handler/space/list_pipelines.go b/internal/api/handler/space/list_pipelines.go index 764145ac4..30aba9b4b 100644 --- a/internal/api/handler/space/list_pipelines.go +++ b/internal/api/handler/space/list_pipelines.go @@ -22,14 +22,14 @@ func HandleListPipelines(spaceCtrl *space.Controller) http.HandlerFunc { return } - pagination := request.ParsePaginationFromRequest(r) - repos, totalCount, err := spaceCtrl.ListPipelines(ctx, session, spaceRef, pagination) + filter := request.ParseListQueryFilterFromRequest(r) + repos, totalCount, err := spaceCtrl.ListPipelines(ctx, session, spaceRef, filter) if err != nil { render.TranslatedUserError(w, err) return } - render.Pagination(r, w, pagination.Page, pagination.Page, int(totalCount)) + render.Pagination(r, w, filter.Page, filter.Size, int(totalCount)) render.JSON(w, http.StatusOK, repos) } } diff --git a/internal/api/handler/space/list_secrets.go b/internal/api/handler/space/list_secrets.go index ab76ee74d..40c0002aa 100644 --- a/internal/api/handler/space/list_secrets.go +++ b/internal/api/handler/space/list_secrets.go @@ -23,8 +23,8 @@ func HandleListSecrets(spaceCtrl *space.Controller) http.HandlerFunc { return } - pagination := request.ParsePaginationFromRequest(r) - ret, totalCount, err := spaceCtrl.ListSecrets(ctx, session, spaceRef, pagination) + filter := request.ParseListQueryFilterFromRequest(r) + ret, totalCount, err := spaceCtrl.ListSecrets(ctx, session, spaceRef, filter) if err != nil { render.TranslatedUserError(w, err) return @@ -36,7 +36,7 @@ func HandleListSecrets(spaceCtrl *space.Controller) http.HandlerFunc { secrets = append(secrets, *s.CopyWithoutData()) } - render.Pagination(r, w, pagination.Page, pagination.Size, int(totalCount)) + render.Pagination(r, w, filter.Page, filter.Size, int(totalCount)) render.JSON(w, http.StatusOK, secrets) } } diff --git a/internal/api/request/pipeline.go b/internal/api/request/pipeline.go index d6259ae32..8806102a3 100644 --- a/internal/api/request/pipeline.go +++ b/internal/api/request/pipeline.go @@ -10,13 +10,12 @@ import ( ) const ( - PipelinePathRef = "pipeline_ref" - PipelineUID = "pipeline_uid" - ExecutionNumber = "execution_number" + PathParamPipelineRef = "pipeline_ref" + PathParamExecutionNumber = "execution_number" ) func GetPipelineRefFromPath(r *http.Request) (string, error) { - rawRef, err := PathParamOrError(r, PipelinePathRef) + rawRef, err := PathParamOrError(r, PathParamPipelineRef) if err != nil { return "", err } @@ -26,5 +25,5 @@ func GetPipelineRefFromPath(r *http.Request) (string, error) { } func GetExecutionNumberFromPath(r *http.Request) (int64, error) { - return PathParamAsPositiveInt64(r, ExecutionNumber) + return PathParamAsPositiveInt64(r, PathParamExecutionNumber) } diff --git a/internal/api/request/secret.go b/internal/api/request/secret.go index 517ff642d..d039a6f5b 100644 --- a/internal/api/request/secret.go +++ b/internal/api/request/secret.go @@ -10,11 +10,11 @@ import ( ) const ( - SecretRef = "secret_ref" + PathParamSecretRef = "secret_ref" ) func GetSecretRefFromPath(r *http.Request) (string, error) { - rawRef, err := PathParamOrError(r, SecretRef) + rawRef, err := PathParamOrError(r, PathParamSecretRef) if err != nil { return "", err } diff --git a/internal/api/request/util.go b/internal/api/request/util.go index 05fc3c81a..cc0be0a28 100644 --- a/internal/api/request/util.go +++ b/internal/api/request/util.go @@ -205,13 +205,18 @@ func ParseSort(r *http.Request) string { return r.URL.Query().Get(QueryParamSort) } -// ParsePaginationFromRequest extracts the pagination info from the url. +// ParsePaginationFromRequest parses pagination related info from the url. func ParsePaginationFromRequest(r *http.Request) types.Pagination { return types.Pagination{ - Page: ParsePage(r), - Size: ParseLimit(r), - Query: ParseQuery(r), - Sort: ParseSort(r), - Order: ParseOrder(r), + Page: ParsePage(r), + Size: ParseLimit(r), + } +} + +// ParseListQueryFilterFromRequest parses pagination and query related info from the url. +func ParseListQueryFilterFromRequest(r *http.Request) types.ListQueryFilter { + return types.ListQueryFilter{ + Query: ParseQuery(r), + Pagination: ParsePaginationFromRequest(r), } } diff --git a/internal/router/api.go b/internal/router/api.go index da2d3c949..5fdaf09be 100644 --- a/internal/router/api.go +++ b/internal/router/api.go @@ -286,7 +286,7 @@ func setupPipelines(r chi.Router, pipelineCtrl *pipeline.Controller, executionCt r.Route("/pipelines", func(r chi.Router) { // Create takes path and parentId via body, not uri r.Post("/", handlerpipeline.HandleCreate(pipelineCtrl)) - r.Route(fmt.Sprintf("/{%s}", request.PipelinePathRef), func(r chi.Router) { + r.Route(fmt.Sprintf("/{%s}", request.PathParamPipelineRef), func(r chi.Router) { r.Get("/", handlerpipeline.HandleFind(pipelineCtrl)) r.Patch("/", handlerpipeline.HandleUpdate(pipelineCtrl)) r.Delete("/", handlerpipeline.HandleDelete(pipelineCtrl)) @@ -299,7 +299,7 @@ func setupSecrets(r chi.Router, secretCtrl *secret.Controller) { r.Route("/secrets", func(r chi.Router) { // Create takes path and parentId via body, not uri r.Post("/", handlersecret.HandleCreate(secretCtrl)) - r.Route(fmt.Sprintf("/{%s}", request.SecretRef), func(r chi.Router) { + r.Route(fmt.Sprintf("/{%s}", request.PathParamSecretRef), func(r chi.Router) { r.Get("/", handlersecret.HandleFind(secretCtrl)) r.Patch("/", handlersecret.HandleUpdate(secretCtrl)) r.Delete("/", handlersecret.HandleDelete(secretCtrl)) @@ -311,7 +311,7 @@ func setupExecutions(r chi.Router, pipelineCtrl *pipeline.Controller, executionC r.Route("/executions", func(r chi.Router) { r.Get("/", handlerexecution.HandleList(executionCtrl)) r.Post("/", handlerexecution.HandleCreate(executionCtrl)) - r.Route(fmt.Sprintf("/{%s}", request.ExecutionNumber), func(r chi.Router) { + r.Route(fmt.Sprintf("/{%s}", request.PathParamExecutionNumber), func(r chi.Router) { r.Get("/", handlerexecution.HandleFind(executionCtrl)) r.Patch("/", handlerexecution.HandleUpdate(executionCtrl)) r.Delete("/", handlerexecution.HandleDelete(executionCtrl)) diff --git a/internal/store/database.go b/internal/store/database.go index 28d9037d7..f716f10ab 100644 --- a/internal/store/database.go +++ b/internal/store/database.go @@ -453,7 +453,7 @@ type ( Update(ctx context.Context, pipeline *types.Pipeline) error // List lists the pipelines present in a parent space ID in the datastore. - List(ctx context.Context, spaceID int64, pagination types.Pagination) ([]*types.Pipeline, error) + List(ctx context.Context, spaceID int64, pagination types.ListQueryFilter) ([]*types.Pipeline, error) // UpdateOptLock updates the pipeline using the optimistic locking mechanism. UpdateOptLock(ctx context.Context, pipeline *types.Pipeline, @@ -463,7 +463,7 @@ type ( Delete(ctx context.Context, id int64) error // Count the number of pipelines in a space matching the given filter. - Count(ctx context.Context, spaceID int64, filter types.Pagination) (int64, error) + Count(ctx context.Context, spaceID int64, filter types.ListQueryFilter) (int64, error) // DeleteByUID deletes a pipeline with a given UID in a space DeleteByUID(ctx context.Context, spaceID int64, uid string) error @@ -483,7 +483,7 @@ type ( Create(ctx context.Context, secret *types.Secret) error // Count the number of secrets in a space matching the given filter. - Count(ctx context.Context, spaceID int64, pagination types.Pagination) (int64, error) + Count(ctx context.Context, spaceID int64, pagination types.ListQueryFilter) (int64, error) // UpdateOptLock updates the secret using the optimistic locking mechanism. UpdateOptLock(ctx context.Context, secret *types.Secret, @@ -499,7 +499,7 @@ type ( DeleteByUID(ctx context.Context, spaceID int64, uid string) error // List lists the secrets in a given space - List(ctx context.Context, spaceID int64, filter types.Pagination) ([]*types.Secret, error) + List(ctx context.Context, spaceID int64, filter types.ListQueryFilter) ([]*types.Secret, error) } ExecutionStore interface { diff --git a/internal/store/database/execution.go b/internal/store/database/execution.go index f78e5d6ce..187d33805 100644 --- a/internal/store/database/execution.go +++ b/internal/store/database/execution.go @@ -176,7 +176,7 @@ func (s *executionStore) Create(ctx context.Context, execution *types.Execution) } // Update tries to update an execution in the datastore with optimistic locking. -func (s *executionStore) Update(ctx context.Context, execution *types.Execution) error { +func (s *executionStore) Update(ctx context.Context, e *types.Execution) error { const executionUpdateStmt = ` UPDATE executions SET @@ -190,6 +190,8 @@ func (s *executionStore) Update(ctx context.Context, execution *types.Execution) WHERE execution_id = :execution_id AND execution_version = :execution_version - 1` updatedAt := time.Now() + execution := *e + execution.Version++ execution.Updated = updatedAt.UnixMilli() @@ -214,6 +216,8 @@ func (s *executionStore) Update(ctx context.Context, execution *types.Execution) return gitness_store.ErrVersionConflict } + e.Version = execution.Version + e.Updated = execution.Updated return nil } diff --git a/internal/store/database/migrate/ci/ci_migrations.sql b/internal/store/database/migrate/ci/ci_migrations.sql index 89975c98a..2b1ed484d 100644 --- a/internal/store/database/migrate/ci/ci_migrations.sql +++ b/internal/store/database/migrate/ci/ci_migrations.sql @@ -14,16 +14,16 @@ CREATE TABLE IF NOT EXISTS pipelines ( ,pipeline_version INTEGER NOT NULL -- Ensure unique combination of UID and ParentID - UNIQUE (pipeline_space_id, pipeline_uid), + ,UNIQUE (pipeline_space_id, pipeline_uid) -- Foreign key to spaces table - CONSTRAINT fk_pipeline_space_id FOREIGN KEY (pipeline_space_id) + ,CONSTRAINT fk_pipeline_space_id FOREIGN KEY (pipeline_space_id) REFERENCES spaces (space_id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE -- Foreign key to repositories table - CONSTRAINT fk_pipelines_repo_id FOREIGN KEY (pipeline_repo_id) + ,CONSTRAINT fk_pipelines_repo_id FOREIGN KEY (pipeline_repo_id) REFERENCES repositories (repo_id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE @@ -67,16 +67,16 @@ CREATE TABLE IF NOT EXISTS executions ( ,execution_version INTEGER NOT NULL -- Ensure unique combination of pipeline ID and number - UNIQUE (execution_pipeline_id, execution_number), + ,UNIQUE (execution_pipeline_id, execution_number) -- Foreign key to pipelines table - CONSTRAINT fk_executions_pipeline_id FOREIGN KEY (,execution_pipeline_id) + ,CONSTRAINT fk_executions_pipeline_id FOREIGN KEY (execution_pipeline_id) REFERENCES pipelines (pipeline_id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE -- Foreign key to repositories table - CONSTRAINT fk_executions_repo_id FOREIGN KEY (,execution_repo_id) + ,CONSTRAINT fk_executions_repo_id FOREIGN KEY (execution_repo_id) REFERENCES repositories (repo_id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE @@ -93,10 +93,10 @@ CREATE TABLE IF NOT EXISTS secrets ( ,secret_version INTEGER NOT NULL -- Ensure unique combination of space ID and UID - UNIQUE (secret_space_id, secret_uid), + ,UNIQUE (secret_space_id, secret_uid) -- Foreign key to spaces table - CONSTRAINT fk_secrets_space_id FOREIGN KEY (secret_space_id) + ,CONSTRAINT fk_secrets_space_id FOREIGN KEY (secret_space_id) REFERENCES spaces (space_id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE diff --git a/internal/store/database/pipeline.go b/internal/store/database/pipeline.go index d341302d6..9ac2aaaf7 100644 --- a/internal/store/database/pipeline.go +++ b/internal/store/database/pipeline.go @@ -127,7 +127,7 @@ func (s *pipelineStore) Create(ctx context.Context, pipeline *types.Pipeline) er } // Update updates a pipeline. -func (s *pipelineStore) Update(ctx context.Context, pipeline *types.Pipeline) error { +func (s *pipelineStore) Update(ctx context.Context, p *types.Pipeline) error { const pipelineUpdateStmt = ` UPDATE pipelines SET @@ -140,6 +140,7 @@ func (s *pipelineStore) Update(ctx context.Context, pipeline *types.Pipeline) er pipeline_version = :pipeline_version WHERE pipeline_id = :pipeline_id AND pipeline_version = :pipeline_version - 1` updatedAt := time.Now() + pipeline := *p pipeline.Version++ pipeline.Updated = updatedAt.UnixMilli() @@ -165,6 +166,8 @@ func (s *pipelineStore) Update(ctx context.Context, pipeline *types.Pipeline) er return gitness_store.ErrVersionConflict } + p.Updated = pipeline.Updated + p.Version = pipeline.Version return nil } @@ -172,19 +175,19 @@ func (s *pipelineStore) Update(ctx context.Context, pipeline *types.Pipeline) er func (s *pipelineStore) List( ctx context.Context, parentID int64, - pagination types.Pagination, + filter types.ListQueryFilter, ) ([]*types.Pipeline, error) { stmt := database.Builder. Select(pipelineColumns). From("pipelines"). Where("pipeline_space_id = ?", fmt.Sprint(parentID)) - if pagination.Query != "" { - stmt = stmt.Where("LOWER(pipeline_uid) LIKE ?", fmt.Sprintf("%%%s%%", strings.ToLower(pagination.Query))) + if filter.Query != "" { + stmt = stmt.Where("LOWER(pipeline_uid) LIKE ?", fmt.Sprintf("%%%s%%", strings.ToLower(filter.Query))) } - stmt = stmt.Limit(database.Limit(pagination.Size)) - stmt = stmt.Offset(database.Offset(pagination.Page, pagination.Size)) + stmt = stmt.Limit(database.Limit(filter.Size)) + stmt = stmt.Offset(database.Offset(filter.Page, filter.Size)) sql, args, err := stmt.ToSql() if err != nil { @@ -229,7 +232,7 @@ func (s *pipelineStore) UpdateOptLock(ctx context.Context, } // Count of pipelines in a space. -func (s *pipelineStore) Count(ctx context.Context, parentID int64, filter types.Pagination) (int64, error) { +func (s *pipelineStore) Count(ctx context.Context, parentID int64, filter types.ListQueryFilter) (int64, error) { stmt := database.Builder. Select("count(*)"). From("pipelines"). diff --git a/internal/store/database/secret.go b/internal/store/database/secret.go index 7f7e9386b..8ade23d57 100644 --- a/internal/store/database/secret.go +++ b/internal/store/database/secret.go @@ -110,7 +110,7 @@ func (s *secretStore) Create(ctx context.Context, secret *types.Secret) error { return nil } -func (s *secretStore) Update(ctx context.Context, secret *types.Secret) error { +func (s *secretStore) Update(ctx context.Context, p *types.Secret) error { const secretUpdateStmt = ` UPDATE secrets SET @@ -121,6 +121,7 @@ func (s *secretStore) Update(ctx context.Context, secret *types.Secret) error { secret_version = :secret_version WHERE secret_id = :secret_id AND secret_version = :secret_version - 1` updatedAt := time.Now() + secret := *p secret.Version++ secret.Updated = updatedAt.UnixMilli() @@ -146,6 +147,8 @@ func (s *secretStore) Update(ctx context.Context, secret *types.Secret) error { return gitness_store.ErrVersionConflict } + p.Version = secret.Version + p.Updated = secret.Updated return nil } @@ -178,18 +181,18 @@ func (s *secretStore) UpdateOptLock(ctx context.Context, } // List lists all the secrets present in a space. -func (s *secretStore) List(ctx context.Context, parentID int64, pagination types.Pagination) ([]*types.Secret, error) { +func (s *secretStore) List(ctx context.Context, parentID int64, filter types.ListQueryFilter) ([]*types.Secret, error) { stmt := database.Builder. Select(secretColumns). From("secrets"). Where("secret_space_id = ?", fmt.Sprint(parentID)) - if pagination.Query != "" { - stmt = stmt.Where("LOWER(secret_uid) LIKE ?", fmt.Sprintf("%%%s%%", strings.ToLower(pagination.Query))) + if filter.Query != "" { + stmt = stmt.Where("LOWER(secret_uid) LIKE ?", fmt.Sprintf("%%%s%%", strings.ToLower(filter.Query))) } - stmt = stmt.Limit(database.Limit(pagination.Size)) - stmt = stmt.Offset(database.Offset(pagination.Page, pagination.Size)) + stmt = stmt.Limit(database.Limit(filter.Size)) + stmt = stmt.Offset(database.Offset(filter.Page, filter.Size)) sql, args, err := stmt.ToSql() if err != nil { @@ -237,7 +240,7 @@ func (s *secretStore) DeleteByUID(ctx context.Context, spaceID int64, uid string } // Count of secrets in a space. -func (s *secretStore) Count(ctx context.Context, parentID int64, filter types.Pagination) (int64, error) { +func (s *secretStore) Count(ctx context.Context, parentID int64, filter types.ListQueryFilter) (int64, error) { stmt := database.Builder. Select("count(*)"). From("secrets"). diff --git a/internal/store/database/wire.go b/internal/store/database/wire.go index 04179824a..d61f7879c 100644 --- a/internal/store/database/wire.go +++ b/internal/store/database/wire.go @@ -7,7 +7,6 @@ package database import ( "context" - "github.com/harness/gitness/encrypt" "github.com/harness/gitness/internal/store" "github.com/harness/gitness/internal/store/database/migrate" "github.com/harness/gitness/store/database" @@ -27,7 +26,6 @@ var WireSet = wire.NewSet( ProvideExecutionStore, ProvidePipelineStore, ProvideSecretStore, - ProvideEncryptor, ProvideRepoGitInfoView, ProvideMembershipStore, ProvideTokenStore, @@ -63,22 +61,6 @@ func ProvidePrincipalStore(db *sqlx.DB, uidTransformation store.PrincipalUIDTran return NewPrincipalStore(db, uidTransformation) } -// ProvideEncryptor provides an encryptor implementation. -func ProvideEncryptor(config database.Config) (encrypt.Encrypter, error) { - enc, err := encrypt.New(config.Secret) - // mixed-content mode should be set to true if the database - // originally had encryption disabled and therefore has - // plaintext entries. This prevents gitness from returning an - // error if decryption fails; on failure, the ciphertext is - // returned as-is and the error is ignored. - if aesgcm, ok := enc.(*encrypt.Aesgcm); ok { - if config.EncryptMixedContent { - aesgcm.Compat = true - } - } - return enc, err -} - // ProvidePrincipalInfoView provides a principal info store. func ProvidePrincipalInfoView(db *sqlx.DB) store.PrincipalInfoView { return NewPrincipalInfoView(db) diff --git a/mocks/mock_client.go b/mocks/mock_client.go index b16a6490e..3cb746055 100644 --- a/mocks/mock_client.go +++ b/mocks/mock_client.go @@ -8,9 +8,10 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" user "github.com/harness/gitness/internal/api/controller/user" types "github.com/harness/gitness/types" + + gomock "github.com/golang/mock/gomock" ) // MockClient is a mock of Client interface. diff --git a/mocks/mock_store.go b/mocks/mock_store.go index 0af0bbc34..9310f3729 100644 --- a/mocks/mock_store.go +++ b/mocks/mock_store.go @@ -8,9 +8,10 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" types "github.com/harness/gitness/types" enum "github.com/harness/gitness/types/enum" + + gomock "github.com/golang/mock/gomock" ) // MockPrincipalStore is a mock of PrincipalStore interface. diff --git a/store/database/config.go b/store/database/config.go index 1b180c787..399e8494d 100644 --- a/store/database/config.go +++ b/store/database/config.go @@ -6,8 +6,6 @@ package database // Config specifies the config for the database package. type Config struct { - Driver string - Datasource string - Secret string - EncryptMixedContent bool + Driver string + Datasource string } diff --git a/types/config.go b/types/config.go index 9f4c10ec0..0af8a1d43 100644 --- a/types/config.go +++ b/types/config.go @@ -52,6 +52,12 @@ type Config struct { DefaultBranch string `envconfig:"GITNESS_GIT_DEFAULTBRANCH" default:"main"` } + // Encrypter defines the parameters for the encrypter + Encrypter struct { + Secret string `envconfig:"GITNESS_ENCRYPTER_SECRET"` // key used for encryption + EncryptMixedContent bool `envconfig:"GITNESS_ENCRYPT_MIXED_CONTENT"` + } + // Server defines the server configuration parameters. Server struct { // HTTP defines the http configuration parameters @@ -75,9 +81,6 @@ type Config struct { Database struct { Driver string `envconfig:"GITNESS_DATABASE_DRIVER" default:"sqlite3"` Datasource string `envconfig:"GITNESS_DATABASE_DATASOURCE" default:"database.sqlite3"` - // secret used for encryption/decryption in the DB - Secret string `envconfig:"GITNESS_DATABASE_SECRET"` - EncryptMixedContent bool `envconfig:"GITNESS_ENCRYPT_MIXED_CONTENT"` } // Token defines token configuration parameters. diff --git a/types/list_filters.go b/types/list_filters.go new file mode 100644 index 000000000..e7493bbe8 --- /dev/null +++ b/types/list_filters.go @@ -0,0 +1,7 @@ +package types + +// ListQueryFilter has pagination related info and a query param +type ListQueryFilter struct { + Pagination + Query string `json:"query"` +} diff --git a/types/pagination.go b/types/pagination.go index 28bd01971..a00c13333 100644 --- a/types/pagination.go +++ b/types/pagination.go @@ -1,12 +1,7 @@ package types -import "github.com/harness/gitness/types/enum" - // Pagination stores pagination related params type Pagination struct { - Page int `json:"page"` - Size int `json:"size"` - Query string `json:"query"` - Sort string `json:"sort"` - Order enum.Order `json:"order"` + Page int `json:"page"` + Size int `json:"size"` } diff --git a/types/secret.go b/types/secret.go index f4bfa5b88..547a5fc69 100644 --- a/types/secret.go +++ b/types/secret.go @@ -9,7 +9,7 @@ type Secret struct { Description string `db:"secret_description" json:"description"` SpaceID int64 `db:"secret_space_id" json:"space_id"` UID string `db:"secret_uid" json:"uid"` - Data string `db:"secret_data" json:"data"` + Data string `db:"secret_data" json:"-"` Created int64 `db:"secret_created" json:"created"` Updated int64 `db:"secret_updated" json:"updated"` Version int64 `db:"secret_version" json:"version"`