From e4a6c6aa7eecad2ef63c527aacdd884abb9ea7aa Mon Sep 17 00:00:00 2001 From: Petri-Johan Last Date: Wed, 28 Dec 2022 10:44:07 +0200 Subject: [PATCH] authz: Move sub-repo perms to enterprise (#45659) --- cmd/frontend/backend/user_emails_test.go | 6 - .../graphqlbackend/user_emails_test.go | 4 - cmd/frontend/internal/cli/serve_cmd.go | 2 - cmd/gitserver/main.go | 2 +- cmd/gitserver/shared/shared.go | 9 +- cmd/worker/main.go | 2 +- cmd/worker/shared/init/db/db.go | 8 - cmd/worker/shared/main.go | 15 +- dev/check/go-dbconn-import.sh | 1 + .../background-information/sg/reference.md | 3 + .../cmd/frontend/internal/authz/init.go | 8 + .../internal/authz/resolvers/resolver.go | 5 +- .../internal/authz/resolvers/resolver_test.go | 4 +- enterprise/cmd/gitserver/main.go | 14 + enterprise/cmd/gitserver/shared/shared.go | 23 + .../shared/shared.go | 4 +- .../internal/authz/perms_syncer.go | 4 +- .../internal/authz/perms_syncer_test.go | 8 +- enterprise/cmd/repo-updater/shared/shared.go | 13 +- enterprise/cmd/worker/main.go | 19 +- .../internal/authz/perforce/protects_test.go | 3 +- .../internal/authz/subrepoperms/mocks_temp.go | 429 +++++ .../authz/subrepoperms/sub_repo_perms.go | 401 ++++ .../authz/subrepoperms/sub_repo_perms_test.go | 430 +++++ enterprise/internal/database/authz.go | 9 +- enterprise/internal/database/database.go | 5 + enterprise/internal/database/mocks_temp.go | 1547 +++++++++++++++- .../database/sub_repo_perms_store.go | 8 +- .../database/sub_repo_perms_store_test.go | 15 +- .../integration_tests/commits_test.go | 158 ++ .../gitserver/integration_tests/tree_test.go | 74 + .../internal/search/symbol/symbol_test.go | 60 + internal/authz/mocks_temp.go | 413 ----- internal/authz/sub_repo_perms.go | 346 ---- internal/authz/sub_repo_perms_test.go | 420 ----- internal/database/database.go | 5 - internal/database/mocks_temp.go | 1636 ----------------- .../integration_tests/commits_test.go | 94 +- .../gitserver/integration_tests/main_test.go | 116 +- .../integration_tests/object_test.go | 2 +- .../gitserver/integration_tests/test_utils.go | 121 ++ .../gitserver/integration_tests/tree_test.go | 65 +- internal/search/symbol/symbol.go | 4 +- internal/search/symbol/symbol_test.go | 51 - mockgen.temp.yaml | 5 +- sg.config.yaml | 43 +- 46 files changed, 3398 insertions(+), 3216 deletions(-) create mode 100644 enterprise/cmd/gitserver/main.go create mode 100644 enterprise/cmd/gitserver/shared/shared.go create mode 100644 enterprise/internal/authz/subrepoperms/mocks_temp.go create mode 100644 enterprise/internal/authz/subrepoperms/sub_repo_perms.go create mode 100644 enterprise/internal/authz/subrepoperms/sub_repo_perms_test.go rename {internal => enterprise/internal}/database/sub_repo_perms_store.go (97%) rename {internal => enterprise/internal}/database/sub_repo_perms_store_test.go (95%) create mode 100644 enterprise/internal/gitserver/integration_tests/commits_test.go create mode 100644 enterprise/internal/gitserver/integration_tests/tree_test.go create mode 100644 enterprise/internal/search/symbol/symbol_test.go create mode 100644 internal/gitserver/integration_tests/test_utils.go diff --git a/cmd/frontend/backend/user_emails_test.go b/cmd/frontend/backend/user_emails_test.go index 334b1c388f1..4cde083f4ba 100644 --- a/cmd/frontend/backend/user_emails_test.go +++ b/cmd/frontend/backend/user_emails_test.go @@ -15,7 +15,6 @@ import ( "github.com/sourcegraph/sourcegraph/cmd/frontend/envvar" "github.com/sourcegraph/sourcegraph/internal/actor" "github.com/sourcegraph/sourcegraph/internal/api" - "github.com/sourcegraph/sourcegraph/internal/authz" "github.com/sourcegraph/sourcegraph/internal/conf" "github.com/sourcegraph/sourcegraph/internal/database" "github.com/sourcegraph/sourcegraph/internal/database/dbtest" @@ -489,11 +488,6 @@ func TestRemoveStalePerforceAccount(t *testing.T) { }) require.NoError(t, err) require.Len(t, accounts, 1) - - // We also want to add some fake sub-repo permissions and check that they are - // deleted - err = db.SubRepoPerms().Upsert(ctx, createdUser.ID, createdRepo.ID, authz.SubRepoPermissions{Paths: []string{"**"}}) - require.NoError(t, err) } assertRemovals := func(t *testing.T) { diff --git a/cmd/frontend/graphqlbackend/user_emails_test.go b/cmd/frontend/graphqlbackend/user_emails_test.go index 008a5704d44..1901b66a5d5 100644 --- a/cmd/frontend/graphqlbackend/user_emails_test.go +++ b/cmd/frontend/graphqlbackend/user_emails_test.go @@ -232,9 +232,6 @@ func TestSetUserEmailVerified(t *testing.T) { userExternalAccounts := database.NewMockUserExternalAccountsStore() userExternalAccounts.DeleteFunc.SetDefaultReturn(nil) - subrepoPerms := database.NewMockSubRepoPermsStore() - subrepoPerms.DeleteByUserFunc.SetDefaultReturn(nil) - db := database.NewMockDB() db.TransactFunc.SetDefaultReturn(db, nil) db.DoneFunc.SetDefaultHook(func(err error) error { @@ -245,7 +242,6 @@ func TestSetUserEmailVerified(t *testing.T) { db.UserEmailsFunc.SetDefaultReturn(userEmails) db.AuthzFunc.SetDefaultReturn(authz) db.UserExternalAccountsFunc.SetDefaultReturn(userExternalAccounts) - db.SubRepoPermsFunc.SetDefaultReturn(subrepoPerms) RunTests(t, test.gqlTests(db)) diff --git a/cmd/frontend/internal/cli/serve_cmd.go b/cmd/frontend/internal/cli/serve_cmd.go index 7b194332436..18bfb1ebc2c 100644 --- a/cmd/frontend/internal/cli/serve_cmd.go +++ b/cmd/frontend/internal/cli/serve_cmd.go @@ -29,7 +29,6 @@ import ( "github.com/sourcegraph/sourcegraph/cmd/frontend/internal/siteid" oce "github.com/sourcegraph/sourcegraph/cmd/frontend/oneclickexport" "github.com/sourcegraph/sourcegraph/internal/adminanalytics" - "github.com/sourcegraph/sourcegraph/internal/authz" "github.com/sourcegraph/sourcegraph/internal/conf" "github.com/sourcegraph/sourcegraph/internal/conf/conftypes" "github.com/sourcegraph/sourcegraph/internal/conf/deploy" @@ -169,7 +168,6 @@ func Main(enterpriseSetupHook func(database.DB, conftypes.UnifiedWatchable) ente // Run enterprise setup hook enterprise := enterpriseSetupHook(db, conf.DefaultClient()) - authz.DefaultSubRepoPermsChecker, err = authz.NewSubRepoPermsClient(db.SubRepoPerms()) if err != nil { return errors.Wrap(err, "Failed to create sub-repo client") } diff --git a/cmd/gitserver/main.go b/cmd/gitserver/main.go index f9ed21bf67d..3f6d675f9f4 100644 --- a/cmd/gitserver/main.go +++ b/cmd/gitserver/main.go @@ -10,5 +10,5 @@ func main() { env.Lock() env.HandleHelpFlag() - shared.Main() + shared.Main(nil) } diff --git a/cmd/gitserver/shared/shared.go b/cmd/gitserver/shared/shared.go index cdaa20bfd9b..60308f61af3 100644 --- a/cmd/gitserver/shared/shared.go +++ b/cmd/gitserver/shared/shared.go @@ -75,7 +75,9 @@ var ( rateLimitSyncerLimitPerSecond = env.MustGetInt("SRC_REPOS_SYNC_RATE_LIMIT_RATE_PER_SECOND", 80, "Rate limit applied to rate limit syncing") ) -func Main() { +type EnterpriseInit func(db database.DB) + +func Main(enterpriseInit EnterpriseInit) { ctx := context.Background() logging.Init() //nolint:staticcheck // Deprecated, but logs unmigrated to sourcegraph/log look really bad without this. @@ -127,7 +129,10 @@ func Main() { logger.Fatal("failed to initialise keyring", log.Error(err)) } - authz.DefaultSubRepoPermsChecker, err = authz.NewSubRepoPermsClient(db.SubRepoPerms()) + if enterpriseInit != nil { + enterpriseInit(db) + } + if err != nil { logger.Fatal("Failed to create sub-repo client", log.Error(err)) } diff --git a/cmd/worker/main.go b/cmd/worker/main.go index 42e1ee16347..bd26bca04d1 100644 --- a/cmd/worker/main.go +++ b/cmd/worker/main.go @@ -23,7 +23,7 @@ func main() { observationCtx := observation.NewContext(logger) authz.SetProviders(true, []authz.Provider{}) - if err := shared.Start(observationCtx, nil, nil); err != nil { + if err := shared.Start(observationCtx, nil, nil, nil); err != nil { logger.Error(err.Error()) os.Exit(1) } diff --git a/cmd/worker/shared/init/db/db.go b/cmd/worker/shared/init/db/db.go index fa1e2bce8bc..fb1484ab59c 100644 --- a/cmd/worker/shared/init/db/db.go +++ b/cmd/worker/shared/init/db/db.go @@ -3,9 +3,6 @@ package workerdb import ( "database/sql" - "github.com/sourcegraph/log" - - "github.com/sourcegraph/sourcegraph/internal/authz" "github.com/sourcegraph/sourcegraph/internal/conf" "github.com/sourcegraph/sourcegraph/internal/conf/conftypes" "github.com/sourcegraph/sourcegraph/internal/database" @@ -33,10 +30,5 @@ var initDatabaseMemo = memo.NewMemoizedConstructorWithArg(func(observationCtx *o return nil, errors.Errorf("failed to connect to frontend database: %s", err) } - // ideally we could memoize the LRU cache only for this, and then create new clients on-demand with a passed-in observationCtx - authz.DefaultSubRepoPermsChecker, err = authz.NewSubRepoPermsClient(database.NewDB(log.Scoped("initDatabaseMemo", ""), db).SubRepoPerms()) - if err != nil { - return nil, errors.Errorf("Failed to create sub-repo client: %v", err) - } return db, nil }) diff --git a/cmd/worker/shared/main.go b/cmd/worker/shared/main.go index a789ba66c3b..82f8339cad3 100644 --- a/cmd/worker/shared/main.go +++ b/cmd/worker/shared/main.go @@ -20,7 +20,9 @@ import ( "github.com/sourcegraph/sourcegraph/cmd/worker/internal/webhooks" "github.com/sourcegraph/sourcegraph/cmd/worker/internal/zoektrepos" "github.com/sourcegraph/sourcegraph/cmd/worker/job" + workerdb "github.com/sourcegraph/sourcegraph/cmd/worker/shared/init/db" "github.com/sourcegraph/sourcegraph/internal/conf" + "github.com/sourcegraph/sourcegraph/internal/database" "github.com/sourcegraph/sourcegraph/internal/debugserver" "github.com/sourcegraph/sourcegraph/internal/encryption/keyring" "github.com/sourcegraph/sourcegraph/internal/env" @@ -37,8 +39,10 @@ import ( const addr = ":3189" +type EnterpriseInit = func(ossDB database.DB) + // Start runs the worker. -func Start(observationCtx *observation.Context, additionalJobs map[string]job.Job, registerEnterpriseMigrators oobmigration.RegisterMigratorsFunc) error { +func Start(observationCtx *observation.Context, additionalJobs map[string]job.Job, registerEnterpriseMigrators oobmigration.RegisterMigratorsFunc, enterpriseInit EnterpriseInit) error { registerMigrators := oobmigration.ComposeRegisterMigratorsFuncs(migrations.RegisterOSSMigrators, registerEnterpriseMigrators) builtins := map[string]job.Job{ @@ -73,6 +77,15 @@ func Start(observationCtx *observation.Context, additionalJobs map[string]job.Jo return errors.Wrap(err, "Failed to intialise keyring") } + if enterpriseInit != nil { + db, err := workerdb.InitDB(observationCtx) + if err != nil { + return errors.Wrap(err, "Failed to create database connection") + } + + enterpriseInit(db) + } + // Start debug server ready := make(chan struct{}) go debugserver.NewServerRoutine(ready).Start() diff --git a/dev/check/go-dbconn-import.sh b/dev/check/go-dbconn-import.sh index 0513f2883c0..c3bab06cc46 100755 --- a/dev/check/go-dbconn-import.sh +++ b/dev/check/go-dbconn-import.sh @@ -17,6 +17,7 @@ allowed_prefix=( github.com/sourcegraph/sourcegraph/cmd/repo-updater github.com/sourcegraph/sourcegraph/cmd/migrator github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend + github.com/sourcegraph/sourcegraph/enterprise/cmd/gitserver github.com/sourcegraph/sourcegraph/enterprise/cmd/worker github.com/sourcegraph/sourcegraph/enterprise/cmd/repo-updater github.com/sourcegraph/sourcegraph/enterprise/cmd/migrator diff --git a/doc/dev/background-information/sg/reference.md b/doc/dev/background-information/sg/reference.md index 4360fd82e06..6bdc96f2c9e 100644 --- a/doc/dev/background-information/sg/reference.md +++ b/doc/dev/background-information/sg/reference.md @@ -108,6 +108,9 @@ Available commands in `sg.config.yaml`: * loki * monitoring-generator * oss-frontend +* oss-gitserver-0 +* oss-gitserver-1 +* oss-gitserver-template * oss-repo-updater * oss-symbols * oss-web: Open source version of the web app diff --git a/enterprise/cmd/frontend/internal/authz/init.go b/enterprise/cmd/frontend/internal/authz/init.go index 52fd2d98eae..0413cf955e8 100644 --- a/enterprise/cmd/frontend/internal/authz/init.go +++ b/enterprise/cmd/frontend/internal/authz/init.go @@ -16,6 +16,7 @@ import ( "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/authz/webhooks" "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/licensing/enforcement" eiauthz "github.com/sourcegraph/sourcegraph/enterprise/internal/authz" + srp "github.com/sourcegraph/sourcegraph/enterprise/internal/authz/subrepoperms" "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel" edb "github.com/sourcegraph/sourcegraph/enterprise/internal/database" "github.com/sourcegraph/sourcegraph/enterprise/internal/licensing" @@ -29,6 +30,7 @@ import ( "github.com/sourcegraph/sourcegraph/internal/extsvc" "github.com/sourcegraph/sourcegraph/internal/observation" "github.com/sourcegraph/sourcegraph/internal/timeutil" + "github.com/sourcegraph/sourcegraph/lib/errors" ) var clock = timeutil.Now @@ -70,6 +72,12 @@ func Init( enterpriseServices.PermissionsGitHubWebhook = webhooks.NewGitHubWebhook(log.Scoped("PermissionsGitHubWebhook", "permissions sync webhook handler for GitHub webhooks")) + var err error + authz.DefaultSubRepoPermsChecker, err = srp.NewSubRepoPermsClient(edb.NewEnterpriseDB(db).SubRepoPerms()) + if err != nil { + return errors.Wrap(err, "Failed to createe sub-repo client") + } + // Warn about usage of authz providers that are not enabled by the license. graphqlbackend.AlertFuncs = append(graphqlbackend.AlertFuncs, func(args graphqlbackend.AlertFuncArgs) []*graphqlbackend.Alert { // Only site admins can act on this alert, so only show it to site admins. diff --git a/enterprise/cmd/frontend/internal/authz/resolvers/resolver.go b/enterprise/cmd/frontend/internal/authz/resolvers/resolver.go index b68fddf27b8..37ea7391048 100644 --- a/enterprise/cmd/frontend/internal/authz/resolvers/resolver.go +++ b/enterprise/cmd/frontend/internal/authz/resolvers/resolver.go @@ -238,11 +238,12 @@ func (r *Resolver) SetSubRepositoryPermissionsForUsers(ctx context.Context, args return nil, err } - db, err := r.db.Transact(ctx) + ossDB, err := r.db.Transact(ctx) if err != nil { return nil, errors.Wrap(err, "start transaction") } - defer func() { err = db.Done(err) }() + defer func() { err = ossDB.Done(err) }() + db := edb.NewEnterpriseDB(ossDB) // Make sure the repo ID is valid. if _, err = db.Repos().Get(ctx, repoID); err != nil { diff --git a/enterprise/cmd/frontend/internal/authz/resolvers/resolver_test.go b/enterprise/cmd/frontend/internal/authz/resolvers/resolver_test.go index 532c7d08a7e..adb2864ee10 100644 --- a/enterprise/cmd/frontend/internal/authz/resolvers/resolver_test.go +++ b/enterprise/cmd/frontend/internal/authz/resolvers/resolver_test.go @@ -1335,7 +1335,7 @@ func TestResolver_SetSubRepositoryPermissionsForUsers(t *testing.T) { users := database.NewStrictMockUserStore() users.GetByCurrentAuthUserFunc.SetDefaultReturn(&types.User{}, nil) - subrepos := database.NewStrictMockSubRepoPermsStore() + subrepos := edb.NewStrictMockSubRepoPermsStore() subrepos.UpsertFunc.SetDefaultHook(func(ctx context.Context, i int32, id api.RepoID, permissions authz.SubRepoPermissions) error { return nil }) @@ -1373,7 +1373,7 @@ func TestResolver_SetSubRepositoryPermissionsForUsers(t *testing.T) { }, nil }) - subReposStore := database.NewStrictMockSubRepoPermsStore() + subReposStore := edb.NewStrictMockSubRepoPermsStore() subReposStore.UpsertFunc.SetDefaultHook(func(ctx context.Context, i int32, id api.RepoID, permissions authz.SubRepoPermissions) error { return nil }) diff --git a/enterprise/cmd/gitserver/main.go b/enterprise/cmd/gitserver/main.go new file mode 100644 index 00000000000..501ea25f275 --- /dev/null +++ b/enterprise/cmd/gitserver/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "github.com/sourcegraph/sourcegraph/cmd/gitserver/shared" + enterprise_shared "github.com/sourcegraph/sourcegraph/enterprise/cmd/gitserver/shared" + "github.com/sourcegraph/sourcegraph/internal/env" +) + +func main() { + env.Lock() + env.HandleHelpFlag() + + shared.Main(enterprise_shared.EnterpriseInit) +} diff --git a/enterprise/cmd/gitserver/shared/shared.go b/enterprise/cmd/gitserver/shared/shared.go new file mode 100644 index 00000000000..7a561aca154 --- /dev/null +++ b/enterprise/cmd/gitserver/shared/shared.go @@ -0,0 +1,23 @@ +// Package shared is the enterprise gitserrver program's shared main entrypoint. +// +// It lets the invoker of the OSS gitserver shared entrypoint inject a few +// proprietary things into it via e.g. blank/underscore imports in this file +// which register side effects with the gitserver package. +package shared + +import ( + "github.com/sourcegraph/log" + srp "github.com/sourcegraph/sourcegraph/enterprise/internal/authz/subrepoperms" + edb "github.com/sourcegraph/sourcegraph/enterprise/internal/database" + "github.com/sourcegraph/sourcegraph/internal/authz" + "github.com/sourcegraph/sourcegraph/internal/database" +) + +func EnterpriseInit(db database.DB) { + logger := log.Scoped("enterprise", "gitserver enterprise edition") + var err error + authz.DefaultSubRepoPermsChecker, err = srp.NewSubRepoPermsClient(edb.NewEnterpriseDB(db).SubRepoPerms()) + if err != nil { + logger.Fatal("Failed to create sub-repo client", log.Error(err)) + } +} diff --git a/enterprise/cmd/precise-code-intel-worker/shared/shared.go b/enterprise/cmd/precise-code-intel-worker/shared/shared.go index ad3d68df871..466efb554b1 100644 --- a/enterprise/cmd/precise-code-intel-worker/shared/shared.go +++ b/enterprise/cmd/precise-code-intel-worker/shared/shared.go @@ -10,10 +10,12 @@ import ( "github.com/sourcegraph/log" eiauthz "github.com/sourcegraph/sourcegraph/enterprise/internal/authz" + srp "github.com/sourcegraph/sourcegraph/enterprise/internal/authz/subrepoperms" "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel" codeintelshared "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/shared" "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/shared/lsifuploadstore" "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/uploads" + edb "github.com/sourcegraph/sourcegraph/enterprise/internal/database" "github.com/sourcegraph/sourcegraph/internal/authz" "github.com/sourcegraph/sourcegraph/internal/conf" "github.com/sourcegraph/sourcegraph/internal/conf/conftypes" @@ -85,7 +87,7 @@ func Main() { // Initialize sub-repo permissions client var err error - authz.DefaultSubRepoPermsChecker, err = authz.NewSubRepoPermsClient(db.SubRepoPerms()) + authz.DefaultSubRepoPermsChecker, err = srp.NewSubRepoPermsClient(edb.NewEnterpriseDB(db).SubRepoPerms()) if err != nil { logger.Fatal("Failed to create sub-repo client", log.Error(err)) } diff --git a/enterprise/cmd/repo-updater/internal/authz/perms_syncer.go b/enterprise/cmd/repo-updater/internal/authz/perms_syncer.go index 069fa0390ef..a069df5444d 100644 --- a/enterprise/cmd/repo-updater/internal/authz/perms_syncer.go +++ b/enterprise/cmd/repo-updater/internal/authz/perms_syncer.go @@ -428,7 +428,7 @@ func (s *PermsSyncer) fetchUserPermsViaExternalAccounts(ctx context.Context, use extPerms = new(authz.ExternalUserPermissions) // Load last synced sub-repo perms for this user and provider - currentSubRepoPerms, err := s.db.SubRepoPerms().GetByUserAndService(ctx, user.ID, provider.ServiceType(), provider.ServiceID()) + currentSubRepoPerms, err := edb.NewEnterpriseDB(s.db).SubRepoPerms().GetByUserAndService(ctx, user.ID, provider.ServiceType(), provider.ServiceID()) if err != nil { return results, errors.Wrap(err, "fetching existing sub-repo permissions") } @@ -598,7 +598,7 @@ func (s *PermsSyncer) syncUserPerms(ctx context.Context, userID int32, noPerms b } // Set sub-repository permissions - srp := s.db.SubRepoPerms() + srp := edb.NewEnterpriseDB(s.db).SubRepoPerms() for spec, perm := range results.subRepoPerms { if err := srp.UpsertWithSpec(ctx, user.ID, spec, *perm); err != nil { return providerStates, errors.Wrapf(err, "upserting sub repo perms %v for user %q (id: %d)", spec, user.Username, user.ID) diff --git a/enterprise/cmd/repo-updater/internal/authz/perms_syncer_test.go b/enterprise/cmd/repo-updater/internal/authz/perms_syncer_test.go index d2710493865..6379c8c5a18 100644 --- a/enterprise/cmd/repo-updater/internal/authz/perms_syncer_test.go +++ b/enterprise/cmd/repo-updater/internal/authz/perms_syncer_test.go @@ -304,10 +304,10 @@ func TestPermsSyncer_syncUserPermsTemporaryProviderError(t *testing.T) { return []*extsvc.Account{&extAccount}, nil }) - subRepoPerms := database.NewMockSubRepoPermsStore() + subRepoPerms := edb.NewMockSubRepoPermsStore() subRepoPerms.GetByUserAndServiceFunc.SetDefaultReturn(nil, nil) - db := database.NewMockDB() + db := edb.NewMockEnterpriseDB() db.UsersFunc.SetDefaultReturn(users) db.ReposFunc.SetDefaultReturn(mockRepos) db.UserEmailsFunc.SetDefaultReturn(userEmails) @@ -619,9 +619,9 @@ func TestPermsSyncer_syncUserPerms_subRepoPermissions(t *testing.T) { externalAccounts := database.NewMockUserExternalAccountsStore() externalAccounts.ListFunc.SetDefaultReturn([]*extsvc.Account{&extAccount}, nil) - subRepoPerms := database.NewMockSubRepoPermsStore() + subRepoPerms := edb.NewMockSubRepoPermsStore() - db := database.NewMockDB() + db := edb.NewMockEnterpriseDB() db.UsersFunc.SetDefaultReturn(users) db.ReposFunc.SetDefaultReturn(mockRepos) db.ExternalServicesFunc.SetDefaultReturn(externalServices) diff --git a/enterprise/cmd/repo-updater/shared/shared.go b/enterprise/cmd/repo-updater/shared/shared.go index 6e9fa34a46b..68d71aa24fc 100644 --- a/enterprise/cmd/repo-updater/shared/shared.go +++ b/enterprise/cmd/repo-updater/shared/shared.go @@ -70,13 +70,12 @@ func startBackgroundPermsSync(ctx context.Context, syncer *authz.PermsSyncer, db go func() { t := time.NewTicker(frontendAuthz.RefreshInterval()) for range t.C { - allowAccessByDefault, authzProviders, _, _, _ := - frontendAuthz.ProvidersFromConfig( - ctx, - conf.Get(), - db.ExternalServices(), - db, - ) + allowAccessByDefault, authzProviders, _, _, _ := frontendAuthz.ProvidersFromConfig( + ctx, + conf.Get(), + db.ExternalServices(), + db, + ) ossAuthz.SetProviders(allowAccessByDefault, authzProviders) } }() diff --git a/enterprise/cmd/worker/main.go b/enterprise/cmd/worker/main.go index c852633f7e5..65ce8e64368 100644 --- a/enterprise/cmd/worker/main.go +++ b/enterprise/cmd/worker/main.go @@ -5,13 +5,30 @@ import ( "github.com/sourcegraph/sourcegraph/cmd/worker/shared" enterprise_shared "github.com/sourcegraph/sourcegraph/enterprise/cmd/worker/shared" + srp "github.com/sourcegraph/sourcegraph/enterprise/internal/authz/subrepoperms" + edb "github.com/sourcegraph/sourcegraph/enterprise/internal/database" "github.com/sourcegraph/sourcegraph/enterprise/internal/oobmigration/migrations" + "github.com/sourcegraph/sourcegraph/internal/authz" + "github.com/sourcegraph/sourcegraph/internal/database" "github.com/sourcegraph/sourcegraph/internal/env" "github.com/sourcegraph/sourcegraph/internal/observation" "github.com/sourcegraph/sourcegraph/internal/oobmigration" "github.com/sourcegraph/sourcegraph/internal/version" ) +func getEnterpriseInit(logger log.Logger) func(database.DB) { + return func(ossDB database.DB) { + enterpriseDB := edb.NewEnterpriseDB(ossDB) + + var err error + authz.DefaultSubRepoPermsChecker, err = srp.NewSubRepoPermsClient(enterpriseDB.SubRepoPerms()) + if err != nil { + logger.Fatal("Failed to create sub-repo client", log.Error(err)) + } + } + +} + func main() { liblog := log.Init(log.Resource{ Name: env.MyName, @@ -24,7 +41,7 @@ func main() { go enterprise_shared.SetAuthzProviders(observationCtx) - if err := shared.Start(observationCtx, enterprise_shared.AdditionalJobs, migrations.RegisterEnterpriseMigrators); err != nil { + if err := shared.Start(observationCtx, enterprise_shared.AdditionalJobs, migrations.RegisterEnterpriseMigrators, getEnterpriseInit(logger)); err != nil { logger.Fatal(err.Error()) } } diff --git a/enterprise/internal/authz/perforce/protects_test.go b/enterprise/internal/authz/perforce/protects_test.go index f6db39109a3..66574ab2a8e 100644 --- a/enterprise/internal/authz/perforce/protects_test.go +++ b/enterprise/internal/authz/perforce/protects_test.go @@ -13,6 +13,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/sourcegraph/log/logtest" + srp "github.com/sourcegraph/sourcegraph/enterprise/internal/authz/subrepoperms" "github.com/sourcegraph/sourcegraph/internal/actor" "github.com/sourcegraph/sourcegraph/internal/api" "github.com/sourcegraph/sourcegraph/internal/authz" @@ -624,7 +625,7 @@ read group Dev1 * //depot/main/.../*.go } else if ok && tc.noRules { t.Fatal("expected no rules") } - checker, err := authz.NewSimpleChecker(api.RepoName(tc.depot), rules.Paths) + checker, err := srp.NewSimpleChecker(api.RepoName(tc.depot), rules.Paths) if err != nil { t.Fatal(err) } diff --git a/enterprise/internal/authz/subrepoperms/mocks_temp.go b/enterprise/internal/authz/subrepoperms/mocks_temp.go new file mode 100644 index 00000000000..0b4e0216e62 --- /dev/null +++ b/enterprise/internal/authz/subrepoperms/mocks_temp.go @@ -0,0 +1,429 @@ +// Code generated by go-mockgen 1.3.7; DO NOT EDIT. +// +// This file was generated by running `sg generate` (or `go-mockgen`) at the root of +// this repository. To add additional mocks to this or another package, add a new entry +// to the mockgen.yaml file in the root of this repository. + +package subrepoperms + +import ( + "context" + "sync" + + api "github.com/sourcegraph/sourcegraph/internal/api" + authz "github.com/sourcegraph/sourcegraph/internal/authz" +) + +// MockSubRepoPermissionsGetter is a mock implementation of the +// SubRepoPermissionsGetter interface (from the package +// github.com/sourcegraph/sourcegraph/enterprise/internal/authz/subrepoperms) +// used for unit testing. +type MockSubRepoPermissionsGetter struct { + // GetByUserFunc is an instance of a mock function object controlling + // the behavior of the method GetByUser. + GetByUserFunc *SubRepoPermissionsGetterGetByUserFunc + // RepoIDSupportedFunc is an instance of a mock function object + // controlling the behavior of the method RepoIDSupported. + RepoIDSupportedFunc *SubRepoPermissionsGetterRepoIDSupportedFunc + // RepoSupportedFunc is an instance of a mock function object + // controlling the behavior of the method RepoSupported. + RepoSupportedFunc *SubRepoPermissionsGetterRepoSupportedFunc +} + +// NewMockSubRepoPermissionsGetter creates a new mock of the +// SubRepoPermissionsGetter interface. All methods return zero values for +// all results, unless overwritten. +func NewMockSubRepoPermissionsGetter() *MockSubRepoPermissionsGetter { + return &MockSubRepoPermissionsGetter{ + GetByUserFunc: &SubRepoPermissionsGetterGetByUserFunc{ + defaultHook: func(context.Context, int32) (r0 map[api.RepoName]authz.SubRepoPermissions, r1 error) { + return + }, + }, + RepoIDSupportedFunc: &SubRepoPermissionsGetterRepoIDSupportedFunc{ + defaultHook: func(context.Context, api.RepoID) (r0 bool, r1 error) { + return + }, + }, + RepoSupportedFunc: &SubRepoPermissionsGetterRepoSupportedFunc{ + defaultHook: func(context.Context, api.RepoName) (r0 bool, r1 error) { + return + }, + }, + } +} + +// NewStrictMockSubRepoPermissionsGetter creates a new mock of the +// SubRepoPermissionsGetter interface. All methods panic on invocation, +// unless overwritten. +func NewStrictMockSubRepoPermissionsGetter() *MockSubRepoPermissionsGetter { + return &MockSubRepoPermissionsGetter{ + GetByUserFunc: &SubRepoPermissionsGetterGetByUserFunc{ + defaultHook: func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + panic("unexpected invocation of MockSubRepoPermissionsGetter.GetByUser") + }, + }, + RepoIDSupportedFunc: &SubRepoPermissionsGetterRepoIDSupportedFunc{ + defaultHook: func(context.Context, api.RepoID) (bool, error) { + panic("unexpected invocation of MockSubRepoPermissionsGetter.RepoIDSupported") + }, + }, + RepoSupportedFunc: &SubRepoPermissionsGetterRepoSupportedFunc{ + defaultHook: func(context.Context, api.RepoName) (bool, error) { + panic("unexpected invocation of MockSubRepoPermissionsGetter.RepoSupported") + }, + }, + } +} + +// NewMockSubRepoPermissionsGetterFrom creates a new mock of the +// MockSubRepoPermissionsGetter interface. All methods delegate to the given +// implementation, unless overwritten. +func NewMockSubRepoPermissionsGetterFrom(i SubRepoPermissionsGetter) *MockSubRepoPermissionsGetter { + return &MockSubRepoPermissionsGetter{ + GetByUserFunc: &SubRepoPermissionsGetterGetByUserFunc{ + defaultHook: i.GetByUser, + }, + RepoIDSupportedFunc: &SubRepoPermissionsGetterRepoIDSupportedFunc{ + defaultHook: i.RepoIDSupported, + }, + RepoSupportedFunc: &SubRepoPermissionsGetterRepoSupportedFunc{ + defaultHook: i.RepoSupported, + }, + } +} + +// SubRepoPermissionsGetterGetByUserFunc describes the behavior when the +// GetByUser method of the parent MockSubRepoPermissionsGetter instance is +// invoked. +type SubRepoPermissionsGetterGetByUserFunc struct { + defaultHook func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) + hooks []func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) + history []SubRepoPermissionsGetterGetByUserFuncCall + mutex sync.Mutex +} + +// GetByUser delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockSubRepoPermissionsGetter) GetByUser(v0 context.Context, v1 int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + r0, r1 := m.GetByUserFunc.nextHook()(v0, v1) + m.GetByUserFunc.appendCall(SubRepoPermissionsGetterGetByUserFuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the GetByUser method of +// the parent MockSubRepoPermissionsGetter instance is invoked and the hook +// queue is empty. +func (f *SubRepoPermissionsGetterGetByUserFunc) SetDefaultHook(hook func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// GetByUser method of the parent MockSubRepoPermissionsGetter instance +// invokes the hook at the front of the queue and discards it. After the +// queue is empty, the default hook function is invoked for any future +// action. +func (f *SubRepoPermissionsGetterGetByUserFunc) PushHook(hook func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *SubRepoPermissionsGetterGetByUserFunc) SetDefaultReturn(r0 map[api.RepoName]authz.SubRepoPermissions, r1 error) { + f.SetDefaultHook(func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *SubRepoPermissionsGetterGetByUserFunc) PushReturn(r0 map[api.RepoName]authz.SubRepoPermissions, r1 error) { + f.PushHook(func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + return r0, r1 + }) +} + +func (f *SubRepoPermissionsGetterGetByUserFunc) nextHook() func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *SubRepoPermissionsGetterGetByUserFunc) appendCall(r0 SubRepoPermissionsGetterGetByUserFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of SubRepoPermissionsGetterGetByUserFuncCall +// objects describing the invocations of this function. +func (f *SubRepoPermissionsGetterGetByUserFunc) History() []SubRepoPermissionsGetterGetByUserFuncCall { + f.mutex.Lock() + history := make([]SubRepoPermissionsGetterGetByUserFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// SubRepoPermissionsGetterGetByUserFuncCall is an object that describes an +// invocation of method GetByUser on an instance of +// MockSubRepoPermissionsGetter. +type SubRepoPermissionsGetterGetByUserFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int32 + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 map[api.RepoName]authz.SubRepoPermissions + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c SubRepoPermissionsGetterGetByUserFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c SubRepoPermissionsGetterGetByUserFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// SubRepoPermissionsGetterRepoIDSupportedFunc describes the behavior when +// the RepoIDSupported method of the parent MockSubRepoPermissionsGetter +// instance is invoked. +type SubRepoPermissionsGetterRepoIDSupportedFunc struct { + defaultHook func(context.Context, api.RepoID) (bool, error) + hooks []func(context.Context, api.RepoID) (bool, error) + history []SubRepoPermissionsGetterRepoIDSupportedFuncCall + mutex sync.Mutex +} + +// RepoIDSupported delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockSubRepoPermissionsGetter) RepoIDSupported(v0 context.Context, v1 api.RepoID) (bool, error) { + r0, r1 := m.RepoIDSupportedFunc.nextHook()(v0, v1) + m.RepoIDSupportedFunc.appendCall(SubRepoPermissionsGetterRepoIDSupportedFuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the RepoIDSupported +// method of the parent MockSubRepoPermissionsGetter instance is invoked and +// the hook queue is empty. +func (f *SubRepoPermissionsGetterRepoIDSupportedFunc) SetDefaultHook(hook func(context.Context, api.RepoID) (bool, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// RepoIDSupported method of the parent MockSubRepoPermissionsGetter +// instance invokes the hook at the front of the queue and discards it. +// After the queue is empty, the default hook function is invoked for any +// future action. +func (f *SubRepoPermissionsGetterRepoIDSupportedFunc) PushHook(hook func(context.Context, api.RepoID) (bool, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *SubRepoPermissionsGetterRepoIDSupportedFunc) SetDefaultReturn(r0 bool, r1 error) { + f.SetDefaultHook(func(context.Context, api.RepoID) (bool, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *SubRepoPermissionsGetterRepoIDSupportedFunc) PushReturn(r0 bool, r1 error) { + f.PushHook(func(context.Context, api.RepoID) (bool, error) { + return r0, r1 + }) +} + +func (f *SubRepoPermissionsGetterRepoIDSupportedFunc) nextHook() func(context.Context, api.RepoID) (bool, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *SubRepoPermissionsGetterRepoIDSupportedFunc) appendCall(r0 SubRepoPermissionsGetterRepoIDSupportedFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of +// SubRepoPermissionsGetterRepoIDSupportedFuncCall objects describing the +// invocations of this function. +func (f *SubRepoPermissionsGetterRepoIDSupportedFunc) History() []SubRepoPermissionsGetterRepoIDSupportedFuncCall { + f.mutex.Lock() + history := make([]SubRepoPermissionsGetterRepoIDSupportedFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// SubRepoPermissionsGetterRepoIDSupportedFuncCall is an object that +// describes an invocation of method RepoIDSupported on an instance of +// MockSubRepoPermissionsGetter. +type SubRepoPermissionsGetterRepoIDSupportedFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 api.RepoID + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 bool + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c SubRepoPermissionsGetterRepoIDSupportedFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c SubRepoPermissionsGetterRepoIDSupportedFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// SubRepoPermissionsGetterRepoSupportedFunc describes the behavior when the +// RepoSupported method of the parent MockSubRepoPermissionsGetter instance +// is invoked. +type SubRepoPermissionsGetterRepoSupportedFunc struct { + defaultHook func(context.Context, api.RepoName) (bool, error) + hooks []func(context.Context, api.RepoName) (bool, error) + history []SubRepoPermissionsGetterRepoSupportedFuncCall + mutex sync.Mutex +} + +// RepoSupported delegates to the next hook function in the queue and stores +// the parameter and result values of this invocation. +func (m *MockSubRepoPermissionsGetter) RepoSupported(v0 context.Context, v1 api.RepoName) (bool, error) { + r0, r1 := m.RepoSupportedFunc.nextHook()(v0, v1) + m.RepoSupportedFunc.appendCall(SubRepoPermissionsGetterRepoSupportedFuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the RepoSupported method +// of the parent MockSubRepoPermissionsGetter instance is invoked and the +// hook queue is empty. +func (f *SubRepoPermissionsGetterRepoSupportedFunc) SetDefaultHook(hook func(context.Context, api.RepoName) (bool, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// RepoSupported method of the parent MockSubRepoPermissionsGetter instance +// invokes the hook at the front of the queue and discards it. After the +// queue is empty, the default hook function is invoked for any future +// action. +func (f *SubRepoPermissionsGetterRepoSupportedFunc) PushHook(hook func(context.Context, api.RepoName) (bool, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *SubRepoPermissionsGetterRepoSupportedFunc) SetDefaultReturn(r0 bool, r1 error) { + f.SetDefaultHook(func(context.Context, api.RepoName) (bool, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *SubRepoPermissionsGetterRepoSupportedFunc) PushReturn(r0 bool, r1 error) { + f.PushHook(func(context.Context, api.RepoName) (bool, error) { + return r0, r1 + }) +} + +func (f *SubRepoPermissionsGetterRepoSupportedFunc) nextHook() func(context.Context, api.RepoName) (bool, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *SubRepoPermissionsGetterRepoSupportedFunc) appendCall(r0 SubRepoPermissionsGetterRepoSupportedFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of +// SubRepoPermissionsGetterRepoSupportedFuncCall objects describing the +// invocations of this function. +func (f *SubRepoPermissionsGetterRepoSupportedFunc) History() []SubRepoPermissionsGetterRepoSupportedFuncCall { + f.mutex.Lock() + history := make([]SubRepoPermissionsGetterRepoSupportedFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// SubRepoPermissionsGetterRepoSupportedFuncCall is an object that describes +// an invocation of method RepoSupported on an instance of +// MockSubRepoPermissionsGetter. +type SubRepoPermissionsGetterRepoSupportedFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 api.RepoName + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 bool + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c SubRepoPermissionsGetterRepoSupportedFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c SubRepoPermissionsGetterRepoSupportedFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} diff --git a/enterprise/internal/authz/subrepoperms/sub_repo_perms.go b/enterprise/internal/authz/subrepoperms/sub_repo_perms.go new file mode 100644 index 00000000000..823c715ff4b --- /dev/null +++ b/enterprise/internal/authz/subrepoperms/sub_repo_perms.go @@ -0,0 +1,401 @@ +package subrepoperms + +import ( + "context" + "strconv" + "strings" + "time" + + "github.com/gobwas/glob" + lru "github.com/hashicorp/golang-lru" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "go.uber.org/atomic" + "golang.org/x/sync/singleflight" + + "github.com/sourcegraph/sourcegraph/internal/api" + "github.com/sourcegraph/sourcegraph/internal/authz" + "github.com/sourcegraph/sourcegraph/internal/conf" + "github.com/sourcegraph/sourcegraph/lib/errors" +) + +// SubRepoPermissionsGetter allows getting sub repository permissions. +type SubRepoPermissionsGetter interface { + // GetByUser returns the sub repository permissions rules known for a user. + GetByUser(ctx context.Context, userID int32) (map[api.RepoName]authz.SubRepoPermissions, error) + + // RepoIDSupported returns true if repo with the given ID has sub-repo permissions. + RepoIDSupported(ctx context.Context, repoID api.RepoID) (bool, error) + + // RepoSupported returns true if repo with the given name has sub-repo permissions. + RepoSupported(ctx context.Context, repo api.RepoName) (bool, error) +} + +// SubRepoPermsClient is a concrete implementation of SubRepoPermissionChecker. +// Always use NewSubRepoPermsClient to instantiate an instance. +type SubRepoPermsClient struct { + permissionsGetter SubRepoPermissionsGetter + clock func() time.Time + since func(time.Time) time.Duration + + group *singleflight.Group + cache *lru.Cache + enabled *atomic.Bool +} + +const ( + defaultCacheSize = 1000 + defaultCacheTTL = 10 * time.Second +) + +// cachedRules caches the perms rules known for a particular user by repo. +type cachedRules struct { + rules map[api.RepoName]compiledRules + timestamp time.Time +} + +type path struct { + globPath glob.Glob + exclusion bool + // the original rule before it was compiled into a glob matcher + original string +} + +type compiledRules struct { + paths []path +} + +// GetPermissionsForPath tries to match a given path to a list of rules. +// Since the last applicable rule is the one that applies, the list is +// traversed in reverse, and the function returns as soon as a match is found. +// If no match is found, None is returned. +func (rules compiledRules) GetPermissionsForPath(path string) authz.Perms { + for i := len(rules.paths) - 1; i >= 0; i-- { + if rules.paths[i].globPath.Match(path) { + if rules.paths[i].exclusion { + return authz.None + } + return authz.Read + } + } + + // Return None if no rule matches + return authz.None +} + +// NewSubRepoPermsClient instantiates an instance of authz.SubRepoPermsClient +// which implements SubRepoPermissionChecker. +// +// SubRepoPermissionChecker is responsible for checking whether a user has access +// to data within a repo. Sub-repository permissions enforcement is on top of +// existing repository permissions, which means the user must already have access +// to the repository itself. The intention is for this client to be created once +// at startup and passed in to all places that need to check sub repo +// permissions. +// +// Note that sub-repo permissions are currently opt-in via the +// experimentalFeatures.enableSubRepoPermissions option. +func NewSubRepoPermsClient(permissionsGetter SubRepoPermissionsGetter) (*SubRepoPermsClient, error) { + cache, err := lru.New(defaultCacheSize) + if err != nil { + return nil, errors.Wrap(err, "creating LRU cache") + } + + enabled := atomic.NewBool(false) + + conf.Watch(func() { + c := conf.Get() + if c.ExperimentalFeatures == nil || c.ExperimentalFeatures.SubRepoPermissions == nil { + enabled.Store(false) + return + } + + cacheSize := c.ExperimentalFeatures.SubRepoPermissions.UserCacheSize + if cacheSize == 0 { + cacheSize = defaultCacheSize + } + cache.Resize(cacheSize) + enabled.Store(c.ExperimentalFeatures.SubRepoPermissions.Enabled) + }) + + return &SubRepoPermsClient{ + permissionsGetter: permissionsGetter, + clock: time.Now, + since: time.Since, + group: &singleflight.Group{}, + cache: cache, + enabled: enabled, + }, nil +} + +var ( + metricSubRepoPermsPermissionsDurationSuccess prometheus.Observer + metricSubRepoPermsPermissionsDurationError prometheus.Observer +) + +func init() { + // We cache the result of WithLabelValues since we call them in + // performance sensitive code. See BenchmarkFilterActorPaths. + metric := promauto.NewHistogramVec(prometheus.HistogramOpts{ + Name: "authz_sub_repo_perms_permissions_duration_seconds", + Help: "Time spent calculating permissions of a file for an actor.", + }, []string{"error"}) + metricSubRepoPermsPermissionsDurationSuccess = metric.WithLabelValues("false") + metricSubRepoPermsPermissionsDurationError = metric.WithLabelValues("true") +} + +var ( + metricSubRepoPermCacheHit prometheus.Counter + metricSubRepoPermCacheMiss prometheus.Counter +) + +func init() { + // We cache the result of WithLabelValues since we call them in + // performance sensitive code. See BenchmarkFilterActorPaths. + metric := promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "authz_sub_repo_perms_permissions_cache_count", + Help: "The number of sub-repo perms cache hits or misses", + }, []string{"hit"}) + metricSubRepoPermCacheHit = metric.WithLabelValues("true") + metricSubRepoPermCacheMiss = metric.WithLabelValues("false") +} + +// Permissions return the current permissions granted to the given user on the +// given content. If sub-repo permissions are disabled, it is a no-op that return +// Read. +func (s *SubRepoPermsClient) Permissions(ctx context.Context, userID int32, content authz.RepoContent) (perms authz.Perms, err error) { + // Are sub-repo permissions enabled at the site level + if !s.Enabled() { + return authz.Read, nil + } + + began := time.Now() + defer func() { + took := time.Since(began).Seconds() + if err == nil { + metricSubRepoPermsPermissionsDurationSuccess.Observe(took) + } else { + metricSubRepoPermsPermissionsDurationError.Observe(took) + } + }() + + f, err := s.FilePermissionsFunc(ctx, userID, content.Repo) + if err != nil { + return authz.None, err + } + return f(content.Path) +} + +// filePermissionsFuncAllRead is a FilePermissionFunc which _always_ returns +// Read. Only use in cases that sub repo permission checks should not be done. +func filePermissionsFuncAllRead(_ string) (authz.Perms, error) { + return authz.Read, nil +} + +func (s *SubRepoPermsClient) FilePermissionsFunc(ctx context.Context, userID int32, repo api.RepoName) (authz.FilePermissionFunc, error) { + // Are sub-repo permissions enabled at the site level + if !s.Enabled() { + return filePermissionsFuncAllRead, nil + } + + if s.permissionsGetter == nil { + return nil, errors.New("permissionsGetter is nil") + } + + if userID == 0 { + return nil, &authz.ErrUnauthenticated{} + } + + repoRules, err := s.getCompiledRules(ctx, userID) + if err != nil { + return nil, errors.Wrap(err, "compiling match rules") + } + + rules, rulesExist := repoRules[repo] + if !rulesExist { + // If we make it this far it implies that we have access at the repo level. + // Having any empty set of rules here implies that we can access the whole repo. + // Repos that support sub-repo permissions will only have an entry in our + // repo_permissions table after all sub-repo permissions have been processed. + return filePermissionsFuncAllRead, nil + } + + return func(path string) (authz.Perms, error) { + // An empty path is equivalent to repo permissions so we can assume it has + // already been checked at that level. + if path == "" { + return authz.Read, nil + } + + // Prefix path with "/", otherwise suffix rules like "**/file.txt" won't match + if !strings.HasPrefix(path, "/") { + path = "/" + path + } + + // Iterate through all rules for the current path, and the final match takes + // preference. + return rules.GetPermissionsForPath(path), nil + }, nil +} + +// getCompiledRules fetches rules for the given repo with caching. +func (s *SubRepoPermsClient) getCompiledRules(ctx context.Context, userID int32) (map[api.RepoName]compiledRules, error) { + // Fast path for cached rules + item, _ := s.cache.Get(userID) + cached, ok := item.(cachedRules) + + ttl := defaultCacheTTL + if c := conf.Get(); c.ExperimentalFeatures != nil && c.ExperimentalFeatures.SubRepoPermissions != nil && c.ExperimentalFeatures.SubRepoPermissions.UserCacheTTLSeconds > 0 { + ttl = time.Duration(c.ExperimentalFeatures.SubRepoPermissions.UserCacheTTLSeconds) * time.Second + } + + if ok && s.since(cached.timestamp) <= ttl { + metricSubRepoPermCacheHit.Inc() + return cached.rules, nil + } + metricSubRepoPermCacheMiss.Inc() + + // Slow path on cache miss or expiry. Ensure that only one goroutine is doing the + // work + groupKey := strconv.FormatInt(int64(userID), 10) + result, err, _ := s.group.Do(groupKey, func() (any, error) { + repoPerms, err := s.permissionsGetter.GetByUser(ctx, userID) + if err != nil { + return nil, errors.Wrap(err, "fetching rules") + } + toCache := cachedRules{ + rules: make(map[api.RepoName]compiledRules, len(repoPerms)), + } + for repo, perms := range repoPerms { + paths := make([]path, 0, len(perms.Paths)) + for _, rule := range perms.Paths { + exclusion := strings.HasPrefix(rule, "-") + rule = strings.TrimPrefix(rule, "-") + + if !strings.HasPrefix(rule, "/") { + rule = "/" + rule + } + + g, err := glob.Compile(rule, '/') + if err != nil { + return nil, errors.Wrap(err, "building include matcher") + } + + paths = append(paths, path{globPath: g, exclusion: exclusion, original: rule}) + + // Special case. Our glob package does not handle rules starting with a double + // wildcard correctly. For example, we would expect `/**/*.java` to match all + // java files, but it does not match files at the root, eg `/foo.java`. To get + // around this we add an extra rule to cover this case. + if strings.HasPrefix(rule, "/**/") { + trimmed := rule + for { + trimmed = strings.TrimPrefix(trimmed, "/**") + if strings.HasPrefix(trimmed, "/**/") { + // Keep trimming + continue + } + g, err := glob.Compile(trimmed, '/') + if err != nil { + return nil, errors.Wrap(err, "building include matcher") + } + paths = append(paths, path{globPath: g, exclusion: exclusion, original: trimmed}) + break + } + } + + // We should include all directories above an include rule so that we can browse + // to the included items. + if exclusion { + // Not required for an exclude rule + continue + } + + dirs := expandDirs(rule) + for _, dir := range dirs { + g, err := glob.Compile(dir, '/') + if err != nil { + return nil, errors.Wrap(err, "building include matcher for dir") + } + paths = append(paths, path{globPath: g, exclusion: false, original: dir}) + } + } + + toCache.rules[repo] = compiledRules{ + paths: paths, + } + } + toCache.timestamp = s.clock() + s.cache.Add(userID, toCache) + return toCache.rules, nil + }) + if err != nil { + return nil, err + } + + compiled := result.(map[api.RepoName]compiledRules) + return compiled, nil +} + +func (s *SubRepoPermsClient) Enabled() bool { + return s.enabled.Load() +} + +func (s *SubRepoPermsClient) EnabledForRepoID(ctx context.Context, id api.RepoID) (bool, error) { + return s.permissionsGetter.RepoIDSupported(ctx, id) +} + +func (s *SubRepoPermsClient) EnabledForRepo(ctx context.Context, repo api.RepoName) (bool, error) { + return s.permissionsGetter.RepoSupported(ctx, repo) +} + +// expandDirs will return a new set of rules that will match all directories +// above the supplied rule. As a special case, if the rule starts with a wildcard +// we return a rule to match all directories. +func expandDirs(rule string) []string { + dirs := make([]string, 0) + + // Make sure the rule starts with a slash + if !strings.HasPrefix(rule, "/") { + rule = "/" + rule + } + + // If a rule starts with a wildcard it can match at any level in the tree + // structure so there's no way of walking up the tree and expand out to the list + // of valid directories. Instead, we just return a rule that matches any + // directory + if strings.HasPrefix(rule, "/*") { + dirs = append(dirs, "**/") + return dirs + } + + for { + lastSlash := strings.LastIndex(rule, "/") + if lastSlash <= 0 { // we have to ignore the slash at index 0 + break + } + // Drop anything after the last slash + rule = rule[:lastSlash] + + dirs = append(dirs, rule+"/") + } + + return dirs +} + +// NewSimpleChecker is exposed for testing and allows creation of a simple +// checker based on the rules provided. The rules are expected to be in glob +// format. +func NewSimpleChecker(repo api.RepoName, paths []string) (authz.SubRepoPermissionChecker, error) { + getter := NewMockSubRepoPermissionsGetter() + getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + return map[api.RepoName]authz.SubRepoPermissions{ + repo: { + Paths: paths, + }, + }, nil + }) + getter.RepoSupportedFunc.SetDefaultReturn(true, nil) + getter.RepoIDSupportedFunc.SetDefaultReturn(true, nil) + return NewSubRepoPermsClient(getter) +} diff --git a/enterprise/internal/authz/subrepoperms/sub_repo_perms_test.go b/enterprise/internal/authz/subrepoperms/sub_repo_perms_test.go new file mode 100644 index 00000000000..f5c98a9b439 --- /dev/null +++ b/enterprise/internal/authz/subrepoperms/sub_repo_perms_test.go @@ -0,0 +1,430 @@ +package subrepoperms + +import ( + "context" + "fmt" + "sort" + "testing" + "time" + + "github.com/sourcegraph/sourcegraph/internal/actor" + "github.com/sourcegraph/sourcegraph/internal/api" + "github.com/sourcegraph/sourcegraph/internal/authz" + "github.com/sourcegraph/sourcegraph/internal/conf" + "github.com/sourcegraph/sourcegraph/schema" +) + +func TestSubRepoPermsPermissions(t *testing.T) { + conf.Mock(&conf.Unified{ + SiteConfiguration: schema.SiteConfiguration{ + ExperimentalFeatures: &schema.ExperimentalFeatures{ + SubRepoPermissions: &schema.SubRepoPermissions{ + Enabled: true, + }, + }, + }, + }) + t.Cleanup(func() { conf.Mock(nil) }) + + testCases := []struct { + name string + userID int32 + content authz.RepoContent + clientFn func() (*SubRepoPermsClient, error) + want authz.Perms + }{ + { + name: "Empty path", + userID: 1, + content: authz.RepoContent{ + Repo: "sample", + Path: "", + }, + clientFn: func() (*SubRepoPermsClient, error) { + return NewSubRepoPermsClient(NewMockSubRepoPermissionsGetter()) + }, + want: authz.Read, + }, + { + name: "No rules", + userID: 1, + content: authz.RepoContent{ + Repo: "sample", + Path: "/dev/thing", + }, + clientFn: func() (*SubRepoPermsClient, error) { + getter := NewMockSubRepoPermissionsGetter() + getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + return map[api.RepoName]authz.SubRepoPermissions{ + "sample": { + Paths: []string{}, + }, + }, nil + }) + return NewSubRepoPermsClient(getter) + }, + want: authz.None, + }, + { + name: "Exclude", + userID: 1, + content: authz.RepoContent{ + Repo: "sample", + Path: "/dev/thing", + }, + clientFn: func() (*SubRepoPermsClient, error) { + getter := NewMockSubRepoPermissionsGetter() + getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + return map[api.RepoName]authz.SubRepoPermissions{ + "sample": { + Paths: []string{"-/dev/*"}, + }, + }, nil + }) + return NewSubRepoPermsClient(getter) + }, + want: authz.None, + }, + { + name: "Include", + userID: 1, + content: authz.RepoContent{ + Repo: "sample", + Path: "/dev/thing", + }, + clientFn: func() (*SubRepoPermsClient, error) { + getter := NewMockSubRepoPermissionsGetter() + getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + return map[api.RepoName]authz.SubRepoPermissions{ + "sample": { + Paths: []string{"/*"}, + }, + }, nil + }) + return NewSubRepoPermsClient(getter) + }, + want: authz.None, + }, + { + name: "Last rule takes precedence (exclude)", + userID: 1, + content: authz.RepoContent{ + Repo: "sample", + Path: "/dev/thing", + }, + clientFn: func() (*SubRepoPermsClient, error) { + getter := NewMockSubRepoPermissionsGetter() + getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + return map[api.RepoName]authz.SubRepoPermissions{ + "sample": { + Paths: []string{"/**", "-/dev/*"}, + }, + }, nil + }) + return NewSubRepoPermsClient(getter) + }, + want: authz.None, + }, + { + name: "Last rule takes precedence (include)", + userID: 1, + content: authz.RepoContent{ + Repo: "sample", + Path: "/dev/thing", + }, + clientFn: func() (*SubRepoPermsClient, error) { + getter := NewMockSubRepoPermissionsGetter() + getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + return map[api.RepoName]authz.SubRepoPermissions{ + "sample": { + Paths: []string{"-/dev/*", "/**"}, + }, + }, nil + }) + return NewSubRepoPermsClient(getter) + }, + want: authz.Read, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + client, err := tc.clientFn() + if err != nil { + t.Fatal(err) + } + have, err := client.Permissions(context.Background(), tc.userID, tc.content) + if err != nil { + t.Fatal(err) + } + if have != tc.want { + t.Fatalf("have %v, want %v", have, tc.want) + } + }) + } +} + +func BenchmarkFilterActorPaths(b *testing.B) { + // This benchmark is simulating the code path taken by a monorepo with sub + // repo permissions. Our goal is to support repos with millions of files. + // For now we target a lower number since large numbers don't give enough + // runs of the benchmark to be useful. + const pathCount = 5_000 + pathPatterns := []string{ + "base/%d/foo.go", + "%d/stuff/baz", + "frontend/%d/stuff/baz/bam", + "subdir/sub/sub/sub/%d", + "%d/foo/README.md", + "subdir/remove/me/please/%d", + "subdir/%d/also-remove/me/please", + "a/deep/path/%d/.secrets.env", + "%d/does/not/match/anything", + "does/%d/not/match/anything", + "does/not/%d/match/anything", + "does/not/match/%d/anything", + "does/not/match/anything/%d", + } + paths := []string{ + "config.yaml", + "dir.yaml", + } + for i := 0; len(paths) < pathCount; i++ { + for _, pat := range pathPatterns { + paths = append(paths, fmt.Sprintf(pat, i)) + } + } + paths = paths[:pathCount] + sort.Strings(paths) + + conf.Mock(&conf.Unified{ + SiteConfiguration: schema.SiteConfiguration{ + ExperimentalFeatures: &schema.ExperimentalFeatures{ + SubRepoPermissions: &schema.SubRepoPermissions{ + Enabled: true, + }, + }, + }, + }) + defer conf.Mock(nil) + repo := api.RepoName("repo") + + getter := NewMockSubRepoPermissionsGetter() + getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + return map[api.RepoName]authz.SubRepoPermissions{ + repo: { + Paths: []string{ + "/base/**", + "/*/stuff/**", + "/frontend/**/stuff/*", + "/config.yaml", + "/subdir/**", + "/**/README.md", + "/dir.yaml", + "-/subdir/remove/", + "-/subdir/*/also-remove/**", + "-/**/.secrets.env", + }, + }, + }, nil + }) + checker, err := NewSubRepoPermsClient(getter) + if err != nil { + b.Fatal(err) + } + a := &actor.Actor{ + UID: 1, + } + ctx := actor.WithActor(context.Background(), a) + + b.ResetTimer() + start := time.Now() + + for n := 0; n <= b.N; n++ { + filtered, err := authz.FilterActorPaths(ctx, checker, a, repo, paths) + if err != nil { + b.Fatal(err) + } + if len(filtered) == 0 { + b.Fatal("expected paths to be returned") + } + if len(filtered) == len(paths) { + b.Fatal("expected to filter out some paths") + } + } + + b.ReportMetric(float64(len(paths))*float64(b.N)/time.Since(start).Seconds(), "paths/s") +} + +func TestSubRepoPermissionsCanReadDirectoriesInPath(t *testing.T) { + conf.Mock(&conf.Unified{ + SiteConfiguration: schema.SiteConfiguration{ + ExperimentalFeatures: &schema.ExperimentalFeatures{ + SubRepoPermissions: &schema.SubRepoPermissions{ + Enabled: true, + }, + }, + }, + }) + t.Cleanup(func() { conf.Mock(nil) }) + repoName := api.RepoName("repo") + + testCases := []struct { + paths []string + canReadAll []string + cannotReadAny []string + }{ + { + paths: []string{"foo/bar/thing.txt"}, + canReadAll: []string{"foo/", "foo/bar/"}, + cannotReadAny: []string{"foo/thing.txt", "foo/bar/other.txt"}, + }, + { + paths: []string{"foo/bar/**"}, + canReadAll: []string{"foo/", "foo/bar/", "foo/bar/baz/", "foo/bar/baz/fox/"}, + }, + { + paths: []string{"foo/bar/"}, + canReadAll: []string{"foo/", "foo/bar/"}, + cannotReadAny: []string{"foo/thing.txt", "foo/bar/thing.txt"}, + }, + { + paths: []string{"baz/*/foo/bar/thing.txt"}, + canReadAll: []string{"baz/", "baz/x/", "baz/x/foo/bar/"}, + cannotReadAny: []string{"baz/thing.txt"}, + }, + // If we have a wildcard in a path we allow all directories that are not + // explicitly excluded. + { + paths: []string{"**/foo/bar/thing.txt"}, + canReadAll: []string{"foo/", "foo/bar/"}, + }, + { + paths: []string{"*/foo/bar/thing.txt"}, + canReadAll: []string{"foo/", "foo/bar/"}, + }, + { + paths: []string{"/**/foo/bar/thing.txt"}, + canReadAll: []string{"foo/", "foo/bar/"}, + }, + { + paths: []string{"/*/foo/bar/thing.txt"}, + canReadAll: []string{"foo/", "foo/bar/"}, + }, + { + paths: []string{"-/**", "/storage/redis/**"}, + canReadAll: []string{"storage/", "/storage/", "/storage/redis/"}, + }, + { + paths: []string{"-/**", "-/storage/**", "/storage/redis/**"}, + canReadAll: []string{"storage/", "/storage/", "/storage/redis/"}, + }, + // Even with a wildcard include rule, we should still exclude directories that + // are explicitly excluded later + { + paths: []string{"/**", "-/storage/**"}, + canReadAll: []string{"/foo"}, + cannotReadAny: []string{"storage/", "/storage/", "/storage/redis/"}, + }, + } + + for _, tc := range testCases { + t.Run("", func(t *testing.T) { + getter := NewMockSubRepoPermissionsGetter() + getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + return map[api.RepoName]authz.SubRepoPermissions{ + repoName: { + Paths: tc.paths, + }, + }, nil + }) + client, err := NewSubRepoPermsClient(getter) + if err != nil { + t.Fatal(err) + } + + ctx := context.Background() + + for _, path := range tc.canReadAll { + content := authz.RepoContent{ + Repo: repoName, + Path: path, + } + perm, err := client.Permissions(ctx, 1, content) + if err != nil { + t.Error(err) + } + if !perm.Include(authz.Read) { + t.Errorf("Should be able to read %q, cannot", path) + } + } + + for _, path := range tc.cannotReadAny { + content := authz.RepoContent{ + Repo: repoName, + Path: path, + } + perm, err := client.Permissions(ctx, 1, content) + if err != nil { + t.Error(err) + } + if perm.Include(authz.Read) { + t.Errorf("Should not be able to read %q, can", path) + } + } + }) + } +} + +func TestSubRepoPermsPermissionsCache(t *testing.T) { + conf.Mock(&conf.Unified{ + SiteConfiguration: schema.SiteConfiguration{ + ExperimentalFeatures: &schema.ExperimentalFeatures{ + SubRepoPermissions: &schema.SubRepoPermissions{ + Enabled: true, + }, + }, + }, + }) + t.Cleanup(func() { conf.Mock(nil) }) + + getter := NewMockSubRepoPermissionsGetter() + client, err := NewSubRepoPermsClient(getter) + if err != nil { + t.Fatal(err) + } + + ctx := context.Background() + content := authz.RepoContent{ + Repo: api.RepoName("thing"), + Path: "/stuff", + } + + // Should hit DB only once + for i := 0; i < 3; i++ { + _, err = client.Permissions(ctx, 1, content) + if err != nil { + t.Fatal(err) + } + + h := getter.GetByUserFunc.History() + if len(h) != 1 { + t.Fatal("Should have been called once") + } + } + + // Trigger expiry + client.since = func(time time.Time) time.Duration { + return defaultCacheTTL + 1 + } + + _, err = client.Permissions(ctx, 1, content) + if err != nil { + t.Fatal(err) + } + + h := getter.GetByUserFunc.History() + if len(h) != 2 { + t.Fatal("Should have been called twice") + } +} diff --git a/enterprise/internal/database/authz.go b/enterprise/internal/database/authz.go index 901c06452c1..b822cbd2bc7 100644 --- a/enterprise/internal/database/authz.go +++ b/enterprise/internal/database/authz.go @@ -16,10 +16,11 @@ import ( // NewAuthzStore returns an OSS database.AuthzStore set with enterprise implementation. func NewAuthzStore(logger log.Logger, db database.DB, clock func() time.Time) database.AuthzStore { + enterpriseDB := NewEnterpriseDB(db) return &authzStore{ logger: logger, - store: Perms(logger, db, clock), - srpStore: database.SubRepoPermsWith(basestore.NewWithHandle(db.Handle())), + store: Perms(logger, enterpriseDB, clock), + srpStore: enterpriseDB.SubRepoPerms(), } } @@ -27,14 +28,14 @@ func NewAuthzStoreWith(logger log.Logger, other basestore.ShareableStore, clock return &authzStore{ logger: logger, store: PermsWith(logger, other, clock), - srpStore: database.SubRepoPermsWith(other), + srpStore: SubRepoPermsWith(other), } } type authzStore struct { logger log.Logger store PermsStore - srpStore database.SubRepoPermsStore + srpStore SubRepoPermsStore } // GrantPendingPermissions grants pending permissions for a user, which implements the database.AuthzStore interface. diff --git a/enterprise/internal/database/database.go b/enterprise/internal/database/database.go index a2fa3a60c24..c3116a91f9f 100644 --- a/enterprise/internal/database/database.go +++ b/enterprise/internal/database/database.go @@ -17,6 +17,7 @@ type EnterpriseDB interface { database.DB CodeMonitors() CodeMonitorStore Perms() PermsStore + SubRepoPerms() SubRepoPermsStore } func NewEnterpriseDB(db database.DB) EnterpriseDB { @@ -42,6 +43,10 @@ func (edb *enterpriseDB) Perms() PermsStore { return &permsStore{Store: basestore.NewWithHandle(edb.Handle()), clock: time.Now} } +func (edb *enterpriseDB) SubRepoPerms() SubRepoPermsStore { + return SubRepoPermsWith(basestore.NewWithHandle(edb.Handle())) +} + type InsightsDB interface { dbutil.DB basestore.ShareableStore diff --git a/enterprise/internal/database/mocks_temp.go b/enterprise/internal/database/mocks_temp.go index d4fea77ff0b..969ff52e37a 100644 --- a/enterprise/internal/database/mocks_temp.go +++ b/enterprise/internal/database/mocks_temp.go @@ -7142,7 +7142,7 @@ func NewMockEnterpriseDB() *MockEnterpriseDB { }, }, SubRepoPermsFunc: &EnterpriseDBSubRepoPermsFunc{ - defaultHook: func() (r0 database.SubRepoPermsStore) { + defaultHook: func() (r0 SubRepoPermsStore) { return }, }, @@ -7384,7 +7384,7 @@ func NewStrictMockEnterpriseDB() *MockEnterpriseDB { }, }, SubRepoPermsFunc: &EnterpriseDBSubRepoPermsFunc{ - defaultHook: func() database.SubRepoPermsStore { + defaultHook: func() SubRepoPermsStore { panic("unexpected invocation of MockEnterpriseDB.SubRepoPerms") }, }, @@ -11226,15 +11226,15 @@ func (c EnterpriseDBSettingsFuncCall) Results() []interface{} { // EnterpriseDBSubRepoPermsFunc describes the behavior when the SubRepoPerms // method of the parent MockEnterpriseDB instance is invoked. type EnterpriseDBSubRepoPermsFunc struct { - defaultHook func() database.SubRepoPermsStore - hooks []func() database.SubRepoPermsStore + defaultHook func() SubRepoPermsStore + hooks []func() SubRepoPermsStore history []EnterpriseDBSubRepoPermsFuncCall mutex sync.Mutex } // SubRepoPerms delegates to the next hook function in the queue and stores // the parameter and result values of this invocation. -func (m *MockEnterpriseDB) SubRepoPerms() database.SubRepoPermsStore { +func (m *MockEnterpriseDB) SubRepoPerms() SubRepoPermsStore { r0 := m.SubRepoPermsFunc.nextHook()() m.SubRepoPermsFunc.appendCall(EnterpriseDBSubRepoPermsFuncCall{r0}) return r0 @@ -11243,7 +11243,7 @@ func (m *MockEnterpriseDB) SubRepoPerms() database.SubRepoPermsStore { // SetDefaultHook sets function that is called when the SubRepoPerms method // of the parent MockEnterpriseDB instance is invoked and the hook queue is // empty. -func (f *EnterpriseDBSubRepoPermsFunc) SetDefaultHook(hook func() database.SubRepoPermsStore) { +func (f *EnterpriseDBSubRepoPermsFunc) SetDefaultHook(hook func() SubRepoPermsStore) { f.defaultHook = hook } @@ -11251,7 +11251,7 @@ func (f *EnterpriseDBSubRepoPermsFunc) SetDefaultHook(hook func() database.SubRe // SubRepoPerms method of the parent MockEnterpriseDB instance invokes the // hook at the front of the queue and discards it. After the queue is empty, // the default hook function is invoked for any future action. -func (f *EnterpriseDBSubRepoPermsFunc) PushHook(hook func() database.SubRepoPermsStore) { +func (f *EnterpriseDBSubRepoPermsFunc) PushHook(hook func() SubRepoPermsStore) { f.mutex.Lock() f.hooks = append(f.hooks, hook) f.mutex.Unlock() @@ -11259,20 +11259,20 @@ func (f *EnterpriseDBSubRepoPermsFunc) PushHook(hook func() database.SubRepoPerm // SetDefaultReturn calls SetDefaultHook with a function that returns the // given values. -func (f *EnterpriseDBSubRepoPermsFunc) SetDefaultReturn(r0 database.SubRepoPermsStore) { - f.SetDefaultHook(func() database.SubRepoPermsStore { +func (f *EnterpriseDBSubRepoPermsFunc) SetDefaultReturn(r0 SubRepoPermsStore) { + f.SetDefaultHook(func() SubRepoPermsStore { return r0 }) } // PushReturn calls PushHook with a function that returns the given values. -func (f *EnterpriseDBSubRepoPermsFunc) PushReturn(r0 database.SubRepoPermsStore) { - f.PushHook(func() database.SubRepoPermsStore { +func (f *EnterpriseDBSubRepoPermsFunc) PushReturn(r0 SubRepoPermsStore) { + f.PushHook(func() SubRepoPermsStore { return r0 }) } -func (f *EnterpriseDBSubRepoPermsFunc) nextHook() func() database.SubRepoPermsStore { +func (f *EnterpriseDBSubRepoPermsFunc) nextHook() func() SubRepoPermsStore { f.mutex.Lock() defer f.mutex.Unlock() @@ -11307,7 +11307,7 @@ func (f *EnterpriseDBSubRepoPermsFunc) History() []EnterpriseDBSubRepoPermsFuncC type EnterpriseDBSubRepoPermsFuncCall struct { // Result0 is the value of the 1st result returned from this method // invocation. - Result0 database.SubRepoPermsStore + Result0 SubRepoPermsStore } // Args returns an interface slice containing the arguments of this @@ -15470,3 +15470,1524 @@ func (c PermsStoreWithFuncCall) Args() []interface{} { func (c PermsStoreWithFuncCall) Results() []interface{} { return []interface{}{c.Result0} } + +// MockSubRepoPermsStore is a mock implementation of the SubRepoPermsStore +// interface (from the package +// github.com/sourcegraph/sourcegraph/enterprise/internal/database) used for +// unit testing. +type MockSubRepoPermsStore struct { + // DeleteByUserFunc is an instance of a mock function object controlling + // the behavior of the method DeleteByUser. + DeleteByUserFunc *SubRepoPermsStoreDeleteByUserFunc + // DoneFunc is an instance of a mock function object controlling the + // behavior of the method Done. + DoneFunc *SubRepoPermsStoreDoneFunc + // GetFunc is an instance of a mock function object controlling the + // behavior of the method Get. + GetFunc *SubRepoPermsStoreGetFunc + // GetByUserFunc is an instance of a mock function object controlling + // the behavior of the method GetByUser. + GetByUserFunc *SubRepoPermsStoreGetByUserFunc + // GetByUserAndServiceFunc is an instance of a mock function object + // controlling the behavior of the method GetByUserAndService. + GetByUserAndServiceFunc *SubRepoPermsStoreGetByUserAndServiceFunc + // HandleFunc is an instance of a mock function object controlling the + // behavior of the method Handle. + HandleFunc *SubRepoPermsStoreHandleFunc + // RepoIDSupportedFunc is an instance of a mock function object + // controlling the behavior of the method RepoIDSupported. + RepoIDSupportedFunc *SubRepoPermsStoreRepoIDSupportedFunc + // RepoSupportedFunc is an instance of a mock function object + // controlling the behavior of the method RepoSupported. + RepoSupportedFunc *SubRepoPermsStoreRepoSupportedFunc + // TransactFunc is an instance of a mock function object controlling the + // behavior of the method Transact. + TransactFunc *SubRepoPermsStoreTransactFunc + // UpsertFunc is an instance of a mock function object controlling the + // behavior of the method Upsert. + UpsertFunc *SubRepoPermsStoreUpsertFunc + // UpsertWithSpecFunc is an instance of a mock function object + // controlling the behavior of the method UpsertWithSpec. + UpsertWithSpecFunc *SubRepoPermsStoreUpsertWithSpecFunc + // WithFunc is an instance of a mock function object controlling the + // behavior of the method With. + WithFunc *SubRepoPermsStoreWithFunc +} + +// NewMockSubRepoPermsStore creates a new mock of the SubRepoPermsStore +// interface. All methods return zero values for all results, unless +// overwritten. +func NewMockSubRepoPermsStore() *MockSubRepoPermsStore { + return &MockSubRepoPermsStore{ + DeleteByUserFunc: &SubRepoPermsStoreDeleteByUserFunc{ + defaultHook: func(context.Context, int32) (r0 error) { + return + }, + }, + DoneFunc: &SubRepoPermsStoreDoneFunc{ + defaultHook: func(error) (r0 error) { + return + }, + }, + GetFunc: &SubRepoPermsStoreGetFunc{ + defaultHook: func(context.Context, int32, api.RepoID) (r0 *authz.SubRepoPermissions, r1 error) { + return + }, + }, + GetByUserFunc: &SubRepoPermsStoreGetByUserFunc{ + defaultHook: func(context.Context, int32) (r0 map[api.RepoName]authz.SubRepoPermissions, r1 error) { + return + }, + }, + GetByUserAndServiceFunc: &SubRepoPermsStoreGetByUserAndServiceFunc{ + defaultHook: func(context.Context, int32, string, string) (r0 map[api.ExternalRepoSpec]authz.SubRepoPermissions, r1 error) { + return + }, + }, + HandleFunc: &SubRepoPermsStoreHandleFunc{ + defaultHook: func() (r0 basestore.TransactableHandle) { + return + }, + }, + RepoIDSupportedFunc: &SubRepoPermsStoreRepoIDSupportedFunc{ + defaultHook: func(context.Context, api.RepoID) (r0 bool, r1 error) { + return + }, + }, + RepoSupportedFunc: &SubRepoPermsStoreRepoSupportedFunc{ + defaultHook: func(context.Context, api.RepoName) (r0 bool, r1 error) { + return + }, + }, + TransactFunc: &SubRepoPermsStoreTransactFunc{ + defaultHook: func(context.Context) (r0 SubRepoPermsStore, r1 error) { + return + }, + }, + UpsertFunc: &SubRepoPermsStoreUpsertFunc{ + defaultHook: func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) (r0 error) { + return + }, + }, + UpsertWithSpecFunc: &SubRepoPermsStoreUpsertWithSpecFunc{ + defaultHook: func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) (r0 error) { + return + }, + }, + WithFunc: &SubRepoPermsStoreWithFunc{ + defaultHook: func(basestore.ShareableStore) (r0 SubRepoPermsStore) { + return + }, + }, + } +} + +// NewStrictMockSubRepoPermsStore creates a new mock of the +// SubRepoPermsStore interface. All methods panic on invocation, unless +// overwritten. +func NewStrictMockSubRepoPermsStore() *MockSubRepoPermsStore { + return &MockSubRepoPermsStore{ + DeleteByUserFunc: &SubRepoPermsStoreDeleteByUserFunc{ + defaultHook: func(context.Context, int32) error { + panic("unexpected invocation of MockSubRepoPermsStore.DeleteByUser") + }, + }, + DoneFunc: &SubRepoPermsStoreDoneFunc{ + defaultHook: func(error) error { + panic("unexpected invocation of MockSubRepoPermsStore.Done") + }, + }, + GetFunc: &SubRepoPermsStoreGetFunc{ + defaultHook: func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error) { + panic("unexpected invocation of MockSubRepoPermsStore.Get") + }, + }, + GetByUserFunc: &SubRepoPermsStoreGetByUserFunc{ + defaultHook: func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + panic("unexpected invocation of MockSubRepoPermsStore.GetByUser") + }, + }, + GetByUserAndServiceFunc: &SubRepoPermsStoreGetByUserAndServiceFunc{ + defaultHook: func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error) { + panic("unexpected invocation of MockSubRepoPermsStore.GetByUserAndService") + }, + }, + HandleFunc: &SubRepoPermsStoreHandleFunc{ + defaultHook: func() basestore.TransactableHandle { + panic("unexpected invocation of MockSubRepoPermsStore.Handle") + }, + }, + RepoIDSupportedFunc: &SubRepoPermsStoreRepoIDSupportedFunc{ + defaultHook: func(context.Context, api.RepoID) (bool, error) { + panic("unexpected invocation of MockSubRepoPermsStore.RepoIDSupported") + }, + }, + RepoSupportedFunc: &SubRepoPermsStoreRepoSupportedFunc{ + defaultHook: func(context.Context, api.RepoName) (bool, error) { + panic("unexpected invocation of MockSubRepoPermsStore.RepoSupported") + }, + }, + TransactFunc: &SubRepoPermsStoreTransactFunc{ + defaultHook: func(context.Context) (SubRepoPermsStore, error) { + panic("unexpected invocation of MockSubRepoPermsStore.Transact") + }, + }, + UpsertFunc: &SubRepoPermsStoreUpsertFunc{ + defaultHook: func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error { + panic("unexpected invocation of MockSubRepoPermsStore.Upsert") + }, + }, + UpsertWithSpecFunc: &SubRepoPermsStoreUpsertWithSpecFunc{ + defaultHook: func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error { + panic("unexpected invocation of MockSubRepoPermsStore.UpsertWithSpec") + }, + }, + WithFunc: &SubRepoPermsStoreWithFunc{ + defaultHook: func(basestore.ShareableStore) SubRepoPermsStore { + panic("unexpected invocation of MockSubRepoPermsStore.With") + }, + }, + } +} + +// NewMockSubRepoPermsStoreFrom creates a new mock of the +// MockSubRepoPermsStore interface. All methods delegate to the given +// implementation, unless overwritten. +func NewMockSubRepoPermsStoreFrom(i SubRepoPermsStore) *MockSubRepoPermsStore { + return &MockSubRepoPermsStore{ + DeleteByUserFunc: &SubRepoPermsStoreDeleteByUserFunc{ + defaultHook: i.DeleteByUser, + }, + DoneFunc: &SubRepoPermsStoreDoneFunc{ + defaultHook: i.Done, + }, + GetFunc: &SubRepoPermsStoreGetFunc{ + defaultHook: i.Get, + }, + GetByUserFunc: &SubRepoPermsStoreGetByUserFunc{ + defaultHook: i.GetByUser, + }, + GetByUserAndServiceFunc: &SubRepoPermsStoreGetByUserAndServiceFunc{ + defaultHook: i.GetByUserAndService, + }, + HandleFunc: &SubRepoPermsStoreHandleFunc{ + defaultHook: i.Handle, + }, + RepoIDSupportedFunc: &SubRepoPermsStoreRepoIDSupportedFunc{ + defaultHook: i.RepoIDSupported, + }, + RepoSupportedFunc: &SubRepoPermsStoreRepoSupportedFunc{ + defaultHook: i.RepoSupported, + }, + TransactFunc: &SubRepoPermsStoreTransactFunc{ + defaultHook: i.Transact, + }, + UpsertFunc: &SubRepoPermsStoreUpsertFunc{ + defaultHook: i.Upsert, + }, + UpsertWithSpecFunc: &SubRepoPermsStoreUpsertWithSpecFunc{ + defaultHook: i.UpsertWithSpec, + }, + WithFunc: &SubRepoPermsStoreWithFunc{ + defaultHook: i.With, + }, + } +} + +// SubRepoPermsStoreDeleteByUserFunc describes the behavior when the +// DeleteByUser method of the parent MockSubRepoPermsStore instance is +// invoked. +type SubRepoPermsStoreDeleteByUserFunc struct { + defaultHook func(context.Context, int32) error + hooks []func(context.Context, int32) error + history []SubRepoPermsStoreDeleteByUserFuncCall + mutex sync.Mutex +} + +// DeleteByUser delegates to the next hook function in the queue and stores +// the parameter and result values of this invocation. +func (m *MockSubRepoPermsStore) DeleteByUser(v0 context.Context, v1 int32) error { + r0 := m.DeleteByUserFunc.nextHook()(v0, v1) + m.DeleteByUserFunc.appendCall(SubRepoPermsStoreDeleteByUserFuncCall{v0, v1, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the DeleteByUser method +// of the parent MockSubRepoPermsStore instance is invoked and the hook +// queue is empty. +func (f *SubRepoPermsStoreDeleteByUserFunc) SetDefaultHook(hook func(context.Context, int32) error) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// DeleteByUser method of the parent MockSubRepoPermsStore instance invokes +// the hook at the front of the queue and discards it. After the queue is +// empty, the default hook function is invoked for any future action. +func (f *SubRepoPermsStoreDeleteByUserFunc) PushHook(hook func(context.Context, int32) error) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *SubRepoPermsStoreDeleteByUserFunc) SetDefaultReturn(r0 error) { + f.SetDefaultHook(func(context.Context, int32) error { + return r0 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *SubRepoPermsStoreDeleteByUserFunc) PushReturn(r0 error) { + f.PushHook(func(context.Context, int32) error { + return r0 + }) +} + +func (f *SubRepoPermsStoreDeleteByUserFunc) nextHook() func(context.Context, int32) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *SubRepoPermsStoreDeleteByUserFunc) appendCall(r0 SubRepoPermsStoreDeleteByUserFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of SubRepoPermsStoreDeleteByUserFuncCall +// objects describing the invocations of this function. +func (f *SubRepoPermsStoreDeleteByUserFunc) History() []SubRepoPermsStoreDeleteByUserFuncCall { + f.mutex.Lock() + history := make([]SubRepoPermsStoreDeleteByUserFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// SubRepoPermsStoreDeleteByUserFuncCall is an object that describes an +// invocation of method DeleteByUser on an instance of +// MockSubRepoPermsStore. +type SubRepoPermsStoreDeleteByUserFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int32 + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c SubRepoPermsStoreDeleteByUserFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c SubRepoPermsStoreDeleteByUserFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} + +// SubRepoPermsStoreDoneFunc describes the behavior when the Done method of +// the parent MockSubRepoPermsStore instance is invoked. +type SubRepoPermsStoreDoneFunc struct { + defaultHook func(error) error + hooks []func(error) error + history []SubRepoPermsStoreDoneFuncCall + mutex sync.Mutex +} + +// Done delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockSubRepoPermsStore) Done(v0 error) error { + r0 := m.DoneFunc.nextHook()(v0) + m.DoneFunc.appendCall(SubRepoPermsStoreDoneFuncCall{v0, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the Done method of the +// parent MockSubRepoPermsStore instance is invoked and the hook queue is +// empty. +func (f *SubRepoPermsStoreDoneFunc) SetDefaultHook(hook func(error) error) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// Done method of the parent MockSubRepoPermsStore instance invokes the hook +// at the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *SubRepoPermsStoreDoneFunc) PushHook(hook func(error) error) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *SubRepoPermsStoreDoneFunc) SetDefaultReturn(r0 error) { + f.SetDefaultHook(func(error) error { + return r0 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *SubRepoPermsStoreDoneFunc) PushReturn(r0 error) { + f.PushHook(func(error) error { + return r0 + }) +} + +func (f *SubRepoPermsStoreDoneFunc) nextHook() func(error) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *SubRepoPermsStoreDoneFunc) appendCall(r0 SubRepoPermsStoreDoneFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of SubRepoPermsStoreDoneFuncCall objects +// describing the invocations of this function. +func (f *SubRepoPermsStoreDoneFunc) History() []SubRepoPermsStoreDoneFuncCall { + f.mutex.Lock() + history := make([]SubRepoPermsStoreDoneFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// SubRepoPermsStoreDoneFuncCall is an object that describes an invocation +// of method Done on an instance of MockSubRepoPermsStore. +type SubRepoPermsStoreDoneFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 error + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c SubRepoPermsStoreDoneFuncCall) Args() []interface{} { + return []interface{}{c.Arg0} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c SubRepoPermsStoreDoneFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} + +// SubRepoPermsStoreGetFunc describes the behavior when the Get method of +// the parent MockSubRepoPermsStore instance is invoked. +type SubRepoPermsStoreGetFunc struct { + defaultHook func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error) + hooks []func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error) + history []SubRepoPermsStoreGetFuncCall + mutex sync.Mutex +} + +// Get delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockSubRepoPermsStore) Get(v0 context.Context, v1 int32, v2 api.RepoID) (*authz.SubRepoPermissions, error) { + r0, r1 := m.GetFunc.nextHook()(v0, v1, v2) + m.GetFunc.appendCall(SubRepoPermsStoreGetFuncCall{v0, v1, v2, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the Get method of the +// parent MockSubRepoPermsStore instance is invoked and the hook queue is +// empty. +func (f *SubRepoPermsStoreGetFunc) SetDefaultHook(hook func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// Get method of the parent MockSubRepoPermsStore instance invokes the hook +// at the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *SubRepoPermsStoreGetFunc) PushHook(hook func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *SubRepoPermsStoreGetFunc) SetDefaultReturn(r0 *authz.SubRepoPermissions, r1 error) { + f.SetDefaultHook(func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *SubRepoPermsStoreGetFunc) PushReturn(r0 *authz.SubRepoPermissions, r1 error) { + f.PushHook(func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error) { + return r0, r1 + }) +} + +func (f *SubRepoPermsStoreGetFunc) nextHook() func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *SubRepoPermsStoreGetFunc) appendCall(r0 SubRepoPermsStoreGetFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of SubRepoPermsStoreGetFuncCall objects +// describing the invocations of this function. +func (f *SubRepoPermsStoreGetFunc) History() []SubRepoPermsStoreGetFuncCall { + f.mutex.Lock() + history := make([]SubRepoPermsStoreGetFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// SubRepoPermsStoreGetFuncCall is an object that describes an invocation of +// method Get on an instance of MockSubRepoPermsStore. +type SubRepoPermsStoreGetFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int32 + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 api.RepoID + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 *authz.SubRepoPermissions + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c SubRepoPermsStoreGetFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c SubRepoPermsStoreGetFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// SubRepoPermsStoreGetByUserFunc describes the behavior when the GetByUser +// method of the parent MockSubRepoPermsStore instance is invoked. +type SubRepoPermsStoreGetByUserFunc struct { + defaultHook func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) + hooks []func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) + history []SubRepoPermsStoreGetByUserFuncCall + mutex sync.Mutex +} + +// GetByUser delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockSubRepoPermsStore) GetByUser(v0 context.Context, v1 int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + r0, r1 := m.GetByUserFunc.nextHook()(v0, v1) + m.GetByUserFunc.appendCall(SubRepoPermsStoreGetByUserFuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the GetByUser method of +// the parent MockSubRepoPermsStore instance is invoked and the hook queue +// is empty. +func (f *SubRepoPermsStoreGetByUserFunc) SetDefaultHook(hook func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// GetByUser method of the parent MockSubRepoPermsStore instance invokes the +// hook at the front of the queue and discards it. After the queue is empty, +// the default hook function is invoked for any future action. +func (f *SubRepoPermsStoreGetByUserFunc) PushHook(hook func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *SubRepoPermsStoreGetByUserFunc) SetDefaultReturn(r0 map[api.RepoName]authz.SubRepoPermissions, r1 error) { + f.SetDefaultHook(func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *SubRepoPermsStoreGetByUserFunc) PushReturn(r0 map[api.RepoName]authz.SubRepoPermissions, r1 error) { + f.PushHook(func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + return r0, r1 + }) +} + +func (f *SubRepoPermsStoreGetByUserFunc) nextHook() func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *SubRepoPermsStoreGetByUserFunc) appendCall(r0 SubRepoPermsStoreGetByUserFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of SubRepoPermsStoreGetByUserFuncCall objects +// describing the invocations of this function. +func (f *SubRepoPermsStoreGetByUserFunc) History() []SubRepoPermsStoreGetByUserFuncCall { + f.mutex.Lock() + history := make([]SubRepoPermsStoreGetByUserFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// SubRepoPermsStoreGetByUserFuncCall is an object that describes an +// invocation of method GetByUser on an instance of MockSubRepoPermsStore. +type SubRepoPermsStoreGetByUserFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int32 + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 map[api.RepoName]authz.SubRepoPermissions + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c SubRepoPermsStoreGetByUserFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c SubRepoPermsStoreGetByUserFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// SubRepoPermsStoreGetByUserAndServiceFunc describes the behavior when the +// GetByUserAndService method of the parent MockSubRepoPermsStore instance +// is invoked. +type SubRepoPermsStoreGetByUserAndServiceFunc struct { + defaultHook func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error) + hooks []func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error) + history []SubRepoPermsStoreGetByUserAndServiceFuncCall + mutex sync.Mutex +} + +// GetByUserAndService delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockSubRepoPermsStore) GetByUserAndService(v0 context.Context, v1 int32, v2 string, v3 string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error) { + r0, r1 := m.GetByUserAndServiceFunc.nextHook()(v0, v1, v2, v3) + m.GetByUserAndServiceFunc.appendCall(SubRepoPermsStoreGetByUserAndServiceFuncCall{v0, v1, v2, v3, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the GetByUserAndService +// method of the parent MockSubRepoPermsStore instance is invoked and the +// hook queue is empty. +func (f *SubRepoPermsStoreGetByUserAndServiceFunc) SetDefaultHook(hook func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// GetByUserAndService method of the parent MockSubRepoPermsStore instance +// invokes the hook at the front of the queue and discards it. After the +// queue is empty, the default hook function is invoked for any future +// action. +func (f *SubRepoPermsStoreGetByUserAndServiceFunc) PushHook(hook func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *SubRepoPermsStoreGetByUserAndServiceFunc) SetDefaultReturn(r0 map[api.ExternalRepoSpec]authz.SubRepoPermissions, r1 error) { + f.SetDefaultHook(func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *SubRepoPermsStoreGetByUserAndServiceFunc) PushReturn(r0 map[api.ExternalRepoSpec]authz.SubRepoPermissions, r1 error) { + f.PushHook(func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error) { + return r0, r1 + }) +} + +func (f *SubRepoPermsStoreGetByUserAndServiceFunc) nextHook() func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *SubRepoPermsStoreGetByUserAndServiceFunc) appendCall(r0 SubRepoPermsStoreGetByUserAndServiceFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of +// SubRepoPermsStoreGetByUserAndServiceFuncCall objects describing the +// invocations of this function. +func (f *SubRepoPermsStoreGetByUserAndServiceFunc) History() []SubRepoPermsStoreGetByUserAndServiceFuncCall { + f.mutex.Lock() + history := make([]SubRepoPermsStoreGetByUserAndServiceFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// SubRepoPermsStoreGetByUserAndServiceFuncCall is an object that describes +// an invocation of method GetByUserAndService on an instance of +// MockSubRepoPermsStore. +type SubRepoPermsStoreGetByUserAndServiceFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int32 + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 string + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 string + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 map[api.ExternalRepoSpec]authz.SubRepoPermissions + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c SubRepoPermsStoreGetByUserAndServiceFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c SubRepoPermsStoreGetByUserAndServiceFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// SubRepoPermsStoreHandleFunc describes the behavior when the Handle method +// of the parent MockSubRepoPermsStore instance is invoked. +type SubRepoPermsStoreHandleFunc struct { + defaultHook func() basestore.TransactableHandle + hooks []func() basestore.TransactableHandle + history []SubRepoPermsStoreHandleFuncCall + mutex sync.Mutex +} + +// Handle delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockSubRepoPermsStore) Handle() basestore.TransactableHandle { + r0 := m.HandleFunc.nextHook()() + m.HandleFunc.appendCall(SubRepoPermsStoreHandleFuncCall{r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the Handle method of the +// parent MockSubRepoPermsStore instance is invoked and the hook queue is +// empty. +func (f *SubRepoPermsStoreHandleFunc) SetDefaultHook(hook func() basestore.TransactableHandle) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// Handle method of the parent MockSubRepoPermsStore instance invokes the +// hook at the front of the queue and discards it. After the queue is empty, +// the default hook function is invoked for any future action. +func (f *SubRepoPermsStoreHandleFunc) PushHook(hook func() basestore.TransactableHandle) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *SubRepoPermsStoreHandleFunc) SetDefaultReturn(r0 basestore.TransactableHandle) { + f.SetDefaultHook(func() basestore.TransactableHandle { + return r0 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *SubRepoPermsStoreHandleFunc) PushReturn(r0 basestore.TransactableHandle) { + f.PushHook(func() basestore.TransactableHandle { + return r0 + }) +} + +func (f *SubRepoPermsStoreHandleFunc) nextHook() func() basestore.TransactableHandle { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *SubRepoPermsStoreHandleFunc) appendCall(r0 SubRepoPermsStoreHandleFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of SubRepoPermsStoreHandleFuncCall objects +// describing the invocations of this function. +func (f *SubRepoPermsStoreHandleFunc) History() []SubRepoPermsStoreHandleFuncCall { + f.mutex.Lock() + history := make([]SubRepoPermsStoreHandleFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// SubRepoPermsStoreHandleFuncCall is an object that describes an invocation +// of method Handle on an instance of MockSubRepoPermsStore. +type SubRepoPermsStoreHandleFuncCall struct { + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 basestore.TransactableHandle +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c SubRepoPermsStoreHandleFuncCall) Args() []interface{} { + return []interface{}{} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c SubRepoPermsStoreHandleFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} + +// SubRepoPermsStoreRepoIDSupportedFunc describes the behavior when the +// RepoIDSupported method of the parent MockSubRepoPermsStore instance is +// invoked. +type SubRepoPermsStoreRepoIDSupportedFunc struct { + defaultHook func(context.Context, api.RepoID) (bool, error) + hooks []func(context.Context, api.RepoID) (bool, error) + history []SubRepoPermsStoreRepoIDSupportedFuncCall + mutex sync.Mutex +} + +// RepoIDSupported delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockSubRepoPermsStore) RepoIDSupported(v0 context.Context, v1 api.RepoID) (bool, error) { + r0, r1 := m.RepoIDSupportedFunc.nextHook()(v0, v1) + m.RepoIDSupportedFunc.appendCall(SubRepoPermsStoreRepoIDSupportedFuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the RepoIDSupported +// method of the parent MockSubRepoPermsStore instance is invoked and the +// hook queue is empty. +func (f *SubRepoPermsStoreRepoIDSupportedFunc) SetDefaultHook(hook func(context.Context, api.RepoID) (bool, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// RepoIDSupported method of the parent MockSubRepoPermsStore instance +// invokes the hook at the front of the queue and discards it. After the +// queue is empty, the default hook function is invoked for any future +// action. +func (f *SubRepoPermsStoreRepoIDSupportedFunc) PushHook(hook func(context.Context, api.RepoID) (bool, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *SubRepoPermsStoreRepoIDSupportedFunc) SetDefaultReturn(r0 bool, r1 error) { + f.SetDefaultHook(func(context.Context, api.RepoID) (bool, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *SubRepoPermsStoreRepoIDSupportedFunc) PushReturn(r0 bool, r1 error) { + f.PushHook(func(context.Context, api.RepoID) (bool, error) { + return r0, r1 + }) +} + +func (f *SubRepoPermsStoreRepoIDSupportedFunc) nextHook() func(context.Context, api.RepoID) (bool, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *SubRepoPermsStoreRepoIDSupportedFunc) appendCall(r0 SubRepoPermsStoreRepoIDSupportedFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of SubRepoPermsStoreRepoIDSupportedFuncCall +// objects describing the invocations of this function. +func (f *SubRepoPermsStoreRepoIDSupportedFunc) History() []SubRepoPermsStoreRepoIDSupportedFuncCall { + f.mutex.Lock() + history := make([]SubRepoPermsStoreRepoIDSupportedFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// SubRepoPermsStoreRepoIDSupportedFuncCall is an object that describes an +// invocation of method RepoIDSupported on an instance of +// MockSubRepoPermsStore. +type SubRepoPermsStoreRepoIDSupportedFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 api.RepoID + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 bool + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c SubRepoPermsStoreRepoIDSupportedFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c SubRepoPermsStoreRepoIDSupportedFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// SubRepoPermsStoreRepoSupportedFunc describes the behavior when the +// RepoSupported method of the parent MockSubRepoPermsStore instance is +// invoked. +type SubRepoPermsStoreRepoSupportedFunc struct { + defaultHook func(context.Context, api.RepoName) (bool, error) + hooks []func(context.Context, api.RepoName) (bool, error) + history []SubRepoPermsStoreRepoSupportedFuncCall + mutex sync.Mutex +} + +// RepoSupported delegates to the next hook function in the queue and stores +// the parameter and result values of this invocation. +func (m *MockSubRepoPermsStore) RepoSupported(v0 context.Context, v1 api.RepoName) (bool, error) { + r0, r1 := m.RepoSupportedFunc.nextHook()(v0, v1) + m.RepoSupportedFunc.appendCall(SubRepoPermsStoreRepoSupportedFuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the RepoSupported method +// of the parent MockSubRepoPermsStore instance is invoked and the hook +// queue is empty. +func (f *SubRepoPermsStoreRepoSupportedFunc) SetDefaultHook(hook func(context.Context, api.RepoName) (bool, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// RepoSupported method of the parent MockSubRepoPermsStore instance invokes +// the hook at the front of the queue and discards it. After the queue is +// empty, the default hook function is invoked for any future action. +func (f *SubRepoPermsStoreRepoSupportedFunc) PushHook(hook func(context.Context, api.RepoName) (bool, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *SubRepoPermsStoreRepoSupportedFunc) SetDefaultReturn(r0 bool, r1 error) { + f.SetDefaultHook(func(context.Context, api.RepoName) (bool, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *SubRepoPermsStoreRepoSupportedFunc) PushReturn(r0 bool, r1 error) { + f.PushHook(func(context.Context, api.RepoName) (bool, error) { + return r0, r1 + }) +} + +func (f *SubRepoPermsStoreRepoSupportedFunc) nextHook() func(context.Context, api.RepoName) (bool, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *SubRepoPermsStoreRepoSupportedFunc) appendCall(r0 SubRepoPermsStoreRepoSupportedFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of SubRepoPermsStoreRepoSupportedFuncCall +// objects describing the invocations of this function. +func (f *SubRepoPermsStoreRepoSupportedFunc) History() []SubRepoPermsStoreRepoSupportedFuncCall { + f.mutex.Lock() + history := make([]SubRepoPermsStoreRepoSupportedFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// SubRepoPermsStoreRepoSupportedFuncCall is an object that describes an +// invocation of method RepoSupported on an instance of +// MockSubRepoPermsStore. +type SubRepoPermsStoreRepoSupportedFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 api.RepoName + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 bool + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c SubRepoPermsStoreRepoSupportedFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c SubRepoPermsStoreRepoSupportedFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// SubRepoPermsStoreTransactFunc describes the behavior when the Transact +// method of the parent MockSubRepoPermsStore instance is invoked. +type SubRepoPermsStoreTransactFunc struct { + defaultHook func(context.Context) (SubRepoPermsStore, error) + hooks []func(context.Context) (SubRepoPermsStore, error) + history []SubRepoPermsStoreTransactFuncCall + mutex sync.Mutex +} + +// Transact delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockSubRepoPermsStore) Transact(v0 context.Context) (SubRepoPermsStore, error) { + r0, r1 := m.TransactFunc.nextHook()(v0) + m.TransactFunc.appendCall(SubRepoPermsStoreTransactFuncCall{v0, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the Transact method of +// the parent MockSubRepoPermsStore instance is invoked and the hook queue +// is empty. +func (f *SubRepoPermsStoreTransactFunc) SetDefaultHook(hook func(context.Context) (SubRepoPermsStore, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// Transact method of the parent MockSubRepoPermsStore instance invokes the +// hook at the front of the queue and discards it. After the queue is empty, +// the default hook function is invoked for any future action. +func (f *SubRepoPermsStoreTransactFunc) PushHook(hook func(context.Context) (SubRepoPermsStore, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *SubRepoPermsStoreTransactFunc) SetDefaultReturn(r0 SubRepoPermsStore, r1 error) { + f.SetDefaultHook(func(context.Context) (SubRepoPermsStore, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *SubRepoPermsStoreTransactFunc) PushReturn(r0 SubRepoPermsStore, r1 error) { + f.PushHook(func(context.Context) (SubRepoPermsStore, error) { + return r0, r1 + }) +} + +func (f *SubRepoPermsStoreTransactFunc) nextHook() func(context.Context) (SubRepoPermsStore, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *SubRepoPermsStoreTransactFunc) appendCall(r0 SubRepoPermsStoreTransactFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of SubRepoPermsStoreTransactFuncCall objects +// describing the invocations of this function. +func (f *SubRepoPermsStoreTransactFunc) History() []SubRepoPermsStoreTransactFuncCall { + f.mutex.Lock() + history := make([]SubRepoPermsStoreTransactFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// SubRepoPermsStoreTransactFuncCall is an object that describes an +// invocation of method Transact on an instance of MockSubRepoPermsStore. +type SubRepoPermsStoreTransactFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 SubRepoPermsStore + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c SubRepoPermsStoreTransactFuncCall) Args() []interface{} { + return []interface{}{c.Arg0} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c SubRepoPermsStoreTransactFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// SubRepoPermsStoreUpsertFunc describes the behavior when the Upsert method +// of the parent MockSubRepoPermsStore instance is invoked. +type SubRepoPermsStoreUpsertFunc struct { + defaultHook func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error + hooks []func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error + history []SubRepoPermsStoreUpsertFuncCall + mutex sync.Mutex +} + +// Upsert delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockSubRepoPermsStore) Upsert(v0 context.Context, v1 int32, v2 api.RepoID, v3 authz.SubRepoPermissions) error { + r0 := m.UpsertFunc.nextHook()(v0, v1, v2, v3) + m.UpsertFunc.appendCall(SubRepoPermsStoreUpsertFuncCall{v0, v1, v2, v3, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the Upsert method of the +// parent MockSubRepoPermsStore instance is invoked and the hook queue is +// empty. +func (f *SubRepoPermsStoreUpsertFunc) SetDefaultHook(hook func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// Upsert method of the parent MockSubRepoPermsStore instance invokes the +// hook at the front of the queue and discards it. After the queue is empty, +// the default hook function is invoked for any future action. +func (f *SubRepoPermsStoreUpsertFunc) PushHook(hook func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *SubRepoPermsStoreUpsertFunc) SetDefaultReturn(r0 error) { + f.SetDefaultHook(func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error { + return r0 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *SubRepoPermsStoreUpsertFunc) PushReturn(r0 error) { + f.PushHook(func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error { + return r0 + }) +} + +func (f *SubRepoPermsStoreUpsertFunc) nextHook() func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *SubRepoPermsStoreUpsertFunc) appendCall(r0 SubRepoPermsStoreUpsertFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of SubRepoPermsStoreUpsertFuncCall objects +// describing the invocations of this function. +func (f *SubRepoPermsStoreUpsertFunc) History() []SubRepoPermsStoreUpsertFuncCall { + f.mutex.Lock() + history := make([]SubRepoPermsStoreUpsertFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// SubRepoPermsStoreUpsertFuncCall is an object that describes an invocation +// of method Upsert on an instance of MockSubRepoPermsStore. +type SubRepoPermsStoreUpsertFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int32 + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 api.RepoID + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 authz.SubRepoPermissions + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c SubRepoPermsStoreUpsertFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c SubRepoPermsStoreUpsertFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} + +// SubRepoPermsStoreUpsertWithSpecFunc describes the behavior when the +// UpsertWithSpec method of the parent MockSubRepoPermsStore instance is +// invoked. +type SubRepoPermsStoreUpsertWithSpecFunc struct { + defaultHook func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error + hooks []func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error + history []SubRepoPermsStoreUpsertWithSpecFuncCall + mutex sync.Mutex +} + +// UpsertWithSpec delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockSubRepoPermsStore) UpsertWithSpec(v0 context.Context, v1 int32, v2 api.ExternalRepoSpec, v3 authz.SubRepoPermissions) error { + r0 := m.UpsertWithSpecFunc.nextHook()(v0, v1, v2, v3) + m.UpsertWithSpecFunc.appendCall(SubRepoPermsStoreUpsertWithSpecFuncCall{v0, v1, v2, v3, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the UpsertWithSpec +// method of the parent MockSubRepoPermsStore instance is invoked and the +// hook queue is empty. +func (f *SubRepoPermsStoreUpsertWithSpecFunc) SetDefaultHook(hook func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// UpsertWithSpec method of the parent MockSubRepoPermsStore instance +// invokes the hook at the front of the queue and discards it. After the +// queue is empty, the default hook function is invoked for any future +// action. +func (f *SubRepoPermsStoreUpsertWithSpecFunc) PushHook(hook func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *SubRepoPermsStoreUpsertWithSpecFunc) SetDefaultReturn(r0 error) { + f.SetDefaultHook(func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error { + return r0 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *SubRepoPermsStoreUpsertWithSpecFunc) PushReturn(r0 error) { + f.PushHook(func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error { + return r0 + }) +} + +func (f *SubRepoPermsStoreUpsertWithSpecFunc) nextHook() func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *SubRepoPermsStoreUpsertWithSpecFunc) appendCall(r0 SubRepoPermsStoreUpsertWithSpecFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of SubRepoPermsStoreUpsertWithSpecFuncCall +// objects describing the invocations of this function. +func (f *SubRepoPermsStoreUpsertWithSpecFunc) History() []SubRepoPermsStoreUpsertWithSpecFuncCall { + f.mutex.Lock() + history := make([]SubRepoPermsStoreUpsertWithSpecFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// SubRepoPermsStoreUpsertWithSpecFuncCall is an object that describes an +// invocation of method UpsertWithSpec on an instance of +// MockSubRepoPermsStore. +type SubRepoPermsStoreUpsertWithSpecFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int32 + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 api.ExternalRepoSpec + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 authz.SubRepoPermissions + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c SubRepoPermsStoreUpsertWithSpecFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c SubRepoPermsStoreUpsertWithSpecFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} + +// SubRepoPermsStoreWithFunc describes the behavior when the With method of +// the parent MockSubRepoPermsStore instance is invoked. +type SubRepoPermsStoreWithFunc struct { + defaultHook func(basestore.ShareableStore) SubRepoPermsStore + hooks []func(basestore.ShareableStore) SubRepoPermsStore + history []SubRepoPermsStoreWithFuncCall + mutex sync.Mutex +} + +// With delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockSubRepoPermsStore) With(v0 basestore.ShareableStore) SubRepoPermsStore { + r0 := m.WithFunc.nextHook()(v0) + m.WithFunc.appendCall(SubRepoPermsStoreWithFuncCall{v0, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the With method of the +// parent MockSubRepoPermsStore instance is invoked and the hook queue is +// empty. +func (f *SubRepoPermsStoreWithFunc) SetDefaultHook(hook func(basestore.ShareableStore) SubRepoPermsStore) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// With method of the parent MockSubRepoPermsStore instance invokes the hook +// at the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *SubRepoPermsStoreWithFunc) PushHook(hook func(basestore.ShareableStore) SubRepoPermsStore) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *SubRepoPermsStoreWithFunc) SetDefaultReturn(r0 SubRepoPermsStore) { + f.SetDefaultHook(func(basestore.ShareableStore) SubRepoPermsStore { + return r0 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *SubRepoPermsStoreWithFunc) PushReturn(r0 SubRepoPermsStore) { + f.PushHook(func(basestore.ShareableStore) SubRepoPermsStore { + return r0 + }) +} + +func (f *SubRepoPermsStoreWithFunc) nextHook() func(basestore.ShareableStore) SubRepoPermsStore { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *SubRepoPermsStoreWithFunc) appendCall(r0 SubRepoPermsStoreWithFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of SubRepoPermsStoreWithFuncCall objects +// describing the invocations of this function. +func (f *SubRepoPermsStoreWithFunc) History() []SubRepoPermsStoreWithFuncCall { + f.mutex.Lock() + history := make([]SubRepoPermsStoreWithFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// SubRepoPermsStoreWithFuncCall is an object that describes an invocation +// of method With on an instance of MockSubRepoPermsStore. +type SubRepoPermsStoreWithFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 basestore.ShareableStore + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 SubRepoPermsStore +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c SubRepoPermsStoreWithFuncCall) Args() []interface{} { + return []interface{}{c.Arg0} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c SubRepoPermsStoreWithFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} diff --git a/internal/database/sub_repo_perms_store.go b/enterprise/internal/database/sub_repo_perms_store.go similarity index 97% rename from internal/database/sub_repo_perms_store.go rename to enterprise/internal/database/sub_repo_perms_store.go index f3396495401..1b02aa68343 100644 --- a/internal/database/sub_repo_perms_store.go +++ b/enterprise/internal/database/sub_repo_perms_store.go @@ -18,8 +18,10 @@ import ( // and exclude patterns. const SubRepoPermsVersion = 1 -var SubRepoSupportedCodeHostTypes = []string{extsvc.TypePerforce} -var supportedTypesQuery = make([]*sqlf.Query, len(SubRepoSupportedCodeHostTypes)) +var ( + SubRepoSupportedCodeHostTypes = []string{extsvc.TypePerforce} + supportedTypesQuery = make([]*sqlf.Query, len(SubRepoSupportedCodeHostTypes)) +) func init() { // Build this up at startup, so we don't need to rebuild it every time @@ -53,6 +55,8 @@ type subRepoPermsStore struct { *basestore.Store } +var _ SubRepoPermsStore = (*subRepoPermsStore)(nil) + func SubRepoPermsWith(other basestore.ShareableStore) SubRepoPermsStore { return &subRepoPermsStore{Store: basestore.NewWithHandle(other.Handle())} } diff --git a/internal/database/sub_repo_perms_store_test.go b/enterprise/internal/database/sub_repo_perms_store_test.go similarity index 95% rename from internal/database/sub_repo_perms_store_test.go rename to enterprise/internal/database/sub_repo_perms_store_test.go index 06a337cb6a9..b6df1397713 100644 --- a/internal/database/sub_repo_perms_store_test.go +++ b/enterprise/internal/database/sub_repo_perms_store_test.go @@ -13,6 +13,7 @@ import ( "github.com/sourcegraph/sourcegraph/internal/api" "github.com/sourcegraph/sourcegraph/internal/authz" "github.com/sourcegraph/sourcegraph/internal/conf" + "github.com/sourcegraph/sourcegraph/internal/database" "github.com/sourcegraph/sourcegraph/internal/database/dbtest" "github.com/sourcegraph/sourcegraph/internal/database/dbutil" "github.com/sourcegraph/sourcegraph/schema" @@ -25,7 +26,7 @@ func TestSubRepoPermsInsert(t *testing.T) { t.Parallel() logger := logtest.Scoped(t) - db := NewDB(logger, dbtest.NewDB(logger, t)) + db := NewEnterpriseDB(database.NewDB(logger, dbtest.NewDB(logger, t))) ctx := context.Background() prepareSubRepoTestData(ctx, t, db) @@ -57,7 +58,7 @@ func TestSubRepoPermsDeleteByUser(t *testing.T) { t.Parallel() logger := logtest.Scoped(t) - db := NewDB(logger, dbtest.NewDB(logger, t)) + db := NewEnterpriseDB(database.NewDB(logger, dbtest.NewDB(logger, t))) ctx := context.Background() prepareSubRepoTestData(ctx, t, db) @@ -92,7 +93,7 @@ func TestSubRepoPermsUpsert(t *testing.T) { t.Parallel() logger := logtest.Scoped(t) - db := NewDB(logger, dbtest.NewDB(logger, t)) + db := NewEnterpriseDB(database.NewDB(logger, dbtest.NewDB(logger, t))) ctx := context.Background() prepareSubRepoTestData(ctx, t, db) @@ -133,7 +134,7 @@ func TestSubRepoPermsUpsertWithSpec(t *testing.T) { t.Parallel() logger := logtest.Scoped(t) - db := NewDB(logger, dbtest.NewDB(logger, t)) + db := NewEnterpriseDB(database.NewDB(logger, dbtest.NewDB(logger, t))) ctx := context.Background() prepareSubRepoTestData(ctx, t, db) @@ -181,7 +182,7 @@ func TestSubRepoPermsGetByUser(t *testing.T) { t.Cleanup(func() { conf.Mock(nil) }) logger := logtest.Scoped(t) - db := NewDB(logger, dbtest.NewDB(logger, t)) + db := NewEnterpriseDB(database.NewDB(logger, dbtest.NewDB(logger, t))) ctx := context.Background() s := db.SubRepoPerms() @@ -264,7 +265,7 @@ func TestSubRepoPermsGetByUserAndService(t *testing.T) { logger := logtest.Scoped(t) - db := NewDB(logger, dbtest.NewDB(logger, t)) + db := NewEnterpriseDB(database.NewDB(logger, dbtest.NewDB(logger, t))) ctx := context.Background() s := db.SubRepoPerms() @@ -342,7 +343,7 @@ func TestSubRepoPermsSupportedForRepoId(t *testing.T) { t.Parallel() logger := logtest.Scoped(t) - db := NewDB(logger, dbtest.NewDB(logger, t)) + db := NewEnterpriseDB(database.NewDB(logger, dbtest.NewDB(logger, t))) ctx := context.Background() s := db.SubRepoPerms() diff --git a/enterprise/internal/gitserver/integration_tests/commits_test.go b/enterprise/internal/gitserver/integration_tests/commits_test.go new file mode 100644 index 00000000000..daf56f60c70 --- /dev/null +++ b/enterprise/internal/gitserver/integration_tests/commits_test.go @@ -0,0 +1,158 @@ +package inttests + +import ( + "context" + "fmt" + "net/http" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + + "github.com/sourcegraph/sourcegraph/internal/actor" + "github.com/sourcegraph/sourcegraph/internal/api" + "github.com/sourcegraph/sourcegraph/internal/authz" + "github.com/sourcegraph/sourcegraph/internal/database" + "github.com/sourcegraph/sourcegraph/internal/gitserver" + "github.com/sourcegraph/sourcegraph/internal/gitserver/gitdomain" + inttests "github.com/sourcegraph/sourcegraph/internal/gitserver/integration_tests" +) + +func TestGetCommits(t *testing.T) { + t.Parallel() + inttests.InitGitserver() + ctx := actor.WithActor(context.Background(), &actor.Actor{ + UID: 1, + }) + db := database.NewMockDB() + gr := database.NewMockGitserverRepoStore() + db.GitserverReposFunc.SetDefaultReturn(gr) + + repo1 := inttests.MakeGitRepository(t, getGitCommandsWithFiles("file1", "file2")...) + repo2 := inttests.MakeGitRepository(t, getGitCommandsWithFiles("file3", "file4")...) + repo3 := inttests.MakeGitRepository(t, getGitCommandsWithFiles("file5", "file6")...) + + repoCommits := []api.RepoCommit{ + {Repo: repo1, CommitID: api.CommitID("HEAD")}, // HEAD (file2) + {Repo: repo1, CommitID: api.CommitID("HEAD~1")}, // HEAD~1 (file1) + {Repo: repo2, CommitID: api.CommitID("67762ad757dd26cac4145f2b744fd93ad10a48e0")}, // HEAD (file4) + {Repo: repo2, CommitID: api.CommitID("2b988222e844b570959a493f5b07ec020b89e122")}, // HEAD~1 (file3) + {Repo: repo3, CommitID: api.CommitID("01bed0a")}, // abbrev HEAD (file6) + {Repo: repo3, CommitID: api.CommitID("unresolvable")}, // unresolvable + {Repo: api.RepoName("unresolvable"), CommitID: api.CommitID("deadbeef")}, // unresolvable + } + + t.Run("with sub-repo permissions", func(t *testing.T) { + expectedCommits := []*gitdomain.Commit{ + { + ID: "2ba4dd2b9a27ec125fea7d72e12b9824ead18631", + Author: gitdomain.Signature{Name: "a", Email: "a@a.com", Date: *mustParseDate("2006-01-02T15:04:05Z", t)}, + Committer: &gitdomain.Signature{Name: "a", Email: "a@a.com", Date: *mustParseDate("2006-01-02T15:04:05Z", t)}, + Message: "commit2", + Parents: []api.CommitID{"d38233a79e037d2ab8170b0d0bc0aa438473e6da"}, + }, + nil, // file 1 + { + ID: "67762ad757dd26cac4145f2b744fd93ad10a48e0", + Author: gitdomain.Signature{Name: "a", Email: "a@a.com", Date: *mustParseDate("2006-01-02T15:04:05Z", t)}, + Committer: &gitdomain.Signature{Name: "a", Email: "a@a.com", Date: *mustParseDate("2006-01-02T15:04:05Z", t)}, + Message: "commit2", + Parents: []api.CommitID{"2b988222e844b570959a493f5b07ec020b89e122"}, + }, + nil, // file 3 + { + ID: "01bed0ae660668c57539cecaacb4c33d77609f43", + Author: gitdomain.Signature{Name: "a", Email: "a@a.com", Date: *mustParseDate("2006-01-02T15:04:05Z", t)}, + Committer: &gitdomain.Signature{Name: "a", Email: "a@a.com", Date: *mustParseDate("2006-01-02T15:04:05Z", t)}, + Message: "commit2", + Parents: []api.CommitID{"d6ce2e76d171569d81c0afdc4573f461cec17d45"}, + }, + nil, + nil, + } + + commits, err := gitserver.NewTestClient(http.DefaultClient, db, inttests.GitserverAddresses).GetCommits(ctx, getTestSubRepoPermsChecker("file1", "file3"), repoCommits, true) + if err != nil { + t.Fatalf("unexpected error calling getCommits: %s", err) + } + if diff := cmp.Diff(expectedCommits, commits); diff != "" { + t.Errorf("unexpected commits (-want +got):\n%s", diff) + } + }) +} + +// get a test sub-repo permissions checker which allows access to all files (so should be a no-op) +func getTestSubRepoPermsChecker(noAccessPaths ...string) authz.SubRepoPermissionChecker { + checker := authz.NewMockSubRepoPermissionChecker() + checker.EnabledFunc.SetDefaultHook(func() bool { + return true + }) + checker.PermissionsFunc.SetDefaultHook(func(ctx context.Context, i int32, content authz.RepoContent) (authz.Perms, error) { + for _, noAccessPath := range noAccessPaths { + if content.Path == noAccessPath { + return authz.None, nil + } + } + return authz.Read, nil + }) + return checker +} + +func getGitCommandsWithFiles(fileName1, fileName2 string) []string { + return []string{ + fmt.Sprintf("touch %s", fileName1), + fmt.Sprintf("git add %s", fileName1), + "GIT_COMMITTER_NAME=a GIT_COMMITTER_EMAIL=a@a.com GIT_COMMITTER_DATE=2006-01-02T15:04:05Z git commit -m commit1 --author='a ' --date 2006-01-02T15:04:05Z", + fmt.Sprintf("touch %s", fileName2), + fmt.Sprintf("git add %s", fileName2), + "GIT_COMMITTER_NAME=a GIT_COMMITTER_EMAIL=a@a.com GIT_COMMITTER_DATE=2006-01-02T15:04:05Z git commit -m commit2 --author='a ' --date 2006-01-02T15:04:05Z", + } +} + +func mustParseDate(s string, t *testing.T) *time.Time { + t.Helper() + date, err := time.Parse(time.RFC3339, s) + if err != nil { + t.Fatalf("unexpected error parsing date string: %s", err) + } + return &date +} + +func TestHead(t *testing.T) { + inttests.InitGitserver() + client := gitserver.NewTestClient(http.DefaultClient, database.NewMockDB(), inttests.GitserverAddresses) + + t.Run("with sub-repo permissions", func(t *testing.T) { + gitCommands := []string{ + "touch file", + "git add file", + "GIT_COMMITTER_NAME=a GIT_COMMITTER_EMAIL=a@a.com GIT_COMMITTER_DATE=2006-01-02T15:04:05Z git commit -m foo --author='a ' --date 2006-01-02T15:04:05Z", + } + repo := inttests.MakeGitRepository(t, gitCommands...) + ctx := actor.WithActor(context.Background(), &actor.Actor{ + UID: 1, + }) + checker := getTestSubRepoPermsChecker("file") + // call Head() when user doesn't have access to view the commit + _, exists, err := client.Head(ctx, checker, repo) + if err != nil { + t.Fatal(err) + } + if exists { + t.Fatalf("exists should be false since the user doesn't have access to view the commit") + } + readAllChecker := getTestSubRepoPermsChecker() + // call Head() when user has access to view the commit; should return expected commit + head, exists, err := client.Head(ctx, readAllChecker, repo) + if err != nil { + t.Fatal(err) + } + wantHead := "46619ad353dbe4ed4108ebde9aa59ef676994a0b" + if head != wantHead { + t.Fatalf("Want %q, got %q", wantHead, head) + } + if !exists { + t.Fatal("Should exist") + } + }) +} diff --git a/enterprise/internal/gitserver/integration_tests/tree_test.go b/enterprise/internal/gitserver/integration_tests/tree_test.go new file mode 100644 index 00000000000..53b10f0ae61 --- /dev/null +++ b/enterprise/internal/gitserver/integration_tests/tree_test.go @@ -0,0 +1,74 @@ +package inttests + +import ( + "context" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" + + srp "github.com/sourcegraph/sourcegraph/enterprise/internal/authz/subrepoperms" + edb "github.com/sourcegraph/sourcegraph/enterprise/internal/database" + "github.com/sourcegraph/sourcegraph/internal/actor" + "github.com/sourcegraph/sourcegraph/internal/api" + "github.com/sourcegraph/sourcegraph/internal/authz" + "github.com/sourcegraph/sourcegraph/internal/conf" + "github.com/sourcegraph/sourcegraph/internal/database" + "github.com/sourcegraph/sourcegraph/internal/gitserver" + inttests "github.com/sourcegraph/sourcegraph/internal/gitserver/integration_tests" + "github.com/sourcegraph/sourcegraph/schema" +) + +func TestReadDir_SubRepoFiltering(t *testing.T) { + inttests.InitGitserver() + + ctx := actor.WithActor(context.Background(), &actor.Actor{ + UID: 1, + }) + gitCommands := []string{ + "touch file1", + "git add file1", + "GIT_COMMITTER_NAME=a GIT_COMMITTER_EMAIL=a@a.com GIT_COMMITTER_DATE=2006-01-02T15:04:05Z git commit -m commit1 --author='a ' --date 2006-01-02T15:04:05Z", + "mkdir app", + "touch app/file2", + "git add app", + "GIT_COMMITTER_NAME=a GIT_COMMITTER_EMAIL=a@a.com GIT_COMMITTER_DATE=2006-01-02T15:04:05Z git commit -m commit2 --author='a ' --date 2006-01-02T15:04:05Z", + } + repo := inttests.MakeGitRepository(t, gitCommands...) + commitID := api.CommitID("b1c725720de2bbd0518731b4a61959797ff345f3") + conf.Mock(&conf.Unified{ + SiteConfiguration: schema.SiteConfiguration{ + ExperimentalFeatures: &schema.ExperimentalFeatures{ + SubRepoPermissions: &schema.SubRepoPermissions{ + Enabled: true, + }, + }, + }, + }) + defer conf.Mock(nil) + srpGetter := edb.NewMockSubRepoPermsStore() + testSubRepoPerms := map[api.RepoName]authz.SubRepoPermissions{ + repo: { + Paths: []string{"/**", "-/app/**"}, + }, + } + srpGetter.GetByUserFunc.SetDefaultReturn(testSubRepoPerms, nil) + checker, err := srp.NewSubRepoPermsClient(srpGetter) + if err != nil { + t.Fatalf("unexpected error creating sub-repo perms client: %s", err) + } + + db := database.NewMockDB() + gr := database.NewMockGitserverRepoStore() + db.GitserverReposFunc.SetDefaultReturn(gr) + client := gitserver.NewTestClient(http.DefaultClient, db, inttests.GitserverAddresses) + files, err := client.ReadDir(ctx, checker, repo, commitID, "", false) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + // Because we have a wildcard matcher we still allow directory visibility + assert.Len(t, files, 1) + assert.Equal(t, "file1", files[0].Name()) + assert.False(t, files[0].IsDir()) +} diff --git a/enterprise/internal/search/symbol/symbol_test.go b/enterprise/internal/search/symbol/symbol_test.go new file mode 100644 index 00000000000..c5f9e0a3b89 --- /dev/null +++ b/enterprise/internal/search/symbol/symbol_test.go @@ -0,0 +1,60 @@ +package symbol + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + + srp "github.com/sourcegraph/sourcegraph/enterprise/internal/authz/subrepoperms" + "github.com/sourcegraph/sourcegraph/internal/actor" + "github.com/sourcegraph/sourcegraph/internal/api" + "github.com/sourcegraph/sourcegraph/internal/conf" + "github.com/sourcegraph/sourcegraph/internal/search/result" + "github.com/sourcegraph/sourcegraph/internal/search/symbol" + "github.com/sourcegraph/sourcegraph/schema" +) + +func TestFilterZoektResults(t *testing.T) { + conf.Mock(&conf.Unified{ + SiteConfiguration: schema.SiteConfiguration{ + ExperimentalFeatures: &schema.ExperimentalFeatures{ + SubRepoPermissions: &schema.SubRepoPermissions{ + Enabled: true, + }, + }, + }, + }) + t.Cleanup(func() { conf.Mock(nil) }) + + repoName := api.RepoName("foo") + ctx := context.Background() + ctx = actor.WithActor(ctx, &actor.Actor{ + UID: 1, + }) + checker, err := srp.NewSimpleChecker(repoName, []string{"/**", "-/*_test.go"}) + if err != nil { + t.Fatal(err) + } + results := []*result.SymbolMatch{ + { + Symbol: result.Symbol{}, + File: &result.File{ + Path: "foo.go", + }, + }, + { + Symbol: result.Symbol{}, + File: &result.File{ + Path: "foo_test.go", + }, + }, + } + filtered, err := symbol.FilterZoektResults(ctx, checker, repoName, results) + if err != nil { + t.Fatal(err) + } + assert.Len(t, filtered, 1) + r := filtered[0] + assert.Equal(t, r.File.Path, "foo.go") +} diff --git a/internal/authz/mocks_temp.go b/internal/authz/mocks_temp.go index 952100652e5..d5483490994 100644 --- a/internal/authz/mocks_temp.go +++ b/internal/authz/mocks_temp.go @@ -677,416 +677,3 @@ func (c SubRepoPermissionCheckerPermissionsFuncCall) Args() []interface{} { func (c SubRepoPermissionCheckerPermissionsFuncCall) Results() []interface{} { return []interface{}{c.Result0, c.Result1} } - -// MockSubRepoPermissionsGetter is a mock implementation of the -// SubRepoPermissionsGetter interface (from the package -// github.com/sourcegraph/sourcegraph/internal/authz) used for unit testing. -type MockSubRepoPermissionsGetter struct { - // GetByUserFunc is an instance of a mock function object controlling - // the behavior of the method GetByUser. - GetByUserFunc *SubRepoPermissionsGetterGetByUserFunc - // RepoIDSupportedFunc is an instance of a mock function object - // controlling the behavior of the method RepoIDSupported. - RepoIDSupportedFunc *SubRepoPermissionsGetterRepoIDSupportedFunc - // RepoSupportedFunc is an instance of a mock function object - // controlling the behavior of the method RepoSupported. - RepoSupportedFunc *SubRepoPermissionsGetterRepoSupportedFunc -} - -// NewMockSubRepoPermissionsGetter creates a new mock of the -// SubRepoPermissionsGetter interface. All methods return zero values for -// all results, unless overwritten. -func NewMockSubRepoPermissionsGetter() *MockSubRepoPermissionsGetter { - return &MockSubRepoPermissionsGetter{ - GetByUserFunc: &SubRepoPermissionsGetterGetByUserFunc{ - defaultHook: func(context.Context, int32) (r0 map[api.RepoName]SubRepoPermissions, r1 error) { - return - }, - }, - RepoIDSupportedFunc: &SubRepoPermissionsGetterRepoIDSupportedFunc{ - defaultHook: func(context.Context, api.RepoID) (r0 bool, r1 error) { - return - }, - }, - RepoSupportedFunc: &SubRepoPermissionsGetterRepoSupportedFunc{ - defaultHook: func(context.Context, api.RepoName) (r0 bool, r1 error) { - return - }, - }, - } -} - -// NewStrictMockSubRepoPermissionsGetter creates a new mock of the -// SubRepoPermissionsGetter interface. All methods panic on invocation, -// unless overwritten. -func NewStrictMockSubRepoPermissionsGetter() *MockSubRepoPermissionsGetter { - return &MockSubRepoPermissionsGetter{ - GetByUserFunc: &SubRepoPermissionsGetterGetByUserFunc{ - defaultHook: func(context.Context, int32) (map[api.RepoName]SubRepoPermissions, error) { - panic("unexpected invocation of MockSubRepoPermissionsGetter.GetByUser") - }, - }, - RepoIDSupportedFunc: &SubRepoPermissionsGetterRepoIDSupportedFunc{ - defaultHook: func(context.Context, api.RepoID) (bool, error) { - panic("unexpected invocation of MockSubRepoPermissionsGetter.RepoIDSupported") - }, - }, - RepoSupportedFunc: &SubRepoPermissionsGetterRepoSupportedFunc{ - defaultHook: func(context.Context, api.RepoName) (bool, error) { - panic("unexpected invocation of MockSubRepoPermissionsGetter.RepoSupported") - }, - }, - } -} - -// NewMockSubRepoPermissionsGetterFrom creates a new mock of the -// MockSubRepoPermissionsGetter interface. All methods delegate to the given -// implementation, unless overwritten. -func NewMockSubRepoPermissionsGetterFrom(i SubRepoPermissionsGetter) *MockSubRepoPermissionsGetter { - return &MockSubRepoPermissionsGetter{ - GetByUserFunc: &SubRepoPermissionsGetterGetByUserFunc{ - defaultHook: i.GetByUser, - }, - RepoIDSupportedFunc: &SubRepoPermissionsGetterRepoIDSupportedFunc{ - defaultHook: i.RepoIDSupported, - }, - RepoSupportedFunc: &SubRepoPermissionsGetterRepoSupportedFunc{ - defaultHook: i.RepoSupported, - }, - } -} - -// SubRepoPermissionsGetterGetByUserFunc describes the behavior when the -// GetByUser method of the parent MockSubRepoPermissionsGetter instance is -// invoked. -type SubRepoPermissionsGetterGetByUserFunc struct { - defaultHook func(context.Context, int32) (map[api.RepoName]SubRepoPermissions, error) - hooks []func(context.Context, int32) (map[api.RepoName]SubRepoPermissions, error) - history []SubRepoPermissionsGetterGetByUserFuncCall - mutex sync.Mutex -} - -// GetByUser delegates to the next hook function in the queue and stores the -// parameter and result values of this invocation. -func (m *MockSubRepoPermissionsGetter) GetByUser(v0 context.Context, v1 int32) (map[api.RepoName]SubRepoPermissions, error) { - r0, r1 := m.GetByUserFunc.nextHook()(v0, v1) - m.GetByUserFunc.appendCall(SubRepoPermissionsGetterGetByUserFuncCall{v0, v1, r0, r1}) - return r0, r1 -} - -// SetDefaultHook sets function that is called when the GetByUser method of -// the parent MockSubRepoPermissionsGetter instance is invoked and the hook -// queue is empty. -func (f *SubRepoPermissionsGetterGetByUserFunc) SetDefaultHook(hook func(context.Context, int32) (map[api.RepoName]SubRepoPermissions, error)) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// GetByUser method of the parent MockSubRepoPermissionsGetter instance -// invokes the hook at the front of the queue and discards it. After the -// queue is empty, the default hook function is invoked for any future -// action. -func (f *SubRepoPermissionsGetterGetByUserFunc) PushHook(hook func(context.Context, int32) (map[api.RepoName]SubRepoPermissions, error)) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *SubRepoPermissionsGetterGetByUserFunc) SetDefaultReturn(r0 map[api.RepoName]SubRepoPermissions, r1 error) { - f.SetDefaultHook(func(context.Context, int32) (map[api.RepoName]SubRepoPermissions, error) { - return r0, r1 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *SubRepoPermissionsGetterGetByUserFunc) PushReturn(r0 map[api.RepoName]SubRepoPermissions, r1 error) { - f.PushHook(func(context.Context, int32) (map[api.RepoName]SubRepoPermissions, error) { - return r0, r1 - }) -} - -func (f *SubRepoPermissionsGetterGetByUserFunc) nextHook() func(context.Context, int32) (map[api.RepoName]SubRepoPermissions, error) { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *SubRepoPermissionsGetterGetByUserFunc) appendCall(r0 SubRepoPermissionsGetterGetByUserFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of SubRepoPermissionsGetterGetByUserFuncCall -// objects describing the invocations of this function. -func (f *SubRepoPermissionsGetterGetByUserFunc) History() []SubRepoPermissionsGetterGetByUserFuncCall { - f.mutex.Lock() - history := make([]SubRepoPermissionsGetterGetByUserFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// SubRepoPermissionsGetterGetByUserFuncCall is an object that describes an -// invocation of method GetByUser on an instance of -// MockSubRepoPermissionsGetter. -type SubRepoPermissionsGetterGetByUserFuncCall struct { - // Arg0 is the value of the 1st argument passed to this method - // invocation. - Arg0 context.Context - // Arg1 is the value of the 2nd argument passed to this method - // invocation. - Arg1 int32 - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 map[api.RepoName]SubRepoPermissions - // Result1 is the value of the 2nd result returned from this method - // invocation. - Result1 error -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c SubRepoPermissionsGetterGetByUserFuncCall) Args() []interface{} { - return []interface{}{c.Arg0, c.Arg1} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c SubRepoPermissionsGetterGetByUserFuncCall) Results() []interface{} { - return []interface{}{c.Result0, c.Result1} -} - -// SubRepoPermissionsGetterRepoIDSupportedFunc describes the behavior when -// the RepoIDSupported method of the parent MockSubRepoPermissionsGetter -// instance is invoked. -type SubRepoPermissionsGetterRepoIDSupportedFunc struct { - defaultHook func(context.Context, api.RepoID) (bool, error) - hooks []func(context.Context, api.RepoID) (bool, error) - history []SubRepoPermissionsGetterRepoIDSupportedFuncCall - mutex sync.Mutex -} - -// RepoIDSupported delegates to the next hook function in the queue and -// stores the parameter and result values of this invocation. -func (m *MockSubRepoPermissionsGetter) RepoIDSupported(v0 context.Context, v1 api.RepoID) (bool, error) { - r0, r1 := m.RepoIDSupportedFunc.nextHook()(v0, v1) - m.RepoIDSupportedFunc.appendCall(SubRepoPermissionsGetterRepoIDSupportedFuncCall{v0, v1, r0, r1}) - return r0, r1 -} - -// SetDefaultHook sets function that is called when the RepoIDSupported -// method of the parent MockSubRepoPermissionsGetter instance is invoked and -// the hook queue is empty. -func (f *SubRepoPermissionsGetterRepoIDSupportedFunc) SetDefaultHook(hook func(context.Context, api.RepoID) (bool, error)) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// RepoIDSupported method of the parent MockSubRepoPermissionsGetter -// instance invokes the hook at the front of the queue and discards it. -// After the queue is empty, the default hook function is invoked for any -// future action. -func (f *SubRepoPermissionsGetterRepoIDSupportedFunc) PushHook(hook func(context.Context, api.RepoID) (bool, error)) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *SubRepoPermissionsGetterRepoIDSupportedFunc) SetDefaultReturn(r0 bool, r1 error) { - f.SetDefaultHook(func(context.Context, api.RepoID) (bool, error) { - return r0, r1 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *SubRepoPermissionsGetterRepoIDSupportedFunc) PushReturn(r0 bool, r1 error) { - f.PushHook(func(context.Context, api.RepoID) (bool, error) { - return r0, r1 - }) -} - -func (f *SubRepoPermissionsGetterRepoIDSupportedFunc) nextHook() func(context.Context, api.RepoID) (bool, error) { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *SubRepoPermissionsGetterRepoIDSupportedFunc) appendCall(r0 SubRepoPermissionsGetterRepoIDSupportedFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of -// SubRepoPermissionsGetterRepoIDSupportedFuncCall objects describing the -// invocations of this function. -func (f *SubRepoPermissionsGetterRepoIDSupportedFunc) History() []SubRepoPermissionsGetterRepoIDSupportedFuncCall { - f.mutex.Lock() - history := make([]SubRepoPermissionsGetterRepoIDSupportedFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// SubRepoPermissionsGetterRepoIDSupportedFuncCall is an object that -// describes an invocation of method RepoIDSupported on an instance of -// MockSubRepoPermissionsGetter. -type SubRepoPermissionsGetterRepoIDSupportedFuncCall struct { - // Arg0 is the value of the 1st argument passed to this method - // invocation. - Arg0 context.Context - // Arg1 is the value of the 2nd argument passed to this method - // invocation. - Arg1 api.RepoID - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 bool - // Result1 is the value of the 2nd result returned from this method - // invocation. - Result1 error -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c SubRepoPermissionsGetterRepoIDSupportedFuncCall) Args() []interface{} { - return []interface{}{c.Arg0, c.Arg1} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c SubRepoPermissionsGetterRepoIDSupportedFuncCall) Results() []interface{} { - return []interface{}{c.Result0, c.Result1} -} - -// SubRepoPermissionsGetterRepoSupportedFunc describes the behavior when the -// RepoSupported method of the parent MockSubRepoPermissionsGetter instance -// is invoked. -type SubRepoPermissionsGetterRepoSupportedFunc struct { - defaultHook func(context.Context, api.RepoName) (bool, error) - hooks []func(context.Context, api.RepoName) (bool, error) - history []SubRepoPermissionsGetterRepoSupportedFuncCall - mutex sync.Mutex -} - -// RepoSupported delegates to the next hook function in the queue and stores -// the parameter and result values of this invocation. -func (m *MockSubRepoPermissionsGetter) RepoSupported(v0 context.Context, v1 api.RepoName) (bool, error) { - r0, r1 := m.RepoSupportedFunc.nextHook()(v0, v1) - m.RepoSupportedFunc.appendCall(SubRepoPermissionsGetterRepoSupportedFuncCall{v0, v1, r0, r1}) - return r0, r1 -} - -// SetDefaultHook sets function that is called when the RepoSupported method -// of the parent MockSubRepoPermissionsGetter instance is invoked and the -// hook queue is empty. -func (f *SubRepoPermissionsGetterRepoSupportedFunc) SetDefaultHook(hook func(context.Context, api.RepoName) (bool, error)) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// RepoSupported method of the parent MockSubRepoPermissionsGetter instance -// invokes the hook at the front of the queue and discards it. After the -// queue is empty, the default hook function is invoked for any future -// action. -func (f *SubRepoPermissionsGetterRepoSupportedFunc) PushHook(hook func(context.Context, api.RepoName) (bool, error)) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *SubRepoPermissionsGetterRepoSupportedFunc) SetDefaultReturn(r0 bool, r1 error) { - f.SetDefaultHook(func(context.Context, api.RepoName) (bool, error) { - return r0, r1 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *SubRepoPermissionsGetterRepoSupportedFunc) PushReturn(r0 bool, r1 error) { - f.PushHook(func(context.Context, api.RepoName) (bool, error) { - return r0, r1 - }) -} - -func (f *SubRepoPermissionsGetterRepoSupportedFunc) nextHook() func(context.Context, api.RepoName) (bool, error) { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *SubRepoPermissionsGetterRepoSupportedFunc) appendCall(r0 SubRepoPermissionsGetterRepoSupportedFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of -// SubRepoPermissionsGetterRepoSupportedFuncCall objects describing the -// invocations of this function. -func (f *SubRepoPermissionsGetterRepoSupportedFunc) History() []SubRepoPermissionsGetterRepoSupportedFuncCall { - f.mutex.Lock() - history := make([]SubRepoPermissionsGetterRepoSupportedFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// SubRepoPermissionsGetterRepoSupportedFuncCall is an object that describes -// an invocation of method RepoSupported on an instance of -// MockSubRepoPermissionsGetter. -type SubRepoPermissionsGetterRepoSupportedFuncCall struct { - // Arg0 is the value of the 1st argument passed to this method - // invocation. - Arg0 context.Context - // Arg1 is the value of the 2nd argument passed to this method - // invocation. - Arg1 api.RepoName - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 bool - // Result1 is the value of the 2nd result returned from this method - // invocation. - Result1 error -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c SubRepoPermissionsGetterRepoSupportedFuncCall) Args() []interface{} { - return []interface{}{c.Arg0, c.Arg1} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c SubRepoPermissionsGetterRepoSupportedFuncCall) Results() []interface{} { - return []interface{}{c.Result0, c.Result1} -} diff --git a/internal/authz/sub_repo_perms.go b/internal/authz/sub_repo_perms.go index 4f1052d1be2..570d93ea221 100644 --- a/internal/authz/sub_repo_perms.go +++ b/internal/authz/sub_repo_perms.go @@ -7,16 +7,11 @@ import ( "strings" "time" - "github.com/gobwas/glob" - lru "github.com/hashicorp/golang-lru" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "go.uber.org/atomic" - "golang.org/x/sync/singleflight" "github.com/sourcegraph/sourcegraph/internal/actor" "github.com/sourcegraph/sourcegraph/internal/api" - "github.com/sourcegraph/sourcegraph/internal/conf" "github.com/sourcegraph/sourcegraph/lib/errors" ) @@ -90,336 +85,12 @@ func (*noopPermsChecker) EnabledForRepo(ctx context.Context, repo api.RepoName) return false, nil } -var _ SubRepoPermissionChecker = &SubRepoPermsClient{} - -// SubRepoPermissionsGetter allows getting sub repository permissions. -type SubRepoPermissionsGetter interface { - // GetByUser returns the sub repository permissions rules known for a user. - GetByUser(ctx context.Context, userID int32) (map[api.RepoName]SubRepoPermissions, error) - - // RepoIDSupported returns true if repo with the given ID has sub-repo permissions. - RepoIDSupported(ctx context.Context, repoID api.RepoID) (bool, error) - - // RepoSupported returns true if repo with the given name has sub-repo permissions. - RepoSupported(ctx context.Context, repo api.RepoName) (bool, error) -} - -// SubRepoPermsClient is a concrete implementation of SubRepoPermissionChecker. -// Always use NewSubRepoPermsClient to instantiate an instance. -type SubRepoPermsClient struct { - permissionsGetter SubRepoPermissionsGetter - clock func() time.Time - since func(time.Time) time.Duration - - group *singleflight.Group - cache *lru.Cache - enabled *atomic.Bool -} - -const defaultCacheSize = 1000 -const defaultCacheTTL = 10 * time.Second - -// cachedRules caches the perms rules known for a particular user by repo. -type cachedRules struct { - rules map[api.RepoName]compiledRules - timestamp time.Time -} - -type path struct { - globPath glob.Glob - exclusion bool - // the original rule before it was compiled into a glob matcher - original string -} - -type compiledRules struct { - paths []path -} - -// GetPermissionsForPath tries to match a given path to a list of rules. -// Since the last applicable rule is the one that applies, the list is -// traversed in reverse, and the function returns as soon as a match is found. -// If no match is found, None is returned. -func (rules compiledRules) GetPermissionsForPath(path string) Perms { - for i := len(rules.paths) - 1; i >= 0; i-- { - if rules.paths[i].globPath.Match(path) { - if rules.paths[i].exclusion { - return None - } - return Read - } - } - - // Return None if no rule matches - return None -} - -// NewSubRepoPermsClient instantiates an instance of authz.SubRepoPermsClient -// which implements SubRepoPermissionChecker. -// -// SubRepoPermissionChecker is responsible for checking whether a user has access -// to data within a repo. Sub-repository permissions enforcement is on top of -// existing repository permissions, which means the user must already have access -// to the repository itself. The intention is for this client to be created once -// at startup and passed in to all places that need to check sub repo -// permissions. -// -// Note that sub-repo permissions are currently opt-in via the -// experimentalFeatures.enableSubRepoPermissions option. -func NewSubRepoPermsClient(permissionsGetter SubRepoPermissionsGetter) (*SubRepoPermsClient, error) { - cache, err := lru.New(defaultCacheSize) - if err != nil { - return nil, errors.Wrap(err, "creating LRU cache") - } - - enabled := atomic.NewBool(false) - - conf.Watch(func() { - c := conf.Get() - if c.ExperimentalFeatures == nil || c.ExperimentalFeatures.SubRepoPermissions == nil { - enabled.Store(false) - return - } - - cacheSize := c.ExperimentalFeatures.SubRepoPermissions.UserCacheSize - if cacheSize == 0 { - cacheSize = defaultCacheSize - } - cache.Resize(cacheSize) - enabled.Store(c.ExperimentalFeatures.SubRepoPermissions.Enabled) - }) - - return &SubRepoPermsClient{ - permissionsGetter: permissionsGetter, - clock: time.Now, - since: time.Since, - group: &singleflight.Group{}, - cache: cache, - enabled: enabled, - }, nil -} - -var ( - metricSubRepoPermsPermissionsDurationSuccess prometheus.Observer - metricSubRepoPermsPermissionsDurationError prometheus.Observer -) - -func init() { - // We cache the result of WithLabelValues since we call them in - // performance sensitive code. See BenchmarkFilterActorPaths. - metric := promauto.NewHistogramVec(prometheus.HistogramOpts{ - Name: "authz_sub_repo_perms_permissions_duration_seconds", - Help: "Time spent calculating permissions of a file for an actor.", - }, []string{"error"}) - metricSubRepoPermsPermissionsDurationSuccess = metric.WithLabelValues("false") - metricSubRepoPermsPermissionsDurationError = metric.WithLabelValues("true") -} - -var ( - metricSubRepoPermCacheHit prometheus.Counter - metricSubRepoPermCacheMiss prometheus.Counter -) - -func init() { - // We cache the result of WithLabelValues since we call them in - // performance sensitive code. See BenchmarkFilterActorPaths. - metric := promauto.NewCounterVec(prometheus.CounterOpts{ - Name: "authz_sub_repo_perms_permissions_cache_count", - Help: "The number of sub-repo perms cache hits or misses", - }, []string{"hit"}) - metricSubRepoPermCacheHit = metric.WithLabelValues("true") - metricSubRepoPermCacheMiss = metric.WithLabelValues("false") -} - -// Permissions return the current permissions granted to the given user on the -// given content. If sub-repo permissions are disabled, it is a no-op that return -// Read. -func (s *SubRepoPermsClient) Permissions(ctx context.Context, userID int32, content RepoContent) (perms Perms, err error) { - // Are sub-repo permissions enabled at the site level - if !s.Enabled() { - return Read, nil - } - - began := time.Now() - defer func() { - took := time.Since(began).Seconds() - if err == nil { - metricSubRepoPermsPermissionsDurationSuccess.Observe(took) - } else { - metricSubRepoPermsPermissionsDurationError.Observe(took) - } - }() - - f, err := s.FilePermissionsFunc(ctx, userID, content.Repo) - if err != nil { - return None, err - } - return f(content.Path) -} - // filePermissionsFuncAllRead is a FilePermissionFunc which _always_ returns // Read. Only use in cases that sub repo permission checks should not be done. func filePermissionsFuncAllRead(_ string) (Perms, error) { return Read, nil } -func (s *SubRepoPermsClient) FilePermissionsFunc(ctx context.Context, userID int32, repo api.RepoName) (FilePermissionFunc, error) { - // Are sub-repo permissions enabled at the site level - if !s.Enabled() { - return filePermissionsFuncAllRead, nil - } - - if s.permissionsGetter == nil { - return nil, errors.New("permissionsGetter is nil") - } - - if userID == 0 { - return nil, &ErrUnauthenticated{} - } - - repoRules, err := s.getCompiledRules(ctx, userID) - if err != nil { - return nil, errors.Wrap(err, "compiling match rules") - } - - rules, rulesExist := repoRules[repo] - if !rulesExist { - // If we make it this far it implies that we have access at the repo level. - // Having any empty set of rules here implies that we can access the whole repo. - // Repos that support sub-repo permissions will only have an entry in our - // repo_permissions table after all sub-repo permissions have been processed. - return filePermissionsFuncAllRead, nil - } - - return func(path string) (Perms, error) { - // An empty path is equivalent to repo permissions so we can assume it has - // already been checked at that level. - if path == "" { - return Read, nil - } - - // Prefix path with "/", otherwise suffix rules like "**/file.txt" won't match - if !strings.HasPrefix(path, "/") { - path = "/" + path - } - - // Iterate through all rules for the current path, and the final match takes - // preference. - return rules.GetPermissionsForPath(path), nil - }, nil -} - -// getCompiledRules fetches rules for the given repo with caching. -func (s *SubRepoPermsClient) getCompiledRules(ctx context.Context, userID int32) (map[api.RepoName]compiledRules, error) { - // Fast path for cached rules - item, _ := s.cache.Get(userID) - cached, ok := item.(cachedRules) - - ttl := defaultCacheTTL - if c := conf.Get(); c.ExperimentalFeatures != nil && c.ExperimentalFeatures.SubRepoPermissions != nil && c.ExperimentalFeatures.SubRepoPermissions.UserCacheTTLSeconds > 0 { - ttl = time.Duration(c.ExperimentalFeatures.SubRepoPermissions.UserCacheTTLSeconds) * time.Second - } - - if ok && s.since(cached.timestamp) <= ttl { - metricSubRepoPermCacheHit.Inc() - return cached.rules, nil - } - metricSubRepoPermCacheMiss.Inc() - - // Slow path on cache miss or expiry. Ensure that only one goroutine is doing the - // work - groupKey := strconv.FormatInt(int64(userID), 10) - result, err, _ := s.group.Do(groupKey, func() (any, error) { - repoPerms, err := s.permissionsGetter.GetByUser(ctx, userID) - if err != nil { - return nil, errors.Wrap(err, "fetching rules") - } - toCache := cachedRules{ - rules: make(map[api.RepoName]compiledRules, len(repoPerms)), - } - for repo, perms := range repoPerms { - paths := make([]path, 0, len(perms.Paths)) - for _, rule := range perms.Paths { - exclusion := strings.HasPrefix(rule, "-") - rule = strings.TrimPrefix(rule, "-") - - if !strings.HasPrefix(rule, "/") { - rule = "/" + rule - } - - g, err := glob.Compile(rule, '/') - if err != nil { - return nil, errors.Wrap(err, "building include matcher") - } - - paths = append(paths, path{globPath: g, exclusion: exclusion, original: rule}) - - // Special case. Our glob package does not handle rules starting with a double - // wildcard correctly. For example, we would expect `/**/*.java` to match all - // java files, but it does not match files at the root, eg `/foo.java`. To get - // around this we add an extra rule to cover this case. - if strings.HasPrefix(rule, "/**/") { - trimmed := rule - for { - trimmed = strings.TrimPrefix(trimmed, "/**") - if strings.HasPrefix(trimmed, "/**/") { - // Keep trimming - continue - } - g, err := glob.Compile(trimmed, '/') - if err != nil { - return nil, errors.Wrap(err, "building include matcher") - } - paths = append(paths, path{globPath: g, exclusion: exclusion, original: trimmed}) - break - } - } - - // We should include all directories above an include rule so that we can browse - // to the included items. - if exclusion { - // Not required for an exclude rule - continue - } - - dirs := expandDirs(rule) - for _, dir := range dirs { - g, err := glob.Compile(dir, '/') - if err != nil { - return nil, errors.Wrap(err, "building include matcher for dir") - } - paths = append(paths, path{globPath: g, exclusion: false, original: dir}) - } - } - - toCache.rules[repo] = compiledRules{ - paths: paths, - } - } - toCache.timestamp = s.clock() - s.cache.Add(userID, toCache) - return toCache.rules, nil - }) - if err != nil { - return nil, err - } - - compiled := result.(map[api.RepoName]compiledRules) - return compiled, nil -} - -func (s *SubRepoPermsClient) Enabled() bool { - return s.enabled.Load() -} - -func (s *SubRepoPermsClient) EnabledForRepoID(ctx context.Context, id api.RepoID) (bool, error) { - return s.permissionsGetter.RepoIDSupported(ctx, id) -} - -func (s *SubRepoPermsClient) EnabledForRepo(ctx context.Context, repo api.RepoName) (bool, error) { - return s.permissionsGetter.RepoSupported(ctx, repo) -} - // expandDirs will return a new set of rules that will match all directories // above the supplied rule. As a special case, if the rule starts with a wildcard // we return a rule to match all directories. @@ -454,23 +125,6 @@ func expandDirs(rule string) []string { return dirs } -// NewSimpleChecker is exposed for testing and allows creation of a simple -// checker based on the rules provided. The rules are expected to be in glob -// format. -func NewSimpleChecker(repo api.RepoName, paths []string) (SubRepoPermissionChecker, error) { - getter := NewMockSubRepoPermissionsGetter() - getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]SubRepoPermissions, error) { - return map[api.RepoName]SubRepoPermissions{ - repo: { - Paths: paths, - }, - }, nil - }) - getter.RepoSupportedFunc.SetDefaultReturn(true, nil) - getter.RepoIDSupportedFunc.SetDefaultReturn(true, nil) - return NewSubRepoPermsClient(getter) -} - // ActorPermissions returns the level of access the given actor has for the requested // content. // diff --git a/internal/authz/sub_repo_perms_test.go b/internal/authz/sub_repo_perms_test.go index 537fbc8ede6..fdeefe397e1 100644 --- a/internal/authz/sub_repo_perms_test.go +++ b/internal/authz/sub_repo_perms_test.go @@ -2,11 +2,8 @@ package authz import ( "context" - "fmt" "io/fs" - "sort" "testing" - "time" "github.com/gobwas/glob" "github.com/google/go-cmp/cmp" @@ -14,161 +11,9 @@ import ( "github.com/sourcegraph/sourcegraph/internal/actor" "github.com/sourcegraph/sourcegraph/internal/api" - "github.com/sourcegraph/sourcegraph/internal/conf" "github.com/sourcegraph/sourcegraph/internal/fileutil" - "github.com/sourcegraph/sourcegraph/schema" ) -func TestSubRepoPermsPermissions(t *testing.T) { - conf.Mock(&conf.Unified{ - SiteConfiguration: schema.SiteConfiguration{ - ExperimentalFeatures: &schema.ExperimentalFeatures{ - SubRepoPermissions: &schema.SubRepoPermissions{ - Enabled: true, - }, - }, - }, - }) - t.Cleanup(func() { conf.Mock(nil) }) - - testCases := []struct { - name string - userID int32 - content RepoContent - clientFn func() (*SubRepoPermsClient, error) - want Perms - }{ - { - name: "Empty path", - userID: 1, - content: RepoContent{ - Repo: "sample", - Path: "", - }, - clientFn: func() (*SubRepoPermsClient, error) { - return NewSubRepoPermsClient(NewMockSubRepoPermissionsGetter()) - }, - want: Read, - }, - { - name: "No rules", - userID: 1, - content: RepoContent{ - Repo: "sample", - Path: "/dev/thing", - }, - clientFn: func() (*SubRepoPermsClient, error) { - getter := NewMockSubRepoPermissionsGetter() - getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]SubRepoPermissions, error) { - return map[api.RepoName]SubRepoPermissions{ - "sample": { - Paths: []string{}, - }, - }, nil - }) - return NewSubRepoPermsClient(getter) - }, - want: None, - }, - { - name: "Exclude", - userID: 1, - content: RepoContent{ - Repo: "sample", - Path: "/dev/thing", - }, - clientFn: func() (*SubRepoPermsClient, error) { - getter := NewMockSubRepoPermissionsGetter() - getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]SubRepoPermissions, error) { - return map[api.RepoName]SubRepoPermissions{ - "sample": { - Paths: []string{"-/dev/*"}, - }, - }, nil - }) - return NewSubRepoPermsClient(getter) - }, - want: None, - }, - { - name: "Include", - userID: 1, - content: RepoContent{ - Repo: "sample", - Path: "/dev/thing", - }, - clientFn: func() (*SubRepoPermsClient, error) { - getter := NewMockSubRepoPermissionsGetter() - getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]SubRepoPermissions, error) { - return map[api.RepoName]SubRepoPermissions{ - "sample": { - Paths: []string{"/*"}, - }, - }, nil - }) - return NewSubRepoPermsClient(getter) - }, - want: None, - }, - { - name: "Last rule takes precedence (exclude)", - userID: 1, - content: RepoContent{ - Repo: "sample", - Path: "/dev/thing", - }, - clientFn: func() (*SubRepoPermsClient, error) { - getter := NewMockSubRepoPermissionsGetter() - getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]SubRepoPermissions, error) { - return map[api.RepoName]SubRepoPermissions{ - "sample": { - Paths: []string{"/**", "-/dev/*"}, - }, - }, nil - }) - return NewSubRepoPermsClient(getter) - }, - want: None, - }, - { - name: "Last rule takes precedence (include)", - userID: 1, - content: RepoContent{ - Repo: "sample", - Path: "/dev/thing", - }, - clientFn: func() (*SubRepoPermsClient, error) { - getter := NewMockSubRepoPermissionsGetter() - getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]SubRepoPermissions, error) { - return map[api.RepoName]SubRepoPermissions{ - "sample": { - Paths: []string{"-/dev/*", "/**"}, - }, - }, nil - }) - return NewSubRepoPermsClient(getter) - }, - want: Read, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - client, err := tc.clientFn() - if err != nil { - t.Fatal(err) - } - have, err := client.Permissions(context.Background(), tc.userID, tc.content) - if err != nil { - t.Fatal(err) - } - if have != tc.want { - t.Fatalf("have %v, want %v", have, tc.want) - } - }) - } -} - func TestFilterActorPaths(t *testing.T) { testPaths := []string{"file1", "file2", "file3"} checker := NewMockSubRepoPermissionChecker() @@ -202,98 +47,6 @@ func TestFilterActorPaths(t *testing.T) { } } -func BenchmarkFilterActorPaths(b *testing.B) { - // This benchmark is simulating the code path taken by a monorepo with sub - // repo permissions. Our goal is to support repos with millions of files. - // For now we target a lower number since large numbers don't give enough - // runs of the benchmark to be useful. - const pathCount = 5_000 - pathPatterns := []string{ - "base/%d/foo.go", - "%d/stuff/baz", - "frontend/%d/stuff/baz/bam", - "subdir/sub/sub/sub/%d", - "%d/foo/README.md", - "subdir/remove/me/please/%d", - "subdir/%d/also-remove/me/please", - "a/deep/path/%d/.secrets.env", - "%d/does/not/match/anything", - "does/%d/not/match/anything", - "does/not/%d/match/anything", - "does/not/match/%d/anything", - "does/not/match/anything/%d", - } - paths := []string{ - "config.yaml", - "dir.yaml", - } - for i := 0; len(paths) < pathCount; i++ { - for _, pat := range pathPatterns { - paths = append(paths, fmt.Sprintf(pat, i)) - } - } - paths = paths[:pathCount] - sort.Strings(paths) - - conf.Mock(&conf.Unified{ - SiteConfiguration: schema.SiteConfiguration{ - ExperimentalFeatures: &schema.ExperimentalFeatures{ - SubRepoPermissions: &schema.SubRepoPermissions{ - Enabled: true, - }, - }, - }, - }) - defer conf.Mock(nil) - repo := api.RepoName("repo") - - getter := NewMockSubRepoPermissionsGetter() - getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]SubRepoPermissions, error) { - return map[api.RepoName]SubRepoPermissions{ - repo: { - Paths: []string{ - "/base/**", - "/*/stuff/**", - "/frontend/**/stuff/*", - "/config.yaml", - "/subdir/**", - "/**/README.md", - "/dir.yaml", - "-/subdir/remove/", - "-/subdir/*/also-remove/**", - "-/**/.secrets.env", - }, - }, - }, nil - }) - checker, err := NewSubRepoPermsClient(getter) - if err != nil { - b.Fatal(err) - } - a := &actor.Actor{ - UID: 1, - } - ctx := actor.WithActor(context.Background(), a) - - b.ResetTimer() - start := time.Now() - - for n := 0; n <= b.N; n++ { - filtered, err := FilterActorPaths(ctx, checker, a, repo, paths) - if err != nil { - b.Fatal(err) - } - if len(filtered) == 0 { - b.Fatal("expected paths to be returned") - } - if len(filtered) == len(paths) { - b.Fatal("expected to filter out some paths") - } - } - - b.ReportMetric(float64(len(paths))*float64(b.N)/time.Since(start).Seconds(), "paths/s") -} - func TestCanReadAllPaths(t *testing.T) { testPaths := []string{"file1", "file2", "file3"} checker := NewMockSubRepoPermissionChecker() @@ -352,179 +105,6 @@ func TestCanReadAllPaths(t *testing.T) { } } -func TestSubRepoPermissionsCanReadDirectoriesInPath(t *testing.T) { - conf.Mock(&conf.Unified{ - SiteConfiguration: schema.SiteConfiguration{ - ExperimentalFeatures: &schema.ExperimentalFeatures{ - SubRepoPermissions: &schema.SubRepoPermissions{ - Enabled: true, - }, - }, - }, - }) - t.Cleanup(func() { conf.Mock(nil) }) - repoName := api.RepoName("repo") - - testCases := []struct { - paths []string - canReadAll []string - cannotReadAny []string - }{ - { - paths: []string{"foo/bar/thing.txt"}, - canReadAll: []string{"foo/", "foo/bar/"}, - cannotReadAny: []string{"foo/thing.txt", "foo/bar/other.txt"}, - }, - { - paths: []string{"foo/bar/**"}, - canReadAll: []string{"foo/", "foo/bar/", "foo/bar/baz/", "foo/bar/baz/fox/"}, - }, - { - paths: []string{"foo/bar/"}, - canReadAll: []string{"foo/", "foo/bar/"}, - cannotReadAny: []string{"foo/thing.txt", "foo/bar/thing.txt"}, - }, - { - paths: []string{"baz/*/foo/bar/thing.txt"}, - canReadAll: []string{"baz/", "baz/x/", "baz/x/foo/bar/"}, - cannotReadAny: []string{"baz/thing.txt"}, - }, - // If we have a wildcard in a path we allow all directories that are not - // explicitly excluded. - { - paths: []string{"**/foo/bar/thing.txt"}, - canReadAll: []string{"foo/", "foo/bar/"}, - }, - { - paths: []string{"*/foo/bar/thing.txt"}, - canReadAll: []string{"foo/", "foo/bar/"}, - }, - { - paths: []string{"/**/foo/bar/thing.txt"}, - canReadAll: []string{"foo/", "foo/bar/"}, - }, - { - paths: []string{"/*/foo/bar/thing.txt"}, - canReadAll: []string{"foo/", "foo/bar/"}, - }, - { - paths: []string{"-/**", "/storage/redis/**"}, - canReadAll: []string{"storage/", "/storage/", "/storage/redis/"}, - }, - { - paths: []string{"-/**", "-/storage/**", "/storage/redis/**"}, - canReadAll: []string{"storage/", "/storage/", "/storage/redis/"}, - }, - // Even with a wildcard include rule, we should still exclude directories that - // are explicitly excluded later - { - paths: []string{"/**", "-/storage/**"}, - canReadAll: []string{"/foo"}, - cannotReadAny: []string{"storage/", "/storage/", "/storage/redis/"}, - }, - } - - for _, tc := range testCases { - t.Run("", func(t *testing.T) { - getter := NewMockSubRepoPermissionsGetter() - getter.GetByUserFunc.SetDefaultHook(func(ctx context.Context, i int32) (map[api.RepoName]SubRepoPermissions, error) { - return map[api.RepoName]SubRepoPermissions{ - repoName: { - Paths: tc.paths, - }, - }, nil - }) - client, err := NewSubRepoPermsClient(getter) - if err != nil { - t.Fatal(err) - } - - ctx := context.Background() - - for _, path := range tc.canReadAll { - content := RepoContent{ - Repo: repoName, - Path: path, - } - perm, err := client.Permissions(ctx, 1, content) - if err != nil { - t.Error(err) - } - if !perm.Include(Read) { - t.Errorf("Should be able to read %q, cannot", path) - } - } - - for _, path := range tc.cannotReadAny { - content := RepoContent{ - Repo: repoName, - Path: path, - } - perm, err := client.Permissions(ctx, 1, content) - if err != nil { - t.Error(err) - } - if perm.Include(Read) { - t.Errorf("Should not be able to read %q, can", path) - } - } - }) - } -} - -func TestSubRepoPermsPermissionsCache(t *testing.T) { - conf.Mock(&conf.Unified{ - SiteConfiguration: schema.SiteConfiguration{ - ExperimentalFeatures: &schema.ExperimentalFeatures{ - SubRepoPermissions: &schema.SubRepoPermissions{ - Enabled: true, - }, - }, - }, - }) - t.Cleanup(func() { conf.Mock(nil) }) - - getter := NewMockSubRepoPermissionsGetter() - client, err := NewSubRepoPermsClient(getter) - if err != nil { - t.Fatal(err) - } - - ctx := context.Background() - content := RepoContent{ - Repo: api.RepoName("thing"), - Path: "/stuff", - } - - // Should hit DB only once - for i := 0; i < 3; i++ { - _, err = client.Permissions(ctx, 1, content) - if err != nil { - t.Fatal(err) - } - - h := getter.GetByUserFunc.History() - if len(h) != 1 { - t.Fatal("Should have been called once") - } - } - - // Trigger expiry - client.since = func(time time.Time) time.Duration { - return defaultCacheTTL + 1 - } - - _, err = client.Permissions(ctx, 1, content) - if err != nil { - t.Fatal(err) - } - - h := getter.GetByUserFunc.History() - if len(h) != 2 { - t.Fatal("Should have been called twice") - } -} - func TestSubRepoEnabled(t *testing.T) { t.Run("checker is nil", func(t *testing.T) { if SubRepoEnabled(nil) { diff --git a/internal/database/database.go b/internal/database/database.go index de474365f59..c716d6548db 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -45,7 +45,6 @@ type DB interface { SavedSearches() SavedSearchStore SearchContexts() SearchContextsStore Settings() SettingsStore - SubRepoPerms() SubRepoPermsStore TemporarySettings() TemporarySettingsStore UserCredentials(encryption.Key) UserCredentialsStore UserEmails() UserEmailsStore @@ -205,10 +204,6 @@ func (d *db) Settings() SettingsStore { return SettingsWith(d.Store) } -func (d *db) SubRepoPerms() SubRepoPermsStore { - return SubRepoPermsWith(d.Store) -} - func (d *db) TemporarySettings() TemporarySettingsStore { return TemporarySettingsWith(d.Store) } diff --git a/internal/database/mocks_temp.go b/internal/database/mocks_temp.go index a1e1f301ea3..10fb120109a 100644 --- a/internal/database/mocks_temp.go +++ b/internal/database/mocks_temp.go @@ -15,7 +15,6 @@ import ( uuid "github.com/google/uuid" sqlf "github.com/keegancsmith/sqlf" api "github.com/sourcegraph/sourcegraph/internal/api" - authz "github.com/sourcegraph/sourcegraph/internal/authz" conf "github.com/sourcegraph/sourcegraph/internal/conf" basestore "github.com/sourcegraph/sourcegraph/internal/database/basestore" encryption "github.com/sourcegraph/sourcegraph/internal/encryption" @@ -3722,9 +3721,6 @@ type MockDB struct { // SettingsFunc is an instance of a mock function object controlling the // behavior of the method Settings. SettingsFunc *DBSettingsFunc - // SubRepoPermsFunc is an instance of a mock function object controlling - // the behavior of the method SubRepoPerms. - SubRepoPermsFunc *DBSubRepoPermsFunc // TemporarySettingsFunc is an instance of a mock function object // controlling the behavior of the method TemporarySettings. TemporarySettingsFunc *DBTemporarySettingsFunc @@ -3931,11 +3927,6 @@ func NewMockDB() *MockDB { return }, }, - SubRepoPermsFunc: &DBSubRepoPermsFunc{ - defaultHook: func() (r0 SubRepoPermsStore) { - return - }, - }, TemporarySettingsFunc: &DBTemporarySettingsFunc{ defaultHook: func() (r0 TemporarySettingsStore) { return @@ -4163,11 +4154,6 @@ func NewStrictMockDB() *MockDB { panic("unexpected invocation of MockDB.Settings") }, }, - SubRepoPermsFunc: &DBSubRepoPermsFunc{ - defaultHook: func() SubRepoPermsStore { - panic("unexpected invocation of MockDB.SubRepoPerms") - }, - }, TemporarySettingsFunc: &DBTemporarySettingsFunc{ defaultHook: func() TemporarySettingsStore { panic("unexpected invocation of MockDB.TemporarySettings") @@ -4327,9 +4313,6 @@ func NewMockDBFrom(i DB) *MockDB { SettingsFunc: &DBSettingsFunc{ defaultHook: i.Settings, }, - SubRepoPermsFunc: &DBSubRepoPermsFunc{ - defaultHook: i.SubRepoPerms, - }, TemporarySettingsFunc: &DBTemporarySettingsFunc{ defaultHook: i.TemporarySettings, }, @@ -7769,104 +7752,6 @@ func (c DBSettingsFuncCall) Results() []interface{} { return []interface{}{c.Result0} } -// DBSubRepoPermsFunc describes the behavior when the SubRepoPerms method of -// the parent MockDB instance is invoked. -type DBSubRepoPermsFunc struct { - defaultHook func() SubRepoPermsStore - hooks []func() SubRepoPermsStore - history []DBSubRepoPermsFuncCall - mutex sync.Mutex -} - -// SubRepoPerms delegates to the next hook function in the queue and stores -// the parameter and result values of this invocation. -func (m *MockDB) SubRepoPerms() SubRepoPermsStore { - r0 := m.SubRepoPermsFunc.nextHook()() - m.SubRepoPermsFunc.appendCall(DBSubRepoPermsFuncCall{r0}) - return r0 -} - -// SetDefaultHook sets function that is called when the SubRepoPerms method -// of the parent MockDB instance is invoked and the hook queue is empty. -func (f *DBSubRepoPermsFunc) SetDefaultHook(hook func() SubRepoPermsStore) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// SubRepoPerms method of the parent MockDB instance invokes the hook at the -// front of the queue and discards it. After the queue is empty, the default -// hook function is invoked for any future action. -func (f *DBSubRepoPermsFunc) PushHook(hook func() SubRepoPermsStore) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *DBSubRepoPermsFunc) SetDefaultReturn(r0 SubRepoPermsStore) { - f.SetDefaultHook(func() SubRepoPermsStore { - return r0 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *DBSubRepoPermsFunc) PushReturn(r0 SubRepoPermsStore) { - f.PushHook(func() SubRepoPermsStore { - return r0 - }) -} - -func (f *DBSubRepoPermsFunc) nextHook() func() SubRepoPermsStore { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *DBSubRepoPermsFunc) appendCall(r0 DBSubRepoPermsFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of DBSubRepoPermsFuncCall objects describing -// the invocations of this function. -func (f *DBSubRepoPermsFunc) History() []DBSubRepoPermsFuncCall { - f.mutex.Lock() - history := make([]DBSubRepoPermsFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// DBSubRepoPermsFuncCall is an object that describes an invocation of -// method SubRepoPerms on an instance of MockDB. -type DBSubRepoPermsFuncCall struct { - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 SubRepoPermsStore -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c DBSubRepoPermsFuncCall) Args() []interface{} { - return []interface{}{} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c DBSubRepoPermsFuncCall) Results() []interface{} { - return []interface{}{c.Result0} -} - // DBTemporarySettingsFunc describes the behavior when the TemporarySettings // method of the parent MockDB instance is invoked. type DBTemporarySettingsFunc struct { @@ -40212,1527 +40097,6 @@ func (c SettingsStoreWithFuncCall) Results() []interface{} { return []interface{}{c.Result0} } -// MockSubRepoPermsStore is a mock implementation of the SubRepoPermsStore -// interface (from the package -// github.com/sourcegraph/sourcegraph/internal/database) used for unit -// testing. -type MockSubRepoPermsStore struct { - // DeleteByUserFunc is an instance of a mock function object controlling - // the behavior of the method DeleteByUser. - DeleteByUserFunc *SubRepoPermsStoreDeleteByUserFunc - // DoneFunc is an instance of a mock function object controlling the - // behavior of the method Done. - DoneFunc *SubRepoPermsStoreDoneFunc - // GetFunc is an instance of a mock function object controlling the - // behavior of the method Get. - GetFunc *SubRepoPermsStoreGetFunc - // GetByUserFunc is an instance of a mock function object controlling - // the behavior of the method GetByUser. - GetByUserFunc *SubRepoPermsStoreGetByUserFunc - // GetByUserAndServiceFunc is an instance of a mock function object - // controlling the behavior of the method GetByUserAndService. - GetByUserAndServiceFunc *SubRepoPermsStoreGetByUserAndServiceFunc - // HandleFunc is an instance of a mock function object controlling the - // behavior of the method Handle. - HandleFunc *SubRepoPermsStoreHandleFunc - // RepoIDSupportedFunc is an instance of a mock function object - // controlling the behavior of the method RepoIDSupported. - RepoIDSupportedFunc *SubRepoPermsStoreRepoIDSupportedFunc - // RepoSupportedFunc is an instance of a mock function object - // controlling the behavior of the method RepoSupported. - RepoSupportedFunc *SubRepoPermsStoreRepoSupportedFunc - // TransactFunc is an instance of a mock function object controlling the - // behavior of the method Transact. - TransactFunc *SubRepoPermsStoreTransactFunc - // UpsertFunc is an instance of a mock function object controlling the - // behavior of the method Upsert. - UpsertFunc *SubRepoPermsStoreUpsertFunc - // UpsertWithSpecFunc is an instance of a mock function object - // controlling the behavior of the method UpsertWithSpec. - UpsertWithSpecFunc *SubRepoPermsStoreUpsertWithSpecFunc - // WithFunc is an instance of a mock function object controlling the - // behavior of the method With. - WithFunc *SubRepoPermsStoreWithFunc -} - -// NewMockSubRepoPermsStore creates a new mock of the SubRepoPermsStore -// interface. All methods return zero values for all results, unless -// overwritten. -func NewMockSubRepoPermsStore() *MockSubRepoPermsStore { - return &MockSubRepoPermsStore{ - DeleteByUserFunc: &SubRepoPermsStoreDeleteByUserFunc{ - defaultHook: func(context.Context, int32) (r0 error) { - return - }, - }, - DoneFunc: &SubRepoPermsStoreDoneFunc{ - defaultHook: func(error) (r0 error) { - return - }, - }, - GetFunc: &SubRepoPermsStoreGetFunc{ - defaultHook: func(context.Context, int32, api.RepoID) (r0 *authz.SubRepoPermissions, r1 error) { - return - }, - }, - GetByUserFunc: &SubRepoPermsStoreGetByUserFunc{ - defaultHook: func(context.Context, int32) (r0 map[api.RepoName]authz.SubRepoPermissions, r1 error) { - return - }, - }, - GetByUserAndServiceFunc: &SubRepoPermsStoreGetByUserAndServiceFunc{ - defaultHook: func(context.Context, int32, string, string) (r0 map[api.ExternalRepoSpec]authz.SubRepoPermissions, r1 error) { - return - }, - }, - HandleFunc: &SubRepoPermsStoreHandleFunc{ - defaultHook: func() (r0 basestore.TransactableHandle) { - return - }, - }, - RepoIDSupportedFunc: &SubRepoPermsStoreRepoIDSupportedFunc{ - defaultHook: func(context.Context, api.RepoID) (r0 bool, r1 error) { - return - }, - }, - RepoSupportedFunc: &SubRepoPermsStoreRepoSupportedFunc{ - defaultHook: func(context.Context, api.RepoName) (r0 bool, r1 error) { - return - }, - }, - TransactFunc: &SubRepoPermsStoreTransactFunc{ - defaultHook: func(context.Context) (r0 SubRepoPermsStore, r1 error) { - return - }, - }, - UpsertFunc: &SubRepoPermsStoreUpsertFunc{ - defaultHook: func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) (r0 error) { - return - }, - }, - UpsertWithSpecFunc: &SubRepoPermsStoreUpsertWithSpecFunc{ - defaultHook: func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) (r0 error) { - return - }, - }, - WithFunc: &SubRepoPermsStoreWithFunc{ - defaultHook: func(basestore.ShareableStore) (r0 SubRepoPermsStore) { - return - }, - }, - } -} - -// NewStrictMockSubRepoPermsStore creates a new mock of the -// SubRepoPermsStore interface. All methods panic on invocation, unless -// overwritten. -func NewStrictMockSubRepoPermsStore() *MockSubRepoPermsStore { - return &MockSubRepoPermsStore{ - DeleteByUserFunc: &SubRepoPermsStoreDeleteByUserFunc{ - defaultHook: func(context.Context, int32) error { - panic("unexpected invocation of MockSubRepoPermsStore.DeleteByUser") - }, - }, - DoneFunc: &SubRepoPermsStoreDoneFunc{ - defaultHook: func(error) error { - panic("unexpected invocation of MockSubRepoPermsStore.Done") - }, - }, - GetFunc: &SubRepoPermsStoreGetFunc{ - defaultHook: func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error) { - panic("unexpected invocation of MockSubRepoPermsStore.Get") - }, - }, - GetByUserFunc: &SubRepoPermsStoreGetByUserFunc{ - defaultHook: func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) { - panic("unexpected invocation of MockSubRepoPermsStore.GetByUser") - }, - }, - GetByUserAndServiceFunc: &SubRepoPermsStoreGetByUserAndServiceFunc{ - defaultHook: func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error) { - panic("unexpected invocation of MockSubRepoPermsStore.GetByUserAndService") - }, - }, - HandleFunc: &SubRepoPermsStoreHandleFunc{ - defaultHook: func() basestore.TransactableHandle { - panic("unexpected invocation of MockSubRepoPermsStore.Handle") - }, - }, - RepoIDSupportedFunc: &SubRepoPermsStoreRepoIDSupportedFunc{ - defaultHook: func(context.Context, api.RepoID) (bool, error) { - panic("unexpected invocation of MockSubRepoPermsStore.RepoIDSupported") - }, - }, - RepoSupportedFunc: &SubRepoPermsStoreRepoSupportedFunc{ - defaultHook: func(context.Context, api.RepoName) (bool, error) { - panic("unexpected invocation of MockSubRepoPermsStore.RepoSupported") - }, - }, - TransactFunc: &SubRepoPermsStoreTransactFunc{ - defaultHook: func(context.Context) (SubRepoPermsStore, error) { - panic("unexpected invocation of MockSubRepoPermsStore.Transact") - }, - }, - UpsertFunc: &SubRepoPermsStoreUpsertFunc{ - defaultHook: func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error { - panic("unexpected invocation of MockSubRepoPermsStore.Upsert") - }, - }, - UpsertWithSpecFunc: &SubRepoPermsStoreUpsertWithSpecFunc{ - defaultHook: func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error { - panic("unexpected invocation of MockSubRepoPermsStore.UpsertWithSpec") - }, - }, - WithFunc: &SubRepoPermsStoreWithFunc{ - defaultHook: func(basestore.ShareableStore) SubRepoPermsStore { - panic("unexpected invocation of MockSubRepoPermsStore.With") - }, - }, - } -} - -// NewMockSubRepoPermsStoreFrom creates a new mock of the -// MockSubRepoPermsStore interface. All methods delegate to the given -// implementation, unless overwritten. -func NewMockSubRepoPermsStoreFrom(i SubRepoPermsStore) *MockSubRepoPermsStore { - return &MockSubRepoPermsStore{ - DeleteByUserFunc: &SubRepoPermsStoreDeleteByUserFunc{ - defaultHook: i.DeleteByUser, - }, - DoneFunc: &SubRepoPermsStoreDoneFunc{ - defaultHook: i.Done, - }, - GetFunc: &SubRepoPermsStoreGetFunc{ - defaultHook: i.Get, - }, - GetByUserFunc: &SubRepoPermsStoreGetByUserFunc{ - defaultHook: i.GetByUser, - }, - GetByUserAndServiceFunc: &SubRepoPermsStoreGetByUserAndServiceFunc{ - defaultHook: i.GetByUserAndService, - }, - HandleFunc: &SubRepoPermsStoreHandleFunc{ - defaultHook: i.Handle, - }, - RepoIDSupportedFunc: &SubRepoPermsStoreRepoIDSupportedFunc{ - defaultHook: i.RepoIDSupported, - }, - RepoSupportedFunc: &SubRepoPermsStoreRepoSupportedFunc{ - defaultHook: i.RepoSupported, - }, - TransactFunc: &SubRepoPermsStoreTransactFunc{ - defaultHook: i.Transact, - }, - UpsertFunc: &SubRepoPermsStoreUpsertFunc{ - defaultHook: i.Upsert, - }, - UpsertWithSpecFunc: &SubRepoPermsStoreUpsertWithSpecFunc{ - defaultHook: i.UpsertWithSpec, - }, - WithFunc: &SubRepoPermsStoreWithFunc{ - defaultHook: i.With, - }, - } -} - -// SubRepoPermsStoreDeleteByUserFunc describes the behavior when the -// DeleteByUser method of the parent MockSubRepoPermsStore instance is -// invoked. -type SubRepoPermsStoreDeleteByUserFunc struct { - defaultHook func(context.Context, int32) error - hooks []func(context.Context, int32) error - history []SubRepoPermsStoreDeleteByUserFuncCall - mutex sync.Mutex -} - -// DeleteByUser delegates to the next hook function in the queue and stores -// the parameter and result values of this invocation. -func (m *MockSubRepoPermsStore) DeleteByUser(v0 context.Context, v1 int32) error { - r0 := m.DeleteByUserFunc.nextHook()(v0, v1) - m.DeleteByUserFunc.appendCall(SubRepoPermsStoreDeleteByUserFuncCall{v0, v1, r0}) - return r0 -} - -// SetDefaultHook sets function that is called when the DeleteByUser method -// of the parent MockSubRepoPermsStore instance is invoked and the hook -// queue is empty. -func (f *SubRepoPermsStoreDeleteByUserFunc) SetDefaultHook(hook func(context.Context, int32) error) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// DeleteByUser method of the parent MockSubRepoPermsStore instance invokes -// the hook at the front of the queue and discards it. After the queue is -// empty, the default hook function is invoked for any future action. -func (f *SubRepoPermsStoreDeleteByUserFunc) PushHook(hook func(context.Context, int32) error) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *SubRepoPermsStoreDeleteByUserFunc) SetDefaultReturn(r0 error) { - f.SetDefaultHook(func(context.Context, int32) error { - return r0 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *SubRepoPermsStoreDeleteByUserFunc) PushReturn(r0 error) { - f.PushHook(func(context.Context, int32) error { - return r0 - }) -} - -func (f *SubRepoPermsStoreDeleteByUserFunc) nextHook() func(context.Context, int32) error { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *SubRepoPermsStoreDeleteByUserFunc) appendCall(r0 SubRepoPermsStoreDeleteByUserFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of SubRepoPermsStoreDeleteByUserFuncCall -// objects describing the invocations of this function. -func (f *SubRepoPermsStoreDeleteByUserFunc) History() []SubRepoPermsStoreDeleteByUserFuncCall { - f.mutex.Lock() - history := make([]SubRepoPermsStoreDeleteByUserFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// SubRepoPermsStoreDeleteByUserFuncCall is an object that describes an -// invocation of method DeleteByUser on an instance of -// MockSubRepoPermsStore. -type SubRepoPermsStoreDeleteByUserFuncCall struct { - // Arg0 is the value of the 1st argument passed to this method - // invocation. - Arg0 context.Context - // Arg1 is the value of the 2nd argument passed to this method - // invocation. - Arg1 int32 - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 error -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c SubRepoPermsStoreDeleteByUserFuncCall) Args() []interface{} { - return []interface{}{c.Arg0, c.Arg1} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c SubRepoPermsStoreDeleteByUserFuncCall) Results() []interface{} { - return []interface{}{c.Result0} -} - -// SubRepoPermsStoreDoneFunc describes the behavior when the Done method of -// the parent MockSubRepoPermsStore instance is invoked. -type SubRepoPermsStoreDoneFunc struct { - defaultHook func(error) error - hooks []func(error) error - history []SubRepoPermsStoreDoneFuncCall - mutex sync.Mutex -} - -// Done delegates to the next hook function in the queue and stores the -// parameter and result values of this invocation. -func (m *MockSubRepoPermsStore) Done(v0 error) error { - r0 := m.DoneFunc.nextHook()(v0) - m.DoneFunc.appendCall(SubRepoPermsStoreDoneFuncCall{v0, r0}) - return r0 -} - -// SetDefaultHook sets function that is called when the Done method of the -// parent MockSubRepoPermsStore instance is invoked and the hook queue is -// empty. -func (f *SubRepoPermsStoreDoneFunc) SetDefaultHook(hook func(error) error) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// Done method of the parent MockSubRepoPermsStore instance invokes the hook -// at the front of the queue and discards it. After the queue is empty, the -// default hook function is invoked for any future action. -func (f *SubRepoPermsStoreDoneFunc) PushHook(hook func(error) error) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *SubRepoPermsStoreDoneFunc) SetDefaultReturn(r0 error) { - f.SetDefaultHook(func(error) error { - return r0 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *SubRepoPermsStoreDoneFunc) PushReturn(r0 error) { - f.PushHook(func(error) error { - return r0 - }) -} - -func (f *SubRepoPermsStoreDoneFunc) nextHook() func(error) error { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *SubRepoPermsStoreDoneFunc) appendCall(r0 SubRepoPermsStoreDoneFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of SubRepoPermsStoreDoneFuncCall objects -// describing the invocations of this function. -func (f *SubRepoPermsStoreDoneFunc) History() []SubRepoPermsStoreDoneFuncCall { - f.mutex.Lock() - history := make([]SubRepoPermsStoreDoneFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// SubRepoPermsStoreDoneFuncCall is an object that describes an invocation -// of method Done on an instance of MockSubRepoPermsStore. -type SubRepoPermsStoreDoneFuncCall struct { - // Arg0 is the value of the 1st argument passed to this method - // invocation. - Arg0 error - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 error -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c SubRepoPermsStoreDoneFuncCall) Args() []interface{} { - return []interface{}{c.Arg0} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c SubRepoPermsStoreDoneFuncCall) Results() []interface{} { - return []interface{}{c.Result0} -} - -// SubRepoPermsStoreGetFunc describes the behavior when the Get method of -// the parent MockSubRepoPermsStore instance is invoked. -type SubRepoPermsStoreGetFunc struct { - defaultHook func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error) - hooks []func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error) - history []SubRepoPermsStoreGetFuncCall - mutex sync.Mutex -} - -// Get delegates to the next hook function in the queue and stores the -// parameter and result values of this invocation. -func (m *MockSubRepoPermsStore) Get(v0 context.Context, v1 int32, v2 api.RepoID) (*authz.SubRepoPermissions, error) { - r0, r1 := m.GetFunc.nextHook()(v0, v1, v2) - m.GetFunc.appendCall(SubRepoPermsStoreGetFuncCall{v0, v1, v2, r0, r1}) - return r0, r1 -} - -// SetDefaultHook sets function that is called when the Get method of the -// parent MockSubRepoPermsStore instance is invoked and the hook queue is -// empty. -func (f *SubRepoPermsStoreGetFunc) SetDefaultHook(hook func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error)) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// Get method of the parent MockSubRepoPermsStore instance invokes the hook -// at the front of the queue and discards it. After the queue is empty, the -// default hook function is invoked for any future action. -func (f *SubRepoPermsStoreGetFunc) PushHook(hook func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error)) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *SubRepoPermsStoreGetFunc) SetDefaultReturn(r0 *authz.SubRepoPermissions, r1 error) { - f.SetDefaultHook(func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error) { - return r0, r1 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *SubRepoPermsStoreGetFunc) PushReturn(r0 *authz.SubRepoPermissions, r1 error) { - f.PushHook(func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error) { - return r0, r1 - }) -} - -func (f *SubRepoPermsStoreGetFunc) nextHook() func(context.Context, int32, api.RepoID) (*authz.SubRepoPermissions, error) { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *SubRepoPermsStoreGetFunc) appendCall(r0 SubRepoPermsStoreGetFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of SubRepoPermsStoreGetFuncCall objects -// describing the invocations of this function. -func (f *SubRepoPermsStoreGetFunc) History() []SubRepoPermsStoreGetFuncCall { - f.mutex.Lock() - history := make([]SubRepoPermsStoreGetFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// SubRepoPermsStoreGetFuncCall is an object that describes an invocation of -// method Get on an instance of MockSubRepoPermsStore. -type SubRepoPermsStoreGetFuncCall struct { - // Arg0 is the value of the 1st argument passed to this method - // invocation. - Arg0 context.Context - // Arg1 is the value of the 2nd argument passed to this method - // invocation. - Arg1 int32 - // Arg2 is the value of the 3rd argument passed to this method - // invocation. - Arg2 api.RepoID - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 *authz.SubRepoPermissions - // Result1 is the value of the 2nd result returned from this method - // invocation. - Result1 error -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c SubRepoPermsStoreGetFuncCall) Args() []interface{} { - return []interface{}{c.Arg0, c.Arg1, c.Arg2} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c SubRepoPermsStoreGetFuncCall) Results() []interface{} { - return []interface{}{c.Result0, c.Result1} -} - -// SubRepoPermsStoreGetByUserFunc describes the behavior when the GetByUser -// method of the parent MockSubRepoPermsStore instance is invoked. -type SubRepoPermsStoreGetByUserFunc struct { - defaultHook func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) - hooks []func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) - history []SubRepoPermsStoreGetByUserFuncCall - mutex sync.Mutex -} - -// GetByUser delegates to the next hook function in the queue and stores the -// parameter and result values of this invocation. -func (m *MockSubRepoPermsStore) GetByUser(v0 context.Context, v1 int32) (map[api.RepoName]authz.SubRepoPermissions, error) { - r0, r1 := m.GetByUserFunc.nextHook()(v0, v1) - m.GetByUserFunc.appendCall(SubRepoPermsStoreGetByUserFuncCall{v0, v1, r0, r1}) - return r0, r1 -} - -// SetDefaultHook sets function that is called when the GetByUser method of -// the parent MockSubRepoPermsStore instance is invoked and the hook queue -// is empty. -func (f *SubRepoPermsStoreGetByUserFunc) SetDefaultHook(hook func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error)) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// GetByUser method of the parent MockSubRepoPermsStore instance invokes the -// hook at the front of the queue and discards it. After the queue is empty, -// the default hook function is invoked for any future action. -func (f *SubRepoPermsStoreGetByUserFunc) PushHook(hook func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error)) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *SubRepoPermsStoreGetByUserFunc) SetDefaultReturn(r0 map[api.RepoName]authz.SubRepoPermissions, r1 error) { - f.SetDefaultHook(func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) { - return r0, r1 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *SubRepoPermsStoreGetByUserFunc) PushReturn(r0 map[api.RepoName]authz.SubRepoPermissions, r1 error) { - f.PushHook(func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) { - return r0, r1 - }) -} - -func (f *SubRepoPermsStoreGetByUserFunc) nextHook() func(context.Context, int32) (map[api.RepoName]authz.SubRepoPermissions, error) { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *SubRepoPermsStoreGetByUserFunc) appendCall(r0 SubRepoPermsStoreGetByUserFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of SubRepoPermsStoreGetByUserFuncCall objects -// describing the invocations of this function. -func (f *SubRepoPermsStoreGetByUserFunc) History() []SubRepoPermsStoreGetByUserFuncCall { - f.mutex.Lock() - history := make([]SubRepoPermsStoreGetByUserFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// SubRepoPermsStoreGetByUserFuncCall is an object that describes an -// invocation of method GetByUser on an instance of MockSubRepoPermsStore. -type SubRepoPermsStoreGetByUserFuncCall struct { - // Arg0 is the value of the 1st argument passed to this method - // invocation. - Arg0 context.Context - // Arg1 is the value of the 2nd argument passed to this method - // invocation. - Arg1 int32 - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 map[api.RepoName]authz.SubRepoPermissions - // Result1 is the value of the 2nd result returned from this method - // invocation. - Result1 error -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c SubRepoPermsStoreGetByUserFuncCall) Args() []interface{} { - return []interface{}{c.Arg0, c.Arg1} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c SubRepoPermsStoreGetByUserFuncCall) Results() []interface{} { - return []interface{}{c.Result0, c.Result1} -} - -// SubRepoPermsStoreGetByUserAndServiceFunc describes the behavior when the -// GetByUserAndService method of the parent MockSubRepoPermsStore instance -// is invoked. -type SubRepoPermsStoreGetByUserAndServiceFunc struct { - defaultHook func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error) - hooks []func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error) - history []SubRepoPermsStoreGetByUserAndServiceFuncCall - mutex sync.Mutex -} - -// GetByUserAndService delegates to the next hook function in the queue and -// stores the parameter and result values of this invocation. -func (m *MockSubRepoPermsStore) GetByUserAndService(v0 context.Context, v1 int32, v2 string, v3 string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error) { - r0, r1 := m.GetByUserAndServiceFunc.nextHook()(v0, v1, v2, v3) - m.GetByUserAndServiceFunc.appendCall(SubRepoPermsStoreGetByUserAndServiceFuncCall{v0, v1, v2, v3, r0, r1}) - return r0, r1 -} - -// SetDefaultHook sets function that is called when the GetByUserAndService -// method of the parent MockSubRepoPermsStore instance is invoked and the -// hook queue is empty. -func (f *SubRepoPermsStoreGetByUserAndServiceFunc) SetDefaultHook(hook func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error)) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// GetByUserAndService method of the parent MockSubRepoPermsStore instance -// invokes the hook at the front of the queue and discards it. After the -// queue is empty, the default hook function is invoked for any future -// action. -func (f *SubRepoPermsStoreGetByUserAndServiceFunc) PushHook(hook func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error)) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *SubRepoPermsStoreGetByUserAndServiceFunc) SetDefaultReturn(r0 map[api.ExternalRepoSpec]authz.SubRepoPermissions, r1 error) { - f.SetDefaultHook(func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error) { - return r0, r1 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *SubRepoPermsStoreGetByUserAndServiceFunc) PushReturn(r0 map[api.ExternalRepoSpec]authz.SubRepoPermissions, r1 error) { - f.PushHook(func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error) { - return r0, r1 - }) -} - -func (f *SubRepoPermsStoreGetByUserAndServiceFunc) nextHook() func(context.Context, int32, string, string) (map[api.ExternalRepoSpec]authz.SubRepoPermissions, error) { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *SubRepoPermsStoreGetByUserAndServiceFunc) appendCall(r0 SubRepoPermsStoreGetByUserAndServiceFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of -// SubRepoPermsStoreGetByUserAndServiceFuncCall objects describing the -// invocations of this function. -func (f *SubRepoPermsStoreGetByUserAndServiceFunc) History() []SubRepoPermsStoreGetByUserAndServiceFuncCall { - f.mutex.Lock() - history := make([]SubRepoPermsStoreGetByUserAndServiceFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// SubRepoPermsStoreGetByUserAndServiceFuncCall is an object that describes -// an invocation of method GetByUserAndService on an instance of -// MockSubRepoPermsStore. -type SubRepoPermsStoreGetByUserAndServiceFuncCall struct { - // Arg0 is the value of the 1st argument passed to this method - // invocation. - Arg0 context.Context - // Arg1 is the value of the 2nd argument passed to this method - // invocation. - Arg1 int32 - // Arg2 is the value of the 3rd argument passed to this method - // invocation. - Arg2 string - // Arg3 is the value of the 4th argument passed to this method - // invocation. - Arg3 string - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 map[api.ExternalRepoSpec]authz.SubRepoPermissions - // Result1 is the value of the 2nd result returned from this method - // invocation. - Result1 error -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c SubRepoPermsStoreGetByUserAndServiceFuncCall) Args() []interface{} { - return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c SubRepoPermsStoreGetByUserAndServiceFuncCall) Results() []interface{} { - return []interface{}{c.Result0, c.Result1} -} - -// SubRepoPermsStoreHandleFunc describes the behavior when the Handle method -// of the parent MockSubRepoPermsStore instance is invoked. -type SubRepoPermsStoreHandleFunc struct { - defaultHook func() basestore.TransactableHandle - hooks []func() basestore.TransactableHandle - history []SubRepoPermsStoreHandleFuncCall - mutex sync.Mutex -} - -// Handle delegates to the next hook function in the queue and stores the -// parameter and result values of this invocation. -func (m *MockSubRepoPermsStore) Handle() basestore.TransactableHandle { - r0 := m.HandleFunc.nextHook()() - m.HandleFunc.appendCall(SubRepoPermsStoreHandleFuncCall{r0}) - return r0 -} - -// SetDefaultHook sets function that is called when the Handle method of the -// parent MockSubRepoPermsStore instance is invoked and the hook queue is -// empty. -func (f *SubRepoPermsStoreHandleFunc) SetDefaultHook(hook func() basestore.TransactableHandle) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// Handle method of the parent MockSubRepoPermsStore instance invokes the -// hook at the front of the queue and discards it. After the queue is empty, -// the default hook function is invoked for any future action. -func (f *SubRepoPermsStoreHandleFunc) PushHook(hook func() basestore.TransactableHandle) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *SubRepoPermsStoreHandleFunc) SetDefaultReturn(r0 basestore.TransactableHandle) { - f.SetDefaultHook(func() basestore.TransactableHandle { - return r0 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *SubRepoPermsStoreHandleFunc) PushReturn(r0 basestore.TransactableHandle) { - f.PushHook(func() basestore.TransactableHandle { - return r0 - }) -} - -func (f *SubRepoPermsStoreHandleFunc) nextHook() func() basestore.TransactableHandle { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *SubRepoPermsStoreHandleFunc) appendCall(r0 SubRepoPermsStoreHandleFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of SubRepoPermsStoreHandleFuncCall objects -// describing the invocations of this function. -func (f *SubRepoPermsStoreHandleFunc) History() []SubRepoPermsStoreHandleFuncCall { - f.mutex.Lock() - history := make([]SubRepoPermsStoreHandleFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// SubRepoPermsStoreHandleFuncCall is an object that describes an invocation -// of method Handle on an instance of MockSubRepoPermsStore. -type SubRepoPermsStoreHandleFuncCall struct { - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 basestore.TransactableHandle -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c SubRepoPermsStoreHandleFuncCall) Args() []interface{} { - return []interface{}{} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c SubRepoPermsStoreHandleFuncCall) Results() []interface{} { - return []interface{}{c.Result0} -} - -// SubRepoPermsStoreRepoIDSupportedFunc describes the behavior when the -// RepoIDSupported method of the parent MockSubRepoPermsStore instance is -// invoked. -type SubRepoPermsStoreRepoIDSupportedFunc struct { - defaultHook func(context.Context, api.RepoID) (bool, error) - hooks []func(context.Context, api.RepoID) (bool, error) - history []SubRepoPermsStoreRepoIDSupportedFuncCall - mutex sync.Mutex -} - -// RepoIDSupported delegates to the next hook function in the queue and -// stores the parameter and result values of this invocation. -func (m *MockSubRepoPermsStore) RepoIDSupported(v0 context.Context, v1 api.RepoID) (bool, error) { - r0, r1 := m.RepoIDSupportedFunc.nextHook()(v0, v1) - m.RepoIDSupportedFunc.appendCall(SubRepoPermsStoreRepoIDSupportedFuncCall{v0, v1, r0, r1}) - return r0, r1 -} - -// SetDefaultHook sets function that is called when the RepoIDSupported -// method of the parent MockSubRepoPermsStore instance is invoked and the -// hook queue is empty. -func (f *SubRepoPermsStoreRepoIDSupportedFunc) SetDefaultHook(hook func(context.Context, api.RepoID) (bool, error)) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// RepoIDSupported method of the parent MockSubRepoPermsStore instance -// invokes the hook at the front of the queue and discards it. After the -// queue is empty, the default hook function is invoked for any future -// action. -func (f *SubRepoPermsStoreRepoIDSupportedFunc) PushHook(hook func(context.Context, api.RepoID) (bool, error)) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *SubRepoPermsStoreRepoIDSupportedFunc) SetDefaultReturn(r0 bool, r1 error) { - f.SetDefaultHook(func(context.Context, api.RepoID) (bool, error) { - return r0, r1 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *SubRepoPermsStoreRepoIDSupportedFunc) PushReturn(r0 bool, r1 error) { - f.PushHook(func(context.Context, api.RepoID) (bool, error) { - return r0, r1 - }) -} - -func (f *SubRepoPermsStoreRepoIDSupportedFunc) nextHook() func(context.Context, api.RepoID) (bool, error) { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *SubRepoPermsStoreRepoIDSupportedFunc) appendCall(r0 SubRepoPermsStoreRepoIDSupportedFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of SubRepoPermsStoreRepoIDSupportedFuncCall -// objects describing the invocations of this function. -func (f *SubRepoPermsStoreRepoIDSupportedFunc) History() []SubRepoPermsStoreRepoIDSupportedFuncCall { - f.mutex.Lock() - history := make([]SubRepoPermsStoreRepoIDSupportedFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// SubRepoPermsStoreRepoIDSupportedFuncCall is an object that describes an -// invocation of method RepoIDSupported on an instance of -// MockSubRepoPermsStore. -type SubRepoPermsStoreRepoIDSupportedFuncCall struct { - // Arg0 is the value of the 1st argument passed to this method - // invocation. - Arg0 context.Context - // Arg1 is the value of the 2nd argument passed to this method - // invocation. - Arg1 api.RepoID - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 bool - // Result1 is the value of the 2nd result returned from this method - // invocation. - Result1 error -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c SubRepoPermsStoreRepoIDSupportedFuncCall) Args() []interface{} { - return []interface{}{c.Arg0, c.Arg1} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c SubRepoPermsStoreRepoIDSupportedFuncCall) Results() []interface{} { - return []interface{}{c.Result0, c.Result1} -} - -// SubRepoPermsStoreRepoSupportedFunc describes the behavior when the -// RepoSupported method of the parent MockSubRepoPermsStore instance is -// invoked. -type SubRepoPermsStoreRepoSupportedFunc struct { - defaultHook func(context.Context, api.RepoName) (bool, error) - hooks []func(context.Context, api.RepoName) (bool, error) - history []SubRepoPermsStoreRepoSupportedFuncCall - mutex sync.Mutex -} - -// RepoSupported delegates to the next hook function in the queue and stores -// the parameter and result values of this invocation. -func (m *MockSubRepoPermsStore) RepoSupported(v0 context.Context, v1 api.RepoName) (bool, error) { - r0, r1 := m.RepoSupportedFunc.nextHook()(v0, v1) - m.RepoSupportedFunc.appendCall(SubRepoPermsStoreRepoSupportedFuncCall{v0, v1, r0, r1}) - return r0, r1 -} - -// SetDefaultHook sets function that is called when the RepoSupported method -// of the parent MockSubRepoPermsStore instance is invoked and the hook -// queue is empty. -func (f *SubRepoPermsStoreRepoSupportedFunc) SetDefaultHook(hook func(context.Context, api.RepoName) (bool, error)) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// RepoSupported method of the parent MockSubRepoPermsStore instance invokes -// the hook at the front of the queue and discards it. After the queue is -// empty, the default hook function is invoked for any future action. -func (f *SubRepoPermsStoreRepoSupportedFunc) PushHook(hook func(context.Context, api.RepoName) (bool, error)) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *SubRepoPermsStoreRepoSupportedFunc) SetDefaultReturn(r0 bool, r1 error) { - f.SetDefaultHook(func(context.Context, api.RepoName) (bool, error) { - return r0, r1 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *SubRepoPermsStoreRepoSupportedFunc) PushReturn(r0 bool, r1 error) { - f.PushHook(func(context.Context, api.RepoName) (bool, error) { - return r0, r1 - }) -} - -func (f *SubRepoPermsStoreRepoSupportedFunc) nextHook() func(context.Context, api.RepoName) (bool, error) { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *SubRepoPermsStoreRepoSupportedFunc) appendCall(r0 SubRepoPermsStoreRepoSupportedFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of SubRepoPermsStoreRepoSupportedFuncCall -// objects describing the invocations of this function. -func (f *SubRepoPermsStoreRepoSupportedFunc) History() []SubRepoPermsStoreRepoSupportedFuncCall { - f.mutex.Lock() - history := make([]SubRepoPermsStoreRepoSupportedFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// SubRepoPermsStoreRepoSupportedFuncCall is an object that describes an -// invocation of method RepoSupported on an instance of -// MockSubRepoPermsStore. -type SubRepoPermsStoreRepoSupportedFuncCall struct { - // Arg0 is the value of the 1st argument passed to this method - // invocation. - Arg0 context.Context - // Arg1 is the value of the 2nd argument passed to this method - // invocation. - Arg1 api.RepoName - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 bool - // Result1 is the value of the 2nd result returned from this method - // invocation. - Result1 error -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c SubRepoPermsStoreRepoSupportedFuncCall) Args() []interface{} { - return []interface{}{c.Arg0, c.Arg1} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c SubRepoPermsStoreRepoSupportedFuncCall) Results() []interface{} { - return []interface{}{c.Result0, c.Result1} -} - -// SubRepoPermsStoreTransactFunc describes the behavior when the Transact -// method of the parent MockSubRepoPermsStore instance is invoked. -type SubRepoPermsStoreTransactFunc struct { - defaultHook func(context.Context) (SubRepoPermsStore, error) - hooks []func(context.Context) (SubRepoPermsStore, error) - history []SubRepoPermsStoreTransactFuncCall - mutex sync.Mutex -} - -// Transact delegates to the next hook function in the queue and stores the -// parameter and result values of this invocation. -func (m *MockSubRepoPermsStore) Transact(v0 context.Context) (SubRepoPermsStore, error) { - r0, r1 := m.TransactFunc.nextHook()(v0) - m.TransactFunc.appendCall(SubRepoPermsStoreTransactFuncCall{v0, r0, r1}) - return r0, r1 -} - -// SetDefaultHook sets function that is called when the Transact method of -// the parent MockSubRepoPermsStore instance is invoked and the hook queue -// is empty. -func (f *SubRepoPermsStoreTransactFunc) SetDefaultHook(hook func(context.Context) (SubRepoPermsStore, error)) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// Transact method of the parent MockSubRepoPermsStore instance invokes the -// hook at the front of the queue and discards it. After the queue is empty, -// the default hook function is invoked for any future action. -func (f *SubRepoPermsStoreTransactFunc) PushHook(hook func(context.Context) (SubRepoPermsStore, error)) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *SubRepoPermsStoreTransactFunc) SetDefaultReturn(r0 SubRepoPermsStore, r1 error) { - f.SetDefaultHook(func(context.Context) (SubRepoPermsStore, error) { - return r0, r1 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *SubRepoPermsStoreTransactFunc) PushReturn(r0 SubRepoPermsStore, r1 error) { - f.PushHook(func(context.Context) (SubRepoPermsStore, error) { - return r0, r1 - }) -} - -func (f *SubRepoPermsStoreTransactFunc) nextHook() func(context.Context) (SubRepoPermsStore, error) { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *SubRepoPermsStoreTransactFunc) appendCall(r0 SubRepoPermsStoreTransactFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of SubRepoPermsStoreTransactFuncCall objects -// describing the invocations of this function. -func (f *SubRepoPermsStoreTransactFunc) History() []SubRepoPermsStoreTransactFuncCall { - f.mutex.Lock() - history := make([]SubRepoPermsStoreTransactFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// SubRepoPermsStoreTransactFuncCall is an object that describes an -// invocation of method Transact on an instance of MockSubRepoPermsStore. -type SubRepoPermsStoreTransactFuncCall struct { - // Arg0 is the value of the 1st argument passed to this method - // invocation. - Arg0 context.Context - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 SubRepoPermsStore - // Result1 is the value of the 2nd result returned from this method - // invocation. - Result1 error -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c SubRepoPermsStoreTransactFuncCall) Args() []interface{} { - return []interface{}{c.Arg0} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c SubRepoPermsStoreTransactFuncCall) Results() []interface{} { - return []interface{}{c.Result0, c.Result1} -} - -// SubRepoPermsStoreUpsertFunc describes the behavior when the Upsert method -// of the parent MockSubRepoPermsStore instance is invoked. -type SubRepoPermsStoreUpsertFunc struct { - defaultHook func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error - hooks []func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error - history []SubRepoPermsStoreUpsertFuncCall - mutex sync.Mutex -} - -// Upsert delegates to the next hook function in the queue and stores the -// parameter and result values of this invocation. -func (m *MockSubRepoPermsStore) Upsert(v0 context.Context, v1 int32, v2 api.RepoID, v3 authz.SubRepoPermissions) error { - r0 := m.UpsertFunc.nextHook()(v0, v1, v2, v3) - m.UpsertFunc.appendCall(SubRepoPermsStoreUpsertFuncCall{v0, v1, v2, v3, r0}) - return r0 -} - -// SetDefaultHook sets function that is called when the Upsert method of the -// parent MockSubRepoPermsStore instance is invoked and the hook queue is -// empty. -func (f *SubRepoPermsStoreUpsertFunc) SetDefaultHook(hook func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// Upsert method of the parent MockSubRepoPermsStore instance invokes the -// hook at the front of the queue and discards it. After the queue is empty, -// the default hook function is invoked for any future action. -func (f *SubRepoPermsStoreUpsertFunc) PushHook(hook func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *SubRepoPermsStoreUpsertFunc) SetDefaultReturn(r0 error) { - f.SetDefaultHook(func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error { - return r0 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *SubRepoPermsStoreUpsertFunc) PushReturn(r0 error) { - f.PushHook(func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error { - return r0 - }) -} - -func (f *SubRepoPermsStoreUpsertFunc) nextHook() func(context.Context, int32, api.RepoID, authz.SubRepoPermissions) error { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *SubRepoPermsStoreUpsertFunc) appendCall(r0 SubRepoPermsStoreUpsertFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of SubRepoPermsStoreUpsertFuncCall objects -// describing the invocations of this function. -func (f *SubRepoPermsStoreUpsertFunc) History() []SubRepoPermsStoreUpsertFuncCall { - f.mutex.Lock() - history := make([]SubRepoPermsStoreUpsertFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// SubRepoPermsStoreUpsertFuncCall is an object that describes an invocation -// of method Upsert on an instance of MockSubRepoPermsStore. -type SubRepoPermsStoreUpsertFuncCall struct { - // Arg0 is the value of the 1st argument passed to this method - // invocation. - Arg0 context.Context - // Arg1 is the value of the 2nd argument passed to this method - // invocation. - Arg1 int32 - // Arg2 is the value of the 3rd argument passed to this method - // invocation. - Arg2 api.RepoID - // Arg3 is the value of the 4th argument passed to this method - // invocation. - Arg3 authz.SubRepoPermissions - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 error -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c SubRepoPermsStoreUpsertFuncCall) Args() []interface{} { - return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c SubRepoPermsStoreUpsertFuncCall) Results() []interface{} { - return []interface{}{c.Result0} -} - -// SubRepoPermsStoreUpsertWithSpecFunc describes the behavior when the -// UpsertWithSpec method of the parent MockSubRepoPermsStore instance is -// invoked. -type SubRepoPermsStoreUpsertWithSpecFunc struct { - defaultHook func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error - hooks []func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error - history []SubRepoPermsStoreUpsertWithSpecFuncCall - mutex sync.Mutex -} - -// UpsertWithSpec delegates to the next hook function in the queue and -// stores the parameter and result values of this invocation. -func (m *MockSubRepoPermsStore) UpsertWithSpec(v0 context.Context, v1 int32, v2 api.ExternalRepoSpec, v3 authz.SubRepoPermissions) error { - r0 := m.UpsertWithSpecFunc.nextHook()(v0, v1, v2, v3) - m.UpsertWithSpecFunc.appendCall(SubRepoPermsStoreUpsertWithSpecFuncCall{v0, v1, v2, v3, r0}) - return r0 -} - -// SetDefaultHook sets function that is called when the UpsertWithSpec -// method of the parent MockSubRepoPermsStore instance is invoked and the -// hook queue is empty. -func (f *SubRepoPermsStoreUpsertWithSpecFunc) SetDefaultHook(hook func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// UpsertWithSpec method of the parent MockSubRepoPermsStore instance -// invokes the hook at the front of the queue and discards it. After the -// queue is empty, the default hook function is invoked for any future -// action. -func (f *SubRepoPermsStoreUpsertWithSpecFunc) PushHook(hook func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *SubRepoPermsStoreUpsertWithSpecFunc) SetDefaultReturn(r0 error) { - f.SetDefaultHook(func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error { - return r0 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *SubRepoPermsStoreUpsertWithSpecFunc) PushReturn(r0 error) { - f.PushHook(func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error { - return r0 - }) -} - -func (f *SubRepoPermsStoreUpsertWithSpecFunc) nextHook() func(context.Context, int32, api.ExternalRepoSpec, authz.SubRepoPermissions) error { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *SubRepoPermsStoreUpsertWithSpecFunc) appendCall(r0 SubRepoPermsStoreUpsertWithSpecFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of SubRepoPermsStoreUpsertWithSpecFuncCall -// objects describing the invocations of this function. -func (f *SubRepoPermsStoreUpsertWithSpecFunc) History() []SubRepoPermsStoreUpsertWithSpecFuncCall { - f.mutex.Lock() - history := make([]SubRepoPermsStoreUpsertWithSpecFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// SubRepoPermsStoreUpsertWithSpecFuncCall is an object that describes an -// invocation of method UpsertWithSpec on an instance of -// MockSubRepoPermsStore. -type SubRepoPermsStoreUpsertWithSpecFuncCall struct { - // Arg0 is the value of the 1st argument passed to this method - // invocation. - Arg0 context.Context - // Arg1 is the value of the 2nd argument passed to this method - // invocation. - Arg1 int32 - // Arg2 is the value of the 3rd argument passed to this method - // invocation. - Arg2 api.ExternalRepoSpec - // Arg3 is the value of the 4th argument passed to this method - // invocation. - Arg3 authz.SubRepoPermissions - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 error -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c SubRepoPermsStoreUpsertWithSpecFuncCall) Args() []interface{} { - return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c SubRepoPermsStoreUpsertWithSpecFuncCall) Results() []interface{} { - return []interface{}{c.Result0} -} - -// SubRepoPermsStoreWithFunc describes the behavior when the With method of -// the parent MockSubRepoPermsStore instance is invoked. -type SubRepoPermsStoreWithFunc struct { - defaultHook func(basestore.ShareableStore) SubRepoPermsStore - hooks []func(basestore.ShareableStore) SubRepoPermsStore - history []SubRepoPermsStoreWithFuncCall - mutex sync.Mutex -} - -// With delegates to the next hook function in the queue and stores the -// parameter and result values of this invocation. -func (m *MockSubRepoPermsStore) With(v0 basestore.ShareableStore) SubRepoPermsStore { - r0 := m.WithFunc.nextHook()(v0) - m.WithFunc.appendCall(SubRepoPermsStoreWithFuncCall{v0, r0}) - return r0 -} - -// SetDefaultHook sets function that is called when the With method of the -// parent MockSubRepoPermsStore instance is invoked and the hook queue is -// empty. -func (f *SubRepoPermsStoreWithFunc) SetDefaultHook(hook func(basestore.ShareableStore) SubRepoPermsStore) { - f.defaultHook = hook -} - -// PushHook adds a function to the end of hook queue. Each invocation of the -// With method of the parent MockSubRepoPermsStore instance invokes the hook -// at the front of the queue and discards it. After the queue is empty, the -// default hook function is invoked for any future action. -func (f *SubRepoPermsStoreWithFunc) PushHook(hook func(basestore.ShareableStore) SubRepoPermsStore) { - f.mutex.Lock() - f.hooks = append(f.hooks, hook) - f.mutex.Unlock() -} - -// SetDefaultReturn calls SetDefaultHook with a function that returns the -// given values. -func (f *SubRepoPermsStoreWithFunc) SetDefaultReturn(r0 SubRepoPermsStore) { - f.SetDefaultHook(func(basestore.ShareableStore) SubRepoPermsStore { - return r0 - }) -} - -// PushReturn calls PushHook with a function that returns the given values. -func (f *SubRepoPermsStoreWithFunc) PushReturn(r0 SubRepoPermsStore) { - f.PushHook(func(basestore.ShareableStore) SubRepoPermsStore { - return r0 - }) -} - -func (f *SubRepoPermsStoreWithFunc) nextHook() func(basestore.ShareableStore) SubRepoPermsStore { - f.mutex.Lock() - defer f.mutex.Unlock() - - if len(f.hooks) == 0 { - return f.defaultHook - } - - hook := f.hooks[0] - f.hooks = f.hooks[1:] - return hook -} - -func (f *SubRepoPermsStoreWithFunc) appendCall(r0 SubRepoPermsStoreWithFuncCall) { - f.mutex.Lock() - f.history = append(f.history, r0) - f.mutex.Unlock() -} - -// History returns a sequence of SubRepoPermsStoreWithFuncCall objects -// describing the invocations of this function. -func (f *SubRepoPermsStoreWithFunc) History() []SubRepoPermsStoreWithFuncCall { - f.mutex.Lock() - history := make([]SubRepoPermsStoreWithFuncCall, len(f.history)) - copy(history, f.history) - f.mutex.Unlock() - - return history -} - -// SubRepoPermsStoreWithFuncCall is an object that describes an invocation -// of method With on an instance of MockSubRepoPermsStore. -type SubRepoPermsStoreWithFuncCall struct { - // Arg0 is the value of the 1st argument passed to this method - // invocation. - Arg0 basestore.ShareableStore - // Result0 is the value of the 1st result returned from this method - // invocation. - Result0 SubRepoPermsStore -} - -// Args returns an interface slice containing the arguments of this -// invocation. -func (c SubRepoPermsStoreWithFuncCall) Args() []interface{} { - return []interface{}{c.Arg0} -} - -// Results returns an interface slice containing the results of this -// invocation. -func (c SubRepoPermsStoreWithFuncCall) Results() []interface{} { - return []interface{}{c.Result0} -} - // MockTemporarySettingsStore is a mock implementation of the // TemporarySettingsStore interface (from the package // github.com/sourcegraph/sourcegraph/internal/database) used for unit diff --git a/internal/gitserver/integration_tests/commits_test.go b/internal/gitserver/integration_tests/commits_test.go index 493ad89bce4..3fb4d4d221c 100644 --- a/internal/gitserver/integration_tests/commits_test.go +++ b/internal/gitserver/integration_tests/commits_test.go @@ -11,7 +11,6 @@ import ( "github.com/sourcegraph/sourcegraph/internal/actor" "github.com/sourcegraph/sourcegraph/internal/api" - "github.com/sourcegraph/sourcegraph/internal/authz" "github.com/sourcegraph/sourcegraph/internal/database" "github.com/sourcegraph/sourcegraph/internal/gitserver" "github.com/sourcegraph/sourcegraph/internal/gitserver/gitdomain" @@ -79,7 +78,7 @@ func TestGetCommits(t *testing.T) { nil, } - commits, err := gitserver.NewTestClient(http.DefaultClient, db, gitserverAddresses).GetCommits(ctx, nil, repoCommits, true) + commits, err := gitserver.NewTestClient(http.DefaultClient, db, GitserverAddresses).GetCommits(ctx, nil, repoCommits, true) if err != nil { t.Fatalf("unexpected error calling getCommits: %s", err) } @@ -87,61 +86,6 @@ func TestGetCommits(t *testing.T) { t.Errorf("unexpected commits (-want +got):\n%s", diff) } }) - - t.Run("with sub-repo permissions", func(t *testing.T) { - expectedCommits := []*gitdomain.Commit{ - { - ID: "2ba4dd2b9a27ec125fea7d72e12b9824ead18631", - Author: gitdomain.Signature{Name: "a", Email: "a@a.com", Date: *mustParseDate("2006-01-02T15:04:05Z", t)}, - Committer: &gitdomain.Signature{Name: "a", Email: "a@a.com", Date: *mustParseDate("2006-01-02T15:04:05Z", t)}, - Message: "commit2", - Parents: []api.CommitID{"d38233a79e037d2ab8170b0d0bc0aa438473e6da"}, - }, - nil, // file 1 - { - ID: "67762ad757dd26cac4145f2b744fd93ad10a48e0", - Author: gitdomain.Signature{Name: "a", Email: "a@a.com", Date: *mustParseDate("2006-01-02T15:04:05Z", t)}, - Committer: &gitdomain.Signature{Name: "a", Email: "a@a.com", Date: *mustParseDate("2006-01-02T15:04:05Z", t)}, - Message: "commit2", - Parents: []api.CommitID{"2b988222e844b570959a493f5b07ec020b89e122"}, - }, - nil, // file 3 - { - ID: "01bed0ae660668c57539cecaacb4c33d77609f43", - Author: gitdomain.Signature{Name: "a", Email: "a@a.com", Date: *mustParseDate("2006-01-02T15:04:05Z", t)}, - Committer: &gitdomain.Signature{Name: "a", Email: "a@a.com", Date: *mustParseDate("2006-01-02T15:04:05Z", t)}, - Message: "commit2", - Parents: []api.CommitID{"d6ce2e76d171569d81c0afdc4573f461cec17d45"}, - }, - nil, - nil, - } - - commits, err := gitserver.NewTestClient(http.DefaultClient, db, gitserverAddresses).GetCommits(ctx, getTestSubRepoPermsChecker("file1", "file3"), repoCommits, true) - if err != nil { - t.Fatalf("unexpected error calling getCommits: %s", err) - } - if diff := cmp.Diff(expectedCommits, commits); diff != "" { - t.Errorf("unexpected commits (-want +got):\n%s", diff) - } - }) -} - -// get a test sub-repo permissions checker which allows access to all files (so should be a no-op) -func getTestSubRepoPermsChecker(noAccessPaths ...string) authz.SubRepoPermissionChecker { - checker := authz.NewMockSubRepoPermissionChecker() - checker.EnabledFunc.SetDefaultHook(func() bool { - return true - }) - checker.PermissionsFunc.SetDefaultHook(func(ctx context.Context, i int32, content authz.RepoContent) (authz.Perms, error) { - for _, noAccessPath := range noAccessPaths { - if content.Path == noAccessPath { - return authz.None, nil - } - } - return authz.Read, nil - }) - return checker } func getGitCommandsWithFiles(fileName1, fileName2 string) []string { @@ -165,7 +109,7 @@ func mustParseDate(s string, t *testing.T) *time.Time { } func TestHead(t *testing.T) { - client := gitserver.NewTestClient(http.DefaultClient, database.NewMockDB(), gitserverAddresses) + client := gitserver.NewTestClient(http.DefaultClient, database.NewMockDB(), GitserverAddresses) t.Run("basic", func(t *testing.T) { gitCommands := []string{ "GIT_COMMITTER_NAME=a GIT_COMMITTER_EMAIL=a@a.com GIT_COMMITTER_DATE=2006-01-02T15:04:05Z git commit --allow-empty -m foo --author='a ' --date 2006-01-02T15:04:05Z", @@ -185,38 +129,4 @@ func TestHead(t *testing.T) { t.Fatal("Should exist") } }) - - t.Run("with sub-repo permissions", func(t *testing.T) { - gitCommands := []string{ - "touch file", - "git add file", - "GIT_COMMITTER_NAME=a GIT_COMMITTER_EMAIL=a@a.com GIT_COMMITTER_DATE=2006-01-02T15:04:05Z git commit -m foo --author='a ' --date 2006-01-02T15:04:05Z", - } - repo := MakeGitRepository(t, gitCommands...) - ctx := actor.WithActor(context.Background(), &actor.Actor{ - UID: 1, - }) - checker := getTestSubRepoPermsChecker("file") - // call Head() when user doesn't have access to view the commit - _, exists, err := client.Head(ctx, checker, repo) - if err != nil { - t.Fatal(err) - } - if exists { - t.Fatalf("exists should be false since the user doesn't have access to view the commit") - } - readAllChecker := getTestSubRepoPermsChecker() - // call Head() when user has access to view the commit; should return expected commit - head, exists, err := client.Head(ctx, readAllChecker, repo) - if err != nil { - t.Fatal(err) - } - wantHead := "46619ad353dbe4ed4108ebde9aa59ef676994a0b" - if head != wantHead { - t.Fatalf("Want %q, got %q", wantHead, head) - } - if !exists { - t.Fatal("Should exist") - } - }) } diff --git a/internal/gitserver/integration_tests/main_test.go b/internal/gitserver/integration_tests/main_test.go index e7652e9d41f..7b05efd5c9d 100644 --- a/internal/gitserver/integration_tests/main_test.go +++ b/internal/gitserver/integration_tests/main_test.go @@ -1,40 +1,18 @@ package inttests import ( - "context" "flag" - "log" - "net" - "net/http" "os" - "os/exec" - "path" - "path/filepath" - "strings" "testing" "time" - "golang.org/x/sync/semaphore" - sglog "github.com/sourcegraph/log" "github.com/sourcegraph/log/logtest" - - "github.com/sourcegraph/sourcegraph/cmd/gitserver/server" - "github.com/sourcegraph/sourcegraph/internal/api" - "github.com/sourcegraph/sourcegraph/internal/database" - "github.com/sourcegraph/sourcegraph/internal/gitserver" - "github.com/sourcegraph/sourcegraph/internal/httpcli" - "github.com/sourcegraph/sourcegraph/internal/observation" ) -var root string - -// This is a default gitserver test client currently used for RequestRepoUpdate -// gitserver calls during invocation of MakeGitRepository function -var testGitserverClient gitserver.Client -var gitserverAddresses []string - func TestMain(m *testing.M) { + InitGitserver() + flag.Parse() if !testing.Verbose() { @@ -48,101 +26,11 @@ func TestMain(m *testing.M) { os.Exit(code) } -// done in init since the go vet analysis "ctrlflow" is tripped up if this is -// done as part of TestMain. -func init() { - // Ignore users configuration in tests - os.Setenv("GIT_CONFIG_NOSYSTEM", "true") - os.Setenv("HOME", "/dev/null") - - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - log.Fatalf("listen failed: %s", err) - } - - root, err = os.MkdirTemp("", "test") - if err != nil { - log.Fatal(err) - } - - db := database.NewMockDB() - gr := database.NewMockGitserverRepoStore() - db.GitserverReposFunc.SetDefaultReturn(gr) - - srv := &http.Server{ - Handler: (&server.Server{ - Logger: sglog.Scoped("server", "the gitserver service"), - ObservationCtx: &observation.TestContext, - ReposDir: filepath.Join(root, "repos"), - GetRemoteURLFunc: func(ctx context.Context, name api.RepoName) (string, error) { - return filepath.Join(root, "remotes", string(name)), nil - }, - GetVCSSyncer: func(ctx context.Context, name api.RepoName) (server.VCSSyncer, error) { - return &server.GitRepoSyncer{}, nil - }, - GlobalBatchLogSemaphore: semaphore.NewWeighted(32), - DB: db, - }).Handler(), - } - go func() { - if err := srv.Serve(l); err != nil { - log.Fatal(err) - } - }() - - serverAddress := l.Addr().String() - testGitserverClient = gitserver.NewTestClient(httpcli.InternalDoer, db, []string{serverAddress}) - gitserverAddresses = []string{serverAddress} -} - var Times = []string{ AppleTime("2006-01-02T15:04:05Z"), AppleTime("2014-05-06T19:20:21Z"), } -// InitGitRepository initializes a new Git repository and runs cmds in a new -// temporary directory (returned as dir). -func InitGitRepository(t testing.TB, cmds ...string) string { - t.Helper() - remotes := filepath.Join(root, "remotes") - if err := os.MkdirAll(remotes, 0o700); err != nil { - t.Fatal(err) - } - dir, err := os.MkdirTemp(remotes, strings.ReplaceAll(t.Name(), "/", "__")) - if err != nil { - t.Fatal(err) - } - cmds = append([]string{"git init"}, cmds...) - for _, cmd := range cmds { - out, err := GitCommand(dir, "bash", "-c", cmd).CombinedOutput() - if err != nil { - t.Fatalf("Command %q failed. Output was:\n\n%s", cmd, out) - } - } - return dir -} - -func GitCommand(dir, name string, args ...string) *exec.Cmd { - c := exec.Command(name, args...) - c.Dir = dir - c.Env = append(os.Environ(), "GIT_CONFIG="+path.Join(dir, ".git", "config")) - return c -} - -// MakeGitRepository calls initGitRepository to create a new Git repository and returns a handle to -// it. -func MakeGitRepository(t testing.TB, cmds ...string) api.RepoName { - t.Helper() - dir := InitGitRepository(t, cmds...) - repo := api.RepoName(filepath.Base(dir)) - if resp, err := testGitserverClient.RequestRepoUpdate(context.Background(), repo, 0); err != nil { - t.Fatal(err) - } else if resp.Error != "" { - t.Fatal(resp.Error) - } - return repo -} - func AppleTime(t string) string { ti, _ := time.Parse(time.RFC3339, t) return ti.Local().Format("200601021504.05") diff --git a/internal/gitserver/integration_tests/object_test.go b/internal/gitserver/integration_tests/object_test.go index 0d3d440f3e4..181744dbcb1 100644 --- a/internal/gitserver/integration_tests/object_test.go +++ b/internal/gitserver/integration_tests/object_test.go @@ -35,7 +35,7 @@ func TestGetObject(t *testing.T) { for label, test := range tests { t.Run(label, func(t *testing.T) { - obj, err := gitserver.NewTestClient(http.DefaultClient, database.NewMockDB(), gitserverAddresses).GetObject(context.Background(), test.repo, test.objectName) + obj, err := gitserver.NewTestClient(http.DefaultClient, database.NewMockDB(), GitserverAddresses).GetObject(context.Background(), test.repo, test.objectName) if err != nil { t.Fatal(err) } diff --git a/internal/gitserver/integration_tests/test_utils.go b/internal/gitserver/integration_tests/test_utils.go new file mode 100644 index 00000000000..59529628a6e --- /dev/null +++ b/internal/gitserver/integration_tests/test_utils.go @@ -0,0 +1,121 @@ +package inttests + +import ( + "context" + "net" + "net/http" + "os" + "os/exec" + "path" + "path/filepath" + "strings" + "testing" + + sglog "github.com/sourcegraph/log" + + "github.com/sourcegraph/sourcegraph/cmd/gitserver/server" + "github.com/sourcegraph/sourcegraph/internal/api" + "github.com/sourcegraph/sourcegraph/internal/database" + "github.com/sourcegraph/sourcegraph/internal/gitserver" + "github.com/sourcegraph/sourcegraph/internal/httpcli" + "github.com/sourcegraph/sourcegraph/internal/observation" + "golang.org/x/sync/semaphore" +) + +var root string + +// This is a default gitserver test client currently used for RequestRepoUpdate +// gitserver calls during invocation of MakeGitRepository function +var ( + testGitserverClient gitserver.Client + GitserverAddresses []string +) + +func InitGitserver() { + // Ignore users configuration in tests + os.Setenv("GIT_CONFIG_NOSYSTEM", "true") + os.Setenv("HOME", "/dev/null") + logger := sglog.Scoped("gitserver_integration_tests", "") + + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + logger.Fatal("listen failed", sglog.Error(err)) + } + + root, err = os.MkdirTemp("", "test") + if err != nil { + logger.Fatal(err.Error()) + } + + db := database.NewMockDB() + gr := database.NewMockGitserverRepoStore() + db.GitserverReposFunc.SetDefaultReturn(gr) + + srv := &http.Server{ + Handler: (&server.Server{ + Logger: sglog.Scoped("server", "the gitserver service"), + ObservationCtx: &observation.TestContext, + ReposDir: filepath.Join(root, "repos"), + GetRemoteURLFunc: func(ctx context.Context, name api.RepoName) (string, error) { + return filepath.Join(root, "remotes", string(name)), nil + }, + GetVCSSyncer: func(ctx context.Context, name api.RepoName) (server.VCSSyncer, error) { + return &server.GitRepoSyncer{}, nil + }, + GlobalBatchLogSemaphore: semaphore.NewWeighted(32), + DB: db, + }).Handler(), + } + go func() { + if err := srv.Serve(l); err != nil { + logger.Fatal(err.Error()) + } + }() + + serverAddress := l.Addr().String() + testGitserverClient = gitserver.NewTestClient(httpcli.InternalDoer, db, []string{serverAddress}) + GitserverAddresses = []string{serverAddress} +} + +// MakeGitRepository calls initGitRepository to create a new Git repository and returns a handle to +// it. +func MakeGitRepository(t testing.TB, cmds ...string) api.RepoName { + t.Helper() + dir := InitGitRepository(t, cmds...) + repo := api.RepoName(filepath.Base(dir)) + if resp, err := testGitserverClient.RequestRepoUpdate(context.Background(), repo, 0); err != nil { + t.Fatal(err) + } else if resp.Error != "" { + t.Fatal(resp.Error) + } + return repo +} + +// InitGitRepository initializes a new Git repository and runs cmds in a new +// temporary directory (returned as dir). +func InitGitRepository(t testing.TB, cmds ...string) string { + t.Helper() + remotes := filepath.Join(root, "remotes") + if err := os.MkdirAll(remotes, 0o700); err != nil { + t.Fatal(err) + } + dir, err := os.MkdirTemp(remotes, strings.ReplaceAll(t.Name(), "/", "__")) + if err != nil { + t.Fatal(err) + } + cmds = append([]string{"git init"}, cmds...) + for _, cmd := range cmds { + out, err := GitCommand(dir, "bash", "-c", cmd).CombinedOutput() + if err != nil { + t.Fatalf("Command %q failed. Output was:\n\n%s", cmd, out) + } + } + return dir +} + +func GitCommand(dir, name string, args ...string) *exec.Cmd { + c := exec.Command(name, args...) + c.Dir = dir + c.Env = append(os.Environ(), "GIT_CONFIG="+path.Join(dir, ".git", "config")) + return c +} diff --git a/internal/gitserver/integration_tests/tree_test.go b/internal/gitserver/integration_tests/tree_test.go index f12e552d81b..e8090503746 100644 --- a/internal/gitserver/integration_tests/tree_test.go +++ b/internal/gitserver/integration_tests/tree_test.go @@ -11,70 +11,13 @@ import ( "sort" "testing" - "github.com/stretchr/testify/assert" - - "github.com/sourcegraph/sourcegraph/internal/actor" "github.com/sourcegraph/sourcegraph/internal/api" "github.com/sourcegraph/sourcegraph/internal/authz" - "github.com/sourcegraph/sourcegraph/internal/conf" "github.com/sourcegraph/sourcegraph/internal/database" "github.com/sourcegraph/sourcegraph/internal/gitserver" "github.com/sourcegraph/sourcegraph/internal/gitserver/gitdomain" - "github.com/sourcegraph/sourcegraph/schema" ) -func TestReadDir_SubRepoFiltering(t *testing.T) { - ctx := actor.WithActor(context.Background(), &actor.Actor{ - UID: 1, - }) - gitCommands := []string{ - "touch file1", - "git add file1", - "GIT_COMMITTER_NAME=a GIT_COMMITTER_EMAIL=a@a.com GIT_COMMITTER_DATE=2006-01-02T15:04:05Z git commit -m commit1 --author='a ' --date 2006-01-02T15:04:05Z", - "mkdir app", - "touch app/file2", - "git add app", - "GIT_COMMITTER_NAME=a GIT_COMMITTER_EMAIL=a@a.com GIT_COMMITTER_DATE=2006-01-02T15:04:05Z git commit -m commit2 --author='a ' --date 2006-01-02T15:04:05Z", - } - repo := MakeGitRepository(t, gitCommands...) - commitID := api.CommitID("b1c725720de2bbd0518731b4a61959797ff345f3") - conf.Mock(&conf.Unified{ - SiteConfiguration: schema.SiteConfiguration{ - ExperimentalFeatures: &schema.ExperimentalFeatures{ - SubRepoPermissions: &schema.SubRepoPermissions{ - Enabled: true, - }, - }, - }, - }) - defer conf.Mock(nil) - srpGetter := database.NewMockSubRepoPermsStore() - testSubRepoPerms := map[api.RepoName]authz.SubRepoPermissions{ - repo: { - Paths: []string{"/**", "-/app/**"}, - }, - } - srpGetter.GetByUserFunc.SetDefaultReturn(testSubRepoPerms, nil) - checker, err := authz.NewSubRepoPermsClient(srpGetter) - if err != nil { - t.Fatalf("unexpected error creating sub-repo perms client: %s", err) - } - - db := database.NewMockDB() - gr := database.NewMockGitserverRepoStore() - db.GitserverReposFunc.SetDefaultReturn(gr) - client := gitserver.NewTestClient(http.DefaultClient, db, gitserverAddresses) - files, err := client.ReadDir(ctx, checker, repo, commitID, "", false) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - - // Because we have a wildcard matcher we still allow directory visibility - assert.Len(t, files, 1) - assert.Equal(t, "file1", files[0].Name()) - assert.False(t, files[0].IsDir()) -} - func TestRepository_FileSystem(t *testing.T) { t.Parallel() ctx := context.Background() @@ -116,7 +59,7 @@ func TestRepository_FileSystem(t *testing.T) { }, } - client := gitserver.NewTestClient(http.DefaultClient, db, gitserverAddresses) + client := gitserver.NewTestClient(http.DefaultClient, db, GitserverAddresses) for label, test := range tests { // notafile should not exist. if _, err := client.Stat(ctx, authz.DefaultSubRepoPermsChecker, test.repo, test.first, "notafile"); !os.IsNotExist(err) { @@ -142,7 +85,7 @@ func TestRepository_FileSystem(t *testing.T) { if got, want := "ab771ba54f5571c99ffdae54f44acc7993d9f115", dir1Info.Sys().(gitdomain.ObjectInfo).OID().String(); got != want { t.Errorf("%s: got dir1 OID %q, want %q", label, got, want) } - client := gitserver.NewTestClient(http.DefaultClient, db, gitserverAddresses) + client := gitserver.NewTestClient(http.DefaultClient, db, GitserverAddresses) // dir1 should contain one entry: file1. dir1Entries, err := client.ReadDir(ctx, authz.DefaultSubRepoPermsChecker, test.repo, test.first, "dir1", false) @@ -311,7 +254,7 @@ func TestRepository_FileSystem_quoteChars(t *testing.T) { }, } - client := gitserver.NewTestClient(http.DefaultClient, db, gitserverAddresses) + client := gitserver.NewTestClient(http.DefaultClient, db, GitserverAddresses) for label, test := range tests { commitID, err := client.ResolveRevision(ctx, test.repo, "master", gitserver.ResolveRevisionOptions{}) if err != nil { @@ -374,7 +317,7 @@ func TestRepository_FileSystem_gitSubmodules(t *testing.T) { }, } - client := gitserver.NewTestClient(http.DefaultClient, db, gitserverAddresses) + client := gitserver.NewTestClient(http.DefaultClient, db, GitserverAddresses) for label, test := range tests { commitID, err := client.ResolveRevision(ctx, test.repo, "master", gitserver.ResolveRevisionOptions{}) if err != nil { diff --git a/internal/search/symbol/symbol.go b/internal/search/symbol/symbol.go index 85979956dca..f1428347dd7 100644 --- a/internal/search/symbol/symbol.go +++ b/internal/search/symbol/symbol.go @@ -51,7 +51,7 @@ func indexedSymbolsBranch(ctx context.Context, repo *types.MinimalRepo, commit s return "" } -func filterZoektResults(ctx context.Context, checker authz.SubRepoPermissionChecker, repo api.RepoName, results []*result.SymbolMatch) ([]*result.SymbolMatch, error) { +func FilterZoektResults(ctx context.Context, checker authz.SubRepoPermissionChecker, repo api.RepoName, results []*result.SymbolMatch) ([]*result.SymbolMatch, error) { if !authz.SubRepoEnabled(checker) { return results, nil } @@ -197,7 +197,7 @@ func Compute(ctx context.Context, checker authz.SubRepoPermissionChecker, repoNa if err != nil { return nil, errors.Wrap(err, "zoekt symbol search") } - results, err = filterZoektResults(ctx, checker, repoName.Name, results) + results, err = FilterZoektResults(ctx, checker, repoName.Name, results) if err != nil { return nil, errors.Wrap(err, "checking permissions") } diff --git a/internal/search/symbol/symbol_test.go b/internal/search/symbol/symbol_test.go index 10d3ea6b72e..15ee5757a7c 100644 --- a/internal/search/symbol/symbol_test.go +++ b/internal/search/symbol/symbol_test.go @@ -8,59 +8,8 @@ import ( "github.com/sourcegraph/sourcegraph/internal/types" "github.com/sourcegraph/sourcegraph/lib/errors" "github.com/stretchr/testify/assert" - - "github.com/sourcegraph/sourcegraph/internal/actor" - "github.com/sourcegraph/sourcegraph/internal/api" - "github.com/sourcegraph/sourcegraph/internal/authz" - "github.com/sourcegraph/sourcegraph/internal/conf" - "github.com/sourcegraph/sourcegraph/internal/search/result" - "github.com/sourcegraph/sourcegraph/schema" ) -func TestFilterZoektResults(t *testing.T) { - conf.Mock(&conf.Unified{ - SiteConfiguration: schema.SiteConfiguration{ - ExperimentalFeatures: &schema.ExperimentalFeatures{ - SubRepoPermissions: &schema.SubRepoPermissions{ - Enabled: true, - }, - }, - }, - }) - t.Cleanup(func() { conf.Mock(nil) }) - - repoName := api.RepoName("foo") - ctx := context.Background() - ctx = actor.WithActor(ctx, &actor.Actor{ - UID: 1, - }) - checker, err := authz.NewSimpleChecker(repoName, []string{"/**", "-/*_test.go"}) - if err != nil { - t.Fatal(err) - } - results := []*result.SymbolMatch{ - { - Symbol: result.Symbol{}, - File: &result.File{ - Path: "foo.go", - }, - }, - { - Symbol: result.Symbol{}, - File: &result.File{ - Path: "foo_test.go", - }, - }, - } - filtered, err := filterZoektResults(ctx, checker, repoName, results) - if err != nil { - t.Fatal(err) - } - assert.Len(t, filtered, 1) - r := filtered[0] - assert.Equal(t, r.File.Path, "foo.go") -} - func TestSearchZoektDoesntPanicWithNilQuery(t *testing.T) { // As soon as we reach Streamer.Search function, we can consider test successful, // that's why we can just mock it. diff --git a/mockgen.temp.yaml b/mockgen.temp.yaml index 7657d9e5e92..6b88d783078 100644 --- a/mockgen.temp.yaml +++ b/mockgen.temp.yaml @@ -17,6 +17,7 @@ - CodeMonitorStore - EnterpriseDB - PermsStore + - SubRepoPermsStore - filename: enterprise/internal/insights/discovery/mocks_temp.go path: github.com/sourcegraph/sourcegraph/enterprise/internal/insights/discovery interfaces: @@ -32,6 +33,9 @@ path: github.com/sourcegraph/sourcegraph/internal/authz interfaces: - SubRepoPermissionChecker +- filename: enterprise/internal/authz/subrepoperms/mocks_temp.go + path: github.com/sourcegraph/sourcegraph/enterprise/internal/authz/subrepoperms + interfaces: - SubRepoPermissionsGetter - filename: internal/database/mocks_temp.go path: github.com/sourcegraph/sourcegraph/internal/database @@ -57,7 +61,6 @@ - SearchContextsStore - SecurityEventLogsStore - SettingsStore - - SubRepoPermsStore - TemporarySettingsStore - UserCredentialsStore - UserEmailsStore diff --git a/sg.config.yaml b/sg.config.yaml index 0eeb325218b..f13c208a825 100644 --- a/sg.config.yaml +++ b/sg.config.yaml @@ -51,6 +51,8 @@ env: { "Name": "frontend", "Host": "127.0.0.1:6063" }, { "Name": "gitserver-0", "Host": "127.0.0.1:3551" }, { "Name": "gitserver-1", "Host": "127.0.0.1:3552" }, + { "Name": "oss-gitserver-0", "Host": "127.0.0.1:3551" }, + { "Name": "oss-gitserver-1", "Host": "127.0.0.1:3552" }, { "Name": "searcher", "Host": "127.0.0.1:6069" }, { "Name": "oss-symbols", "Host": "127.0.0.1:6071" }, { "Name": "symbols", "Host": "127.0.0.1:6071" }, @@ -189,7 +191,7 @@ commands: if [ -n "$DELVE" ]; then export GCFLAGS='all=-N -l' fi - go build -gcflags="$GCFLAGS" -o .bin/gitserver github.com/sourcegraph/sourcegraph/cmd/gitserver + go build -gcflags="$GCFLAGS" -o .bin/gitserver github.com/sourcegraph/sourcegraph/enterprise/cmd/gitserver checkBinary: .bin/gitserver env: &gitserverenv HOSTNAME: 127.0.0.1:3178 @@ -197,6 +199,41 @@ commands: - lib - internal - cmd/gitserver + - enterprise/internal + - enterprise/cmd/gitserver + + oss-gitserver-template: &oss_gitserver_template + cmd: .bin/oss-gitserver + install: | + if [ -n "$DELVE" ]; then + export GCFLAGS='all=-N -l' + fi + go build -gcflags="$GCFLAGS" -o .bin/oss-gitserver github.com/sourcegraph/sourcegraph/cmd/gitserver + checkBinary: .bin/oss-gitserver + env: &oss_gitserverenv + HOSTNAME: 127.0.0.1:3178 + watch: + - lib + - internal + - cmd/gitserver + + oss-gitserver-0: + <<: *oss_gitserver_template + env: + <<: *gitserverenv + HOSTNAME: 127.0.0.1:3501 + GITSERVER_ADDR: 127.0.0.1:3501 + SRC_REPOS_DIR: $HOME/.sourcegraph/repos_1 + SRC_PROF_HTTP: 127.0.0.1:3551 + + oss-gitserver-1: + <<: *oss_gitserver_template + env: + <<: *oss_gitserverenv + HOSTNAME: 127.0.0.1:3502 + GITSERVER_ADDR: 127.0.0.1:3502 + SRC_REPOS_DIR: $HOME/.sourcegraph/repos_2 + SRC_PROF_HTTP: 127.0.0.1:3552 # This is only here to stay backwards-compatible with people's custom # `sg.config.overwrite.yaml` files @@ -794,8 +831,8 @@ commandsets: - oss-worker - oss-repo-updater - oss-symbols - - gitserver-0 - - gitserver-1 + - oss-gitserver-0 + - oss-gitserver-1 - searcher - oss-web - caddy