mirror of
https://github.com/harness/drone.git
synced 2025-05-06 08:20:34 +08:00
Adding Repo Level Settings (#1145)
This commit is contained in:
parent
4deed68349
commit
39a998eacd
@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/harness/gitness/app/auth/authz"
|
"github.com/harness/gitness/app/auth/authz"
|
||||||
eventsgit "github.com/harness/gitness/app/events/git"
|
eventsgit "github.com/harness/gitness/app/events/git"
|
||||||
"github.com/harness/gitness/app/services/protection"
|
"github.com/harness/gitness/app/services/protection"
|
||||||
|
"github.com/harness/gitness/app/services/settings"
|
||||||
"github.com/harness/gitness/app/store"
|
"github.com/harness/gitness/app/store"
|
||||||
"github.com/harness/gitness/app/url"
|
"github.com/harness/gitness/app/url"
|
||||||
"github.com/harness/gitness/types"
|
"github.com/harness/gitness/types"
|
||||||
@ -38,7 +39,8 @@ type Controller struct {
|
|||||||
pullreqStore store.PullReqStore
|
pullreqStore store.PullReqStore
|
||||||
urlProvider url.Provider
|
urlProvider url.Provider
|
||||||
protectionManager *protection.Manager
|
protectionManager *protection.Manager
|
||||||
resourceLimiter limiter.ResourceLimiter
|
limiter limiter.ResourceLimiter
|
||||||
|
settings *settings.Service
|
||||||
preReceiveExtender PreReceiveExtender
|
preReceiveExtender PreReceiveExtender
|
||||||
updateExtender UpdateExtender
|
updateExtender UpdateExtender
|
||||||
postReceiveExtender PostReceiveExtender
|
postReceiveExtender PostReceiveExtender
|
||||||
@ -53,6 +55,7 @@ func NewController(
|
|||||||
urlProvider url.Provider,
|
urlProvider url.Provider,
|
||||||
protectionManager *protection.Manager,
|
protectionManager *protection.Manager,
|
||||||
limiter limiter.ResourceLimiter,
|
limiter limiter.ResourceLimiter,
|
||||||
|
settings *settings.Service,
|
||||||
preReceiveExtender PreReceiveExtender,
|
preReceiveExtender PreReceiveExtender,
|
||||||
updateExtender UpdateExtender,
|
updateExtender UpdateExtender,
|
||||||
postReceiveExtender PostReceiveExtender,
|
postReceiveExtender PostReceiveExtender,
|
||||||
@ -66,7 +69,8 @@ func NewController(
|
|||||||
pullreqStore: pullreqStore,
|
pullreqStore: pullreqStore,
|
||||||
urlProvider: urlProvider,
|
urlProvider: urlProvider,
|
||||||
protectionManager: protectionManager,
|
protectionManager: protectionManager,
|
||||||
resourceLimiter: limiter,
|
limiter: limiter,
|
||||||
|
settings: settings,
|
||||||
preReceiveExtender: preReceiveExtender,
|
preReceiveExtender: preReceiveExtender,
|
||||||
updateExtender: updateExtender,
|
updateExtender: updateExtender,
|
||||||
postReceiveExtender: postReceiveExtender,
|
postReceiveExtender: postReceiveExtender,
|
||||||
|
@ -46,7 +46,7 @@ func (c *Controller) PreReceive(
|
|||||||
return hook.Output{}, err
|
return hook.Output{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.resourceLimiter.RepoSize(ctx, in.RepoID); err != nil {
|
if err := c.limiter.RepoSize(ctx, in.RepoID); err != nil {
|
||||||
return hook.Output{}, fmt.Errorf(
|
return hook.Output{}, fmt.Errorf(
|
||||||
"resource limit exceeded: %w",
|
"resource limit exceeded: %w",
|
||||||
limiter.ErrMaxRepoSizeReached)
|
limiter.ErrMaxRepoSizeReached)
|
||||||
|
@ -30,6 +30,7 @@ import (
|
|||||||
"github.com/harness/gitness/app/services/importer"
|
"github.com/harness/gitness/app/services/importer"
|
||||||
"github.com/harness/gitness/app/services/keywordsearch"
|
"github.com/harness/gitness/app/services/keywordsearch"
|
||||||
"github.com/harness/gitness/app/services/protection"
|
"github.com/harness/gitness/app/services/protection"
|
||||||
|
"github.com/harness/gitness/app/services/settings"
|
||||||
"github.com/harness/gitness/app/store"
|
"github.com/harness/gitness/app/store"
|
||||||
"github.com/harness/gitness/app/url"
|
"github.com/harness/gitness/app/url"
|
||||||
"github.com/harness/gitness/git"
|
"github.com/harness/gitness/git"
|
||||||
@ -56,6 +57,7 @@ type Controller struct {
|
|||||||
pipelineStore store.PipelineStore
|
pipelineStore store.PipelineStore
|
||||||
principalStore store.PrincipalStore
|
principalStore store.PrincipalStore
|
||||||
ruleStore store.RuleStore
|
ruleStore store.RuleStore
|
||||||
|
settings *settings.Service
|
||||||
principalInfoCache store.PrincipalInfoCache
|
principalInfoCache store.PrincipalInfoCache
|
||||||
protectionManager *protection.Manager
|
protectionManager *protection.Manager
|
||||||
git git.Interface
|
git git.Interface
|
||||||
@ -79,6 +81,7 @@ func NewController(
|
|||||||
pipelineStore store.PipelineStore,
|
pipelineStore store.PipelineStore,
|
||||||
principalStore store.PrincipalStore,
|
principalStore store.PrincipalStore,
|
||||||
ruleStore store.RuleStore,
|
ruleStore store.RuleStore,
|
||||||
|
settings *settings.Service,
|
||||||
principalInfoCache store.PrincipalInfoCache,
|
principalInfoCache store.PrincipalInfoCache,
|
||||||
protectionManager *protection.Manager,
|
protectionManager *protection.Manager,
|
||||||
git git.Interface,
|
git git.Interface,
|
||||||
@ -102,6 +105,7 @@ func NewController(
|
|||||||
pipelineStore: pipelineStore,
|
pipelineStore: pipelineStore,
|
||||||
principalStore: principalStore,
|
principalStore: principalStore,
|
||||||
ruleStore: ruleStore,
|
ruleStore: ruleStore,
|
||||||
|
settings: settings,
|
||||||
principalInfoCache: principalInfoCache,
|
principalInfoCache: principalInfoCache,
|
||||||
protectionManager: protectionManager,
|
protectionManager: protectionManager,
|
||||||
git: git,
|
git: git,
|
||||||
@ -121,20 +125,11 @@ func (c *Controller) getRepo(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
repoRef string,
|
repoRef string,
|
||||||
) (*types.Repository, error) {
|
) (*types.Repository, error) {
|
||||||
if repoRef == "" {
|
return GetRepo(
|
||||||
return nil, usererror.BadRequest("A valid repository reference must be provided.")
|
ctx,
|
||||||
}
|
c.repoStore,
|
||||||
|
repoRef,
|
||||||
repo, err := c.repoStore.FindByRef(ctx, repoRef)
|
)
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to find repository: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if repo.Importing {
|
|
||||||
return nil, usererror.BadRequest("Repository import is in progress.")
|
|
||||||
}
|
|
||||||
|
|
||||||
return repo, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getRepoCheckAccess fetches an active repo (not one that is currently being imported)
|
// getRepoCheckAccess fetches an active repo (not one that is currently being imported)
|
||||||
@ -146,16 +141,15 @@ func (c *Controller) getRepoCheckAccess(
|
|||||||
reqPermission enum.Permission,
|
reqPermission enum.Permission,
|
||||||
orPublic bool,
|
orPublic bool,
|
||||||
) (*types.Repository, error) {
|
) (*types.Repository, error) {
|
||||||
repo, err := c.getRepo(ctx, repoRef)
|
return GetRepoCheckAccess(
|
||||||
if err != nil {
|
ctx,
|
||||||
return nil, fmt.Errorf("failed to find repo: %w", err)
|
c.repoStore,
|
||||||
}
|
c.authorizer,
|
||||||
|
session,
|
||||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, reqPermission, orPublic); err != nil {
|
repoRef,
|
||||||
return nil, fmt.Errorf("access check failed: %w", err)
|
reqPermission,
|
||||||
}
|
orPublic,
|
||||||
|
)
|
||||||
return repo, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) validateParentRef(parentRef string) error {
|
func (c *Controller) validateParentRef(parentRef string) error {
|
||||||
|
73
app/api/controller/repo/helper.go
Normal file
73
app/api/controller/repo/helper.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
apiauth "github.com/harness/gitness/app/api/auth"
|
||||||
|
"github.com/harness/gitness/app/api/usererror"
|
||||||
|
"github.com/harness/gitness/app/auth"
|
||||||
|
"github.com/harness/gitness/app/auth/authz"
|
||||||
|
"github.com/harness/gitness/app/store"
|
||||||
|
"github.com/harness/gitness/types"
|
||||||
|
"github.com/harness/gitness/types/enum"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetRepo fetches an active repo (not one that is currently being imported).
|
||||||
|
func GetRepo(
|
||||||
|
ctx context.Context,
|
||||||
|
repoStore store.RepoStore,
|
||||||
|
repoRef string,
|
||||||
|
) (*types.Repository, error) {
|
||||||
|
if repoRef == "" {
|
||||||
|
return nil, usererror.BadRequest("A valid repository reference must be provided.")
|
||||||
|
}
|
||||||
|
|
||||||
|
repo, err := repoStore.FindByRef(ctx, repoRef)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to find repository: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if repo.Importing {
|
||||||
|
return nil, usererror.BadRequest("Repository import is in progress.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return repo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRepoCheckAccess fetches an active repo (not one that is currently being imported)
|
||||||
|
// and checks if the current user has permission to access it.
|
||||||
|
func GetRepoCheckAccess(
|
||||||
|
ctx context.Context,
|
||||||
|
repoStore store.RepoStore,
|
||||||
|
authorizer authz.Authorizer,
|
||||||
|
session *auth.Session,
|
||||||
|
repoRef string,
|
||||||
|
reqPermission enum.Permission,
|
||||||
|
orPublic bool,
|
||||||
|
) (*types.Repository, error) {
|
||||||
|
repo, err := GetRepo(ctx, repoStore, repoRef)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to find repo: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = apiauth.CheckRepo(ctx, authorizer, session, repo, reqPermission, orPublic); err != nil {
|
||||||
|
return nil, fmt.Errorf("access check failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return repo, nil
|
||||||
|
}
|
@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/harness/gitness/app/services/importer"
|
"github.com/harness/gitness/app/services/importer"
|
||||||
"github.com/harness/gitness/app/services/keywordsearch"
|
"github.com/harness/gitness/app/services/keywordsearch"
|
||||||
"github.com/harness/gitness/app/services/protection"
|
"github.com/harness/gitness/app/services/protection"
|
||||||
|
"github.com/harness/gitness/app/services/settings"
|
||||||
"github.com/harness/gitness/app/store"
|
"github.com/harness/gitness/app/store"
|
||||||
"github.com/harness/gitness/app/url"
|
"github.com/harness/gitness/app/url"
|
||||||
"github.com/harness/gitness/git"
|
"github.com/harness/gitness/git"
|
||||||
@ -48,6 +49,7 @@ func ProvideController(
|
|||||||
pipelineStore store.PipelineStore,
|
pipelineStore store.PipelineStore,
|
||||||
principalStore store.PrincipalStore,
|
principalStore store.PrincipalStore,
|
||||||
ruleStore store.RuleStore,
|
ruleStore store.RuleStore,
|
||||||
|
settings *settings.Service,
|
||||||
principalInfoCache store.PrincipalInfoCache,
|
principalInfoCache store.PrincipalInfoCache,
|
||||||
protectionManager *protection.Manager,
|
protectionManager *protection.Manager,
|
||||||
rpcClient git.Interface,
|
rpcClient git.Interface,
|
||||||
@ -63,7 +65,7 @@ func ProvideController(
|
|||||||
return NewController(config, tx, urlProvider,
|
return NewController(config, tx, urlProvider,
|
||||||
authorizer, repoStore,
|
authorizer, repoStore,
|
||||||
spaceStore, pipelineStore,
|
spaceStore, pipelineStore,
|
||||||
principalStore, ruleStore, principalInfoCache, protectionManager,
|
principalStore, ruleStore, settings, principalInfoCache, protectionManager,
|
||||||
rpcClient, importer, codeOwners, reporeporter, indexer, limiter, mtxManager, identifierCheck, repoChecks)
|
rpcClient, importer, codeOwners, reporeporter, indexer, limiter, mtxManager, identifierCheck, repoChecks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
65
app/api/controller/reposettings/controller.go
Normal file
65
app/api/controller/reposettings/controller.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package reposettings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/app/api/controller/repo"
|
||||||
|
"github.com/harness/gitness/app/auth"
|
||||||
|
"github.com/harness/gitness/app/auth/authz"
|
||||||
|
"github.com/harness/gitness/app/services/settings"
|
||||||
|
"github.com/harness/gitness/app/store"
|
||||||
|
"github.com/harness/gitness/types"
|
||||||
|
"github.com/harness/gitness/types/enum"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Controller struct {
|
||||||
|
authorizer authz.Authorizer
|
||||||
|
repoStore store.RepoStore
|
||||||
|
settings *settings.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewController(
|
||||||
|
authorizer authz.Authorizer,
|
||||||
|
repoStore store.RepoStore,
|
||||||
|
settings *settings.Service,
|
||||||
|
) *Controller {
|
||||||
|
return &Controller{
|
||||||
|
authorizer: authorizer,
|
||||||
|
repoStore: repoStore,
|
||||||
|
settings: settings,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRepoCheckAccess fetches an active repo (not one that is currently being imported)
|
||||||
|
// and checks if the current user has permission to access it.
|
||||||
|
func (c *Controller) getRepoCheckAccess(
|
||||||
|
ctx context.Context,
|
||||||
|
session *auth.Session,
|
||||||
|
repoRef string,
|
||||||
|
reqPermission enum.Permission,
|
||||||
|
orPublic bool,
|
||||||
|
) (*types.Repository, error) {
|
||||||
|
return repo.GetRepoCheckAccess(
|
||||||
|
ctx,
|
||||||
|
c.repoStore,
|
||||||
|
c.authorizer,
|
||||||
|
session,
|
||||||
|
repoRef,
|
||||||
|
reqPermission,
|
||||||
|
orPublic,
|
||||||
|
)
|
||||||
|
}
|
46
app/api/controller/reposettings/security.go
Normal file
46
app/api/controller/reposettings/security.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package reposettings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/harness/gitness/app/services/settings"
|
||||||
|
|
||||||
|
"github.com/gotidy/ptr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SecuritySettings represents the security related part of repository settings as exposed externally.
|
||||||
|
type SecuritySettings struct {
|
||||||
|
SecretScanningEnabled *bool `json:"secret_scanning_enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDefaultSecuritySettings() *SecuritySettings {
|
||||||
|
return &SecuritySettings{
|
||||||
|
SecretScanningEnabled: ptr.Bool(settings.DefaultSecretScanningEnabled),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSecuritySettingsMappings(s *SecuritySettings) []settings.SettingHandler {
|
||||||
|
return []settings.SettingHandler{
|
||||||
|
settings.Mapping(settings.KeySecretScanningEnabled, s.SecretScanningEnabled),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSecuritySettingsAsKeyValues(s *SecuritySettings) []settings.KeyValue {
|
||||||
|
kvs := make([]settings.KeyValue, 0, 1)
|
||||||
|
if s.SecretScanningEnabled != nil {
|
||||||
|
kvs = append(kvs, settings.KeyValue{Key: settings.KeySecretScanningEnabled, Value: *s.SecretScanningEnabled})
|
||||||
|
}
|
||||||
|
return kvs
|
||||||
|
}
|
44
app/api/controller/reposettings/security_find.go
Normal file
44
app/api/controller/reposettings/security_find.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package reposettings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/app/auth"
|
||||||
|
"github.com/harness/gitness/types/enum"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SecurityFind returns the security settings of a repo.
|
||||||
|
func (c *Controller) SecurityFind(
|
||||||
|
ctx context.Context,
|
||||||
|
session *auth.Session,
|
||||||
|
repoRef string,
|
||||||
|
) (*SecuritySettings, error) {
|
||||||
|
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out := GetDefaultSecuritySettings()
|
||||||
|
mappings := GetSecuritySettingsMappings(out)
|
||||||
|
err = c.settings.RepoMap(ctx, repo.ID, mappings...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to map settings: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
51
app/api/controller/reposettings/security_update.go
Normal file
51
app/api/controller/reposettings/security_update.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package reposettings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/app/auth"
|
||||||
|
"github.com/harness/gitness/types/enum"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SecurityUpdate updates the security settings of the repo.
|
||||||
|
func (c *Controller) SecurityUpdate(
|
||||||
|
ctx context.Context,
|
||||||
|
session *auth.Session,
|
||||||
|
repoRef string,
|
||||||
|
in *SecuritySettings,
|
||||||
|
) (*SecuritySettings, error) {
|
||||||
|
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.settings.RepoSetMany(ctx, repo.ID, GetSecuritySettingsAsKeyValues(in)...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to set settings: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// read all settings and return complete config
|
||||||
|
out := GetDefaultSecuritySettings()
|
||||||
|
mappings := GetSecuritySettingsMappings(out)
|
||||||
|
err = c.settings.RepoMap(ctx, repo.ID, mappings...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to map settings: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
36
app/api/controller/reposettings/wire.go
Normal file
36
app/api/controller/reposettings/wire.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package reposettings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/harness/gitness/app/auth/authz"
|
||||||
|
"github.com/harness/gitness/app/services/settings"
|
||||||
|
"github.com/harness/gitness/app/store"
|
||||||
|
|
||||||
|
"github.com/google/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WireSet provides a wire set for this package.
|
||||||
|
var WireSet = wire.NewSet(
|
||||||
|
ProvideController,
|
||||||
|
)
|
||||||
|
|
||||||
|
func ProvideController(
|
||||||
|
authorizer authz.Authorizer,
|
||||||
|
repoStore store.RepoStore,
|
||||||
|
settings *settings.Service,
|
||||||
|
) *Controller {
|
||||||
|
return NewController(authorizer, repoStore, settings)
|
||||||
|
}
|
43
app/api/handler/reposettings/security_find.go
Normal file
43
app/api/handler/reposettings/security_find.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package reposettings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/app/api/controller/reposettings"
|
||||||
|
"github.com/harness/gitness/app/api/render"
|
||||||
|
"github.com/harness/gitness/app/api/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HandleSecurityFind(repoSettingCtrl *reposettings.Controller) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
session, _ := request.AuthSessionFrom(ctx)
|
||||||
|
repoRef, err := request.GetRepoRefFromPath(r)
|
||||||
|
if err != nil {
|
||||||
|
render.TranslatedUserError(ctx, w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
settings, err := repoSettingCtrl.SecurityFind(ctx, session, repoRef)
|
||||||
|
if err != nil {
|
||||||
|
render.TranslatedUserError(ctx, w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
render.JSON(w, http.StatusOK, settings)
|
||||||
|
}
|
||||||
|
}
|
51
app/api/handler/reposettings/security_update.go
Normal file
51
app/api/handler/reposettings/security_update.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package reposettings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/app/api/controller/reposettings"
|
||||||
|
"github.com/harness/gitness/app/api/render"
|
||||||
|
"github.com/harness/gitness/app/api/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HandleSecurityUpdate(repoSettingCtrl *reposettings.Controller) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
session, _ := request.AuthSessionFrom(ctx)
|
||||||
|
repoRef, err := request.GetRepoRefFromPath(r)
|
||||||
|
if err != nil {
|
||||||
|
render.TranslatedUserError(ctx, w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
in := new(reposettings.SecuritySettings)
|
||||||
|
err = json.NewDecoder(r.Body).Decode(in)
|
||||||
|
if err != nil {
|
||||||
|
render.BadRequestf(ctx, w, "Invalid request body: %s.", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
settings, err := repoSettingCtrl.SecurityUpdate(ctx, session, repoRef, in)
|
||||||
|
if err != nil {
|
||||||
|
render.TranslatedUserError(ctx, w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
render.JSON(w, http.StatusOK, settings)
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/harness/gitness/app/auth/authz"
|
"github.com/harness/gitness/app/auth/authz"
|
||||||
eventsgit "github.com/harness/gitness/app/events/git"
|
eventsgit "github.com/harness/gitness/app/events/git"
|
||||||
"github.com/harness/gitness/app/services/protection"
|
"github.com/harness/gitness/app/services/protection"
|
||||||
|
"github.com/harness/gitness/app/services/settings"
|
||||||
"github.com/harness/gitness/app/store"
|
"github.com/harness/gitness/app/store"
|
||||||
"github.com/harness/gitness/app/url"
|
"github.com/harness/gitness/app/url"
|
||||||
"github.com/harness/gitness/git"
|
"github.com/harness/gitness/git"
|
||||||
@ -52,6 +53,7 @@ func ProvideController(
|
|||||||
protectionManager *protection.Manager,
|
protectionManager *protection.Manager,
|
||||||
githookFactory hook.ClientFactory,
|
githookFactory hook.ClientFactory,
|
||||||
limiter limiter.ResourceLimiter,
|
limiter limiter.ResourceLimiter,
|
||||||
|
settings *settings.Service,
|
||||||
preReceiveExtender githook.PreReceiveExtender,
|
preReceiveExtender githook.PreReceiveExtender,
|
||||||
updateExtender githook.UpdateExtender,
|
updateExtender githook.UpdateExtender,
|
||||||
postReceiveExtender githook.PostReceiveExtender,
|
postReceiveExtender githook.PostReceiveExtender,
|
||||||
@ -65,6 +67,7 @@ func ProvideController(
|
|||||||
urlProvider,
|
urlProvider,
|
||||||
protectionManager,
|
protectionManager,
|
||||||
limiter,
|
limiter,
|
||||||
|
settings,
|
||||||
preReceiveExtender,
|
preReceiveExtender,
|
||||||
updateExtender,
|
updateExtender,
|
||||||
postReceiveExtender,
|
postReceiveExtender,
|
||||||
|
@ -30,6 +30,7 @@ import (
|
|||||||
"github.com/harness/gitness/app/api/controller/principal"
|
"github.com/harness/gitness/app/api/controller/principal"
|
||||||
"github.com/harness/gitness/app/api/controller/pullreq"
|
"github.com/harness/gitness/app/api/controller/pullreq"
|
||||||
"github.com/harness/gitness/app/api/controller/repo"
|
"github.com/harness/gitness/app/api/controller/repo"
|
||||||
|
"github.com/harness/gitness/app/api/controller/reposettings"
|
||||||
"github.com/harness/gitness/app/api/controller/secret"
|
"github.com/harness/gitness/app/api/controller/secret"
|
||||||
"github.com/harness/gitness/app/api/controller/serviceaccount"
|
"github.com/harness/gitness/app/api/controller/serviceaccount"
|
||||||
"github.com/harness/gitness/app/api/controller/space"
|
"github.com/harness/gitness/app/api/controller/space"
|
||||||
@ -51,6 +52,7 @@ import (
|
|||||||
handlerprincipal "github.com/harness/gitness/app/api/handler/principal"
|
handlerprincipal "github.com/harness/gitness/app/api/handler/principal"
|
||||||
handlerpullreq "github.com/harness/gitness/app/api/handler/pullreq"
|
handlerpullreq "github.com/harness/gitness/app/api/handler/pullreq"
|
||||||
handlerrepo "github.com/harness/gitness/app/api/handler/repo"
|
handlerrepo "github.com/harness/gitness/app/api/handler/repo"
|
||||||
|
handlerreposettings "github.com/harness/gitness/app/api/handler/reposettings"
|
||||||
"github.com/harness/gitness/app/api/handler/resource"
|
"github.com/harness/gitness/app/api/handler/resource"
|
||||||
handlersecret "github.com/harness/gitness/app/api/handler/secret"
|
handlersecret "github.com/harness/gitness/app/api/handler/secret"
|
||||||
handlerserviceaccount "github.com/harness/gitness/app/api/handler/serviceaccount"
|
handlerserviceaccount "github.com/harness/gitness/app/api/handler/serviceaccount"
|
||||||
@ -97,6 +99,7 @@ func NewAPIHandler(
|
|||||||
config *types.Config,
|
config *types.Config,
|
||||||
authenticator authn.Authenticator,
|
authenticator authn.Authenticator,
|
||||||
repoCtrl *repo.Controller,
|
repoCtrl *repo.Controller,
|
||||||
|
repoSettingsCtrl *reposettings.Controller,
|
||||||
executionCtrl *execution.Controller,
|
executionCtrl *execution.Controller,
|
||||||
logCtrl *logs.Controller,
|
logCtrl *logs.Controller,
|
||||||
spaceCtrl *space.Controller,
|
spaceCtrl *space.Controller,
|
||||||
@ -139,7 +142,7 @@ func NewAPIHandler(
|
|||||||
r.Use(middlewareauthn.Attempt(authenticator))
|
r.Use(middlewareauthn.Attempt(authenticator))
|
||||||
|
|
||||||
r.Route("/v1", func(r chi.Router) {
|
r.Route("/v1", func(r chi.Router) {
|
||||||
setupRoutesV1(r, appCtx, config, repoCtrl, executionCtrl, triggerCtrl, logCtrl, pipelineCtrl,
|
setupRoutesV1(r, appCtx, config, repoCtrl, repoSettingsCtrl, executionCtrl, triggerCtrl, logCtrl, pipelineCtrl,
|
||||||
connectorCtrl, templateCtrl, pluginCtrl, secretCtrl, spaceCtrl, pullreqCtrl,
|
connectorCtrl, templateCtrl, pluginCtrl, secretCtrl, spaceCtrl, pullreqCtrl,
|
||||||
webhookCtrl, githookCtrl, git, saCtrl, userCtrl, principalCtrl, checkCtrl, sysCtrl, uploadCtrl,
|
webhookCtrl, githookCtrl, git, saCtrl, userCtrl, principalCtrl, checkCtrl, sysCtrl, uploadCtrl,
|
||||||
searchCtrl)
|
searchCtrl)
|
||||||
@ -167,6 +170,7 @@ func setupRoutesV1(r chi.Router,
|
|||||||
appCtx context.Context,
|
appCtx context.Context,
|
||||||
config *types.Config,
|
config *types.Config,
|
||||||
repoCtrl *repo.Controller,
|
repoCtrl *repo.Controller,
|
||||||
|
repoSettingsCtrl *reposettings.Controller,
|
||||||
executionCtrl *execution.Controller,
|
executionCtrl *execution.Controller,
|
||||||
triggerCtrl *trigger.Controller,
|
triggerCtrl *trigger.Controller,
|
||||||
logCtrl *logs.Controller,
|
logCtrl *logs.Controller,
|
||||||
@ -189,8 +193,8 @@ func setupRoutesV1(r chi.Router,
|
|||||||
searchCtrl *keywordsearch.Controller,
|
searchCtrl *keywordsearch.Controller,
|
||||||
) {
|
) {
|
||||||
setupSpaces(r, appCtx, spaceCtrl)
|
setupSpaces(r, appCtx, spaceCtrl)
|
||||||
setupRepos(r, repoCtrl, pipelineCtrl, executionCtrl, triggerCtrl, logCtrl, pullreqCtrl, webhookCtrl, checkCtrl,
|
setupRepos(r, repoCtrl, repoSettingsCtrl, pipelineCtrl, executionCtrl, triggerCtrl,
|
||||||
uploadCtrl)
|
logCtrl, pullreqCtrl, webhookCtrl, checkCtrl, uploadCtrl)
|
||||||
setupConnectors(r, connectorCtrl)
|
setupConnectors(r, connectorCtrl)
|
||||||
setupTemplates(r, templateCtrl)
|
setupTemplates(r, templateCtrl)
|
||||||
setupSecrets(r, secretCtrl)
|
setupSecrets(r, secretCtrl)
|
||||||
@ -248,6 +252,7 @@ func setupSpaces(r chi.Router, appCtx context.Context, spaceCtrl *space.Controll
|
|||||||
|
|
||||||
func setupRepos(r chi.Router,
|
func setupRepos(r chi.Router,
|
||||||
repoCtrl *repo.Controller,
|
repoCtrl *repo.Controller,
|
||||||
|
repoSettingsCtrl *reposettings.Controller,
|
||||||
pipelineCtrl *pipeline.Controller,
|
pipelineCtrl *pipeline.Controller,
|
||||||
executionCtrl *execution.Controller,
|
executionCtrl *execution.Controller,
|
||||||
triggerCtrl *trigger.Controller,
|
triggerCtrl *trigger.Controller,
|
||||||
@ -269,6 +274,9 @@ func setupRepos(r chi.Router,
|
|||||||
r.Post("/purge", handlerrepo.HandlePurge(repoCtrl))
|
r.Post("/purge", handlerrepo.HandlePurge(repoCtrl))
|
||||||
r.Post("/restore", handlerrepo.HandleRestore(repoCtrl))
|
r.Post("/restore", handlerrepo.HandleRestore(repoCtrl))
|
||||||
|
|
||||||
|
r.Get("/settings/security", handlerreposettings.HandleSecurityFind(repoSettingsCtrl))
|
||||||
|
r.Patch("/settings/security", handlerreposettings.HandleSecurityUpdate(repoSettingsCtrl))
|
||||||
|
|
||||||
r.Post("/move", handlerrepo.HandleMove(repoCtrl))
|
r.Post("/move", handlerrepo.HandleMove(repoCtrl))
|
||||||
r.Get("/service-accounts", handlerrepo.HandleListServiceAccounts(repoCtrl))
|
r.Get("/service-accounts", handlerrepo.HandleListServiceAccounts(repoCtrl))
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
"github.com/harness/gitness/app/api/controller/principal"
|
"github.com/harness/gitness/app/api/controller/principal"
|
||||||
"github.com/harness/gitness/app/api/controller/pullreq"
|
"github.com/harness/gitness/app/api/controller/pullreq"
|
||||||
"github.com/harness/gitness/app/api/controller/repo"
|
"github.com/harness/gitness/app/api/controller/repo"
|
||||||
|
"github.com/harness/gitness/app/api/controller/reposettings"
|
||||||
"github.com/harness/gitness/app/api/controller/secret"
|
"github.com/harness/gitness/app/api/controller/secret"
|
||||||
"github.com/harness/gitness/app/api/controller/serviceaccount"
|
"github.com/harness/gitness/app/api/controller/serviceaccount"
|
||||||
"github.com/harness/gitness/app/api/controller/space"
|
"github.com/harness/gitness/app/api/controller/space"
|
||||||
@ -92,6 +93,7 @@ func ProvideAPIHandler(
|
|||||||
config *types.Config,
|
config *types.Config,
|
||||||
authenticator authn.Authenticator,
|
authenticator authn.Authenticator,
|
||||||
repoCtrl *repo.Controller,
|
repoCtrl *repo.Controller,
|
||||||
|
repoSettingsCtrl *reposettings.Controller,
|
||||||
executionCtrl *execution.Controller,
|
executionCtrl *execution.Controller,
|
||||||
logCtrl *logs.Controller,
|
logCtrl *logs.Controller,
|
||||||
spaceCtrl *space.Controller,
|
spaceCtrl *space.Controller,
|
||||||
@ -114,7 +116,7 @@ func ProvideAPIHandler(
|
|||||||
searchCtrl *keywordsearch.Controller,
|
searchCtrl *keywordsearch.Controller,
|
||||||
) APIHandler {
|
) APIHandler {
|
||||||
return NewAPIHandler(appCtx, config,
|
return NewAPIHandler(appCtx, config,
|
||||||
authenticator, repoCtrl, executionCtrl, logCtrl, spaceCtrl, pipelineCtrl,
|
authenticator, repoCtrl, repoSettingsCtrl, executionCtrl, logCtrl, spaceCtrl, pipelineCtrl,
|
||||||
secretCtrl, triggerCtrl, connectorCtrl, templateCtrl, pluginCtrl, pullreqCtrl, webhookCtrl,
|
secretCtrl, triggerCtrl, connectorCtrl, templateCtrl, pluginCtrl, pullreqCtrl, webhookCtrl,
|
||||||
githookCtrl, git, saCtrl, userCtrl, principalCtrl, checkCtrl, sysCtrl, blobCtrl, searchCtrl)
|
githookCtrl, git, saCtrl, userCtrl, principalCtrl, checkCtrl, sysCtrl, blobCtrl, searchCtrl)
|
||||||
}
|
}
|
||||||
|
62
app/services/settings/helpers.go
Normal file
62
app/services/settings/helpers.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RepoGet is a helper method for getting a setting of a specific type for a repo.
|
||||||
|
func RepoGet[T any](
|
||||||
|
ctx context.Context,
|
||||||
|
s *Service,
|
||||||
|
repoID int64,
|
||||||
|
key Key,
|
||||||
|
dflt T,
|
||||||
|
) (T, error) {
|
||||||
|
var out T
|
||||||
|
ok, err := s.RepoGet(ctx, repoID, key, &out)
|
||||||
|
if err != nil {
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return dflt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepoGetRequired is a helper method for getting a setting of a specific type for a repo.
|
||||||
|
// If the setting isn't found, an error is returned.
|
||||||
|
func RepoGetRequired[T any](
|
||||||
|
ctx context.Context,
|
||||||
|
s *Service,
|
||||||
|
repoID int64,
|
||||||
|
key Key,
|
||||||
|
) (T, error) {
|
||||||
|
var out T
|
||||||
|
ok, err := s.RepoGet(ctx, repoID, key, &out)
|
||||||
|
if err != nil {
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return out, fmt.Errorf("setting %q not found", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
72
app/services/settings/mapping.go
Normal file
72
app/services/settings/mapping.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Mapping returns a SettingHandler that maps the value of the setting with the given key to the target.
|
||||||
|
func Mapping[T any](key Key, target *T) SettingHandler {
|
||||||
|
if target == nil {
|
||||||
|
panic("mapping target can't be nil")
|
||||||
|
}
|
||||||
|
return &settingHandlerMapping[T]{
|
||||||
|
key: key,
|
||||||
|
required: false,
|
||||||
|
target: target,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MappingRequired returns a SettingHandler that maps the value of the setting with the given key to the target.
|
||||||
|
// If the setting wasn't found an error is returned.
|
||||||
|
func MappingRequired[T any](key Key, target *T) SettingHandler {
|
||||||
|
if target == nil {
|
||||||
|
panic("mapping target can't be nil")
|
||||||
|
}
|
||||||
|
return &settingHandlerMapping[T]{
|
||||||
|
key: key,
|
||||||
|
required: true,
|
||||||
|
target: target,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ SettingHandler = (*settingHandlerMapping[any])(nil)
|
||||||
|
|
||||||
|
// settingHandlerMapping is a setting handler that maps the value of a setting to the provided target.
|
||||||
|
type settingHandlerMapping[T any] struct {
|
||||||
|
key Key
|
||||||
|
required bool
|
||||||
|
target *T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *settingHandlerMapping[T]) Key() Key {
|
||||||
|
return q.key
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *settingHandlerMapping[T]) Required() bool {
|
||||||
|
return q.required
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *settingHandlerMapping[T]) Handle(_ context.Context, raw []byte) error {
|
||||||
|
err := json.Unmarshal(raw, q.target)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to unmarshal setting value: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
169
app/services/settings/service.go
Normal file
169
app/services/settings/service.go
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
appstore "github.com/harness/gitness/app/store"
|
||||||
|
"github.com/harness/gitness/store"
|
||||||
|
"github.com/harness/gitness/types/enum"
|
||||||
|
)
|
||||||
|
|
||||||
|
// KeyValue is a struct used for upserting many entries.
|
||||||
|
type KeyValue struct {
|
||||||
|
Key Key
|
||||||
|
Value any
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingHandler is an abstraction of a component that's handling a single setting value as part of
|
||||||
|
// calling service.Map.
|
||||||
|
type SettingHandler interface {
|
||||||
|
Key() Key
|
||||||
|
Required() bool
|
||||||
|
Handle(ctx context.Context, raw []byte) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service is used to enhance interaction with the settings store.
|
||||||
|
type Service struct {
|
||||||
|
settingsStore appstore.SettingsStore
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(
|
||||||
|
settingsStore appstore.SettingsStore,
|
||||||
|
) *Service {
|
||||||
|
return &Service{
|
||||||
|
settingsStore: settingsStore,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the value of the setting with the given key for the given scope.
|
||||||
|
func (s *Service) Set(
|
||||||
|
ctx context.Context,
|
||||||
|
scope enum.SettingsScope,
|
||||||
|
scopeID int64,
|
||||||
|
key Key,
|
||||||
|
value any,
|
||||||
|
) error {
|
||||||
|
raw, err := json.Marshal(value)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to marshal setting value: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.settingsStore.Upsert(
|
||||||
|
ctx,
|
||||||
|
scope,
|
||||||
|
scopeID,
|
||||||
|
string(key),
|
||||||
|
raw,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to upsert setting in store: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMany sets the value of the settings with the given keys for the given scope.
|
||||||
|
func (s *Service) SetMany(
|
||||||
|
ctx context.Context,
|
||||||
|
scope enum.SettingsScope,
|
||||||
|
scopeID int64,
|
||||||
|
keyValues ...KeyValue,
|
||||||
|
) error {
|
||||||
|
// TODO: batch upsert
|
||||||
|
for _, kv := range keyValues {
|
||||||
|
if err := s.Set(ctx, scope, scopeID, kv.Key, kv.Value); err != nil {
|
||||||
|
return fmt.Errorf("failed to set setting for key %q: %w", kv.Key, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the value of the setting with the given key for the given scope.
|
||||||
|
func (s *Service) Get(
|
||||||
|
ctx context.Context,
|
||||||
|
scope enum.SettingsScope,
|
||||||
|
scopeID int64,
|
||||||
|
key Key,
|
||||||
|
out any,
|
||||||
|
) (bool, error) {
|
||||||
|
raw, err := s.settingsStore.Find(
|
||||||
|
ctx,
|
||||||
|
scope,
|
||||||
|
scopeID,
|
||||||
|
string(key),
|
||||||
|
)
|
||||||
|
if errors.Is(err, store.ErrResourceNotFound) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("failed to find setting in store: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(raw, &out)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("failed to unmarshal setting value: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map maps all available settings using the provided handlers for the given scope.
|
||||||
|
func (s *Service) Map(
|
||||||
|
ctx context.Context,
|
||||||
|
scope enum.SettingsScope,
|
||||||
|
scopeID int64,
|
||||||
|
handlers ...SettingHandler,
|
||||||
|
) error {
|
||||||
|
if len(handlers) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := make([]string, len(handlers))
|
||||||
|
for i, m := range handlers {
|
||||||
|
keys[i] = string(m.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
rawValues, err := s.settingsStore.FindMany(
|
||||||
|
ctx,
|
||||||
|
scope,
|
||||||
|
scopeID,
|
||||||
|
keys...,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to find settings in store: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range handlers {
|
||||||
|
rawValue, found := rawValues[string(m.Key())]
|
||||||
|
if !found && m.Required() {
|
||||||
|
return fmt.Errorf("required setting %q not found", m.Key())
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = m.Handle(ctx, rawValue); err != nil {
|
||||||
|
return fmt.Errorf("failed to handle value for setting %q: %w", m.Key(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
81
app/services/settings/service_repo.go
Normal file
81
app/services/settings/service_repo.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/types/enum"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RepoSet sets the value of the setting with the given key for the given repo.
|
||||||
|
func (s *Service) RepoSet(
|
||||||
|
ctx context.Context,
|
||||||
|
repoID int64,
|
||||||
|
key Key,
|
||||||
|
value any,
|
||||||
|
) error {
|
||||||
|
return s.Set(
|
||||||
|
ctx,
|
||||||
|
enum.SettingsScopeRepo,
|
||||||
|
repoID,
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepoSetMany sets the value of the settings with the given keys for the given repo.
|
||||||
|
func (s *Service) RepoSetMany(
|
||||||
|
ctx context.Context,
|
||||||
|
repoID int64,
|
||||||
|
keyValues ...KeyValue,
|
||||||
|
) error {
|
||||||
|
return s.SetMany(
|
||||||
|
ctx,
|
||||||
|
enum.SettingsScopeRepo,
|
||||||
|
repoID,
|
||||||
|
keyValues...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepoGet returns the value of the setting with the given key for the given repo.
|
||||||
|
func (s *Service) RepoGet(
|
||||||
|
ctx context.Context,
|
||||||
|
repoID int64,
|
||||||
|
key Key,
|
||||||
|
out any,
|
||||||
|
) (bool, error) {
|
||||||
|
return s.Get(
|
||||||
|
ctx,
|
||||||
|
enum.SettingsScopeRepo,
|
||||||
|
repoID,
|
||||||
|
key,
|
||||||
|
out,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepoMap maps all available settings using the provided handlers for the given repo.
|
||||||
|
func (s *Service) RepoMap(
|
||||||
|
ctx context.Context,
|
||||||
|
repoID int64,
|
||||||
|
handlers ...SettingHandler,
|
||||||
|
) error {
|
||||||
|
return s.Map(
|
||||||
|
ctx,
|
||||||
|
enum.SettingsScopeRepo,
|
||||||
|
repoID,
|
||||||
|
handlers...,
|
||||||
|
)
|
||||||
|
}
|
23
app/services/settings/settings.go
Normal file
23
app/services/settings/settings.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package settings
|
||||||
|
|
||||||
|
type Key string
|
||||||
|
|
||||||
|
var (
|
||||||
|
// KeySecretScanningEnabled [bool] enables secret scanning if set to true.
|
||||||
|
KeySecretScanningEnabled Key = "secret_scanning_enabled"
|
||||||
|
DefaultSecretScanningEnabled = false
|
||||||
|
)
|
31
app/services/settings/wire.go
Normal file
31
app/services/settings/wire.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/harness/gitness/app/store"
|
||||||
|
|
||||||
|
"github.com/google/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
var WireSet = wire.NewSet(
|
||||||
|
ProvideService,
|
||||||
|
)
|
||||||
|
|
||||||
|
func ProvideService(
|
||||||
|
settingsStore store.SettingsStore,
|
||||||
|
) *Service {
|
||||||
|
return NewService(settingsStore)
|
||||||
|
}
|
@ -17,6 +17,7 @@ package store
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/harness/gitness/types"
|
"github.com/harness/gitness/types"
|
||||||
@ -239,6 +240,35 @@ type (
|
|||||||
ListSizeInfos(ctx context.Context) ([]*types.RepositorySizeInfo, error)
|
ListSizeInfos(ctx context.Context) ([]*types.RepositorySizeInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SettingsStore defines the settings storage.
|
||||||
|
SettingsStore interface {
|
||||||
|
// Find returns the value of the setting with the given key for the provided scope.
|
||||||
|
Find(
|
||||||
|
ctx context.Context,
|
||||||
|
scope enum.SettingsScope,
|
||||||
|
scopeID int64,
|
||||||
|
key string,
|
||||||
|
) (json.RawMessage, error)
|
||||||
|
|
||||||
|
// FindMany returns the values of the settings with the given keys for the provided scope.
|
||||||
|
// NOTE: if a setting key doesn't exist the map just won't contain an entry for it (no error returned).
|
||||||
|
FindMany(
|
||||||
|
ctx context.Context,
|
||||||
|
scope enum.SettingsScope,
|
||||||
|
scopeID int64,
|
||||||
|
keys ...string,
|
||||||
|
) (map[string]json.RawMessage, error)
|
||||||
|
|
||||||
|
// Upsert upserts the value of the setting with the given key for the provided scope.
|
||||||
|
Upsert(
|
||||||
|
ctx context.Context,
|
||||||
|
scope enum.SettingsScope,
|
||||||
|
scopeID int64,
|
||||||
|
key string,
|
||||||
|
value json.RawMessage,
|
||||||
|
) error
|
||||||
|
}
|
||||||
|
|
||||||
// RepoGitInfoView defines the repository GitUID view.
|
// RepoGitInfoView defines the repository GitUID view.
|
||||||
RepoGitInfoView interface {
|
RepoGitInfoView interface {
|
||||||
Find(ctx context.Context, id int64) (*types.RepositoryGitInfo, error)
|
Find(ctx context.Context, id int64) (*types.RepositoryGitInfo, error)
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE settings;
|
@ -0,0 +1,24 @@
|
|||||||
|
CREATE TABLE settings (
|
||||||
|
setting_id SERIAL PRIMARY KEY
|
||||||
|
,setting_space_id INTEGER
|
||||||
|
,setting_repo_id INTEGER
|
||||||
|
,setting_key TEXT NOT NULL
|
||||||
|
,setting_value JSON
|
||||||
|
|
||||||
|
,CONSTRAINT fk_settings_space_id FOREIGN KEY (setting_space_id)
|
||||||
|
REFERENCES spaces (space_id) MATCH SIMPLE
|
||||||
|
ON UPDATE NO ACTION
|
||||||
|
ON DELETE CASCADE
|
||||||
|
,CONSTRAINT fk_settings_repo_id FOREIGN KEY (setting_repo_id)
|
||||||
|
REFERENCES repositories (repo_id) MATCH SIMPLE
|
||||||
|
ON UPDATE NO ACTION
|
||||||
|
ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX settings_space_id_key
|
||||||
|
ON settings(setting_space_id, LOWER(setting_key))
|
||||||
|
WHERE setting_space_id IS NOT NULL;
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX settings_repo_id_key
|
||||||
|
ON settings(setting_repo_id, LOWER(setting_key))
|
||||||
|
WHERE setting_repo_id IS NOT NULL;
|
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE settings;
|
@ -0,0 +1,24 @@
|
|||||||
|
CREATE TABLE settings (
|
||||||
|
setting_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||||
|
,setting_space_id INTEGER
|
||||||
|
,setting_repo_id INTEGER
|
||||||
|
,setting_key TEXT NOT NULL
|
||||||
|
,setting_value TEXT
|
||||||
|
|
||||||
|
,CONSTRAINT fk_settings_space_id FOREIGN KEY (setting_space_id)
|
||||||
|
REFERENCES spaces (space_id) MATCH SIMPLE
|
||||||
|
ON UPDATE NO ACTION
|
||||||
|
ON DELETE CASCADE
|
||||||
|
,CONSTRAINT fk_settings_repo_id FOREIGN KEY (setting_repo_id)
|
||||||
|
REFERENCES repositories (repo_id) MATCH SIMPLE
|
||||||
|
ON UPDATE NO ACTION
|
||||||
|
ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX settings_space_id_key
|
||||||
|
ON settings(setting_space_id, LOWER(setting_key))
|
||||||
|
WHERE setting_space_id IS NOT NULL;
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX settings_repo_id_key
|
||||||
|
ON settings(setting_repo_id, LOWER(setting_key))
|
||||||
|
WHERE setting_repo_id IS NOT NULL;
|
194
app/store/database/settings.go
Normal file
194
app/store/database/settings.go
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/app/store"
|
||||||
|
"github.com/harness/gitness/store/database"
|
||||||
|
"github.com/harness/gitness/store/database/dbtx"
|
||||||
|
"github.com/harness/gitness/types/enum"
|
||||||
|
|
||||||
|
"github.com/Masterminds/squirrel"
|
||||||
|
"github.com/guregu/null"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ store.SettingsStore = (*SettingsStore)(nil)
|
||||||
|
|
||||||
|
// NewSettingsStore returns a new SettingsStore.
|
||||||
|
func NewSettingsStore(db *sqlx.DB) *SettingsStore {
|
||||||
|
return &SettingsStore{
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingsStore implements store.SettingsStore backed by a relational database.
|
||||||
|
type SettingsStore struct {
|
||||||
|
db *sqlx.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// setting is an internal representation used to store setting data in the database.
|
||||||
|
type setting struct {
|
||||||
|
ID int64 `db:"setting_id"`
|
||||||
|
SpaceID null.Int `db:"setting_space_id"`
|
||||||
|
RepoID null.Int `db:"setting_repo_id"`
|
||||||
|
Key string `db:"setting_key"`
|
||||||
|
Value json.RawMessage `db:"setting_value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
settingsColumns = `
|
||||||
|
setting_id
|
||||||
|
,setting_space_id
|
||||||
|
,setting_repo_id
|
||||||
|
,setting_key
|
||||||
|
,setting_value`
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *SettingsStore) Find(
|
||||||
|
ctx context.Context,
|
||||||
|
scope enum.SettingsScope,
|
||||||
|
scopeID int64,
|
||||||
|
key string,
|
||||||
|
) (json.RawMessage, error) {
|
||||||
|
stmt := database.Builder.
|
||||||
|
Select(settingsColumns).
|
||||||
|
From("settings").
|
||||||
|
Where("LOWER(setting_key) = ?", strings.ToLower(key))
|
||||||
|
|
||||||
|
switch scope {
|
||||||
|
case enum.SettingsScopeSpace:
|
||||||
|
stmt = stmt.Where("setting_space_id = ?", scopeID)
|
||||||
|
case enum.SettingsScopeRepo:
|
||||||
|
stmt = stmt.Where("setting_repo_id = ?", scopeID)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("setting scope %q is not supported", scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
sql, args, err := stmt.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to convert query to sql: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db := dbtx.GetAccessor(ctx, s.db)
|
||||||
|
|
||||||
|
dst := &setting{}
|
||||||
|
if err := db.GetContext(ctx, dst, sql, args...); err != nil {
|
||||||
|
return nil, database.ProcessSQLErrorf(ctx, err, "Select query failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst.Value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SettingsStore) FindMany(
|
||||||
|
ctx context.Context,
|
||||||
|
scope enum.SettingsScope,
|
||||||
|
scopeID int64,
|
||||||
|
keys ...string,
|
||||||
|
) (map[string]json.RawMessage, error) {
|
||||||
|
if len(keys) == 0 {
|
||||||
|
return map[string]json.RawMessage{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
keysLower := make([]string, len(keys))
|
||||||
|
for i, k := range keys {
|
||||||
|
keysLower[i] = strings.ToLower(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt := database.Builder.
|
||||||
|
Select(settingsColumns).
|
||||||
|
From("settings").
|
||||||
|
Where(squirrel.Eq{"LOWER(setting_key)": keysLower})
|
||||||
|
|
||||||
|
switch scope {
|
||||||
|
case enum.SettingsScopeSpace:
|
||||||
|
stmt = stmt.Where("setting_space_id = ?", scopeID)
|
||||||
|
case enum.SettingsScopeRepo:
|
||||||
|
stmt = stmt.Where("setting_repo_id = ?", scopeID)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("setting scope %q is not supported", scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
sql, args, err := stmt.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to convert query to sql: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db := dbtx.GetAccessor(ctx, s.db)
|
||||||
|
|
||||||
|
dst := []*setting{}
|
||||||
|
if err := db.SelectContext(ctx, &dst, sql, args...); err != nil {
|
||||||
|
return nil, database.ProcessSQLErrorf(ctx, err, "Select query failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
out := map[string]json.RawMessage{}
|
||||||
|
for _, d := range dst {
|
||||||
|
out[d.Key] = d.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SettingsStore) Upsert(ctx context.Context,
|
||||||
|
scope enum.SettingsScope,
|
||||||
|
scopeID int64,
|
||||||
|
key string,
|
||||||
|
value json.RawMessage,
|
||||||
|
) error {
|
||||||
|
stmt := database.Builder.
|
||||||
|
Insert("").
|
||||||
|
Into("settings").
|
||||||
|
Columns(
|
||||||
|
"setting_space_id",
|
||||||
|
"setting_repo_id",
|
||||||
|
"setting_key",
|
||||||
|
"setting_value",
|
||||||
|
)
|
||||||
|
|
||||||
|
switch scope {
|
||||||
|
case enum.SettingsScopeSpace:
|
||||||
|
stmt = stmt.Values(null.IntFrom(scopeID), null.Int{}, key, value)
|
||||||
|
stmt = stmt.Suffix(`ON CONFLICT (setting_space_id, LOWER(setting_key)) WHERE setting_space_id IS NOT NULL DO`)
|
||||||
|
case enum.SettingsScopeRepo:
|
||||||
|
stmt = stmt.Values(null.Int{}, null.IntFrom(scopeID), key, value)
|
||||||
|
stmt = stmt.Suffix(`ON CONFLICT (setting_repo_id, LOWER(setting_key)) WHERE setting_repo_id IS NOT NULL DO`)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("setting scope %q is not supported", scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt = stmt.Suffix(`
|
||||||
|
UPDATE SET
|
||||||
|
setting_value = EXCLUDED.setting_value
|
||||||
|
WHERE
|
||||||
|
settings.setting_value <> EXCLUDED.setting_value`)
|
||||||
|
|
||||||
|
sql, args, err := stmt.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to convert query to sql: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db := dbtx.GetAccessor(ctx, s.db)
|
||||||
|
|
||||||
|
if _, err := db.ExecContext(ctx, sql, args...); err != nil {
|
||||||
|
return database.ProcessSQLErrorf(ctx, err, "Upsert query failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -52,6 +52,7 @@ var WireSet = wire.NewSet(
|
|||||||
ProvidePullReqFileViewStore,
|
ProvidePullReqFileViewStore,
|
||||||
ProvideWebhookStore,
|
ProvideWebhookStore,
|
||||||
ProvideWebhookExecutionStore,
|
ProvideWebhookExecutionStore,
|
||||||
|
ProvideSettingsStore,
|
||||||
ProvideCheckStore,
|
ProvideCheckStore,
|
||||||
ProvideConnectorStore,
|
ProvideConnectorStore,
|
||||||
ProvideTemplateStore,
|
ProvideTemplateStore,
|
||||||
@ -241,3 +242,8 @@ func ProvideCheckStore(db *sqlx.DB,
|
|||||||
) store.CheckStore {
|
) store.CheckStore {
|
||||||
return NewCheckStore(db, principalInfoCache)
|
return NewCheckStore(db, principalInfoCache)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProvideSettingsStore provides a settings store.
|
||||||
|
func ProvideSettingsStore(db *sqlx.DB) store.SettingsStore {
|
||||||
|
return NewSettingsStore(db)
|
||||||
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/harness/gitness/app/api/controller/principal"
|
"github.com/harness/gitness/app/api/controller/principal"
|
||||||
"github.com/harness/gitness/app/api/controller/pullreq"
|
"github.com/harness/gitness/app/api/controller/pullreq"
|
||||||
"github.com/harness/gitness/app/api/controller/repo"
|
"github.com/harness/gitness/app/api/controller/repo"
|
||||||
|
"github.com/harness/gitness/app/api/controller/reposettings"
|
||||||
"github.com/harness/gitness/app/api/controller/secret"
|
"github.com/harness/gitness/app/api/controller/secret"
|
||||||
"github.com/harness/gitness/app/api/controller/service"
|
"github.com/harness/gitness/app/api/controller/service"
|
||||||
"github.com/harness/gitness/app/api/controller/serviceaccount"
|
"github.com/harness/gitness/app/api/controller/serviceaccount"
|
||||||
@ -64,6 +65,7 @@ import (
|
|||||||
"github.com/harness/gitness/app/services/protection"
|
"github.com/harness/gitness/app/services/protection"
|
||||||
pullreqservice "github.com/harness/gitness/app/services/pullreq"
|
pullreqservice "github.com/harness/gitness/app/services/pullreq"
|
||||||
"github.com/harness/gitness/app/services/reposize"
|
"github.com/harness/gitness/app/services/reposize"
|
||||||
|
"github.com/harness/gitness/app/services/settings"
|
||||||
"github.com/harness/gitness/app/services/trigger"
|
"github.com/harness/gitness/app/services/trigger"
|
||||||
"github.com/harness/gitness/app/services/usergroup"
|
"github.com/harness/gitness/app/services/usergroup"
|
||||||
"github.com/harness/gitness/app/services/webhook"
|
"github.com/harness/gitness/app/services/webhook"
|
||||||
@ -112,6 +114,7 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e
|
|||||||
space.WireSet,
|
space.WireSet,
|
||||||
limiter.WireSet,
|
limiter.WireSet,
|
||||||
repo.WireSet,
|
repo.WireSet,
|
||||||
|
reposettings.WireSet,
|
||||||
pullreq.WireSet,
|
pullreq.WireSet,
|
||||||
controllerwebhook.WireSet,
|
controllerwebhook.WireSet,
|
||||||
serviceaccount.WireSet,
|
serviceaccount.WireSet,
|
||||||
@ -181,6 +184,7 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e
|
|||||||
cliserver.ProvideKeywordSearchConfig,
|
cliserver.ProvideKeywordSearchConfig,
|
||||||
keywordsearch.WireSet,
|
keywordsearch.WireSet,
|
||||||
controllerkeywordsearch.WireSet,
|
controllerkeywordsearch.WireSet,
|
||||||
|
settings.WireSet,
|
||||||
usergroup.WireSet,
|
usergroup.WireSet,
|
||||||
openapi.WireSet,
|
openapi.WireSet,
|
||||||
repo.ProvideRepoCheck,
|
repo.ProvideRepoCheck,
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/harness/gitness/app/api/controller/principal"
|
"github.com/harness/gitness/app/api/controller/principal"
|
||||||
pullreq2 "github.com/harness/gitness/app/api/controller/pullreq"
|
pullreq2 "github.com/harness/gitness/app/api/controller/pullreq"
|
||||||
"github.com/harness/gitness/app/api/controller/repo"
|
"github.com/harness/gitness/app/api/controller/repo"
|
||||||
|
"github.com/harness/gitness/app/api/controller/reposettings"
|
||||||
"github.com/harness/gitness/app/api/controller/secret"
|
"github.com/harness/gitness/app/api/controller/secret"
|
||||||
"github.com/harness/gitness/app/api/controller/service"
|
"github.com/harness/gitness/app/api/controller/service"
|
||||||
"github.com/harness/gitness/app/api/controller/serviceaccount"
|
"github.com/harness/gitness/app/api/controller/serviceaccount"
|
||||||
@ -63,6 +64,7 @@ import (
|
|||||||
"github.com/harness/gitness/app/services/protection"
|
"github.com/harness/gitness/app/services/protection"
|
||||||
"github.com/harness/gitness/app/services/pullreq"
|
"github.com/harness/gitness/app/services/pullreq"
|
||||||
"github.com/harness/gitness/app/services/reposize"
|
"github.com/harness/gitness/app/services/reposize"
|
||||||
|
"github.com/harness/gitness/app/services/settings"
|
||||||
trigger2 "github.com/harness/gitness/app/services/trigger"
|
trigger2 "github.com/harness/gitness/app/services/trigger"
|
||||||
"github.com/harness/gitness/app/services/usergroup"
|
"github.com/harness/gitness/app/services/usergroup"
|
||||||
"github.com/harness/gitness/app/services/webhook"
|
"github.com/harness/gitness/app/services/webhook"
|
||||||
@ -126,6 +128,8 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
|||||||
repoStore := database.ProvideRepoStore(db, spacePathCache, spacePathStore, spaceStore)
|
repoStore := database.ProvideRepoStore(db, spacePathCache, spacePathStore, spaceStore)
|
||||||
pipelineStore := database.ProvidePipelineStore(db)
|
pipelineStore := database.ProvidePipelineStore(db)
|
||||||
ruleStore := database.ProvideRuleStore(db, principalInfoCache)
|
ruleStore := database.ProvideRuleStore(db, principalInfoCache)
|
||||||
|
settingsStore := database.ProvideSettingsStore(db)
|
||||||
|
settingsService := settings.ProvideService(settingsStore)
|
||||||
protectionManager, err := protection.ProvideManager(ruleStore)
|
protectionManager, err := protection.ProvideManager(ruleStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -190,7 +194,8 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
|||||||
}
|
}
|
||||||
repoIdentifier := check.ProvideRepoIdentifierCheck()
|
repoIdentifier := check.ProvideRepoIdentifierCheck()
|
||||||
repoCheck := repo.ProvideRepoCheck()
|
repoCheck := repo.ProvideRepoCheck()
|
||||||
repoController := repo.ProvideController(config, transactor, provider, authorizer, repoStore, spaceStore, pipelineStore, principalStore, ruleStore, principalInfoCache, protectionManager, gitInterface, repository, codeownersService, reporter, indexer, resourceLimiter, mutexManager, repoIdentifier, repoCheck)
|
repoController := repo.ProvideController(config, transactor, provider, authorizer, repoStore, spaceStore, pipelineStore, principalStore, ruleStore, settingsService, principalInfoCache, protectionManager, gitInterface, repository, codeownersService, reporter, indexer, resourceLimiter, mutexManager, repoIdentifier, repoCheck)
|
||||||
|
reposettingsController := reposettings.ProvideController(authorizer, repoStore, settingsService)
|
||||||
executionStore := database.ProvideExecutionStore(db)
|
executionStore := database.ProvideExecutionStore(db)
|
||||||
checkStore := database.ProvideCheckStore(db, principalInfoCache)
|
checkStore := database.ProvideCheckStore(db, principalInfoCache)
|
||||||
stageStore := database.ProvideStageStore(db)
|
stageStore := database.ProvideStageStore(db)
|
||||||
@ -274,7 +279,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
githookController := githook.ProvideController(authorizer, principalStore, repoStore, reporter2, gitInterface, pullReqStore, provider, protectionManager, clientFactory, resourceLimiter, preReceiveExtender, updateExtender, postReceiveExtender)
|
githookController := githook.ProvideController(authorizer, principalStore, repoStore, reporter2, gitInterface, pullReqStore, provider, protectionManager, clientFactory, resourceLimiter, settingsService, preReceiveExtender, updateExtender, postReceiveExtender)
|
||||||
serviceaccountController := serviceaccount.NewController(principalUID, authorizer, principalStore, spaceStore, repoStore, tokenStore)
|
serviceaccountController := serviceaccount.NewController(principalUID, authorizer, principalStore, spaceStore, repoStore, tokenStore)
|
||||||
principalController := principal.ProvideController(principalStore)
|
principalController := principal.ProvideController(principalStore)
|
||||||
v := check2.ProvideCheckSanitizers()
|
v := check2.ProvideCheckSanitizers()
|
||||||
@ -291,7 +296,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
|||||||
uploadController := upload.ProvideController(authorizer, repoStore, blobStore)
|
uploadController := upload.ProvideController(authorizer, repoStore, blobStore)
|
||||||
searcher := keywordsearch.ProvideSearcher(localIndexSearcher)
|
searcher := keywordsearch.ProvideSearcher(localIndexSearcher)
|
||||||
keywordsearchController := keywordsearch2.ProvideController(authorizer, searcher, repoController, spaceController)
|
keywordsearchController := keywordsearch2.ProvideController(authorizer, searcher, repoController, spaceController)
|
||||||
apiHandler := router.ProvideAPIHandler(ctx, config, authenticator, repoController, executionController, logsController, spaceController, pipelineController, secretController, triggerController, connectorController, templateController, pluginController, pullreqController, webhookController, githookController, gitInterface, serviceaccountController, controller, principalController, checkController, systemController, uploadController, keywordsearchController)
|
apiHandler := router.ProvideAPIHandler(ctx, config, authenticator, repoController, reposettingsController, executionController, logsController, spaceController, pipelineController, secretController, triggerController, connectorController, templateController, pluginController, pullreqController, webhookController, githookController, gitInterface, serviceaccountController, controller, principalController, checkController, systemController, uploadController, keywordsearchController)
|
||||||
gitHandler := router.ProvideGitHandler(provider, authenticator, repoController)
|
gitHandler := router.ProvideGitHandler(provider, authenticator, repoController)
|
||||||
openapiService := openapi.ProvideOpenAPIService()
|
openapiService := openapi.ProvideOpenAPIService()
|
||||||
webHandler := router.ProvideWebHandler(config, openapiService)
|
webHandler := router.ProvideWebHandler(config, openapiService)
|
||||||
|
37
types/enum/settings.go
Normal file
37
types/enum/settings.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package enum
|
||||||
|
|
||||||
|
// SettingsScope defines the different scopes of a setting.
|
||||||
|
type SettingsScope string
|
||||||
|
|
||||||
|
func (SettingsScope) Enum() []interface{} {
|
||||||
|
return toInterfaceSlice(GetAllSettingsScopes())
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// SettingsScopeSpace defines settings stored on a space level.
|
||||||
|
SettingsScopeSpace SettingsScope = "space"
|
||||||
|
|
||||||
|
// SettingsScopeRepo defines settings stored on a repo level.
|
||||||
|
SettingsScopeRepo SettingsScope = "repo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetAllSettingsScopes() []SettingsScope {
|
||||||
|
return []SettingsScope{
|
||||||
|
SettingsScopeSpace,
|
||||||
|
SettingsScopeRepo,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user