From 606ca938819a3b533fca1b603863d15b06d715d6 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Tue, 26 Jul 2016 15:12:22 +0200 Subject: [PATCH 01/10] Properly formatted bitbucketserver --- remote/bitbucketserver/bitbucketserver.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/remote/bitbucketserver/bitbucketserver.go b/remote/bitbucketserver/bitbucketserver.go index 196d44dd1..1aa1f24a8 100644 --- a/remote/bitbucketserver/bitbucketserver.go +++ b/remote/bitbucketserver/bitbucketserver.go @@ -122,7 +122,7 @@ func (c *client) Login(res http.ResponseWriter, req *http.Request) (*model.User, defer response1.Body.Close() contents, err := ioutil.ReadAll(response1.Body) - if err !=nil { + if err != nil { return nil, err } @@ -152,7 +152,7 @@ func (*client) Teams(u *model.User) ([]*model.Team, error) { func (c *client) Repo(u *model.User, owner, name string) (*model.Repo, error) { client := NewClientWithToken(&c.Consumer, u.Token) - repo , err := c.FindRepo(client,owner,name) + repo, err := c.FindRepo(client, owner, name) if err != nil { return nil, err } @@ -202,7 +202,7 @@ func (c *client) Perm(u *model.User, owner, repo string) (*model.Perm, error) { } // Must have admin to be able to list hooks. If have access the enable perms - _, err = client.Get(fmt.Sprintf("%s/rest/api/1.0/projects/%s/repos/%s/settings/hooks/%s", c.URL, owner, repo,"com.atlassian.stash.plugin.stash-web-post-receive-hooks-plugin:postReceiveHook")) + _, err = client.Get(fmt.Sprintf("%s/rest/api/1.0/projects/%s/repos/%s/settings/hooks/%s", c.URL, owner, repo, "com.atlassian.stash.plugin.stash-web-post-receive-hooks-plugin:postReceiveHook")) if err == nil { perms.Push = true perms.Admin = true @@ -339,7 +339,7 @@ func (bs *client) DeleteHook(client *http.Client, project, slug, hook_key, link return nil } -func (c *client) FindRepo(client *http.Client, owner string, name string) (*model.Repo, error){ +func (c *client) FindRepo(client *http.Client, owner string, name string) (*model.Repo, error) { urlString := fmt.Sprintf("%s/rest/api/1.0/projects/%s/repos/%s", c.URL, owner, name) @@ -351,7 +351,7 @@ func (c *client) FindRepo(client *http.Client, owner string, name string) (*mode contents, err := ioutil.ReadAll(response.Body) bsRepo := BSRepo{} err = json.Unmarshal(contents, &bsRepo) - if err !=nil { + if err != nil { return nil, err } repo := &model.Repo{ From 86e4e53e77c8d87bd02b9bd1190af068f86dbf95 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Mon, 25 Jul 2016 17:03:54 +0200 Subject: [PATCH 02/10] Integrated org secrets into client --- client/client.go | 9 ++++++ client/client_impl.go | 70 ++++++++++++++++++++++++++++--------------- 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/client/client.go b/client/client.go index c9d141677..8a423aad2 100644 --- a/client/client.go +++ b/client/client.go @@ -61,6 +61,15 @@ type Client interface { // SecretDel deletes a named repository secret. SecretDel(string, string, string) error + // TeamSecretList returns a list of all team secrets. + TeamSecretList(string) ([]*model.Secret, error) + + // TeamSecretPost create or updates a team secret. + TeamSecretPost(string, *model.Secret) error + + // TeamSecretDel deletes a named team secret. + TeamSecretDel(string, string) error + // Build returns a repository build by number. Build(string, string, int) (*model.Build, error) diff --git a/client/client_impl.go b/client/client_impl.go index 2c7357ab7..89f78f7c0 100644 --- a/client/client_impl.go +++ b/client/client_impl.go @@ -28,26 +28,28 @@ const ( pathLogs = "%s/api/queue/logs/%d" pathLogsAuth = "%s/api/queue/logs/%d?access_token=%s" - pathSelf = "%s/api/user" - pathFeed = "%s/api/user/feed" - pathRepos = "%s/api/user/repos" - pathRepo = "%s/api/repos/%s/%s" - pathChown = "%s/api/repos/%s/%s/chown" - pathEncrypt = "%s/api/repos/%s/%s/encrypt" - pathBuilds = "%s/api/repos/%s/%s/builds" - pathBuild = "%s/api/repos/%s/%s/builds/%v" - pathJob = "%s/api/repos/%s/%s/builds/%d/%d" - pathLog = "%s/api/repos/%s/%s/logs/%d/%d" - pathKey = "%s/api/repos/%s/%s/key" - pathSign = "%s/api/repos/%s/%s/sign" - pathSecrets = "%s/api/repos/%s/%s/secrets" - pathSecret = "%s/api/repos/%s/%s/secrets/%s" - pathNodes = "%s/api/nodes" - pathNode = "%s/api/nodes/%d" - pathUsers = "%s/api/users" - pathUser = "%s/api/users/%s" - pathBuildQueue = "%s/api/builds" - pathAgent = "%s/api/agents" + pathSelf = "%s/api/user" + pathFeed = "%s/api/user/feed" + pathRepos = "%s/api/user/repos" + pathRepo = "%s/api/repos/%s/%s" + pathChown = "%s/api/repos/%s/%s/chown" + pathEncrypt = "%s/api/repos/%s/%s/encrypt" + pathBuilds = "%s/api/repos/%s/%s/builds" + pathBuild = "%s/api/repos/%s/%s/builds/%v" + pathJob = "%s/api/repos/%s/%s/builds/%d/%d" + pathLog = "%s/api/repos/%s/%s/logs/%d/%d" + pathKey = "%s/api/repos/%s/%s/key" + pathSign = "%s/api/repos/%s/%s/sign" + pathRepoSecrets = "%s/api/repos/%s/%s/secrets" + pathRepoSecret = "%s/api/repos/%s/%s/secrets/%s" + pathTeamSecrets = "%s/api/teams/%s/secrets" + pathTeamSecret = "%s/api/teams/%s/secrets/%s" + pathNodes = "%s/api/nodes" + pathNode = "%s/api/nodes/%d" + pathUsers = "%s/api/users" + pathUser = "%s/api/users/%s" + pathBuildQueue = "%s/api/builds" + pathAgent = "%s/api/agents" ) type client struct { @@ -78,7 +80,7 @@ func NewClientTokenTLS(uri, token string, c *tls.Config) Client { if trans, ok := auther.Transport.(*oauth2.Transport); ok { trans.Base = &http.Transport{ TLSClientConfig: c, - Proxy: http.ProxyFromEnvironment, + Proxy: http.ProxyFromEnvironment, } } } @@ -265,20 +267,40 @@ func (c *client) Deploy(owner, name string, num int, env string, params map[stri // SecretList returns a list of a repository secrets. func (c *client) SecretList(owner, name string) ([]*model.Secret, error) { var out []*model.Secret - uri := fmt.Sprintf(pathSecrets, c.base, owner, name) + uri := fmt.Sprintf(pathRepoSecrets, c.base, owner, name) err := c.get(uri, &out) return out, err } // SecretPost create or updates a repository secret. func (c *client) SecretPost(owner, name string, secret *model.Secret) error { - uri := fmt.Sprintf(pathSecrets, c.base, owner, name) + uri := fmt.Sprintf(pathRepoSecrets, c.base, owner, name) return c.post(uri, secret, nil) } // SecretDel deletes a named repository secret. func (c *client) SecretDel(owner, name, secret string) error { - uri := fmt.Sprintf(pathSecret, c.base, owner, name, secret) + uri := fmt.Sprintf(pathRepoSecret, c.base, owner, name, secret) + return c.delete(uri) +} + +// TeamSecretList returns a list of a repository secrets. +func (c *client) TeamSecretList(team string) ([]*model.Secret, error) { + var out []*model.Secret + uri := fmt.Sprintf(pathTeamSecrets, c.base, team) + err := c.get(uri, &out) + return out, err +} + +// TeamSecretPost create or updates a repository secret. +func (c *client) TeamSecretPost(team string, secret *model.Secret) error { + uri := fmt.Sprintf(pathTeamSecrets, c.base, team) + return c.post(uri, secret, nil) +} + +// TeamSecretDel deletes a named repository secret. +func (c *client) TeamSecretDel(team, secret string) error { + uri := fmt.Sprintf(pathTeamSecret, c.base, team, secret) return c.delete(uri) } From 225d1c82880f051b43654342ae460a3eeef421a1 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Sun, 31 Jul 2016 22:09:55 +0200 Subject: [PATCH 03/10] Integrated org secret commands --- drone/main.go | 1 + drone/org.go | 11 +++++ drone/org_secret.go | 13 ++++++ drone/org_secret_add.go | 83 ++++++++++++++++++++++++++++++++++++++ drone/org_secret_info.go | 1 + drone/org_secret_list.go | 87 ++++++++++++++++++++++++++++++++++++++++ drone/org_secret_rm.go | 34 ++++++++++++++++ 7 files changed, 230 insertions(+) create mode 100644 drone/org.go create mode 100644 drone/org_secret.go create mode 100644 drone/org_secret_add.go create mode 100644 drone/org_secret_info.go create mode 100644 drone/org_secret_list.go create mode 100644 drone/org_secret_rm.go diff --git a/drone/main.go b/drone/main.go index f50e71881..738382f05 100644 --- a/drone/main.go +++ b/drone/main.go @@ -42,6 +42,7 @@ func main() { signCmd, repoCmd, userCmd, + orgCmd, } app.Run(os.Args) diff --git a/drone/org.go b/drone/org.go new file mode 100644 index 000000000..d9ffaefe0 --- /dev/null +++ b/drone/org.go @@ -0,0 +1,11 @@ +package main + +import "github.com/codegangsta/cli" + +var orgCmd = cli.Command{ + Name: "org", + Usage: "manage organizations", + Subcommands: []cli.Command{ + orgSecretCmd, + }, +} diff --git a/drone/org_secret.go b/drone/org_secret.go new file mode 100644 index 000000000..1bf4e812d --- /dev/null +++ b/drone/org_secret.go @@ -0,0 +1,13 @@ +package main + +import "github.com/codegangsta/cli" + +var orgSecretCmd = cli.Command{ + Name: "secret", + Usage: "manage secrets", + Subcommands: []cli.Command{ + orgSecretAddCmd, + orgSecretRemoveCmd, + orgSecretListCmd, + }, +} diff --git a/drone/org_secret_add.go b/drone/org_secret_add.go new file mode 100644 index 000000000..52ac250dc --- /dev/null +++ b/drone/org_secret_add.go @@ -0,0 +1,83 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "strings" + + "github.com/codegangsta/cli" + "github.com/drone/drone/model" +) + +var orgSecretAddCmd = cli.Command{ + Name: "add", + Usage: "adds a secret", + ArgsUsage: "[org] [key] [value]", + Action: func(c *cli.Context) { + if err := orgSecretAdd(c); err != nil { + log.Fatalln(err) + } + }, + Flags: []cli.Flag{ + cli.StringSliceFlag{ + Name: "event", + Usage: "inject the secret for these event types", + Value: &cli.StringSlice{ + model.EventPush, + model.EventTag, + model.EventDeploy, + }, + }, + cli.StringSliceFlag{ + Name: "image", + Usage: "inject the secret for these image types", + Value: &cli.StringSlice{}, + }, + cli.StringFlag{ + Name: "input", + Usage: "input secret value from a file", + }, + }, +} + +func orgSecretAdd(c *cli.Context) error { + if len(c.Args().Tail()) != 3 { + cli.ShowSubcommandHelp(c) + return nil + } + + team := c.Args().First() + name := c.Args().Get(1) + value := c.Args().Get(2) + + secret := &model.Secret{} + secret.Name = name + secret.Value = value + secret.Images = c.StringSlice("image") + secret.Events = c.StringSlice("event") + + if len(secret.Images) == 0 { + return fmt.Errorf("Please specify the --image parameter") + } + + // TODO(bradrydzewski) below we use an @ sybmol to denote that the secret + // value should be loaded from a file (inspired by curl). I'd prefer to use + // a --input flag to explicitly specify a filepath instead. + + if strings.HasPrefix(secret.Value, "@") { + path := secret.Value[1:] + out, ferr := ioutil.ReadFile(path) + if ferr != nil { + return ferr + } + secret.Value = string(out) + } + + client, err := newClient(c) + if err != nil { + return err + } + + return client.TeamSecretPost(team, secret) +} diff --git a/drone/org_secret_info.go b/drone/org_secret_info.go new file mode 100644 index 000000000..06ab7d0f9 --- /dev/null +++ b/drone/org_secret_info.go @@ -0,0 +1 @@ +package main diff --git a/drone/org_secret_list.go b/drone/org_secret_list.go new file mode 100644 index 000000000..ea0144b9b --- /dev/null +++ b/drone/org_secret_list.go @@ -0,0 +1,87 @@ +package main + +import ( + "log" + "os" + "strings" + "text/template" + + "github.com/codegangsta/cli" +) + +var orgSecretListCmd = cli.Command{ + Name: "ls", + Usage: "list all secrets", + Action: func(c *cli.Context) { + if err := orgSecretList(c); err != nil { + log.Fatalln(err) + } + }, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "format", + Usage: "format output", + Value: tmplOrgSecretList, + }, + cli.StringFlag{ + Name: "image", + Usage: "filter by image", + }, + cli.StringFlag{ + Name: "event", + Usage: "filter by event", + }, + }, +} + +func orgSecretList(c *cli.Context) error { + if len(c.Args().Tail()) != 1 { + cli.ShowSubcommandHelp(c) + return nil + } + + team := c.Args().First() + + client, err := newClient(c) + if err != nil { + return err + } + + secrets, err := client.TeamSecretList(team) + + if err != nil || len(secrets) == 0 { + return err + } + + tmpl, err := template.New("_").Funcs(orgSecretFuncMap).Parse(c.String("format") + "\n") + + if err != nil { + return err + } + + for _, secret := range secrets { + if c.String("image") != "" && !stringInSlice(c.String("image"), secret.Images) { + continue + } + + if c.String("event") != "" && !stringInSlice(c.String("event"), secret.Events) { + continue + } + + tmpl.Execute(os.Stdout, secret) + } + + return nil +} + +// template for secret list items +var tmplOrgSecretList = "\x1b[33m{{ .Name }} \x1b[0m" + ` +Images: {{ list .Images }} +Events: {{ list .Events }} +` + +var orgSecretFuncMap = template.FuncMap{ + "list": func(s []string) string { + return strings.Join(s, ", ") + }, +} diff --git a/drone/org_secret_rm.go b/drone/org_secret_rm.go new file mode 100644 index 000000000..c0b4170d0 --- /dev/null +++ b/drone/org_secret_rm.go @@ -0,0 +1,34 @@ +package main + +import ( + "log" + + "github.com/codegangsta/cli" +) + +var orgSecretRemoveCmd = cli.Command{ + Name: "rm", + Usage: "remove a secret", + Action: func(c *cli.Context) { + if err := orgSecretRemove(c); err != nil { + log.Fatalln(err) + } + }, +} + +func orgSecretRemove(c *cli.Context) error { + if len(c.Args().Tail()) != 2 { + cli.ShowSubcommandHelp(c) + return nil + } + + team := c.Args().First() + secret := c.Args().Get(1) + + client, err := newClient(c) + if err != nil { + return err + } + + return client.TeamSecretDel(team, secret) +} From 1b84375db501f4fd7d73b933a9c6d9178fba8725 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Tue, 26 Jul 2016 17:22:35 +0200 Subject: [PATCH 04/10] Added migrations for team_secrets --- store/datastore/ddl/mysql/7.sql | 19 +++++++++++++++++++ store/datastore/ddl/postgres/7.sql | 19 +++++++++++++++++++ store/datastore/ddl/sqlite3/7.sql | 19 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 store/datastore/ddl/mysql/7.sql create mode 100644 store/datastore/ddl/postgres/7.sql create mode 100644 store/datastore/ddl/sqlite3/7.sql diff --git a/store/datastore/ddl/mysql/7.sql b/store/datastore/ddl/mysql/7.sql new file mode 100644 index 000000000..e009572b6 --- /dev/null +++ b/store/datastore/ddl/mysql/7.sql @@ -0,0 +1,19 @@ +-- +migrate Up + +CREATE TABLE team_secrets ( + team_secret_id INTEGER PRIMARY KEY AUTO_INCREMENT +,team_secret_key VARCHAR(255) +,team_secret_name VARCHAR(255) +,team_secret_value MEDIUMBLOB +,team_secret_images VARCHAR(2000) +,team_secret_events VARCHAR(2000) + +,UNIQUE(team_secret_name, team_secret_key) +); + +CREATE INDEX ix_team_secrets_key ON team_secrets (team_secret_key); + +-- +migrate Down + +DROP INDEX ix_team_secrets_key; +DROP TABLE team_secrets; diff --git a/store/datastore/ddl/postgres/7.sql b/store/datastore/ddl/postgres/7.sql new file mode 100644 index 000000000..225ccb8a6 --- /dev/null +++ b/store/datastore/ddl/postgres/7.sql @@ -0,0 +1,19 @@ +-- +migrate Up + +CREATE TABLE team_secrets ( + team_secret_id SERIAL PRIMARY KEY +,team_secret_key VARCHAR(255) +,team_secret_name VARCHAR(255) +,team_secret_value BYTEA +,team_secret_images VARCHAR(2000) +,team_secret_events VARCHAR(2000) + +,UNIQUE(team_secret_name, team_secret_key) +); + +CREATE INDEX ix_team_secrets_key ON team_secrets (team_secret_key); + +-- +migrate Down + +DROP INDEX ix_team_secrets_key; +DROP TABLE team_secrets; diff --git a/store/datastore/ddl/sqlite3/7.sql b/store/datastore/ddl/sqlite3/7.sql new file mode 100644 index 000000000..ce3e05145 --- /dev/null +++ b/store/datastore/ddl/sqlite3/7.sql @@ -0,0 +1,19 @@ +-- +migrate Up + +CREATE TABLE team_secrets ( + team_secret_id INTEGER PRIMARY KEY AUTOINCREMENT +,team_secret_key TEXT +,team_secret_name TEXT +,team_secret_value TEXT +,team_secret_images TEXT +,team_secret_events TEXT + +,UNIQUE(team_secret_name, team_secret_key) +); + +CREATE INDEX ix_team_secrets_key ON team_secrets (team_secret_key); + +-- +migrate Down + +DROP INDEX ix_team_secrets_key; +DROP TABLE team_secrets; From 9aac9e5bf79f566b470c3eaa012bbf823bf3d916 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Mon, 25 Jul 2016 17:20:14 +0200 Subject: [PATCH 05/10] Integrated team secrets dummy API --- router/router.go | 12 ++++++++++++ server/secret.go | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/router/router.go b/router/router.go index 446b4d641..5d37b53a1 100644 --- a/router/router.go +++ b/router/router.go @@ -62,6 +62,18 @@ func Load(middleware ...gin.HandlerFunc) http.Handler { users.DELETE("/:login", server.DeleteUser) } + teams := e.Group("/api/teams") + { + // TODO: Restrict access + + team := teams.Group("/:team") + { + team.GET("/secrets", server.GetTeamSecrets) + team.POST("/secrets", server.PostTeamSecret) + team.DELETE("/secrets/:secret", server.DeleteTeamSecret) + } + } + repos := e.Group("/api/repos/:owner/:name") { repos.POST("", server.PostRepo) diff --git a/server/secret.go b/server/secret.go index bc241dca1..39e5bd352 100644 --- a/server/secret.go +++ b/server/secret.go @@ -28,6 +28,15 @@ func GetSecrets(c *gin.Context) { c.JSON(http.StatusOK, list) } +func GetTeamSecrets(c *gin.Context) { + var ( + list []*model.Secret + ) + + // TODO(must): Integrate a real implementation + c.JSON(http.StatusOK, list) +} + func PostSecret(c *gin.Context) { repo := session.Repo(c) @@ -49,6 +58,11 @@ func PostSecret(c *gin.Context) { c.String(http.StatusOK, "") } +func PostTeamSecret(c *gin.Context) { + c.String(http.StatusOK, "") + // TODO(must): Integrate a real implementation +} + func DeleteSecret(c *gin.Context) { repo := session.Repo(c) name := c.Param("secret") @@ -66,3 +80,8 @@ func DeleteSecret(c *gin.Context) { c.String(http.StatusOK, "") } + +func DeleteTeamSecret(c *gin.Context) { + c.String(http.StatusOK, "") + // TODO(must): Integrate a real implementation +} From 0e424a25273fda6e5162f91596bad66e04b2abbf Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Sun, 31 Jul 2016 22:29:56 +0200 Subject: [PATCH 06/10] Separated repo and team secret models --- model/repo_secret.go | 48 ++++++++++++++++++++++++++++++++++++++++++++ model/secret.go | 27 +++++++------------------ model/team_secret.go | 48 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 20 deletions(-) create mode 100644 model/repo_secret.go create mode 100644 model/team_secret.go diff --git a/model/repo_secret.go b/model/repo_secret.go new file mode 100644 index 000000000..a450f434a --- /dev/null +++ b/model/repo_secret.go @@ -0,0 +1,48 @@ +package model + +type RepoSecret struct { + // the id for this secret. + ID int64 `json:"id" meddler:"secret_id,pk"` + + // the foreign key for this secret. + RepoID int64 `json:"-" meddler:"secret_repo_id"` + + // the name of the secret which will be used as the environment variable + // name at runtime. + Name string `json:"name" meddler:"secret_name"` + + // the value of the secret which will be provided to the runtime environment + // as a named environment variable. + Value string `json:"value" meddler:"secret_value"` + + // the secret is restricted to this list of images. + Images []string `json:"image,omitempty" meddler:"secret_images,json"` + + // the secret is restricted to this list of events. + Events []string `json:"event,omitempty" meddler:"secret_events,json"` +} + +// Secret transforms a repo secret into a simple secret. +func (s *RepoSecret) Secret() *Secret { + return &Secret{ + Name: s.Name, + Value: s.Value, + Images: s.Images, + Events: s.Events, + } +} + +// Clone provides a repo secrets clone without the value. +func (s *RepoSecret) Clone() *RepoSecret { + return &RepoSecret{ + ID: s.ID, + Name: s.Name, + Images: s.Images, + Events: s.Events, + } +} + +// Validate validates the required fields and formats. +func (s *RepoSecret) Validate() error { + return nil +} diff --git a/model/secret.go b/model/secret.go index 9f1c2f798..b28a57e3b 100644 --- a/model/secret.go +++ b/model/secret.go @@ -1,27 +1,23 @@ package model -import "path/filepath" +import ( + "path/filepath" +) type Secret struct { - // the id for this secret. - ID int64 `json:"id" meddler:"secret_id,pk"` - - // the foreign key for this secret. - RepoID int64 `json:"-" meddler:"secret_repo_id"` - // the name of the secret which will be used as the environment variable // name at runtime. - Name string `json:"name" meddler:"secret_name"` + Name string `json:"name"` // the value of the secret which will be provided to the runtime environment // as a named environment variable. - Value string `json:"value" meddler:"secret_value"` + Value string `json:"value"` // the secret is restricted to this list of images. - Images []string `json:"image,omitempty" meddler:"secret_images,json"` + Images []string `json:"image,omitempty"` // the secret is restricted to this list of events. - Events []string `json:"event,omitempty" meddler:"secret_events,json"` + Events []string `json:"event,omitempty"` } // Match returns true if an image and event match the restricted list. @@ -55,12 +51,3 @@ func (s *Secret) MatchEvent(event string) bool { func (s *Secret) Validate() error { return nil } - -func (s *Secret) Clone() *Secret { - return &Secret{ - ID: s.ID, - Name: s.Name, - Images: s.Images, - Events: s.Events, - } -} diff --git a/model/team_secret.go b/model/team_secret.go new file mode 100644 index 000000000..75108b454 --- /dev/null +++ b/model/team_secret.go @@ -0,0 +1,48 @@ +package model + +type TeamSecret struct { + // the id for this secret. + ID int64 `json:"id" meddler:"team_secret_id,pk"` + + // the foreign key for this secret. + Key string `json:"-" meddler:"team_secret_key"` + + // the name of the secret which will be used as the environment variable + // name at runtime. + Name string `json:"name" meddler:"team_secret_name"` + + // the value of the secret which will be provided to the runtime environment + // as a named environment variable. + Value string `json:"value" meddler:"team_secret_value"` + + // the secret is restricted to this list of images. + Images []string `json:"image,omitempty" meddler:"team_secret_images,json"` + + // the secret is restricted to this list of events. + Events []string `json:"event,omitempty" meddler:"team_secret_events,json"` +} + +// Secret transforms a repo secret into a simple secret. +func (s *TeamSecret) Secret() *Secret { + return &Secret{ + Name: s.Name, + Value: s.Value, + Images: s.Images, + Events: s.Events, + } +} + +// Clone provides a repo secrets clone without the value. +func (s *TeamSecret) Clone() *TeamSecret { + return &TeamSecret{ + ID: s.ID, + Name: s.Name, + Images: s.Images, + Events: s.Events, + } +} + +// Validate validates the required fields and formats. +func (s *TeamSecret) Validate() error { + return nil +} From 889b88d38f68f96de7d30a4203830a67cb30cee0 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Sun, 31 Jul 2016 22:40:21 +0200 Subject: [PATCH 07/10] Integrated store layer for org secrets --- store/datastore/repo_secret.go | 53 ++++++++++++++++ store/datastore/repo_secret_test.go | 94 +++++++++++++++++++++++++++++ store/datastore/secret.go | 66 +++++++------------- store/datastore/secret_test.go | 70 ++++----------------- store/datastore/team_secret.go | 53 ++++++++++++++++ store/datastore/team_secret_test.go | 94 +++++++++++++++++++++++++++++ store/store.go | 51 +++++++++++++--- 7 files changed, 371 insertions(+), 110 deletions(-) create mode 100644 store/datastore/repo_secret.go create mode 100644 store/datastore/repo_secret_test.go create mode 100644 store/datastore/team_secret.go create mode 100644 store/datastore/team_secret_test.go diff --git a/store/datastore/repo_secret.go b/store/datastore/repo_secret.go new file mode 100644 index 000000000..6252c0bc8 --- /dev/null +++ b/store/datastore/repo_secret.go @@ -0,0 +1,53 @@ +package datastore + +import ( + "github.com/drone/drone/model" + "github.com/russross/meddler" +) + +func (db *datastore) GetSecretList(repo *model.Repo) ([]*model.RepoSecret, error) { + var secrets = []*model.RepoSecret{} + var err = meddler.QueryAll(db, &secrets, rebind(secretListQuery), repo.ID) + return secrets, err +} + +func (db *datastore) GetSecret(repo *model.Repo, name string) (*model.RepoSecret, error) { + var secret = new(model.RepoSecret) + var err = meddler.QueryRow(db, secret, rebind(secretNameQuery), repo.ID, name) + return secret, err +} + +func (db *datastore) SetSecret(sec *model.RepoSecret) error { + var got = new(model.RepoSecret) + var err = meddler.QueryRow(db, got, rebind(secretNameQuery), sec.RepoID, sec.Name) + if err == nil && got.ID != 0 { + sec.ID = got.ID // update existing id + } + return meddler.Save(db, secretTable, sec) +} + +func (db *datastore) DeleteSecret(sec *model.RepoSecret) error { + _, err := db.Exec(rebind(secretDeleteStmt), sec.ID) + return err +} + +const secretTable = "secrets" + +const secretListQuery = ` +SELECT * +FROM secrets +WHERE secret_repo_id = ? +` + +const secretNameQuery = ` +SELECT * +FROM secrets +WHERE secret_repo_id = ? + AND secret_name = ? +LIMIT 1; +` + +const secretDeleteStmt = ` +DELETE FROM secrets +WHERE secret_id = ? +` diff --git a/store/datastore/repo_secret_test.go b/store/datastore/repo_secret_test.go new file mode 100644 index 000000000..945ed305f --- /dev/null +++ b/store/datastore/repo_secret_test.go @@ -0,0 +1,94 @@ +package datastore + +import ( + "testing" + + "github.com/drone/drone/model" + "github.com/franela/goblin" +) + +func TestRepoSecrets(t *testing.T) { + db := openTest() + defer db.Close() + + s := From(db) + g := goblin.Goblin(t) + g.Describe("RepoSecrets", func() { + + // before each test be sure to purge the package + // table data from the database. + g.BeforeEach(func() { + db.Exec(rebind("DELETE FROM secrets")) + }) + + g.It("Should set and get a secret", func() { + secret := &model.RepoSecret{ + RepoID: 1, + Name: "foo", + Value: "bar", + Images: []string{"docker", "gcr"}, + Events: []string{"push", "tag"}, + } + err := s.SetSecret(secret) + g.Assert(err == nil).IsTrue() + g.Assert(secret.ID != 0).IsTrue() + + got, err := s.GetSecret(&model.Repo{ID: 1}, secret.Name) + g.Assert(err == nil).IsTrue() + g.Assert(got.Name).Equal(secret.Name) + g.Assert(got.Value).Equal(secret.Value) + g.Assert(got.Images).Equal(secret.Images) + g.Assert(got.Events).Equal(secret.Events) + }) + + g.It("Should update a secret", func() { + secret := &model.RepoSecret{ + RepoID: 1, + Name: "foo", + Value: "bar", + } + s.SetSecret(secret) + secret.Value = "baz" + s.SetSecret(secret) + + got, err := s.GetSecret(&model.Repo{ID: 1}, secret.Name) + g.Assert(err == nil).IsTrue() + g.Assert(got.Name).Equal(secret.Name) + g.Assert(got.Value).Equal(secret.Value) + }) + + g.It("Should list secrets", func() { + s.SetSecret(&model.RepoSecret{ + RepoID: 1, + Name: "foo", + Value: "bar", + }) + s.SetSecret(&model.RepoSecret{ + RepoID: 1, + Name: "bar", + Value: "baz", + }) + secrets, err := s.GetSecretList(&model.Repo{ID: 1}) + g.Assert(err == nil).IsTrue() + g.Assert(len(secrets)).Equal(2) + }) + + g.It("Should delete a secret", func() { + secret := &model.RepoSecret{ + RepoID: 1, + Name: "foo", + Value: "bar", + } + s.SetSecret(secret) + + _, err := s.GetSecret(&model.Repo{ID: 1}, secret.Name) + g.Assert(err == nil).IsTrue() + + err = s.DeleteSecret(secret) + g.Assert(err == nil).IsTrue() + + _, err = s.GetSecret(&model.Repo{ID: 1}, secret.Name) + g.Assert(err != nil).IsTrue("expect a no rows in result set error") + }) + }) +} diff --git a/store/datastore/secret.go b/store/datastore/secret.go index d25079a3d..3f3399c6e 100644 --- a/store/datastore/secret.go +++ b/store/datastore/secret.go @@ -2,52 +2,32 @@ package datastore import ( "github.com/drone/drone/model" - "github.com/russross/meddler" ) -func (db *datastore) GetSecretList(repo *model.Repo) ([]*model.Secret, error) { - var secrets = []*model.Secret{} - var err = meddler.QueryAll(db, &secrets, rebind(secretListQuery), repo.ID) - return secrets, err -} +func (db *datastore) GetMergedSecretList(repo *model.Repo) ([]*model.Secret, error) { + var ( + secrets []*model.Secret + ) -func (db *datastore) GetSecret(repo *model.Repo, name string) (*model.Secret, error) { - var secret = new(model.Secret) - var err = meddler.QueryRow(db, secret, rebind(secretNameQuery), repo.ID, name) - return secret, err -} + repoSecs, err := db.GetSecretList(repo) -func (db *datastore) SetSecret(sec *model.Secret) error { - var got = new(model.Secret) - var err = meddler.QueryRow(db, got, rebind(secretNameQuery), sec.RepoID, sec.Name) - if err == nil && got.ID != 0 { - sec.ID = got.ID // update existing id + if err != nil { + return nil, err } - return meddler.Save(db, secretTable, sec) + + for _, secret := range repoSecs { + secrets = append(secrets, secret.Secret()) + } + + teamSecs, err := db.GetTeamSecretList(repo.Owner) + + if err != nil { + return nil, err + } + + for _, secret := range teamSecs { + secrets = append(secrets, secret.Secret()) + } + + return secrets, nil } - -func (db *datastore) DeleteSecret(sec *model.Secret) error { - _, err := db.Exec(rebind(secretDeleteStmt), sec.ID) - return err -} - -const secretTable = "secrets" - -const secretListQuery = ` -SELECT * -FROM secrets -WHERE secret_repo_id = ? -` - -const secretNameQuery = ` -SELECT * -FROM secrets -WHERE secret_repo_id = ? - AND secret_name = ? -LIMIT 1; -` - -const secretDeleteStmt = ` -DELETE FROM secrets -WHERE secret_id = ? -` diff --git a/store/datastore/secret_test.go b/store/datastore/secret_test.go index 5de32f71e..c955ac0df 100644 --- a/store/datastore/secret_test.go +++ b/store/datastore/secret_test.go @@ -19,76 +19,28 @@ func TestSecrets(t *testing.T) { // table data from the database. g.BeforeEach(func() { db.Exec(rebind("DELETE FROM secrets")) + db.Exec(rebind("DELETE FROM team_secrets")) }) - g.It("Should set and get a secret", func() { - secret := &model.Secret{ - RepoID: 1, - Name: "foo", - Value: "bar", - Images: []string{"docker", "gcr"}, - Events: []string{"push", "tag"}, + g.It("Should list all secrets", func() { + teamSec := &model.TeamSecret{ + Key: "octocat", + Name: "foo", + Value: "team", } - err := s.SetSecret(secret) - g.Assert(err == nil).IsTrue() - g.Assert(secret.ID != 0).IsTrue() - got, err := s.GetSecret(&model.Repo{ID: 1}, secret.Name) - g.Assert(err == nil).IsTrue() - g.Assert(got.Name).Equal(secret.Name) - g.Assert(got.Value).Equal(secret.Value) - g.Assert(got.Images).Equal(secret.Images) - g.Assert(got.Events).Equal(secret.Events) - }) - - g.It("Should update a secret", func() { - secret := &model.Secret{ + repoSec := &model.RepoSecret{ RepoID: 1, Name: "foo", - Value: "bar", + Value: "repo", } - s.SetSecret(secret) - secret.Value = "baz" - s.SetSecret(secret) - got, err := s.GetSecret(&model.Repo{ID: 1}, secret.Name) - g.Assert(err == nil).IsTrue() - g.Assert(got.Name).Equal(secret.Name) - g.Assert(got.Value).Equal(secret.Value) - }) + s.SetSecret(repoSec) + s.SetTeamSecret(teamSec) - g.It("Should list secrets", func() { - s.SetSecret(&model.Secret{ - RepoID: 1, - Name: "foo", - Value: "bar", - }) - s.SetSecret(&model.Secret{ - RepoID: 1, - Name: "bar", - Value: "baz", - }) - secrets, err := s.GetSecretList(&model.Repo{ID: 1}) + secrets, err := s.GetMergedSecretList(&model.Repo{ID: 1, Owner: "octocat"}) g.Assert(err == nil).IsTrue() g.Assert(len(secrets)).Equal(2) }) - - g.It("Should delete a secret", func() { - secret := &model.Secret{ - RepoID: 1, - Name: "foo", - Value: "bar", - } - s.SetSecret(secret) - - _, err := s.GetSecret(&model.Repo{ID: 1}, secret.Name) - g.Assert(err == nil).IsTrue() - - err = s.DeleteSecret(secret) - g.Assert(err == nil).IsTrue() - - _, err = s.GetSecret(&model.Repo{ID: 1}, secret.Name) - g.Assert(err != nil).IsTrue("expect a no rows in result set error") - }) }) } diff --git a/store/datastore/team_secret.go b/store/datastore/team_secret.go new file mode 100644 index 000000000..edf86b8ed --- /dev/null +++ b/store/datastore/team_secret.go @@ -0,0 +1,53 @@ +package datastore + +import ( + "github.com/drone/drone/model" + "github.com/russross/meddler" +) + +func (db *datastore) GetTeamSecretList(team string) ([]*model.TeamSecret, error) { + var secrets = []*model.TeamSecret{} + var err = meddler.QueryAll(db, &secrets, rebind(teamSecretListQuery), team) + return secrets, err +} + +func (db *datastore) GetTeamSecret(team, name string) (*model.TeamSecret, error) { + var secret = new(model.TeamSecret) + var err = meddler.QueryRow(db, secret, rebind(teamSecretNameQuery), team, name) + return secret, err +} + +func (db *datastore) SetTeamSecret(sec *model.TeamSecret) error { + var got = new(model.TeamSecret) + var err = meddler.QueryRow(db, got, rebind(teamSecretNameQuery), sec.Key, sec.Name) + if err == nil && got.ID != 0 { + sec.ID = got.ID // update existing id + } + return meddler.Save(db, teamSecretTable, sec) +} + +func (db *datastore) DeleteTeamSecret(sec *model.TeamSecret) error { + _, err := db.Exec(rebind(teamSecretDeleteStmt), sec.ID) + return err +} + +const teamSecretTable = "team_secrets" + +const teamSecretListQuery = ` +SELECT * +FROM team_secrets +WHERE team_secret_key = ? +` + +const teamSecretNameQuery = ` +SELECT * +FROM team_secrets +WHERE team_secret_key = ? + AND team_secret_name = ? +LIMIT 1; +` + +const teamSecretDeleteStmt = ` +DELETE FROM team_secrets +WHERE team_secret_id = ? +` diff --git a/store/datastore/team_secret_test.go b/store/datastore/team_secret_test.go new file mode 100644 index 000000000..92beb42ef --- /dev/null +++ b/store/datastore/team_secret_test.go @@ -0,0 +1,94 @@ +package datastore + +import ( + "testing" + + "github.com/drone/drone/model" + "github.com/franela/goblin" +) + +func TestTeamSecrets(t *testing.T) { + db := openTest() + defer db.Close() + + s := From(db) + g := goblin.Goblin(t) + g.Describe("TeamSecrets", func() { + + // before each test be sure to purge the package + // table data from the database. + g.BeforeEach(func() { + db.Exec(rebind("DELETE FROM team_secrets")) + }) + + g.It("Should set and get a secret", func() { + secret := &model.TeamSecret{ + Key: "octocat", + Name: "foo", + Value: "bar", + Images: []string{"docker", "gcr"}, + Events: []string{"push", "tag"}, + } + err := s.SetTeamSecret(secret) + g.Assert(err == nil).IsTrue() + g.Assert(secret.ID != 0).IsTrue() + + got, err := s.GetTeamSecret("octocat", secret.Name) + g.Assert(err == nil).IsTrue() + g.Assert(got.Name).Equal(secret.Name) + g.Assert(got.Value).Equal(secret.Value) + g.Assert(got.Images).Equal(secret.Images) + g.Assert(got.Events).Equal(secret.Events) + }) + + g.It("Should update a secret", func() { + secret := &model.TeamSecret{ + Key: "octocat", + Name: "foo", + Value: "bar", + } + s.SetTeamSecret(secret) + secret.Value = "baz" + s.SetTeamSecret(secret) + + got, err := s.GetTeamSecret("octocat", secret.Name) + g.Assert(err == nil).IsTrue() + g.Assert(got.Name).Equal(secret.Name) + g.Assert(got.Value).Equal(secret.Value) + }) + + g.It("Should list secrets", func() { + s.SetTeamSecret(&model.TeamSecret{ + Key: "octocat", + Name: "foo", + Value: "bar", + }) + s.SetTeamSecret(&model.TeamSecret{ + Key: "octocat", + Name: "bar", + Value: "baz", + }) + secrets, err := s.GetTeamSecretList("octocat") + g.Assert(err == nil).IsTrue() + g.Assert(len(secrets)).Equal(2) + }) + + g.It("Should delete a secret", func() { + secret := &model.TeamSecret{ + Key: "octocat", + Name: "foo", + Value: "bar", + } + s.SetTeamSecret(secret) + + _, err := s.GetTeamSecret("octocat", secret.Name) + g.Assert(err == nil).IsTrue() + + err = s.DeleteTeamSecret(secret) + g.Assert(err == nil).IsTrue() + + _, err = s.GetTeamSecret("octocat", secret.Name) + g.Assert(err != nil).IsTrue("expect a no rows in result set error") + }) + }) +} diff --git a/store/store.go b/store/store.go index 7c7e1de19..624ae58d0 100644 --- a/store/store.go +++ b/store/store.go @@ -59,16 +59,31 @@ type Store interface { DeleteRepo(*model.Repo) error // GetSecretList gets a list of repository secrets - GetSecretList(*model.Repo) ([]*model.Secret, error) + GetSecretList(*model.Repo) ([]*model.RepoSecret, error) // GetSecret gets the named repository secret. - GetSecret(*model.Repo, string) (*model.Secret, error) + GetSecret(*model.Repo, string) (*model.RepoSecret, error) // SetSecret sets the named repository secret. - SetSecret(*model.Secret) error + SetSecret(*model.RepoSecret) error // DeleteSecret deletes the named repository secret. - DeleteSecret(*model.Secret) error + DeleteSecret(*model.RepoSecret) error + + // GetTeamSecretList gets a list of team secrets + GetTeamSecretList(string) ([]*model.TeamSecret, error) + + // GetTeamSecret gets the named team secret. + GetTeamSecret(string, string) (*model.TeamSecret, error) + + // SetTeamSecret sets the named team secret. + SetTeamSecret(*model.TeamSecret) error + + // DeleteTeamSecret deletes the named team secret. + DeleteTeamSecret(*model.TeamSecret) error + + // GetMergedSecretList gets a list of repo and team secrets + GetMergedSecretList(*model.Repo) ([]*model.Secret, error) // GetBuild gets a build by unique ID. GetBuild(int64) (*model.Build, error) @@ -202,22 +217,42 @@ func DeleteRepo(c context.Context, repo *model.Repo) error { return FromContext(c).DeleteRepo(repo) } -func GetSecretList(c context.Context, r *model.Repo) ([]*model.Secret, error) { +func GetSecretList(c context.Context, r *model.Repo) ([]*model.RepoSecret, error) { return FromContext(c).GetSecretList(r) } -func GetSecret(c context.Context, r *model.Repo, name string) (*model.Secret, error) { +func GetSecret(c context.Context, r *model.Repo, name string) (*model.RepoSecret, error) { return FromContext(c).GetSecret(r, name) } -func SetSecret(c context.Context, s *model.Secret) error { +func SetSecret(c context.Context, s *model.RepoSecret) error { return FromContext(c).SetSecret(s) } -func DeleteSecret(c context.Context, s *model.Secret) error { +func DeleteSecret(c context.Context, s *model.RepoSecret) error { return FromContext(c).DeleteSecret(s) } +func GetTeamSecretList(c context.Context, team string) ([]*model.TeamSecret, error) { + return FromContext(c).GetTeamSecretList(team) +} + +func GetTeamSecret(c context.Context, team, name string) (*model.TeamSecret, error) { + return FromContext(c).GetTeamSecret(team, name) +} + +func SetTeamSecret(c context.Context, s *model.TeamSecret) error { + return FromContext(c).SetTeamSecret(s) +} + +func DeleteTeamSecret(c context.Context, s *model.TeamSecret) error { + return FromContext(c).DeleteTeamSecret(s) +} + +func GetMergedSecretList(c context.Context, r *model.Repo) ([]*model.Secret, error) { + return FromContext(c).GetMergedSecretList(r) +} + func GetBuild(c context.Context, id int64) (*model.Build, error) { return FromContext(c).GetBuild(id) } From 298dcd5a50947cb598ac440d7b69b5ceffd0ec99 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Sun, 31 Jul 2016 22:58:29 +0200 Subject: [PATCH 08/10] Integrated real API implementation for org secrets --- server/build.go | 2 +- server/hook.go | 2 +- server/{secret.go => repo_secret.go} | 23 +--------- server/team_secret.go | 67 ++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 23 deletions(-) rename server/{secret.go => repo_secret.go} (74%) create mode 100644 server/team_secret.go diff --git a/server/build.go b/server/build.go index d65cb1ae3..e2cbb3c5e 100644 --- a/server/build.go +++ b/server/build.go @@ -291,7 +291,7 @@ func PostBuild(c *gin.Context) { // get the previous build so that we can send // on status change notifications last, _ := store.GetBuildLastBefore(c, repo, build.Branch, build.ID) - secs, err := store.GetSecretList(c, repo) + secs, err := store.GetMergedSecretList(c, repo) if err != nil { log.Errorf("Error getting secrets for %s#%d. %s", repo.FullName, build.Number, err) } diff --git a/server/hook.go b/server/hook.go index 19e2d912d..1c93ed867 100644 --- a/server/hook.go +++ b/server/hook.go @@ -206,7 +206,7 @@ func PostHook(c *gin.Context) { // get the previous build so that we can send // on status change notifications last, _ := store.GetBuildLastBefore(c, repo, build.Branch, build.ID) - secs, err := store.GetSecretList(c, repo) + secs, err := store.GetMergedSecretList(c, repo) if err != nil { log.Errorf("Error getting secrets for %s#%d. %s", repo.FullName, build.Number, err) } diff --git a/server/secret.go b/server/repo_secret.go similarity index 74% rename from server/secret.go rename to server/repo_secret.go index 39e5bd352..336adf00b 100644 --- a/server/secret.go +++ b/server/repo_secret.go @@ -19,7 +19,7 @@ func GetSecrets(c *gin.Context) { return } - var list []*model.Secret + var list []*model.RepoSecret for _, s := range secrets { list = append(list, s.Clone()) @@ -28,19 +28,10 @@ func GetSecrets(c *gin.Context) { c.JSON(http.StatusOK, list) } -func GetTeamSecrets(c *gin.Context) { - var ( - list []*model.Secret - ) - - // TODO(must): Integrate a real implementation - c.JSON(http.StatusOK, list) -} - func PostSecret(c *gin.Context) { repo := session.Repo(c) - in := &model.Secret{} + in := &model.RepoSecret{} err := c.Bind(in) if err != nil { c.String(http.StatusBadRequest, "Invalid JSON input. %s", err.Error()) @@ -58,11 +49,6 @@ func PostSecret(c *gin.Context) { c.String(http.StatusOK, "") } -func PostTeamSecret(c *gin.Context) { - c.String(http.StatusOK, "") - // TODO(must): Integrate a real implementation -} - func DeleteSecret(c *gin.Context) { repo := session.Repo(c) name := c.Param("secret") @@ -80,8 +66,3 @@ func DeleteSecret(c *gin.Context) { c.String(http.StatusOK, "") } - -func DeleteTeamSecret(c *gin.Context) { - c.String(http.StatusOK, "") - // TODO(must): Integrate a real implementation -} diff --git a/server/team_secret.go b/server/team_secret.go new file mode 100644 index 000000000..ec508b9a9 --- /dev/null +++ b/server/team_secret.go @@ -0,0 +1,67 @@ +package server + +import ( + "net/http" + + "github.com/drone/drone/model" + "github.com/drone/drone/store" + + "github.com/gin-gonic/gin" +) + +func GetTeamSecrets(c *gin.Context) { + team := c.Param("team") + secrets, err := store.GetTeamSecretList(c, team) + + if err != nil { + c.AbortWithStatus(http.StatusInternalServerError) + return + } + + var list []*model.TeamSecret + + for _, s := range secrets { + list = append(list, s.Clone()) + } + + c.JSON(http.StatusOK, list) +} + +func PostTeamSecret(c *gin.Context) { + team := c.Param("team") + + in := &model.TeamSecret{} + err := c.Bind(in) + if err != nil { + c.String(http.StatusBadRequest, "Invalid JSON input. %s", err.Error()) + return + } + in.ID = 0 + in.Key = team + + err = store.SetTeamSecret(c, in) + if err != nil { + c.String(http.StatusInternalServerError, "Unable to persist team secret. %s", err.Error()) + return + } + + c.String(http.StatusOK, "") +} + +func DeleteTeamSecret(c *gin.Context) { + team := c.Param("team") + name := c.Param("secret") + + secret, err := store.GetTeamSecret(c, team, name) + if err != nil { + c.String(http.StatusNotFound, "Cannot find secret %s.", name) + return + } + err = store.DeleteTeamSecret(c, secret) + if err != nil { + c.String(http.StatusInternalServerError, "Unable to delete team secret. %s", err.Error()) + return + } + + c.String(http.StatusOK, "") +} From 4d431954791347d086a2c816633e5e48506ff7aa Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Mon, 1 Aug 2016 23:01:19 +0200 Subject: [PATCH 09/10] Moved merged secret list into store --- store/datastore/secret.go | 33 ------------------------ store/datastore/secret_test.go | 46 ---------------------------------- store/store.go | 29 ++++++++++++++++++--- 3 files changed, 25 insertions(+), 83 deletions(-) delete mode 100644 store/datastore/secret.go delete mode 100644 store/datastore/secret_test.go diff --git a/store/datastore/secret.go b/store/datastore/secret.go deleted file mode 100644 index 3f3399c6e..000000000 --- a/store/datastore/secret.go +++ /dev/null @@ -1,33 +0,0 @@ -package datastore - -import ( - "github.com/drone/drone/model" -) - -func (db *datastore) GetMergedSecretList(repo *model.Repo) ([]*model.Secret, error) { - var ( - secrets []*model.Secret - ) - - repoSecs, err := db.GetSecretList(repo) - - if err != nil { - return nil, err - } - - for _, secret := range repoSecs { - secrets = append(secrets, secret.Secret()) - } - - teamSecs, err := db.GetTeamSecretList(repo.Owner) - - if err != nil { - return nil, err - } - - for _, secret := range teamSecs { - secrets = append(secrets, secret.Secret()) - } - - return secrets, nil -} diff --git a/store/datastore/secret_test.go b/store/datastore/secret_test.go deleted file mode 100644 index c955ac0df..000000000 --- a/store/datastore/secret_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package datastore - -import ( - "testing" - - "github.com/drone/drone/model" - "github.com/franela/goblin" -) - -func TestSecrets(t *testing.T) { - db := openTest() - defer db.Close() - - s := From(db) - g := goblin.Goblin(t) - g.Describe("Secrets", func() { - - // before each test be sure to purge the package - // table data from the database. - g.BeforeEach(func() { - db.Exec(rebind("DELETE FROM secrets")) - db.Exec(rebind("DELETE FROM team_secrets")) - }) - - g.It("Should list all secrets", func() { - teamSec := &model.TeamSecret{ - Key: "octocat", - Name: "foo", - Value: "team", - } - - repoSec := &model.RepoSecret{ - RepoID: 1, - Name: "foo", - Value: "repo", - } - - s.SetSecret(repoSec) - s.SetTeamSecret(teamSec) - - secrets, err := s.GetMergedSecretList(&model.Repo{ID: 1, Owner: "octocat"}) - g.Assert(err == nil).IsTrue() - g.Assert(len(secrets)).Equal(2) - }) - }) -} diff --git a/store/store.go b/store/store.go index 624ae58d0..e531054e5 100644 --- a/store/store.go +++ b/store/store.go @@ -82,9 +82,6 @@ type Store interface { // DeleteTeamSecret deletes the named team secret. DeleteTeamSecret(*model.TeamSecret) error - // GetMergedSecretList gets a list of repo and team secrets - GetMergedSecretList(*model.Repo) ([]*model.Secret, error) - // GetBuild gets a build by unique ID. GetBuild(int64) (*model.Build, error) @@ -250,7 +247,31 @@ func DeleteTeamSecret(c context.Context, s *model.TeamSecret) error { } func GetMergedSecretList(c context.Context, r *model.Repo) ([]*model.Secret, error) { - return FromContext(c).GetMergedSecretList(r) + var ( + secrets []*model.Secret + ) + + repoSecs, err := FromContext(c).GetSecretList(r) + + if err != nil { + return nil, err + } + + for _, secret := range repoSecs { + secrets = append(secrets, secret.Secret()) + } + + teamSecs, err := FromContext(c).GetTeamSecretList(r.Owner) + + if err != nil { + return nil, err + } + + for _, secret := range teamSecs { + secrets = append(secrets, secret.Secret()) + } + + return secrets, nil } func GetBuild(c context.Context, id int64) (*model.Build, error) { From 31cead0eb4fcbd2d251e590cfcbb49f7dbed1206 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Mon, 1 Aug 2016 23:58:13 +0200 Subject: [PATCH 10/10] Copied MustAdmin into MustTeamAdmin for now --- router/middleware/session/team.go | 21 +++++++++++++++++++++ router/router.go | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 router/middleware/session/team.go diff --git a/router/middleware/session/team.go b/router/middleware/session/team.go new file mode 100644 index 000000000..c9fc7ce5f --- /dev/null +++ b/router/middleware/session/team.go @@ -0,0 +1,21 @@ +package session + +import ( + "github.com/gin-gonic/gin" +) + +func MustTeamAdmin() gin.HandlerFunc { + return func(c *gin.Context) { + user := User(c) + switch { + case user == nil: + c.String(401, "User not authorized") + c.Abort() + case user.Admin == false: + c.String(413, "User not authorized") + c.Abort() + default: + c.Next() + } + } +} diff --git a/router/router.go b/router/router.go index 5d37b53a1..912ae2736 100644 --- a/router/router.go +++ b/router/router.go @@ -64,7 +64,7 @@ func Load(middleware ...gin.HandlerFunc) http.Handler { teams := e.Group("/api/teams") { - // TODO: Restrict access + user.Use(session.MustTeamAdmin()) team := teams.Group("/:team") {