diff --git a/cmd/drone-server/server.go b/cmd/drone-server/server.go index 9a6d69848..d2fe0b214 100644 --- a/cmd/drone-server/server.go +++ b/cmd/drone-server/server.go @@ -102,6 +102,11 @@ var flags = []cli.Flag{ Name: "orgs", Usage: "list of approved organizations", }, + cli.StringSliceFlag{ + EnvVar: "DRONE_REPO_OWNERS", + Name: "repo-owners", + Usage: "List of syncable repo owners", + }, cli.BoolFlag{ EnvVar: "DRONE_OPEN", Name: "open", diff --git a/model/settings.go b/model/settings.go index 1f73a89e5..26a021ce2 100644 --- a/model/settings.go +++ b/model/settings.go @@ -20,6 +20,7 @@ type Settings struct { Secret string // Secret token used to authenticate agents Admins map[string]bool // Administrative users Orgs map[string]bool // Organization whitelist + OwnersWhitelist map[string]bool // Owners whitelist } // IsAdmin returns true if the user is a member of the administrator list. diff --git a/router/middleware/config.go b/router/middleware/config.go index 27e692bbc..5a2ad6814 100644 --- a/router/middleware/config.go +++ b/router/middleware/config.go @@ -39,6 +39,7 @@ func setupConfig(c *cli.Context) *model.Settings { Secret: c.String("agent-secret"), Admins: sliceToMap2(c.StringSlice("admin")), Orgs: sliceToMap2(c.StringSlice("orgs")), + OwnersWhitelist: sliceToMap2(c.StringSlice("repo-owners")), } } diff --git a/server/sync.go b/server/sync.go index a14cde446..1c2d9a019 100644 --- a/server/sync.go +++ b/server/sync.go @@ -31,6 +31,35 @@ type syncer struct { remote remote.Remote store store.Store perms model.PermStore + match FilterFunc +} + +// FilterFunc can be used to filter which repositories are +// synchronized with the local datastore. +type FilterFunc func(*model.Repo) bool + +// NamespaceFilter +func NamespaceFilter(namespaces map[string]bool) FilterFunc { + if namespaces == nil || len(namespaces) == 0 { + return noopFilter + } + return func(repo *model.Repo) bool { + if namespaces[repo.Owner] { + return true + } else { + return false + } + } +} + +// noopFilter is a filter function that always returns true. +func noopFilter(*model.Repo) bool { + return true +} + +// SetFilter sets the filter function. +func (s *syncer) SetFilter(fn FilterFunc) { + s.match = fn } func (s *syncer) Sync(user *model.User) error { @@ -40,22 +69,27 @@ func (s *syncer) Sync(user *model.User) error { return err } + var remote []*model.Repo var perms []*model.Perm + for _, repo := range repos { - perm := model.Perm{ - UserID: user.ID, - Repo: repo.FullName, - Pull: true, - Synced: unix, + if s.match(repo) { + remote = append(remote, repo) + perm := model.Perm{ + UserID: user.ID, + Repo: repo.FullName, + Pull: true, + Synced: unix, + } + if repo.Perm != nil { + perm.Push = repo.Perm.Push + perm.Admin = repo.Perm.Admin + } + perms = append(perms, &perm) } - if repo.Perm != nil { - perm.Push = repo.Perm.Push - perm.Admin = repo.Perm.Admin - } - perms = append(perms, &perm) } - err = s.store.RepoBatch(repos) + err = s.store.RepoBatch(remote) if err != nil { return err } diff --git a/server/user.go b/server/user.go index 18ad347bf..146f8eda6 100644 --- a/server/user.go +++ b/server/user.go @@ -45,10 +45,13 @@ func GetFeed(c *gin.Context) { user.Synced = time.Now().Unix() store.FromContext(c).UpdateUser(user) + config := ToConfig(c) + sync := syncer{ remote: remote.FromContext(c), store: store.FromContext(c), perms: store.FromContext(c), + match: NamespaceFilter(config.OwnersWhitelist), } if err := sync.Sync(user); err != nil { logrus.Debugf("sync error: %s: %s", user.Login, err) @@ -87,11 +90,16 @@ func GetRepos(c *gin.Context) { user.Synced = time.Now().Unix() store.FromContext(c).UpdateUser(user) + config := ToConfig(c) + sync := syncer{ remote: remote.FromContext(c), store: store.FromContext(c), perms: store.FromContext(c), + match: NamespaceFilter(config.OwnersWhitelist), } + + if err := sync.Sync(user); err != nil { logrus.Debugf("sync error: %s: %s", user.Login, err) } else {