block 'api' as root space name, minor improvements

jobatzil/rename
Johannes Batzill 2022-09-05 18:45:16 -07:00
parent d7f0ae4b2c
commit ff806fb492
26 changed files with 389 additions and 63 deletions

View File

@ -12,18 +12,16 @@ import (
"github.com/harness/gitness/internal/api/render"
"github.com/harness/gitness/internal/api/request"
"github.com/harness/gitness/internal/auth/authz"
"github.com/harness/gitness/internal/store"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
type Guard struct {
authorizer authz.Authorizer
spaces store.SpaceStore
}
func New(spaces store.SpaceStore, authorizer authz.Authorizer) *Guard {
return &Guard{authorizer: authorizer, spaces: spaces}
func New(authorizer authz.Authorizer) *Guard {
return &Guard{authorizer: authorizer}
}
/*

View File

@ -42,8 +42,8 @@ func (g *Guard) Repo(permission enum.Permission, orPublic bool, guarded http.Han
return
}
// Enforce permission
if (!orPublic || !rep.IsPublic) && !g.EnforceRepo(w, r, permission, rep.Fqn) {
// Enforce permission (renders error)
if !(orPublic && rep.IsPublic) && !g.EnforceRepo(w, r, permission, rep.Fqn) {
return
}

View File

@ -6,7 +6,6 @@ package guard
import (
"errors"
"fmt"
"net/http"
"github.com/harness/gitness/internal/api/render"
@ -43,10 +42,8 @@ func (g *Guard) Space(permission enum.Permission, orPublic bool, guarded http.Ha
return
}
fmt.Printf("check for space '%s'", s.Fqn)
// Enforce permission (renders error)
if (!orPublic || !s.IsPublic) && !g.EnforceSpace(w, r, permission, s.Fqn) {
if !(orPublic && s.IsPublic) && !g.EnforceSpace(w, r, permission, s.Fqn) {
return
}

View File

@ -72,7 +72,7 @@ func HandleCreate(guard *guard.Guard, spaces store.SpaceStore, repos store.RepoS
/*
* AUTHORIZATION - has to be done on parent space!
*/
if !guard.EnforceSpace(w, r, enum.PermissionRepoCreate, parentFqn) {
if !guard.EnforceRepo(w, r, enum.PermissionRepoCreate, parentFqn) {
return
}

View File

@ -35,7 +35,7 @@ func HandleCreate(guard *guard.Guard, spaces store.SpaceStore) http.HandlerFunc
ctx := r.Context()
log := hlog.FromRequest(r)
// get fqn (requires parent if child space)
// get fqn (requires parent of child space)
sref, err := request.GetSpaceRef(r)
if err != nil {
render.BadRequest(w, err)
@ -81,7 +81,7 @@ func HandleCreate(guard *guard.Guard, spaces store.SpaceStore) http.HandlerFunc
}
// get parentId if needed
parentId := int64(-1)
parentId := int64(0)
if parentFqn != "" {
parentSpace, err := spaces.FindFqn(ctx, parentFqn)
if err != nil {

View File

@ -32,7 +32,6 @@ func HandleDelete(guard *guard.Guard, spaces store.SpaceStore) http.HandlerFunc
if err != nil {
render.InternalError(w, err)
log.Error().Err(err).
Int64("space_id", s.ID).
Str("space_fqn", s.Fqn).
Msg("Failed to delete space.")
return

View File

@ -36,7 +36,8 @@ func HandleList(guard *guard.Guard, spaces store.SpaceStore) http.HandlerFunc {
if err != nil {
render.InternalError(w, err)
log.Error().Err(err).
Msgf("Failed to retrieve count of spaces under '%s'.", s.Fqn)
Str("space_fqn", s.Fqn).
Msg("Failed to retrieve count of child spaces.")
return
}
@ -44,7 +45,8 @@ func HandleList(guard *guard.Guard, spaces store.SpaceStore) http.HandlerFunc {
if err != nil {
render.InternalError(w, err)
log.Error().Err(err).
Msgf("Failed to retrieve list of spaces under '%s'.", s.Fqn)
Str("space_fqn", s.Fqn).
Msg("Failed to retrieve list of child spaces.")
return
}

View File

@ -36,7 +36,8 @@ func HandleListRepos(guard *guard.Guard, repos store.RepoStore) http.HandlerFunc
if err != nil {
render.InternalError(w, err)
log.Error().Err(err).
Msgf("Failed to retrieve count of repos under '%s'.", s.Fqn)
Str("space_fqn", s.Fqn).
Msg("Failed to retrieve count of repos.")
return
}
@ -44,7 +45,8 @@ func HandleListRepos(guard *guard.Guard, repos store.RepoStore) http.HandlerFunc
if err != nil {
render.InternalError(w, err)
log.Error().Err(err).
Msgf("Failed to retrieve list of repos under '%s'.", s.Fqn)
Str("space_fqn", s.Fqn).
Msg("Failed to retrieve list of repos.")
return
}

View File

@ -26,11 +26,15 @@ func Attempt(authenticator authn.Authenticator) func(http.Handler) http.Handler
if err != nil {
render.Unauthorized(w, err)
return
} else if user == nil {
}
// if there was no auth info - continue as is
if user == nil {
next.ServeHTTP(w, r)
return
}
// otherwise update the logging context and inject user in context
ctx := r.Context()
log.Ctx(ctx).UpdateContext(func(c zerolog.Context) zerolog.Context {
return c.Str("session_email", user.Email).Bool("session_admin", user.Admin)

View File

@ -14,7 +14,7 @@ import (
*/
func GitFqnBefore(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
r, _ = encodeFQNWithCustomMarker(r, "", ".git", false)
r, _ = encodeFQNWithMarker(r, "", ".git", false)
h.ServeHTTP(w, r)
}
}
@ -27,8 +27,9 @@ func GitFqnBefore(h http.HandlerFunc) http.HandlerFunc {
func TerminatedFqnBefore(prefixes []string, h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
for _, p := range prefixes {
// IMPORTANT: define changed separately to avoid overshadowing r
changed := false
if r, changed = encodeFQNWithCustomMarker(r, p, "/+", false); changed {
if r, changed = encodeFQNWithMarker(r, p, "/+", false); changed {
break
}
}
@ -44,10 +45,10 @@ func TerminatedFqnBefore(prefixes []string, h http.HandlerFunc) http.HandlerFunc
*
* Examples:
* Prefix: "" Path: "/space1/space2/+" => "/space1%2Fspace2"
* Prefix: "" Path: "/space1/space2.git" => "/space1%2Fspace2.git"
* Prefix: "" Path: "/space1/space2.git" => "/space1%2Fspace2"
* Prefix: "/spaces" Path: "/spaces/space1/space2/+/authToken" => "/spaces/space1%2Fspace2/authToken"
*/
func encodeFQNWithCustomMarker(r *http.Request, prefix string, marker string, keepMarker bool) (*http.Request, bool) {
func encodeFQNWithMarker(r *http.Request, prefix string, marker string, keepMarker bool) (*http.Request, bool) {
// In case path doesn't start with prefix - nothing to encode
if len(r.URL.Path) < len(prefix) || r.URL.Path[0:len(prefix)] != prefix {
return r, false
@ -58,11 +59,12 @@ func encodeFQNWithCustomMarker(r *http.Request, prefix string, marker string, ke
// If we don't find a marker - nothing to encode
if !found {
fmt.Println("what")
return r, false
}
// if marker was found - convert to escaped version
escapedFqn := "/" + strings.Replace(fqn[1:], "/", "%2F", -1)
// if marker was found - convert to escaped version (skip first character in case path starts with '/')
escapedFqn := fqn[0:1] + strings.Replace(fqn[1:], "/", "%2F", -1)
if keepMarker {
escapedFqn += marker
}

View File

@ -31,7 +31,7 @@ func WithUser(parent context.Context, v *types.User) context.Context {
// context.
func UserFrom(ctx context.Context) (*types.User, bool) {
v, ok := ctx.Value(userKey).(*types.User)
return v, ok
return v, ok && v != nil
}
// WithSpace returns a copy of parent in which the space value is set

View File

@ -87,7 +87,7 @@ func ParseUserFilter(r *http.Request) types.UserFilter {
}
}
// ParseSpaceFilter extracts the user query parameter from the url.
// ParseSpaceFilter extracts the space query parameter from the url.
func ParseSpaceFilter(r *http.Request) types.SpaceFilter {
return types.SpaceFilter{
Order: ParseOrder(r),
@ -97,7 +97,7 @@ func ParseSpaceFilter(r *http.Request) types.SpaceFilter {
}
}
// ParseRepoFilter extracts the user query parameter from the url.
// ParseRepoFilter extracts the repository query parameter from the url.
func ParseRepoFilter(r *http.Request) types.RepoFilter {
return types.RepoFilter{
Order: ParseOrder(r),

View File

@ -16,9 +16,7 @@ import (
"github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/token"
"github.com/harness/gitness/types"
"github.com/rs/zerolog"
"github.com/rs/zerolog/hlog"
"github.com/rs/zerolog/log"
)
var _ Authenticator = (*TokenAuthenticator)(nil)
@ -81,10 +79,6 @@ func (a *TokenAuthenticator) Authenticate(r *http.Request) (*types.User, error)
}
}
log.Ctx(ctx).UpdateContext(func(c zerolog.Context) zerolog.Context {
return c.Str("session_email", user.Email).Bool("session_admin", user.Admin)
})
return user, nil
}

View File

@ -27,7 +27,7 @@ import (
)
/*
* Mounts the Rest API Router under mountPath.
* Mounts the Rest API Router under mountPath (path has to end with ).
* The handler is wrapped within a layer that handles encoding terminated FQNs.
*/
func newApiHandler(
@ -40,8 +40,9 @@ func newApiHandler(
authorizer authz.Authorizer) (http.Handler, error) {
config := systemStore.Config(nocontext)
guard := guard.New(authorizer)
// User go-chi router for inner routing (restricted to mountPath!)
// Use go-chi router for inner routing (restricted to mountPath!)
r := chi.NewRouter()
r.Route(mountPath, func(r chi.Router) {
@ -72,7 +73,7 @@ func newApiHandler(
r.Use(middleware_authn.Attempt(authenticator))
r.Route("/v1", func(r chi.Router) {
setupRoutesV1(r, systemStore, userStore, spaceStore, repoStore, authenticator, authorizer)
setupRoutesV1(r, systemStore, userStore, spaceStore, repoStore, authenticator, guard)
})
})
@ -92,10 +93,7 @@ func setupRoutesV1(
spaceStore store.SpaceStore,
repoStore store.RepoStore,
authenticator authn.Authenticator,
authorizer authz.Authorizer) {
// Create singleton middlewares for later usage
guard := guard.New(spaceStore, authorizer)
guard *guard.Guard) {
// SPACES
r.Route("/spaces", func(r chi.Router) {

View File

@ -12,6 +12,7 @@ import (
"github.com/harness/gitness/internal/auth/authn"
"github.com/harness/gitness/internal/auth/authz"
"github.com/harness/gitness/internal/store"
"github.com/harness/gitness/types/enum"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
@ -32,13 +33,12 @@ func newGitHandler(
authenticator authn.Authenticator,
authorizer authz.Authorizer) (http.Handler, error) {
// User go-chi router for inner routing (restricted to mountPath!)
guard := guard.New(authorizer)
// Use go-chi router for inner routing (restricted to mountPath!)
r := chi.NewRouter()
r.Route(mountPath, func(r chi.Router) {
// Create singleton middlewares for later usage
guard := guard.New(spaceStore, authorizer)
// Apply common api middleware
r.Use(middleware.NoCache)
r.Use(middleware.Recoverer)
@ -56,15 +56,19 @@ func newGitHandler(
// resolves the repo and stores in the context
r.Use(repo.Required(repoStore))
// Operations that require auth (write)
// Write operations (need auth)
r.Group(func(r chi.Router) {
r.Use(guard.EnforceAuthenticated)
// TODO: specific permission for pushing code?
r.Use(guard.ForRepo(enum.PermissionRepoEdit, false))
r.Handle("/git-upload-pack", http.HandlerFunc(stubGitHandler))
})
// Operations that not always require auth (read)
// Read operations (only need of it not public)
r.Group(func(r chi.Router) {
r.Use(guard.ForRepo(enum.PermissionRepoView, true))
r.Post("/git-receive-pack", stubGitHandler)
r.Get("/info/refs", stubGitHandler)
r.Get("/HEAD", stubGitHandler)
@ -88,7 +92,7 @@ func stubGitHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusForbidden)
w.Write([]byte(fmt.Sprintf(
"Work in progress ... \n"+
"Oooops, seems you hit a major construction site ... \n"+
" Repo: '%s' (%s)\n"+
" Method: '%s'\n"+
" Path: '%s'\n"+

View File

@ -17,7 +17,8 @@ import (
)
const (
restMount = "/api/"
restMount = "/api"
gitUserAgentPrefix = "git/"
)
// empty context
@ -39,7 +40,7 @@ func New(
authenticator authn.Authenticator,
authorizer authz.Authorizer,
) (http.Handler, error) {
api, err := newApiHandler("/api", systemStore, userStore, spaceStore, repoStore, authenticator, authorizer)
api, err := newApiHandler(restMount, systemStore, userStore, spaceStore, repoStore, authenticator, authorizer)
if err != nil {
return nil, err
}
@ -68,8 +69,8 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
* This can collide with other API endpoints and thus has to be checked first.
* To avoid any false positives, we use the user-agent header to identify git agents.
*/
a := req.Header.Get("user-agent")
if strings.HasPrefix(a, "git/") {
ua := req.Header.Get("user-agent")
if strings.HasPrefix(ua, gitUserAgentPrefix) {
r.git.ServeHTTP(w, req)
return
}

View File

@ -22,7 +22,7 @@ func newWebHandler(
config := systemStore.Config(nocontext)
// User go-chi router for inner routing (restricted to mountPath!)
// Use go-chi router for inner routing (restricted to mountPath!)
r := chi.NewRouter()
r.Route(mountPath, func(r chi.Router) {

View File

@ -199,7 +199,7 @@ INSERT INTO repositories (
,:repo_numPulls
,:repo_numClosedPulls
,:repo_numOpenPulls
)RETURNING repo_id
) RETURNING repo_id
`
const repoUpdate = `

View File

@ -176,7 +176,7 @@ WHERE space_id = $1
const spaceInsert = `
INSERT INTO spaces (
space_name
space_name
,space_fqn
,space_parentId
,space_displayName
@ -195,7 +195,7 @@ INSERT INTO spaces (
,:space_createdBy
,:space_created
,:space_updated
)RETURNING space_id
) RETURNING space_id
`
const spaceUpdate = `

View File

@ -0,0 +1,36 @@
[
{
"id": 1,
"name": "repo1",
"spaceId": 1,
"fqn": "space1/repo1",
"displayName": "Repository 1",
"description": "Some repository.",
"isPublic": true,
"createdBy": 1,
"created": 1662427496787,
"updated": 1662427496787,
"forkId": 0,
"numForks": 0,
"numPulls": 0,
"numClosedPulls": 0,
"numOpenPulls": 0
},
{
"id": 2,
"name": "repo2",
"spaceId": 2,
"fqn": "space1/space2/repo2",
"displayName": "Repository 2",
"description": "Some other repository.",
"isPublic": true,
"createdBy": 1,
"created": 1662427602488,
"updated": 1662427602488,
"forkId": 0,
"numForks": 0,
"numPulls": 0,
"numClosedPulls": 0,
"numOpenPulls": 0
}
]

View File

@ -0,0 +1,26 @@
[
{
"id": 1,
"name": "space1",
"fqn": "space1",
"parentId": 0,
"displayName": "Space 1",
"description": "Some space.",
"isPublic": true,
"createdBy": 1,
"created": 1662427417128,
"updated": 1662427417128
},
{
"id": 2,
"name": "space2",
"fqn": "space1/space2",
"parentId": 1,
"displayName": "Space 2",
"description": "Some subspace.",
"isPublic": true,
"createdBy": 1,
"created": 1662427428536,
"updated": 1662427428536
}
]

View File

@ -1,6 +1,6 @@
[
{
"id": 0,
"id": 1,
"email": "jane@example.com",
"name": "jane",
"company": "acme",
@ -11,7 +11,7 @@
"authed": 0
},
{
"id": 0,
"id": 2,
"email": "john@example.com",
"name": "john",
"company": "acme",

View File

@ -5,5 +5,5 @@
// Package mocks provides mock interfaces.
package mocks
//go:generate mockgen -package=mocks -destination=mock_store.go github.com/harness/gitness/internal/store SystemStore,UserStore
//go:generate mockgen -package=mocks -destination=mock_store.go github.com/harness/gitness/internal/store SystemStore,UserStore,SpaceStore,RepoStore
//go:generate mockgen -package=mocks -destination=mock_client.go github.com/harness/gitness/client Client

View File

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/harness/gitness/internal/store (interfaces: SystemStore,UserStore)
// Source: github.com/harness/gitness/internal/store (interfaces: SystemStore,UserStore,SpaceStore,RepoStore)
// Package mocks is a generated GoMock package.
package mocks
@ -188,3 +188,253 @@ func (mr *MockUserStoreMockRecorder) Update(arg0, arg1 interface{}) *gomock.Call
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockUserStore)(nil).Update), arg0, arg1)
}
// MockSpaceStore is a mock of SpaceStore interface.
type MockSpaceStore struct {
ctrl *gomock.Controller
recorder *MockSpaceStoreMockRecorder
}
// MockSpaceStoreMockRecorder is the mock recorder for MockSpaceStore.
type MockSpaceStoreMockRecorder struct {
mock *MockSpaceStore
}
// NewMockSpaceStore creates a new mock instance.
func NewMockSpaceStore(ctrl *gomock.Controller) *MockSpaceStore {
mock := &MockSpaceStore{ctrl: ctrl}
mock.recorder = &MockSpaceStoreMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockSpaceStore) EXPECT() *MockSpaceStoreMockRecorder {
return m.recorder
}
// Count mocks base method.
func (m *MockSpaceStore) Count(arg0 context.Context, arg1 int64) (int64, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Count", arg0, arg1)
ret0, _ := ret[0].(int64)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Count indicates an expected call of Count.
func (mr *MockSpaceStoreMockRecorder) Count(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Count", reflect.TypeOf((*MockSpaceStore)(nil).Count), arg0, arg1)
}
// Create mocks base method.
func (m *MockSpaceStore) Create(arg0 context.Context, arg1 *types.Space) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Create", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// Create indicates an expected call of Create.
func (mr *MockSpaceStoreMockRecorder) Create(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockSpaceStore)(nil).Create), arg0, arg1)
}
// Delete mocks base method.
func (m *MockSpaceStore) Delete(arg0 context.Context, arg1 int64) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// Delete indicates an expected call of Delete.
func (mr *MockSpaceStoreMockRecorder) Delete(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockSpaceStore)(nil).Delete), arg0, arg1)
}
// Find mocks base method.
func (m *MockSpaceStore) Find(arg0 context.Context, arg1 int64) (*types.Space, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Find", arg0, arg1)
ret0, _ := ret[0].(*types.Space)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Find indicates an expected call of Find.
func (mr *MockSpaceStoreMockRecorder) Find(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Find", reflect.TypeOf((*MockSpaceStore)(nil).Find), arg0, arg1)
}
// FindFqn mocks base method.
func (m *MockSpaceStore) FindFqn(arg0 context.Context, arg1 string) (*types.Space, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindFqn", arg0, arg1)
ret0, _ := ret[0].(*types.Space)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindFqn indicates an expected call of FindFqn.
func (mr *MockSpaceStoreMockRecorder) FindFqn(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindFqn", reflect.TypeOf((*MockSpaceStore)(nil).FindFqn), arg0, arg1)
}
// List mocks base method.
func (m *MockSpaceStore) List(arg0 context.Context, arg1 int64, arg2 types.SpaceFilter) ([]*types.Space, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "List", arg0, arg1, arg2)
ret0, _ := ret[0].([]*types.Space)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// List indicates an expected call of List.
func (mr *MockSpaceStoreMockRecorder) List(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockSpaceStore)(nil).List), arg0, arg1, arg2)
}
// Update mocks base method.
func (m *MockSpaceStore) Update(arg0 context.Context, arg1 *types.Space) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Update", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// Update indicates an expected call of Update.
func (mr *MockSpaceStoreMockRecorder) Update(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockSpaceStore)(nil).Update), arg0, arg1)
}
// MockRepoStore is a mock of RepoStore interface.
type MockRepoStore struct {
ctrl *gomock.Controller
recorder *MockRepoStoreMockRecorder
}
// MockRepoStoreMockRecorder is the mock recorder for MockRepoStore.
type MockRepoStoreMockRecorder struct {
mock *MockRepoStore
}
// NewMockRepoStore creates a new mock instance.
func NewMockRepoStore(ctrl *gomock.Controller) *MockRepoStore {
mock := &MockRepoStore{ctrl: ctrl}
mock.recorder = &MockRepoStoreMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockRepoStore) EXPECT() *MockRepoStoreMockRecorder {
return m.recorder
}
// Count mocks base method.
func (m *MockRepoStore) Count(arg0 context.Context, arg1 int64) (int64, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Count", arg0, arg1)
ret0, _ := ret[0].(int64)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Count indicates an expected call of Count.
func (mr *MockRepoStoreMockRecorder) Count(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Count", reflect.TypeOf((*MockRepoStore)(nil).Count), arg0, arg1)
}
// Create mocks base method.
func (m *MockRepoStore) Create(arg0 context.Context, arg1 *types.Repository) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Create", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// Create indicates an expected call of Create.
func (mr *MockRepoStoreMockRecorder) Create(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockRepoStore)(nil).Create), arg0, arg1)
}
// Delete mocks base method.
func (m *MockRepoStore) Delete(arg0 context.Context, arg1 int64) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// Delete indicates an expected call of Delete.
func (mr *MockRepoStoreMockRecorder) Delete(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockRepoStore)(nil).Delete), arg0, arg1)
}
// Find mocks base method.
func (m *MockRepoStore) Find(arg0 context.Context, arg1 int64) (*types.Repository, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Find", arg0, arg1)
ret0, _ := ret[0].(*types.Repository)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Find indicates an expected call of Find.
func (mr *MockRepoStoreMockRecorder) Find(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Find", reflect.TypeOf((*MockRepoStore)(nil).Find), arg0, arg1)
}
// FindFqn mocks base method.
func (m *MockRepoStore) FindFqn(arg0 context.Context, arg1 string) (*types.Repository, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindFqn", arg0, arg1)
ret0, _ := ret[0].(*types.Repository)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindFqn indicates an expected call of FindFqn.
func (mr *MockRepoStoreMockRecorder) FindFqn(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindFqn", reflect.TypeOf((*MockRepoStore)(nil).FindFqn), arg0, arg1)
}
// List mocks base method.
func (m *MockRepoStore) List(arg0 context.Context, arg1 int64, arg2 types.RepoFilter) ([]*types.Repository, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "List", arg0, arg1, arg2)
ret0, _ := ret[0].([]*types.Repository)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// List indicates an expected call of List.
func (mr *MockRepoStoreMockRecorder) List(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockRepoStore)(nil).List), arg0, arg1, arg2)
}
// Update mocks base method.
func (m *MockRepoStore) Update(arg0 context.Context, arg1 *types.Repository) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Update", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// Update indicates an expected call of Update.
func (mr *MockRepoStoreMockRecorder) Update(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockRepoStore)(nil).Update), arg0, arg1)
}

View File

@ -26,7 +26,7 @@ var (
ErrRepoNameLength = errors.New(fmt.Sprintf("Repository name has to be between %d and %d in length.", minRepoNameLength, maxRepoNameLength))
ErrRepoNameRegex = errors.New("Repository name has start with a letter and only contain the following [a-z0-9-_].")
ErrRepoDisplayNameLength = errors.New(fmt.Sprintf("Repository name has to be between %d and %d in length.", minRepoDisplayNameLength, maxRepoDisplayNameLength))
ErrRepoDisplayNameLength = errors.New(fmt.Sprintf("Repository display name has to be between %d and %d in length.", minRepoDisplayNameLength, maxRepoDisplayNameLength))
ErrRepoDisplayNameRegex = errors.New("Repository display name has start with a letter and only contain the following [a-zA-Z0-9-_ ].")
)

View File

@ -8,6 +8,7 @@ import (
"errors"
"fmt"
"regexp"
"strings"
"github.com/harness/gitness/types"
)
@ -26,8 +27,11 @@ var (
ErrSpaceNameLength = errors.New(fmt.Sprintf("Space name has to be between %d and %d in length.", minSpaceNameLength, maxSpaceNameLength))
ErrSpaceNameRegex = errors.New("Space name has start with a letter and only contain the following [a-z0-9-_].")
ErrSpaceDisplayNameLength = errors.New(fmt.Sprintf("Space name has to be between %d and %d in length.", minSpaceDisplayNameLength, maxSpaceDisplayNameLength))
ErrSpaceDisplayNameLength = errors.New(fmt.Sprintf("Space display name has to be between %d and %d in length.", minSpaceDisplayNameLength, maxSpaceDisplayNameLength))
ErrSpaceDisplayNameRegex = errors.New("Space display name has start with a letter and only contain the following [a-zA-Z0-9-_ ].")
illegalRootSpaceNames = []string{"api"}
ErrRootSpaceNameNotAllowed = errors.New(fmt.Sprintf("The following names are not allowed for a root space: %v", illegalRootSpaceNames))
)
// User returns true if the User if valid.
@ -50,5 +54,14 @@ func Space(space *types.Space) (bool, error) {
return false, ErrSpaceDisplayNameRegex
}
// root space specific validations
if space.ParentId <= 0 {
for _, p := range illegalRootSpaceNames {
if strings.HasPrefix(space.Name, p) {
return false, ErrRootSpaceNameNotAllowed
}
}
}
return true, nil
}