You've already forked woodpecker
							
							
				mirror of
				https://github.com/woodpecker-ci/woodpecker.git
				synced 2025-10-30 23:27:39 +02:00 
			
		
		
		
	wip enable pluggable secret and registry backends
This commit is contained in:
		| @@ -26,9 +26,6 @@ type Client interface { | ||||
| 	// UserDel deletes a user account. | ||||
| 	UserDel(string) error | ||||
|  | ||||
| 	// // UserFeed returns the user's activity feed. | ||||
| 	// UserFeed() ([]*Activity, error) | ||||
|  | ||||
| 	// Repo returns a repository by name. | ||||
| 	Repo(string, string) (*model.Repo, error) | ||||
|  | ||||
| @@ -48,36 +45,6 @@ type Client interface { | ||||
| 	// RepoDel deletes a repository. | ||||
| 	RepoDel(string, string) error | ||||
|  | ||||
| 	// Sign returns a cryptographic signature for the input string. | ||||
| 	Sign(string, string, []byte) ([]byte, error) | ||||
|  | ||||
| 	// SecretList returns a list of all repository secrets. | ||||
| 	SecretList(string, string) ([]*model.Secret, error) | ||||
|  | ||||
| 	// SecretPost create or updates a repository secret. | ||||
| 	SecretPost(string, string, *model.Secret) error | ||||
|  | ||||
| 	// 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 | ||||
|  | ||||
| 	// GlobalSecretList returns a list of global secrets. | ||||
| 	GlobalSecretList() ([]*model.Secret, error) | ||||
|  | ||||
| 	// GlobalSecretPost create or updates a global secret. | ||||
| 	GlobalSecretPost(secret *model.Secret) error | ||||
|  | ||||
| 	// GlobalSecretDel deletes a named global secret. | ||||
| 	GlobalSecretDel(secret string) error | ||||
|  | ||||
| 	// Build returns a repository build by number. | ||||
| 	Build(string, string, int) (*model.Build, error) | ||||
|  | ||||
| @@ -129,4 +96,19 @@ type Client interface { | ||||
|  | ||||
| 	// RegistryDelete deletes a registry. | ||||
| 	RegistryDelete(owner, name, hostname string) error | ||||
|  | ||||
| 	// Secret returns a secret by name. | ||||
| 	Secret(owner, name, secret string) (*model.Secret, error) | ||||
|  | ||||
| 	// SecretList returns a list of all repository secrets. | ||||
| 	SecretList(owner, name string) ([]*model.Secret, error) | ||||
|  | ||||
| 	// SecretCreate creates a registry. | ||||
| 	SecretCreate(owner, name string, secret *model.Secret) (*model.Secret, error) | ||||
|  | ||||
| 	// SecretUpdate updates a registry. | ||||
| 	SecretUpdate(owner, name string, secret *model.Secret) (*model.Secret, error) | ||||
|  | ||||
| 	// SecretDelete deletes a secret. | ||||
| 	SecretDelete(owner, name, secret string) error | ||||
| } | ||||
|   | ||||
| @@ -31,25 +31,16 @@ const ( | ||||
| 	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" | ||||
| 	pathApprove        = "%s/api/repos/%s/%s/builds/%d/approve" | ||||
| 	pathDecline        = "%s/api/repos/%s/%s/builds/%d/decline" | ||||
| 	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" | ||||
| 	pathRepoRegistries = "%s/api/repos/%s/%s/registry" | ||||
| 	pathRepoRegistry   = "%s/api/repos/%s/%s/registry/%s" | ||||
| 	pathTeamSecrets    = "%s/api/teams/%s/secrets" | ||||
| 	pathTeamSecret     = "%s/api/teams/%s/secrets/%s" | ||||
| 	pathGlobalSecrets  = "%s/api/global/secrets" | ||||
| 	pathGlobalSecret   = "%s/api/global/secrets/%s" | ||||
| 	pathNodes          = "%s/api/nodes" | ||||
| 	pathNode           = "%s/api/nodes/%d" | ||||
| 	pathUsers          = "%s/api/users" | ||||
| 	pathUser           = "%s/api/users/%s" | ||||
| 	pathBuildQueue     = "%s/api/builds" | ||||
| @@ -295,77 +286,6 @@ func (c *client) Deploy(owner, name string, num int, env string, params map[stri | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // 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(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(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(pathRepoSecret, c.base, owner, name, secret) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
|  | ||||
| // TeamSecretList returns a list of organizational 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 organizational 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 orgainization secret. | ||||
| func (c *client) TeamSecretDel(team, secret string) error { | ||||
| 	uri := fmt.Sprintf(pathTeamSecret, c.base, team, secret) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
|  | ||||
| // GlobalSecretList returns a list of global secrets. | ||||
| func (c *client) GlobalSecretList() ([]*model.Secret, error) { | ||||
| 	var out []*model.Secret | ||||
| 	uri := fmt.Sprintf(pathGlobalSecrets, c.base) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // GlobalSecretPost create or updates a global secret. | ||||
| func (c *client) GlobalSecretPost(secret *model.Secret) error { | ||||
| 	uri := fmt.Sprintf(pathGlobalSecrets, c.base) | ||||
| 	return c.post(uri, secret, nil) | ||||
| } | ||||
|  | ||||
| // GlobalSecretDel deletes a named global secret. | ||||
| func (c *client) GlobalSecretDel(secret string) error { | ||||
| 	uri := fmt.Sprintf(pathGlobalSecret, c.base, secret) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
|  | ||||
| // Sign returns a cryptographic signature for the input string. | ||||
| func (c *client) Sign(owner, name string, in []byte) ([]byte, error) { | ||||
| 	uri := fmt.Sprintf(pathSign, c.base, owner, name) | ||||
| 	rc, err := stream(c.client, uri, "POST", in, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer rc.Close() | ||||
| 	return ioutil.ReadAll(rc) | ||||
| } | ||||
|  | ||||
| // Registry returns a registry by hostname. | ||||
| func (c *client) Registry(owner, name, hostname string) (*model.Registry, error) { | ||||
| 	out := new(model.Registry) | ||||
| @@ -404,6 +324,44 @@ func (c *client) RegistryDelete(owner, name, hostname string) error { | ||||
| 	return c.delete(uri) | ||||
| } | ||||
|  | ||||
| // Secret returns a secret by name. | ||||
| func (c *client) Secret(owner, name, secret string) (*model.Secret, error) { | ||||
| 	out := new(model.Secret) | ||||
| 	uri := fmt.Sprintf(pathRepoSecret, c.base, owner, name, secret) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // SecretList returns a list of all repository secrets. | ||||
| func (c *client) SecretList(owner string, name string) ([]*model.Secret, error) { | ||||
| 	var out []*model.Secret | ||||
| 	uri := fmt.Sprintf(pathRepoSecrets, c.base, owner, name) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // SecretCreate creates a secret. | ||||
| func (c *client) SecretCreate(owner, name string, in *model.Secret) (*model.Secret, error) { | ||||
| 	out := new(model.Secret) | ||||
| 	uri := fmt.Sprintf(pathRepoSecrets, c.base, owner, name) | ||||
| 	err := c.post(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // SecretUpdate updates a secret. | ||||
| func (c *client) SecretUpdate(owner, name string, in *model.Secret) (*model.Secret, error) { | ||||
| 	out := new(model.Secret) | ||||
| 	uri := fmt.Sprintf(pathRepoSecret, c.base, owner, name, in.Name) | ||||
| 	err := c.patch(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // SecretDelete deletes a secret. | ||||
| func (c *client) SecretDelete(owner, name, secret string) error { | ||||
| 	uri := fmt.Sprintf(pathRepoSecret, c.base, owner, name, secret) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
|  | ||||
| // | ||||
| // http request helper functions | ||||
| // | ||||
|   | ||||
| @@ -1,11 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import "github.com/urfave/cli" | ||||
|  | ||||
| var globalCmd = cli.Command{ | ||||
| 	Name:  "global", | ||||
| 	Usage: "manage global state", | ||||
| 	Subcommands: []cli.Command{ | ||||
| 		globalSecretCmd, | ||||
| 	}, | ||||
| } | ||||
| @@ -1,13 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import "github.com/urfave/cli" | ||||
|  | ||||
| var globalSecretCmd = cli.Command{ | ||||
| 	Name:  "secret", | ||||
| 	Usage: "manage secrets", | ||||
| 	Subcommands: []cli.Command{ | ||||
| 		globalSecretAddCmd, | ||||
| 		globalSecretRemoveCmd, | ||||
| 		globalSecretListCmd, | ||||
| 	}, | ||||
| } | ||||
| @@ -1,33 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import "github.com/urfave/cli" | ||||
|  | ||||
| var globalSecretAddCmd = cli.Command{ | ||||
| 	Name:      "add", | ||||
| 	Usage:     "adds a secret", | ||||
| 	ArgsUsage: "[key] [value]", | ||||
| 	Action:    globalSecretAdd, | ||||
| 	Flags:     secretAddFlags(), | ||||
| } | ||||
|  | ||||
| func globalSecretAdd(c *cli.Context) error { | ||||
| 	if len(c.Args()) != 2 { | ||||
| 		cli.ShowSubcommandHelp(c) | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	name := c.Args().First() | ||||
| 	value := c.Args().Get(1) | ||||
|  | ||||
| 	secret, err := secretParseCmd(name, value, c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	client, err := newClient(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return client.GlobalSecretPost(secret) | ||||
| } | ||||
| @@ -1 +0,0 @@ | ||||
| package main | ||||
| @@ -1,25 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import "github.com/urfave/cli" | ||||
|  | ||||
| var globalSecretListCmd = cli.Command{ | ||||
| 	Name:   "ls", | ||||
| 	Usage:  "list all secrets", | ||||
| 	Action: globalSecretList, | ||||
| 	Flags:  secretListFlags(), | ||||
| } | ||||
|  | ||||
| func globalSecretList(c *cli.Context) error { | ||||
| 	client, err := newClient(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	secrets, err := client.GlobalSecretList() | ||||
|  | ||||
| 	if err != nil || len(secrets) == 0 { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return secretDisplayList(secrets, c) | ||||
| } | ||||
| @@ -1,25 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import "github.com/urfave/cli" | ||||
|  | ||||
| var globalSecretRemoveCmd = cli.Command{ | ||||
| 	Name:   "rm", | ||||
| 	Usage:  "remove a secret", | ||||
| 	Action: globalSecretRemove, | ||||
| } | ||||
|  | ||||
| func globalSecretRemove(c *cli.Context) error { | ||||
| 	if len(c.Args()) != 1 { | ||||
| 		cli.ShowSubcommandHelp(c) | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	secret := c.Args().First() | ||||
|  | ||||
| 	client, err := newClient(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return client.GlobalSecretDel(secret) | ||||
| } | ||||
| @@ -40,11 +40,8 @@ func main() { | ||||
| 		registryCmd, | ||||
| 		secretCmd, | ||||
| 		serverCmd, | ||||
| 		signCmd, | ||||
| 		repoCmd, | ||||
| 		userCmd, | ||||
| 		orgCmd, | ||||
| 		globalCmd, | ||||
| 	} | ||||
|  | ||||
| 	if err := app.Run(os.Args); err != nil { | ||||
|   | ||||
							
								
								
									
										11
									
								
								drone/org.go
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								drone/org.go
									
									
									
									
									
								
							| @@ -1,11 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import "github.com/urfave/cli" | ||||
|  | ||||
| var orgCmd = cli.Command{ | ||||
| 	Name:  "org", | ||||
| 	Usage: "manage organizations", | ||||
| 	Subcommands: []cli.Command{ | ||||
| 		orgSecretCmd, | ||||
| 	}, | ||||
| } | ||||
| @@ -1,13 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import "github.com/urfave/cli" | ||||
|  | ||||
| var orgSecretCmd = cli.Command{ | ||||
| 	Name:  "secret", | ||||
| 	Usage: "manage secrets", | ||||
| 	Subcommands: []cli.Command{ | ||||
| 		orgSecretAddCmd, | ||||
| 		orgSecretRemoveCmd, | ||||
| 		orgSecretListCmd, | ||||
| 	}, | ||||
| } | ||||
| @@ -1,34 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import "github.com/urfave/cli" | ||||
|  | ||||
| var orgSecretAddCmd = cli.Command{ | ||||
| 	Name:      "add", | ||||
| 	Usage:     "adds a secret", | ||||
| 	ArgsUsage: "[org] [key] [value]", | ||||
| 	Action:    orgSecretAdd, | ||||
| 	Flags:     secretAddFlags(), | ||||
| } | ||||
|  | ||||
| func orgSecretAdd(c *cli.Context) error { | ||||
| 	if len(c.Args()) != 3 { | ||||
| 		cli.ShowSubcommandHelp(c) | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	team := c.Args().First() | ||||
| 	name := c.Args().Get(1) | ||||
| 	value := c.Args().Get(2) | ||||
|  | ||||
| 	secret, err := secretParseCmd(name, value, c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	client, err := newClient(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return client.TeamSecretPost(team, secret) | ||||
| } | ||||
| @@ -1 +0,0 @@ | ||||
| package main | ||||
| @@ -1,32 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import "github.com/urfave/cli" | ||||
|  | ||||
| var orgSecretListCmd = cli.Command{ | ||||
| 	Name:   "ls", | ||||
| 	Usage:  "list all secrets", | ||||
| 	Action: orgSecretList, | ||||
| 	Flags:  secretListFlags(), | ||||
| } | ||||
|  | ||||
| func orgSecretList(c *cli.Context) error { | ||||
| 	if len(c.Args()) != 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 | ||||
| 	} | ||||
|  | ||||
| 	return secretDisplayList(secrets, c) | ||||
| } | ||||
| @@ -1,34 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"log" | ||||
|  | ||||
| 	"github.com/urfave/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()) != 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) | ||||
| } | ||||
| @@ -23,7 +23,7 @@ var registryInfoCmd = cli.Command{ | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			Name:   "format", | ||||
| 			Usage:  "repository name (e.g. octocat/hello-world)", | ||||
| 			Usage:  "format output", | ||||
| 			Value:  tmplRegistryList, | ||||
| 			Hidden: true, | ||||
| 		}, | ||||
|   | ||||
| @@ -18,7 +18,7 @@ var registryListCmd = cli.Command{ | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			Name:   "format", | ||||
| 			Usage:  "repository name (e.g. octocat/hello-world)", | ||||
| 			Usage:  "format output", | ||||
| 			Value:  tmplRegistryList, | ||||
| 			Hidden: true, | ||||
| 		}, | ||||
| @@ -58,6 +58,5 @@ func registryList(c *cli.Context) error { | ||||
| // template for build list information | ||||
| var tmplRegistryList = "\x1b[33m{{ .Address }} \x1b[0m" + ` | ||||
| Username: {{ .Username }} | ||||
| Password: ******** | ||||
| Email: {{ .Email }} | ||||
| ` | ||||
|   | ||||
							
								
								
									
										131
									
								
								drone/secret.go
									
									
									
									
									
								
							
							
						
						
									
										131
									
								
								drone/secret.go
									
									
									
									
									
								
							| @@ -1,136 +1,15 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"text/template" | ||||
|  | ||||
| 	"github.com/drone/drone/model" | ||||
| 	"github.com/urfave/cli" | ||||
| ) | ||||
| import "github.com/urfave/cli" | ||||
|  | ||||
| var secretCmd = cli.Command{ | ||||
| 	Name:  "secret", | ||||
| 	Usage: "manage secrets", | ||||
| 	Subcommands: []cli.Command{ | ||||
| 		secretAddCmd, | ||||
| 		secretRemoveCmd, | ||||
| 		secretCreateCmd, | ||||
| 		secretDeleteCmd, | ||||
| 		secretUpdateCmd, | ||||
| 		secretInfoCmd, | ||||
| 		secretListCmd, | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func secretAddFlags() []cli.Flag { | ||||
| 	return []cli.Flag{ | ||||
| 		cli.StringSliceFlag{ | ||||
| 			Name:  "event", | ||||
| 			Usage: "inject the secret for these event types", | ||||
| 		}, | ||||
| 		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", | ||||
| 		}, | ||||
| 		cli.BoolFlag{ | ||||
| 			Name:  "skip-verify", | ||||
| 			Usage: "skip verification for the secret", | ||||
| 		}, | ||||
| 		cli.BoolFlag{ | ||||
| 			Name:  "conceal", | ||||
| 			Usage: "conceal secret in build logs", | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func secretListFlags() []cli.Flag { | ||||
| 	return []cli.Flag{ | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "format", | ||||
| 			Usage: "format output", | ||||
| 			Value: tmplSecretList, | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "image", | ||||
| 			Usage: "filter by image", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "event", | ||||
| 			Usage: "filter by event", | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func secretParseCmd(name string, value string, c *cli.Context) (*model.Secret, error) { | ||||
| 	secret := &model.Secret{} | ||||
| 	secret.Name = name | ||||
| 	secret.Value = value | ||||
| 	secret.Images = c.StringSlice("image") | ||||
| 	secret.Events = c.StringSlice("event") | ||||
| 	secret.SkipVerify = c.Bool("skip-verify") | ||||
| 	secret.Conceal = c.Bool("conceal") | ||||
| 	if len(secret.Events) == 0 { | ||||
| 		secret.Events = []string{ | ||||
| 			model.EventPush, | ||||
| 			model.EventTag, | ||||
| 			model.EventDeploy, | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// 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 nil, ferr | ||||
| 		} | ||||
| 		secret.Value = string(out) | ||||
| 	} | ||||
|  | ||||
| 	return secret, nil | ||||
| } | ||||
|  | ||||
| func secretDisplayList(secrets []*model.Secret, c *cli.Context) error { | ||||
| 	tmpl, err := template.New("_").Funcs(secretFuncMap).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 tmplSecretList = "\x1b[33m{{ .Name }} \x1b[0m" + ` | ||||
| Events: {{ list .Events }} | ||||
| {{- if .Images }} | ||||
| Images: {{ list .Images }} | ||||
| {{- else }} | ||||
| Images: <any> | ||||
| {{- end }} | ||||
| ` | ||||
|  | ||||
| var secretFuncMap = template.FuncMap{ | ||||
| 	"list": func(s []string) string { | ||||
| 		return strings.Join(s, ", ") | ||||
| 	}, | ||||
| } | ||||
|   | ||||
| @@ -1,37 +1,66 @@ | ||||
| package main | ||||
|  | ||||
| import "github.com/urfave/cli" | ||||
| import ( | ||||
| 	"github.com/drone/drone/model" | ||||
| 	"github.com/urfave/cli" | ||||
| ) | ||||
|  | ||||
| var secretAddCmd = cli.Command{ | ||||
| 	Name:      "add", | ||||
| 	Usage:     "adds a secret", | ||||
| 	ArgsUsage: "[repo] [key] [value]", | ||||
| 	Action:    secretAdd, | ||||
| 	Flags:     secretAddFlags(), | ||||
| var secretCreateCmd = cli.Command{ | ||||
| 	Name:   "add", | ||||
| 	Usage:  "adds a secret", | ||||
| 	Action: secretCreate, | ||||
| 	Flags: []cli.Flag{ | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "repository", | ||||
| 			Usage: "repository name (e.g. octocat/hello-world)", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "name", | ||||
| 			Usage: "secret name", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "value", | ||||
| 			Usage: "secret value", | ||||
| 		}, | ||||
| 		cli.StringSliceFlag{ | ||||
| 			Name:  "event", | ||||
| 			Usage: "secret limited to these events", | ||||
| 		}, | ||||
| 		cli.StringSliceFlag{ | ||||
| 			Name:  "image", | ||||
| 			Usage: "secret limited to these images", | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func secretAdd(c *cli.Context) error { | ||||
| 	repo := c.Args().First() | ||||
| 	owner, name, err := parseRepo(repo) | ||||
| func secretCreate(c *cli.Context) error { | ||||
| 	reponame := c.String("repository") | ||||
| 	if reponame == "" { | ||||
| 		reponame = c.Args().First() | ||||
| 	} | ||||
| 	owner, name, err := parseRepo(reponame) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	tail := c.Args().Tail() | ||||
| 	if len(tail) != 2 { | ||||
| 		cli.ShowSubcommandHelp(c) | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	secret, err := secretParseCmd(tail[0], tail[1], c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	client, err := newClient(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return client.SecretPost(owner, name, secret) | ||||
| 	secret := &model.Secret{ | ||||
| 		Name:   c.String("name"), | ||||
| 		Value:  c.String("value"), | ||||
| 		Images: c.StringSlice("image"), | ||||
| 		Events: c.StringSlice("events"), | ||||
| 	} | ||||
| 	if len(secret.Events) == 0 { | ||||
| 		secret.Events = defaultSecretEvents | ||||
| 	} | ||||
| 	_, err = client.SecretUpdate(owner, name, secret) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| var defaultSecretEvents = []string{ | ||||
| 	model.EventPush, | ||||
| 	model.EventTag, | ||||
| 	model.EventDeploy, | ||||
| } | ||||
|   | ||||
| @@ -1 +1,58 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"html/template" | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/urfave/cli" | ||||
| ) | ||||
|  | ||||
| var secretInfoCmd = cli.Command{ | ||||
| 	Name:   "info", | ||||
| 	Usage:  "display secret info", | ||||
| 	Action: secretInfo, | ||||
| 	Flags: []cli.Flag{ | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "repository", | ||||
| 			Usage: "repository name (e.g. octocat/hello-world)", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "name", | ||||
| 			Usage: "secret name", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			Name:   "format", | ||||
| 			Usage:  "format output", | ||||
| 			Value:  tmplSecretList, | ||||
| 			Hidden: true, | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func secretInfo(c *cli.Context) error { | ||||
| 	var ( | ||||
| 		secretName = c.String("name") | ||||
| 		repoName   = c.String("repository") | ||||
| 		format     = c.String("format") + "\n" | ||||
| 	) | ||||
| 	if repoName == "" { | ||||
| 		repoName = c.Args().First() | ||||
| 	} | ||||
| 	owner, name, err := parseRepo(repoName) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	client, err := newClient(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	secret, err := client.Secret(owner, name, secretName) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return tmpl.Execute(os.Stdout, secret) | ||||
| } | ||||
|   | ||||
| @@ -1,32 +1,73 @@ | ||||
| package main | ||||
|  | ||||
| import "github.com/urfave/cli" | ||||
| import ( | ||||
| 	"html/template" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/urfave/cli" | ||||
| ) | ||||
|  | ||||
| var secretListCmd = cli.Command{ | ||||
| 	Name:   "ls", | ||||
| 	Usage:  "list all secrets", | ||||
| 	Usage:  "list secrets", | ||||
| 	Action: secretList, | ||||
| 	Flags:  secretListFlags(), | ||||
| 	Flags: []cli.Flag{ | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "repository", | ||||
| 			Usage: "repository name (e.g. octocat/hello-world)", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			Name:   "format", | ||||
| 			Usage:  "format output", | ||||
| 			Value:  tmplSecretList, | ||||
| 			Hidden: true, | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func secretList(c *cli.Context) error { | ||||
| 	owner, name, err := parseRepo(c.Args().First()) | ||||
|  | ||||
| 	var ( | ||||
| 		format   = c.String("format") + "\n" | ||||
| 		reponame = c.String("repository") | ||||
| 	) | ||||
| 	if reponame == "" { | ||||
| 		reponame = c.Args().First() | ||||
| 	} | ||||
| 	owner, name, err := parseRepo(reponame) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	client, err := newClient(c) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	secrets, err := client.SecretList(owner, name) | ||||
|  | ||||
| 	if err != nil || len(secrets) == 0 { | ||||
| 	list, err := client.SecretList(owner, name) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return secretDisplayList(secrets, c) | ||||
| 	tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, registry := range list { | ||||
| 		tmpl.Execute(os.Stdout, registry) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // template for secret list items | ||||
| var tmplSecretList = "\x1b[33m{{ .Name }} \x1b[0m" + ` | ||||
| Events: {{ list .Events }} | ||||
| {{- if .Images }} | ||||
| Images: {{ list .Images }} | ||||
| {{- else }} | ||||
| Images: <any> | ||||
| {{- end }} | ||||
| ` | ||||
|  | ||||
| var secretFuncMap = template.FuncMap{ | ||||
| 	"list": func(s []string) string { | ||||
| 		return strings.Join(s, ", ") | ||||
| 	}, | ||||
| } | ||||
|   | ||||
| @@ -2,24 +2,37 @@ package main | ||||
|  | ||||
| import "github.com/urfave/cli" | ||||
|  | ||||
| var secretRemoveCmd = cli.Command{ | ||||
| var secretDeleteCmd = cli.Command{ | ||||
| 	Name:   "rm", | ||||
| 	Usage:  "remove a secret", | ||||
| 	Action: secretRemove, | ||||
| 	Action: secretDelete, | ||||
| 	Flags: []cli.Flag{ | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "repository", | ||||
| 			Usage: "repository name (e.g. octocat/hello-world)", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "name", | ||||
| 			Usage: "secret name", | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func secretRemove(c *cli.Context) error { | ||||
| 	repo := c.Args().First() | ||||
| 	owner, name, err := parseRepo(repo) | ||||
| func secretDelete(c *cli.Context) error { | ||||
| 	var ( | ||||
| 		secret   = c.String("name") | ||||
| 		reponame = c.String("repository") | ||||
| 	) | ||||
| 	if reponame == "" { | ||||
| 		reponame = c.Args().First() | ||||
| 	} | ||||
| 	owner, name, err := parseRepo(reponame) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	secret := c.Args().Get(1) | ||||
|  | ||||
| 	client, err := newClient(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return client.SecretDel(owner, name, secret) | ||||
| 	return client.SecretDelete(owner, name, secret) | ||||
| } | ||||
|   | ||||
							
								
								
									
										57
									
								
								drone/secret_set.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								drone/secret_set.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"github.com/drone/drone/model" | ||||
| 	"github.com/urfave/cli" | ||||
| ) | ||||
|  | ||||
| var secretUpdateCmd = cli.Command{ | ||||
| 	Name:   "update", | ||||
| 	Usage:  "update a secret", | ||||
| 	Action: secretUpdate, | ||||
| 	Flags: []cli.Flag{ | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "repository", | ||||
| 			Usage: "repository name (e.g. octocat/hello-world)", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "name", | ||||
| 			Usage: "secret name", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "value", | ||||
| 			Usage: "secret value", | ||||
| 		}, | ||||
| 		cli.StringSliceFlag{ | ||||
| 			Name:  "event", | ||||
| 			Usage: "secret limited to these events", | ||||
| 		}, | ||||
| 		cli.StringSliceFlag{ | ||||
| 			Name:  "image", | ||||
| 			Usage: "secret limited to these images", | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func secretUpdate(c *cli.Context) error { | ||||
| 	reponame := c.String("repository") | ||||
| 	if reponame == "" { | ||||
| 		reponame = c.Args().First() | ||||
| 	} | ||||
| 	owner, name, err := parseRepo(reponame) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	client, err := newClient(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	secret := &model.Secret{ | ||||
| 		Name:   c.String("name"), | ||||
| 		Value:  c.String("value"), | ||||
| 		Images: c.StringSlice("image"), | ||||
| 		Events: c.StringSlice("events"), | ||||
| 	} | ||||
| 	_, err = client.SecretUpdate(owner, name, secret) | ||||
| 	return err | ||||
| } | ||||
| @@ -22,10 +22,10 @@ var serverCmd = cli.Command{ | ||||
| 			Name:   "debug", | ||||
| 			Usage:  "start the server in debug mode", | ||||
| 		}, | ||||
| 		cli.BoolFlag{ | ||||
| 			EnvVar: "DRONE_BROKER_DEBUG", | ||||
| 			Name:   "broker-debug", | ||||
| 			Usage:  "start the broker in debug mode", | ||||
| 		cli.StringFlag{ | ||||
| 			EnvVar: "DRONE_SERVER_HOST", | ||||
| 			Name:   "server-host", | ||||
| 			Usage:  "server host", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			EnvVar: "DRONE_SERVER_ADDR", | ||||
| @@ -58,12 +58,6 @@ var serverCmd = cli.Command{ | ||||
| 			Name:   "open", | ||||
| 			Usage:  "open user registration", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			EnvVar: "DRONE_YAML", | ||||
| 			Name:   "yaml", | ||||
| 			Usage:  "build configuraton file name", | ||||
| 			Value:  ".drone.yml", | ||||
| 		}, | ||||
| 		cli.DurationFlag{ | ||||
| 			EnvVar: "DRONE_CACHE_TTL", | ||||
| 			Name:   "cache-ttl", | ||||
| @@ -75,6 +69,21 @@ var serverCmd = cli.Command{ | ||||
| 			Name:   "agent-secret", | ||||
| 			Usage:  "agent secret passcode", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			EnvVar: "DRONE_SECRET_ENDPOINT", | ||||
| 			Name:   "secret-service", | ||||
| 			Usage:  "secret plugin endpoint", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			EnvVar: "DRONE_REGISTRY_ENDPOINT", | ||||
| 			Name:   "registry-service", | ||||
| 			Usage:  "registry plugin endpoint", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			EnvVar: "DRONE_GATEKEEPER_ENDPOINT", | ||||
| 			Name:   "gating-service", | ||||
| 			Usage:  "gated build endpoint", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			EnvVar: "DRONE_DATABASE_DRIVER,DATABASE_DRIVER", | ||||
| 			Name:   "driver", | ||||
|   | ||||
| @@ -1,50 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
|  | ||||
| 	"github.com/urfave/cli" | ||||
| ) | ||||
|  | ||||
| var signCmd = cli.Command{ | ||||
| 	Name:   "sign", | ||||
| 	Usage:  "creates a secure yaml file", | ||||
| 	Action: sign, | ||||
| 	Flags: []cli.Flag{ | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "in", | ||||
| 			Usage: "input file", | ||||
| 			Value: ".drone.yml", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			Name:  "out", | ||||
| 			Usage: "output file signature", | ||||
| 			Value: ".drone.yml.sig", | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func sign(c *cli.Context) error { | ||||
| 	repo := c.Args().First() | ||||
| 	owner, name, err := parseRepo(repo) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	in, err := readInput(c.String("in")) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	client, err := newClient(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	sig, err := client.Sign(owner, name, in) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return ioutil.WriteFile(c.String("out"), sig, 0664) | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| package model | ||||
|  | ||||
| type ( | ||||
| 	// ApprovalStore persists approved committers to storage. | ||||
| 	ApprovalStore interface { | ||||
| 		Approve(*Repo) error | ||||
| 	} | ||||
|  | ||||
| 	// Approval represents an approved committer. | ||||
| 	Approval struct { | ||||
| 		Username  string `json:"username"   meddler:"approval_username"` | ||||
| 		Approved  bool   `json:"approved"   meddler:"approval_approved"` | ||||
| 		Comments  string `json:"comments"   meddler:"approval_comments"` | ||||
| 		CreatedBy string `json:"created_by" meddler:"approval_created_by"` | ||||
| 		CreatedAt int64  `json:"created_at" meddler:"approval_created_at"` | ||||
| 	} | ||||
| ) | ||||
| @@ -1,23 +0,0 @@ | ||||
| package model | ||||
|  | ||||
| // Gated indicates a build is gated and requires approval to proceed. It also | ||||
| // includes the reason the build was gated. | ||||
| type Gated struct { | ||||
| 	Gated  bool   `json:"gated"` | ||||
| 	Reason string `json:"reason"` | ||||
| } | ||||
|  | ||||
| // GateService defines a service for gating builds. | ||||
| type GateService interface { | ||||
| 	Gated(*User, *Repo, *Build) (*Gated, error) | ||||
| } | ||||
|  | ||||
| type gateService struct{} | ||||
|  | ||||
| func (s *gateService) Gated(owner *User, repo *Repo, build *Build) (*Gated, error) { | ||||
| 	g := new(Gated) | ||||
| 	if repo.IsPrivate && build.Event == EventPull && build.Sender != owner.Login { | ||||
| 		g.Gated = true | ||||
| 	} | ||||
| 	return g, nil | ||||
| } | ||||
| @@ -8,6 +8,15 @@ var ( | ||||
| 	errRegistryPasswordInvalid = errors.New("Invalid Registry Password") | ||||
| ) | ||||
|  | ||||
| // RegistryService defines a service for managing registries. | ||||
| type RegistryService interface { | ||||
| 	RegistryFind(*Repo, string) (*Registry, error) | ||||
| 	RegistryList(*Repo) ([]*Registry, error) | ||||
| 	RegistryCreate(*Repo, *Registry) error | ||||
| 	RegistryUpdate(*Repo, *Registry) error | ||||
| 	RegistryDelete(*Repo, string) error | ||||
| } | ||||
|  | ||||
| // RegistryStore persists registry information to storage. | ||||
| type RegistryStore interface { | ||||
| 	RegistryFind(*Repo, string) (*Registry, error) | ||||
|   | ||||
| @@ -25,6 +25,7 @@ type Repo struct { | ||||
| 	IsPrivate   bool   `json:"private,omitempty"        meddler:"repo_private"` | ||||
| 	IsTrusted   bool   `json:"trusted"                  meddler:"repo_trusted"` | ||||
| 	IsStarred   bool   `json:"starred,omitempty"        meddler:"-"` | ||||
| 	IsGated     bool   `json:"gated"                    meddler:"repo_gated"` | ||||
| 	AllowPull   bool   `json:"allow_pr"                 meddler:"repo_allow_pr"` | ||||
| 	AllowPush   bool   `json:"allow_push"               meddler:"repo_allow_push"` | ||||
| 	AllowDeploy bool   `json:"allow_deploys"            meddler:"repo_allow_deploys"` | ||||
|   | ||||
| @@ -1,58 +0,0 @@ | ||||
| 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"` | ||||
|  | ||||
| 	// whether the secret requires verification | ||||
| 	SkipVerify bool `json:"skip_verify" meddler:"secret_skip_verify"` | ||||
|  | ||||
| 	// whether the secret should be concealed in the build log | ||||
| 	Conceal bool `json:"conceal" meddler:"secret_conceal"` | ||||
| } | ||||
|  | ||||
| // 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, | ||||
| 		SkipVerify: s.SkipVerify, | ||||
| 		Conceal:    s.Conceal, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 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, | ||||
| 		SkipVerify: s.SkipVerify, | ||||
| 		Conceal:    s.Conceal, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Validate validates the required fields and formats. | ||||
| func (s *RepoSecret) Validate() error { | ||||
| 	return nil | ||||
| } | ||||
| @@ -1,50 +1,48 @@ | ||||
| package model | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"path/filepath" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	errSecretNameInvalid  = errors.New("Invalid Secret Name") | ||||
| 	errSecretValueInvalid = errors.New("Invalid Secret Value") | ||||
| ) | ||||
|  | ||||
| // SecretService defines a service for managing secrets. | ||||
| type SecretService interface { | ||||
| 	SecretFind(*Repo, string) (*Secret, error) | ||||
| 	SecretList(*Repo) ([]*Secret, error) | ||||
| 	SecretCreate(*Repo, *Secret) error | ||||
| 	SecretUpdate(*Repo, *Secret) error | ||||
| 	SecretDelete(*Repo, string) error | ||||
| } | ||||
|  | ||||
| // SecretStore persists secret information to storage. | ||||
| type SecretStore interface { | ||||
| 	SecretFind(*Repo, string) (*Secret, error) | ||||
| 	SecretList(*Repo) ([]*Secret, error) | ||||
| 	SecretCreate(*Secret) error | ||||
| 	SecretUpdate(*Secret) error | ||||
| 	SecretDelete(*Secret) error | ||||
| } | ||||
|  | ||||
| // Secret represents a secret variable, such as a password or token. | ||||
| // swagger:model registry | ||||
| type Secret struct { | ||||
| 	// the name of the secret which will be used as the environment variable | ||||
| 	// name at runtime. | ||||
| 	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"` | ||||
|  | ||||
| 	// the secret is restricted to this list of images. | ||||
| 	Images []string `json:"image,omitempty"` | ||||
|  | ||||
| 	// the secret is restricted to this list of events. | ||||
| 	Events []string `json:"event,omitempty"` | ||||
|  | ||||
| 	// whether the secret requires verification | ||||
| 	SkipVerify bool `json:"skip_verify"` | ||||
|  | ||||
| 	// whether the secret should be concealed in the build log | ||||
| 	Conceal bool `json:"conceal"` | ||||
| 	ID         int64    `json:"id"              meddler:"secret_id,pk"` | ||||
| 	RepoID     int64    `json:"-"               meddler:"secret_repo_id"` | ||||
| 	Name       string   `json:"name"            meddler:"secret_name"` | ||||
| 	Value      string   `json:"value,omitempty" meddler:"secret_value"` | ||||
| 	Images     []string `json:"image"           meddler:"secret_images,json"` | ||||
| 	Events     []string `json:"event"           meddler:"secret_events,json"` | ||||
| 	SkipVerify bool     `json:"-"               meddler:"secret_skip_verify"` | ||||
| 	Conceal    bool     `json:"-"               meddler:"secret_conceal"` | ||||
| } | ||||
|  | ||||
| // Match returns true if an image and event match the restricted list. | ||||
| func (s *Secret) Match(image, event string) bool { | ||||
| 	return s.MatchImage(image) && s.MatchEvent(event) | ||||
| } | ||||
|  | ||||
| // MatchImage returns true if an image matches the restricted list. | ||||
| func (s *Secret) MatchImage(image string) bool { | ||||
| 	for _, pattern := range s.Images { | ||||
| 		if match, _ := filepath.Match(pattern, image); match { | ||||
| 			return true | ||||
| 		} else if pattern == "*" { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // MatchEvent returns true if an event matches the restricted list. | ||||
| func (s *Secret) MatchEvent(event string) bool { | ||||
| func (s *Secret) Match(event string) bool { | ||||
| 	for _, pattern := range s.Events { | ||||
| 		if match, _ := filepath.Match(pattern, event); match { | ||||
| 			return true | ||||
| @@ -55,5 +53,23 @@ func (s *Secret) MatchEvent(event string) bool { | ||||
|  | ||||
| // Validate validates the required fields and formats. | ||||
| func (s *Secret) Validate() error { | ||||
| 	return nil | ||||
| 	switch { | ||||
| 	case len(s.Name) == 0: | ||||
| 		return errSecretNameInvalid | ||||
| 	case len(s.Value) == 0: | ||||
| 		return errSecretValueInvalid | ||||
| 	default: | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Copy makes a copy of the secret without the value. | ||||
| func (s *Secret) Copy() *Secret { | ||||
| 	return &Secret{ | ||||
| 		ID:     s.ID, | ||||
| 		RepoID: s.RepoID, | ||||
| 		Name:   s.Name, | ||||
| 		Images: s.Images, | ||||
| 		Events: s.Events, | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -11,52 +11,15 @@ func TestSecret(t *testing.T) { | ||||
| 	g := goblin.Goblin(t) | ||||
| 	g.Describe("Secret", func() { | ||||
|  | ||||
| 		g.It("should match image", func() { | ||||
| 			secret := Secret{} | ||||
| 			secret.Images = []string{"golang"} | ||||
| 			g.Assert(secret.MatchImage("golang")).IsTrue() | ||||
| 		}) | ||||
| 		g.It("should match event", func() { | ||||
| 			secret := Secret{} | ||||
| 			secret.Events = []string{"pull_request"} | ||||
| 			g.Assert(secret.MatchEvent("pull_request")).IsTrue() | ||||
| 		}) | ||||
| 		g.It("should match image patterns", func() { | ||||
| 			secret := Secret{} | ||||
| 			secret.Images = []string{"golang:*"} | ||||
| 			g.Assert(secret.MatchImage("golang:1.4.2")).IsTrue() | ||||
| 		}) | ||||
| 		g.It("should match any image", func() { | ||||
| 			secret := Secret{} | ||||
| 			secret.Images = []string{"*"} | ||||
| 			g.Assert(secret.MatchImage("custom/golang")).IsTrue() | ||||
| 		}) | ||||
| 		g.It("should match any event", func() { | ||||
| 			secret := Secret{} | ||||
| 			secret.Events = []string{"*"} | ||||
| 			g.Assert(secret.MatchEvent("pull_request")).IsTrue() | ||||
| 		}) | ||||
| 		g.It("should not match image", func() { | ||||
| 			secret := Secret{} | ||||
| 			secret.Images = []string{"golang"} | ||||
| 			g.Assert(secret.MatchImage("node")).IsFalse() | ||||
| 		}) | ||||
| 		g.It("should not match image substring", func() { | ||||
| 			secret := Secret{} | ||||
| 			secret.Images = []string{"golang"} | ||||
|  | ||||
| 			// image is only authorized for golang, not golang:1.4.2 | ||||
| 			g.Assert(secret.MatchImage("golang:1.4.2")).IsFalse() | ||||
| 		}) | ||||
| 		g.It("should not match empty image", func() { | ||||
| 			secret := Secret{} | ||||
| 			secret.Images = []string{} | ||||
| 			g.Assert(secret.MatchImage("node")).IsFalse() | ||||
| 			g.Assert(secret.Match("pull_request")).IsTrue() | ||||
| 		}) | ||||
| 		g.It("should not match event", func() { | ||||
| 			secret := Secret{} | ||||
| 			secret.Events = []string{"pull_request"} | ||||
| 			g.Assert(secret.MatchEvent("push")).IsFalse() | ||||
| 			g.Assert(secret.Match("push")).IsFalse() | ||||
| 		}) | ||||
| 		g.It("should pass validation") | ||||
| 		g.Describe("should fail validation", func() { | ||||
|   | ||||
							
								
								
									
										28
									
								
								model/sender.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								model/sender.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| package model | ||||
|  | ||||
| type SenderService interface { | ||||
| 	SenderAllowed(*User, *Repo, *Build) (bool, error) | ||||
| 	SenderCreate(*Repo, *Sender) error | ||||
| 	SenderUpdate(*Repo, *Sender) error | ||||
| 	SenderDelete(*Repo, string) error | ||||
| 	SenderList(*Repo) ([]*Sender, error) | ||||
| } | ||||
|  | ||||
| type SenderStore interface { | ||||
| 	SenderFind(*Repo, string) (*Sender, error) | ||||
| 	SenderList(*Repo) ([]*Sender, error) | ||||
| 	SenderCreate(*Sender) error | ||||
| 	SenderUpdate(*Sender) error | ||||
| 	SenderDelete(*Sender) error | ||||
| } | ||||
|  | ||||
| type Sender struct { | ||||
| 	ID     int64    `json:"-"      meddler:"sender_id,pk"` | ||||
| 	RepoID int64    `json:"-"      meddler:"sender_repo_id"` | ||||
| 	Login  string   `json:"login"  meddler:"sender_login"` | ||||
| 	Allow  bool     `json:"allow"  meddler:"sender_allow"` | ||||
| 	Block  bool     `json:"block"  meddler:"sender_block"` | ||||
| 	Branch []string `json:"branch" meddler:"-"` | ||||
| 	Deploy []string `json:"deploy" meddler:"-"` | ||||
| 	Event  []string `json:"event"  meddler:"-"` | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| package model | ||||
|  | ||||
| type System struct { | ||||
| 	Version   string   `json:"version"` | ||||
| 	Link      string   `json:"link_url"` | ||||
| 	Plugins   []string `json:"plugins"` | ||||
| 	Globals   []string `json:"globals"` | ||||
| 	Escalates []string `json:"privileged_plugins"` | ||||
| } | ||||
| @@ -1,58 +0,0 @@ | ||||
| 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"` | ||||
|  | ||||
| 	// whether the secret requires verification | ||||
| 	SkipVerify bool `json:"skip_verify" meddler:"team_secret_skip_verify"` | ||||
|  | ||||
| 	// whether the secret should be concealed in the build log | ||||
| 	Conceal bool `json:"conceal" meddler:"team_secret_conceal"` | ||||
| } | ||||
|  | ||||
| // 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, | ||||
| 		SkipVerify: s.SkipVerify, | ||||
| 		Conceal:    s.Conceal, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 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, | ||||
| 		SkipVerify: s.SkipVerify, | ||||
| 		Conceal:    s.Conceal, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Validate validates the required fields and formats. | ||||
| func (s *TeamSecret) Validate() error { | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										61
									
								
								plugins/internal/http.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								plugins/internal/http.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| package internal | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| ) | ||||
|  | ||||
| // Send makes an http request to the given endpoint, writing the input | ||||
| // to the request body and unmarshaling the output from the response body. | ||||
| func Send(method, path string, in, out interface{}) error { | ||||
| 	uri, err := url.Parse(path) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// if we are posting or putting data, we need to | ||||
| 	// write it to the body of the request. | ||||
| 	var buf io.ReadWriter | ||||
| 	if in != nil { | ||||
| 		buf = new(bytes.Buffer) | ||||
| 		jsonerr := json.NewEncoder(buf).Encode(in) | ||||
| 		if jsonerr != nil { | ||||
| 			return jsonerr | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// creates a new http request to bitbucket. | ||||
| 	req, err := http.NewRequest(method, uri.String(), buf) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if in != nil { | ||||
| 		req.Header.Set("Content-Type", "application/json") | ||||
| 	} | ||||
|  | ||||
| 	resp, err := http.DefaultClient.Do(req) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	// if an error is encountered, parse and return the | ||||
| 	// error response. | ||||
| 	if resp.StatusCode > http.StatusPartialContent { | ||||
| 		out, _ := ioutil.ReadAll(resp.Body) | ||||
| 		return errors.New(string(out)) | ||||
| 	} | ||||
|  | ||||
| 	// if a json response is expected, parse and return | ||||
| 	// the json response. | ||||
| 	if out != nil { | ||||
| 		return json.NewDecoder(resp.Body).Decode(out) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										45
									
								
								plugins/registry.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								plugins/registry.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| package plugins | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/drone/drone/model" | ||||
| ) | ||||
|  | ||||
| type registryPlugin struct { | ||||
| 	endpoint string | ||||
| } | ||||
|  | ||||
| // NewRegistry returns a new registry plugin. | ||||
| func NewRegistry(endpoint string) interface{} { | ||||
| 	return registryPlugin{endpoint} | ||||
| } | ||||
|  | ||||
| func (r *registryPlugin) RegistryFind(repo *model.Repo, name string) (*model.Registry, error) { | ||||
| 	path := fmt.Sprintf("%s/registry/%s/%s/%s", r.endpoint, repo.Owner, repo.Name, name) | ||||
| 	out := new(model.Registry) | ||||
| 	err := do("GET", path, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| func (r *registryPlugin) RegistryList(repo *model.Repo) ([]*model.Registry, error) { | ||||
| 	path := fmt.Sprintf("%s/registry/%s/%s", r.endpoint, repo.Owner, repo.Name) | ||||
| 	out := []*model.Registry{} | ||||
| 	err := do("GET", path, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| func (r *registryPlugin) RegistryCreate(repo *model.Repo, in *model.Registry) error { | ||||
| 	path := fmt.Sprintf("%s/registry/%s/%s", r.endpoint, repo.Owner, repo.Name) | ||||
| 	return do("PATCH", path, in, nil) | ||||
| } | ||||
|  | ||||
| func (r *registryPlugin) RegistryUpdate(repo *model.Repo, in *model.Registry) error { | ||||
| 	path := fmt.Sprintf("%s/registry/%s/%s/%s", r.endpoint, repo.Owner, repo.Name, in.Address) | ||||
| 	return do("PATCH", path, in, nil) | ||||
| } | ||||
|  | ||||
| func (r *registryPlugin) RegistryDelete(repo *model.Repo, name string) error { | ||||
| 	path := fmt.Sprintf("%s/registry/%s/%s/%s", r.endpoint, repo.Owner, repo.Name, name) | ||||
| 	return do("DELETE", path, nil, nil) | ||||
| } | ||||
							
								
								
									
										38
									
								
								plugins/registry/builtin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								plugins/registry/builtin.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| package registry | ||||
|  | ||||
| import ( | ||||
| 	"github.com/drone/drone/model" | ||||
| ) | ||||
|  | ||||
| type builtin struct { | ||||
| 	store model.RegistryStore | ||||
| } | ||||
|  | ||||
| // New returns a new local registry service. | ||||
| func New(store model.RegistryStore) model.RegistryService { | ||||
| 	return &builtin{store} | ||||
| } | ||||
|  | ||||
| func (b *builtin) RegistryFind(repo *model.Repo, name string) (*model.Registry, error) { | ||||
| 	return b.store.RegistryFind(repo, name) | ||||
| } | ||||
|  | ||||
| func (b *builtin) RegistryList(repo *model.Repo) ([]*model.Registry, error) { | ||||
| 	return b.store.RegistryList(repo) | ||||
| } | ||||
|  | ||||
| func (b *builtin) RegistryCreate(repo *model.Repo, in *model.Registry) error { | ||||
| 	return b.store.RegistryCreate(in) | ||||
| } | ||||
|  | ||||
| func (b *builtin) RegistryUpdate(repo *model.Repo, in *model.Registry) error { | ||||
| 	return b.store.RegistryUpdate(in) | ||||
| } | ||||
|  | ||||
| func (b *builtin) RegistryDelete(repo *model.Repo, addr string) error { | ||||
| 	registry, err := b.RegistryFind(repo, addr) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return b.store.RegistryDelete(registry) | ||||
| } | ||||
							
								
								
									
										1
									
								
								plugins/registry/builtin_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								plugins/registry/builtin_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| package registry | ||||
							
								
								
									
										46
									
								
								plugins/registry/plugin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								plugins/registry/plugin.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| package registry | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/drone/drone/model" | ||||
| 	"github.com/drone/drone/plugins/internal" | ||||
| ) | ||||
|  | ||||
| type plugin struct { | ||||
| 	endpoint string | ||||
| } | ||||
|  | ||||
| // NewRemote returns a new remote registry service. | ||||
| func NewRemote(endpoint string) model.RegistryService { | ||||
| 	return &plugin{endpoint} | ||||
| } | ||||
|  | ||||
| func (p *plugin) RegistryFind(repo *model.Repo, name string) (*model.Registry, error) { | ||||
| 	path := fmt.Sprintf("%s/registry/%s/%s/%s", p.endpoint, repo.Owner, repo.Name, name) | ||||
| 	out := new(model.Registry) | ||||
| 	err := internal.Send("GET", path, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| func (p *plugin) RegistryList(repo *model.Repo) ([]*model.Registry, error) { | ||||
| 	path := fmt.Sprintf("%s/registry/%s/%s", p.endpoint, repo.Owner, repo.Name) | ||||
| 	out := []*model.Registry{} | ||||
| 	err := internal.Send("GET", path, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| func (p *plugin) RegistryCreate(repo *model.Repo, in *model.Registry) error { | ||||
| 	path := fmt.Sprintf("%s/registry/%s/%s", p.endpoint, repo.Owner, repo.Name) | ||||
| 	return internal.Send("PATCH", path, in, nil) | ||||
| } | ||||
|  | ||||
| func (p *plugin) RegistryUpdate(repo *model.Repo, in *model.Registry) error { | ||||
| 	path := fmt.Sprintf("%s/registry/%s/%s/%s", p.endpoint, repo.Owner, repo.Name, in.Address) | ||||
| 	return internal.Send("PATCH", path, in, nil) | ||||
| } | ||||
|  | ||||
| func (p *plugin) RegistryDelete(repo *model.Repo, name string) error { | ||||
| 	path := fmt.Sprintf("%s/registry/%s/%s/%s", p.endpoint, repo.Owner, repo.Name, name) | ||||
| 	return internal.Send("DELETE", path, nil, nil) | ||||
| } | ||||
							
								
								
									
										1
									
								
								plugins/registry/plugin_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								plugins/registry/plugin_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| package registry | ||||
							
								
								
									
										45
									
								
								plugins/secrets.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								plugins/secrets.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| package plugins | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/drone/drone/model" | ||||
| ) | ||||
|  | ||||
| type secretPlugin struct { | ||||
| 	endpoint string | ||||
| } | ||||
|  | ||||
| // NewSecret returns a new secret plugin. | ||||
| func NewSecret(endpoint string) interface{} { | ||||
| 	return secretPlugin{endpoint} | ||||
| } | ||||
|  | ||||
| func (s *secretPlugin) SecretFind(repo *model.Repo, name string) (*model.Secret, error) { | ||||
| 	path := fmt.Sprintf("%s/secrets/%s/%s/%s", s.endpoint, repo.Owner, repo.Name, name) | ||||
| 	out := new(model.Secret) | ||||
| 	err := do("GET", path, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| func (s *secretPlugin) SecretList(repo *model.Repo) ([]*model.Secret, error) { | ||||
| 	path := fmt.Sprintf("%s/secrets/%s/%s", s.endpoint, repo.Owner, repo.Name) | ||||
| 	out := []*model.Secret{} | ||||
| 	err := do("GET", path, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| func (s *secretPlugin) SecretCreate(repo *model.Repo, in *model.Secret) error { | ||||
| 	path := fmt.Sprintf("%s/secrets/%s/%s", s.endpoint, repo.Owner, repo.Name) | ||||
| 	return do("POST", path, in, nil) | ||||
| } | ||||
|  | ||||
| func (s *secretPlugin) SecretUpdate(repo *model.Repo, in *model.Secret) error { | ||||
| 	path := fmt.Sprintf("%s/secrets/%s/%s/%s", s.endpoint, repo.Owner, repo.Name, in.Name) | ||||
| 	return do("PATCH", path, in, nil) | ||||
| } | ||||
|  | ||||
| func (s *secretPlugin) SecretDelete(repo *model.Repo, name string) error { | ||||
| 	path := fmt.Sprintf("%s/secrets/%s/%s/%s", s.endpoint, repo.Owner, repo.Name, name) | ||||
| 	return do("DELETE", path, nil, nil) | ||||
| } | ||||
							
								
								
									
										38
									
								
								plugins/secrets/builtin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								plugins/secrets/builtin.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| package secrets | ||||
|  | ||||
| import ( | ||||
| 	"github.com/drone/drone/model" | ||||
| ) | ||||
|  | ||||
| type builtin struct { | ||||
| 	store model.SecretStore | ||||
| } | ||||
|  | ||||
| // New returns a new local secret service. | ||||
| func New(store model.SecretStore) model.SecretService { | ||||
| 	return &builtin{store} | ||||
| } | ||||
|  | ||||
| func (b *builtin) SecretFind(repo *model.Repo, name string) (*model.Secret, error) { | ||||
| 	return b.store.SecretFind(repo, name) | ||||
| } | ||||
|  | ||||
| func (b *builtin) SecretList(repo *model.Repo) ([]*model.Secret, error) { | ||||
| 	return b.store.SecretList(repo) | ||||
| } | ||||
|  | ||||
| func (b *builtin) SecretCreate(repo *model.Repo, in *model.Secret) error { | ||||
| 	return b.store.SecretCreate(in) | ||||
| } | ||||
|  | ||||
| func (b *builtin) SecretUpdate(repo *model.Repo, in *model.Secret) error { | ||||
| 	return b.store.SecretUpdate(in) | ||||
| } | ||||
|  | ||||
| func (b *builtin) SecretDelete(repo *model.Repo, name string) error { | ||||
| 	secret, err := b.store.SecretFind(repo, name) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return b.store.SecretDelete(secret) | ||||
| } | ||||
							
								
								
									
										1
									
								
								plugins/secrets/builtin_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								plugins/secrets/builtin_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| package secrets | ||||
							
								
								
									
										46
									
								
								plugins/secrets/plugin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								plugins/secrets/plugin.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| package secrets | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/drone/drone/model" | ||||
| 	"github.com/drone/drone/plugins/internal" | ||||
| ) | ||||
|  | ||||
| type plugin struct { | ||||
| 	endpoint string | ||||
| } | ||||
|  | ||||
| // NewRemote returns a new remote secret service. | ||||
| func NewRemote(endpoint string) model.SecretService { | ||||
| 	return &plugin{endpoint} | ||||
| } | ||||
|  | ||||
| func (p *plugin) SecretFind(repo *model.Repo, name string) (*model.Secret, error) { | ||||
| 	path := fmt.Sprintf("%s/secrets/%s/%s/%s", p.endpoint, repo.Owner, repo.Name, name) | ||||
| 	out := new(model.Secret) | ||||
| 	err := internal.Send("GET", path, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| func (p *plugin) SecretList(repo *model.Repo) ([]*model.Secret, error) { | ||||
| 	path := fmt.Sprintf("%s/secrets/%s/%s", p.endpoint, repo.Owner, repo.Name) | ||||
| 	out := []*model.Secret{} | ||||
| 	err := internal.Send("GET", path, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| func (p *plugin) SecretCreate(repo *model.Repo, in *model.Secret) error { | ||||
| 	path := fmt.Sprintf("%s/secrets/%s/%s", p.endpoint, repo.Owner, repo.Name) | ||||
| 	return internal.Send("POST", path, in, nil) | ||||
| } | ||||
|  | ||||
| func (p *plugin) SecretUpdate(repo *model.Repo, in *model.Secret) error { | ||||
| 	path := fmt.Sprintf("%s/secrets/%s/%s/%s", p.endpoint, repo.Owner, repo.Name, in.Name) | ||||
| 	return internal.Send("PATCH", path, in, nil) | ||||
| } | ||||
|  | ||||
| func (p *plugin) SecretDelete(repo *model.Repo, name string) error { | ||||
| 	path := fmt.Sprintf("%s/secrets/%s/%s/%s", p.endpoint, repo.Owner, repo.Name, name) | ||||
| 	return internal.Send("DELETE", path, nil, nil) | ||||
| } | ||||
							
								
								
									
										1
									
								
								plugins/secrets/plugin_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								plugins/secrets/plugin_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| package secrets | ||||
							
								
								
									
										44
									
								
								plugins/sender/builtin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								plugins/sender/builtin.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| package sender | ||||
|  | ||||
| import ( | ||||
| 	"github.com/drone/drone/model" | ||||
| ) | ||||
|  | ||||
| type builtin struct { | ||||
| 	store model.SenderStore | ||||
| } | ||||
|  | ||||
| // New returns a new local gating service. | ||||
| func New(store model.SenderStore) model.SenderService { | ||||
| 	return &builtin{store} | ||||
| } | ||||
|  | ||||
| func (b *builtin) SenderAllowed(user *model.User, repo *model.Repo, build *model.Build) (bool, error) { | ||||
| 	if repo.IsPrivate == false && build.Event == model.EventPull && build.Sender != user.Login { | ||||
| 		sender, err := b.store.SenderFind(repo, build.Sender) | ||||
| 		if err != nil || sender.Block { | ||||
| 			return false, nil | ||||
| 		} | ||||
| 	} | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| func (b *builtin) SenderCreate(repo *model.Repo, sender *model.Sender) error { | ||||
| 	return b.store.SenderCreate(sender) | ||||
| } | ||||
|  | ||||
| func (b *builtin) SenderUpdate(repo *model.Repo, sender *model.Sender) error { | ||||
| 	return b.store.SenderUpdate(sender) | ||||
| } | ||||
|  | ||||
| func (b *builtin) SenderDelete(repo *model.Repo, login string) error { | ||||
| 	sender, err := b.store.SenderFind(repo, login) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return b.store.SenderDelete(sender) | ||||
| } | ||||
|  | ||||
| func (b *builtin) SenderList(repo *model.Repo) ([]*model.Sender, error) { | ||||
| 	return b.store.SenderList(repo) | ||||
| } | ||||
							
								
								
									
										1
									
								
								plugins/sender/builtin_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								plugins/sender/builtin_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| package sender | ||||
							
								
								
									
										49
									
								
								plugins/sender/plugin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								plugins/sender/plugin.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| package sender | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/drone/drone/model" | ||||
| 	"github.com/drone/drone/plugins/internal" | ||||
| ) | ||||
|  | ||||
| type plugin struct { | ||||
| 	endpoint string | ||||
| } | ||||
|  | ||||
| // NewRemote returns a new remote gating service. | ||||
| func NewRemote(endpoint string) model.SenderService { | ||||
| 	return &plugin{endpoint} | ||||
| } | ||||
|  | ||||
| func (p *plugin) SenderAllowed(user *model.User, repo *model.Repo, build *model.Build) (bool, error) { | ||||
| 	path := fmt.Sprintf("%s/sender/%s/%s/%s", p.endpoint, repo.Owner, repo.Name, build.Sender) | ||||
| 	out := new(model.Sender) | ||||
| 	err := internal.Send("POST", path, build, out) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	return out.Allow, nil | ||||
| } | ||||
|  | ||||
| func (p *plugin) SenderCreate(repo *model.Repo, sender *model.Sender) error { | ||||
| 	path := fmt.Sprintf("%s/sender/%s/%s", p.endpoint, repo.Owner, repo.Name) | ||||
| 	return internal.Send("POST", path, sender, nil) | ||||
| } | ||||
|  | ||||
| func (p *plugin) SenderUpdate(repo *model.Repo, sender *model.Sender) error { | ||||
| 	path := fmt.Sprintf("%s/sender/%s/%s", p.endpoint, repo.Owner, repo.Name) | ||||
| 	return internal.Send("PUT", path, sender, nil) | ||||
| } | ||||
|  | ||||
| func (p *plugin) SenderDelete(repo *model.Repo, login string) error { | ||||
| 	path := fmt.Sprintf("%s/sender/%s/%s/%s", p.endpoint, repo.Owner, repo.Name, login) | ||||
| 	return internal.Send("DELETE", path, nil, nil) | ||||
| } | ||||
|  | ||||
| func (p *plugin) SenderList(repo *model.Repo) ([]*model.Sender, error) { | ||||
| 	path := fmt.Sprintf("%s/sender/%s/%s", p.endpoint, repo.Owner, repo.Name) | ||||
| 	out := []*model.Sender{} | ||||
| 	err := internal.Send("GET", path, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
							
								
								
									
										1
									
								
								plugins/sender/plugin_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								plugins/sender/plugin_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| package sender | ||||
| @@ -23,13 +23,13 @@ func setupConfig(c *cli.Context) *model.Config { | ||||
| 	return &model.Config{ | ||||
| 		Open:   c.Bool("open"), | ||||
| 		Secret: c.String("agent-secret"), | ||||
| 		Admins: sliceToMap(c.StringSlice("admin")), | ||||
| 		Orgs:   sliceToMap(c.StringSlice("orgs")), | ||||
| 		Admins: sliceToMap2(c.StringSlice("admin")), | ||||
| 		Orgs:   sliceToMap2(c.StringSlice("orgs")), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // helper function to convert a string slice to a map. | ||||
| func sliceToMap(s []string) map[string]bool { | ||||
| func sliceToMap2(s []string) map[string]bool { | ||||
| 	v := map[string]bool{} | ||||
| 	for _, ss := range s { | ||||
| 		v[ss] = true | ||||
|   | ||||
| @@ -1,6 +1,15 @@ | ||||
| package middleware | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"github.com/cncd/logging" | ||||
| 	"github.com/cncd/pubsub" | ||||
| 	"github.com/cncd/queue" | ||||
| 	"github.com/drone/drone/plugins/registry" | ||||
| 	"github.com/drone/drone/plugins/secrets" | ||||
| 	"github.com/drone/drone/plugins/sender" | ||||
| 	"github.com/drone/drone/server" | ||||
| 	"github.com/drone/drone/store" | ||||
| 	"github.com/drone/drone/store/datastore" | ||||
| 	"github.com/urfave/cli" | ||||
| @@ -12,6 +21,40 @@ import ( | ||||
| // the context of every http.Request. | ||||
| func Store(cli *cli.Context) gin.HandlerFunc { | ||||
| 	v := setupStore(cli) | ||||
|  | ||||
| 	// HACK during refactor period. Please ignore my mess. | ||||
|  | ||||
| 	// storage | ||||
| 	server.Config.Storage.Files = v | ||||
|  | ||||
| 	// services | ||||
| 	server.Config.Services.Queue = queue.New() | ||||
| 	server.Config.Services.Logs = logging.New() | ||||
| 	server.Config.Services.Pubsub = pubsub.New() | ||||
| 	server.Config.Services.Pubsub.Create(context.Background(), "topic/events") | ||||
| 	server.Config.Services.Registries = registry.New(v) | ||||
| 	server.Config.Services.Secrets = secrets.New(v) | ||||
| 	server.Config.Services.Senders = sender.New(v) | ||||
| 	if endpoint := cli.String("registry-service"); endpoint != "" { | ||||
| 		server.Config.Services.Registries = registry.NewRemote(endpoint) | ||||
| 	} | ||||
| 	if endpoint := cli.String("secret-service"); endpoint != "" { | ||||
| 		server.Config.Services.Secrets = secrets.NewRemote(endpoint) | ||||
| 	} | ||||
| 	if endpoint := cli.String("gating-service"); endpoint != "" { | ||||
| 		server.Config.Services.Senders = sender.NewRemote(endpoint) | ||||
| 	} | ||||
|  | ||||
| 	// server configuration | ||||
| 	server.Config.Server.Cert = cli.String("server-cert") | ||||
| 	server.Config.Server.Key = cli.String("server-key") | ||||
| 	server.Config.Server.Pass = cli.String("agent-secret") | ||||
| 	server.Config.Server.Host = cli.String("server-host") | ||||
| 	server.Config.Server.Port = cli.String("server-addr") | ||||
| 	// server.Config.Server.Open = cli.Bool("open") | ||||
| 	// server.Config.Server.Orgs = sliceToMap(cli.StringSlice("orgs")) | ||||
| 	// server.Config.Server.Admins = sliceToMap(cli.StringSlice("admin")) | ||||
|  | ||||
| 	return func(c *gin.Context) { | ||||
| 		store.ToContext(c, v) | ||||
| 		c.Next() | ||||
| @@ -25,3 +68,12 @@ func setupStore(c *cli.Context) store.Store { | ||||
| 		c.String("datasource"), | ||||
| 	) | ||||
| } | ||||
|  | ||||
| // helper function to convert a string slice to a map. | ||||
| func sliceToMap(s []string) map[string]struct{} { | ||||
| 	v := map[string]struct{}{} | ||||
| 	for _, ss := range s { | ||||
| 		v[ss] = struct{}{} | ||||
| 	} | ||||
| 	return v | ||||
| } | ||||
|   | ||||
| @@ -70,27 +70,6 @@ func Load(middleware ...gin.HandlerFunc) http.Handler { | ||||
| 		users.DELETE("/:login", server.DeleteUser) | ||||
| 	} | ||||
|  | ||||
| 	teams := e.Group("/api/teams") | ||||
| 	{ | ||||
| 		teams.Use(session.MustTeamAdmin()) | ||||
|  | ||||
| 		team := teams.Group("/:team") | ||||
| 		{ | ||||
| 			team.GET("/secrets", server.GetTeamSecrets) | ||||
| 			team.POST("/secrets", server.PostTeamSecret) | ||||
| 			team.DELETE("/secrets/:secret", server.DeleteTeamSecret) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	global := e.Group("/api/global") | ||||
| 	{ | ||||
| 		global.Use(session.MustAdmin()) | ||||
|  | ||||
| 		global.GET("/secrets", server.GetGlobalSecrets) | ||||
| 		global.POST("/secrets", server.PostGlobalSecret) | ||||
| 		global.DELETE("/secrets/:secret", server.DeleteGlobalSecret) | ||||
| 	} | ||||
|  | ||||
| 	repos := e.Group("/api/repos/:owner/:name") | ||||
| 	{ | ||||
| 		repos.POST("", server.PostRepo) | ||||
| @@ -107,8 +86,11 @@ func Load(middleware ...gin.HandlerFunc) http.Handler { | ||||
| 			repo.GET("/logs/:number/:ppid/:proc", server.GetBuildLogs) | ||||
| 			repo.POST("/sign", session.MustPush, server.Sign) | ||||
|  | ||||
| 			repo.GET("/secrets", session.MustPush, server.GetSecrets) | ||||
| 			// requires push permissions | ||||
| 			repo.GET("/secrets", session.MustPush, server.GetSecretList) | ||||
| 			repo.POST("/secrets", session.MustPush, server.PostSecret) | ||||
| 			repo.GET("/secrets/:secret", session.MustPush, server.GetSecret) | ||||
| 			repo.PATCH("/secrets/:secret", session.MustPush, server.PatchSecret) | ||||
| 			repo.DELETE("/secrets/:secret", session.MustPush, server.DeleteSecret) | ||||
|  | ||||
| 			// requires push permissions | ||||
|   | ||||
| @@ -138,7 +138,7 @@ func DeleteBuild(c *gin.Context) { | ||||
| 	// TODO cancel child procs | ||||
| 	store.FromContext(c).ProcUpdate(proc) | ||||
|  | ||||
| 	config.queue.Error(context.Background(), fmt.Sprint(proc.ID), queue.ErrCancel) | ||||
| 	Config.Services.Queue.Error(context.Background(), fmt.Sprint(proc.ID), queue.ErrCancel) | ||||
| 	c.String(204, "") | ||||
| } | ||||
|  | ||||
| @@ -197,11 +197,11 @@ func PostApproval(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.GetMergedSecretList(c, repo) | ||||
| 	secs, err := Config.Services.Secrets.SecretList(repo) | ||||
| 	if err != nil { | ||||
| 		logrus.Debugf("Error getting secrets for %s#%d. %s", repo.FullName, build.Number, err) | ||||
| 	} | ||||
| 	regs, err := store.FromContext(c).RegistryList(repo) | ||||
| 	regs, err := Config.Services.Registries.RegistryList(repo) | ||||
| 	if err != nil { | ||||
| 		logrus.Debugf("Error getting registry credentials for %s#%d. %s", repo.FullName, build.Number, err) | ||||
| 	} | ||||
| @@ -277,7 +277,7 @@ func PostApproval(c *gin.Context) { | ||||
| 		Build: buildCopy, | ||||
| 	}) | ||||
| 	// TODO remove global reference | ||||
| 	config.pubsub.Publish(c, "topic/events", message) | ||||
| 	Config.Services.Pubsub.Publish(c, "topic/events", message) | ||||
|  | ||||
| 	// | ||||
| 	// end publish topic | ||||
| @@ -298,8 +298,8 @@ func PostApproval(c *gin.Context) { | ||||
| 			Timeout: b.Repo.Timeout, | ||||
| 		}) | ||||
|  | ||||
| 		config.logger.Open(context.Background(), task.ID) | ||||
| 		config.queue.Push(context.Background(), task) | ||||
| 		Config.Services.Logs.Open(context.Background(), task.ID) | ||||
| 		Config.Services.Queue.Push(context.Background(), task) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -476,11 +476,11 @@ 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.GetMergedSecretList(c, repo) | ||||
| 	secs, err := Config.Services.Secrets.SecretList(repo) | ||||
| 	if err != nil { | ||||
| 		logrus.Debugf("Error getting secrets for %s#%d. %s", repo.FullName, build.Number, err) | ||||
| 	} | ||||
| 	regs, err := store.FromContext(c).RegistryList(repo) | ||||
| 	regs, err := Config.Services.Registries.RegistryList(repo) | ||||
| 	if err != nil { | ||||
| 		logrus.Debugf("Error getting registry credentials for %s#%d. %s", repo.FullName, build.Number, err) | ||||
| 	} | ||||
| @@ -561,7 +561,7 @@ func PostBuild(c *gin.Context) { | ||||
| 		Build: buildCopy, | ||||
| 	}) | ||||
| 	// TODO remove global reference | ||||
| 	config.pubsub.Publish(c, "topic/events", message) | ||||
| 	Config.Services.Pubsub.Publish(c, "topic/events", message) | ||||
| 	// | ||||
| 	// end publish topic | ||||
| 	// | ||||
| @@ -581,7 +581,7 @@ func PostBuild(c *gin.Context) { | ||||
| 			Timeout: b.Repo.Timeout, | ||||
| 		}) | ||||
|  | ||||
| 		config.logger.Open(context.Background(), task.ID) | ||||
| 		config.queue.Push(context.Background(), task) | ||||
| 		Config.Services.Logs.Open(context.Background(), task.ID) | ||||
| 		Config.Services.Queue.Push(context.Background(), task) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -40,7 +40,7 @@ var skipRe = regexp.MustCompile(`\[(?i:ci *skip|skip *ci)\]`) | ||||
|  | ||||
| func GetQueueInfo(c *gin.Context) { | ||||
| 	c.IndentedJSON(200, | ||||
| 		config.queue.Info(c), | ||||
| 		Config.Services.Queue.Info(c), | ||||
| 	) | ||||
| } | ||||
|  | ||||
| @@ -153,80 +153,30 @@ func PostHook(c *gin.Context) { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	secs, err := store.GetMergedSecretList(c, repo) | ||||
| 	secs, err := Config.Services.Secrets.SecretList(repo) | ||||
| 	if err != nil { | ||||
| 		logrus.Debugf("Error getting secrets for %s#%d. %s", repo.FullName, build.Number, err) | ||||
| 	} | ||||
|  | ||||
| 	regs, err := store.FromContext(c).RegistryList(repo) | ||||
| 	regs, err := Config.Services.Registries.RegistryList(repo) | ||||
| 	if err != nil { | ||||
| 		logrus.Debugf("Error getting registry credentials for %s#%d. %s", repo.FullName, build.Number, err) | ||||
| 	} | ||||
|  | ||||
| 	// var mustApprove bool | ||||
| 	// if build.Event == model.EventPull { | ||||
| 	// 	for _, sec := range secs { | ||||
| 	// 		if sec.SkipVerify { | ||||
| 	// 			continue | ||||
| 	// 		} | ||||
| 	// 		if sec.MatchEvent(model.EventPull) { | ||||
| 	// 			mustApprove = true | ||||
| 	// 			break | ||||
| 	// 		} | ||||
| 	// 	} | ||||
| 	// 	if !mustApprove { | ||||
| 	// 		logrus.Debugf("no secrets exposed to pull_request: status: accepted") | ||||
| 	// 	} | ||||
| 	// } | ||||
|  | ||||
| 	// if build.Event == model.EventPull && mustApprove { | ||||
| 	// 	old, ferr := remote_.FileRef(user, repo, build.Branch, repo.Config) | ||||
| 	// 	if ferr != nil { | ||||
| 	// 		build.Status = model.StatusBlocked | ||||
| 	// 		logrus.Debugf("cannot fetch base yaml: status: blocked") | ||||
| 	// 	} else if bytes.Equal(old, raw) { | ||||
| 	// 		build.Status = model.StatusPending | ||||
| 	// 		logrus.Debugf("base yaml matches head yaml: status: accepted") | ||||
| 	// 	} else { | ||||
| 	// 		// this block is executed if the target yaml file | ||||
| 	// 		// does not match the base yaml. | ||||
| 	// | ||||
| 	// 		// TODO unfortunately we have no good way to get the | ||||
| 	// 		// sender repository permissions unless the user is | ||||
| 	// 		// a registered drone user. | ||||
| 	// 		sender, uerr := store.GetUserLogin(c, build.Sender) | ||||
| 	// 		if uerr != nil { | ||||
| 	// 			build.Status = model.StatusBlocked | ||||
| 	// 			logrus.Debugf("sender does not have a drone account: status: blocked") | ||||
| 	// 		} else { | ||||
| 	// 			if refresher, ok := remote_.(remote.Refresher); ok { | ||||
| 	// 				ok, _ := refresher.Refresh(sender) | ||||
| 	// 				if ok { | ||||
| 	// 					store.UpdateUser(c, sender) | ||||
| 	// 				} | ||||
| 	// 			} | ||||
| 	// 			// if the sender does not have push access to the | ||||
| 	// 			// repository the pull request should be blocked. | ||||
| 	// 			perm, perr := remote_.Perm(sender, repo.Owner, repo.Name) | ||||
| 	// 			if perr == nil && perm.Push == true { | ||||
| 	// 				build.Status = model.StatusPending | ||||
| 	// 				logrus.Debugf("sender %s has push access: status: accepted", sender.Login) | ||||
| 	// 			} else { | ||||
| 	// 				build.Status = model.StatusBlocked | ||||
| 	// 				logrus.Debugf("sender %s does not have push access: status: blocked", sender.Login) | ||||
| 	// 			} | ||||
| 	// 		} | ||||
| 	// 	} | ||||
| 	// } else { | ||||
| 	// 	build.Status = model.StatusPending | ||||
| 	// } | ||||
|  | ||||
| 	// update some build fields | ||||
| 	build.RepoID = repo.ID | ||||
| 	build.Verified = true | ||||
| 	build.Status = model.StatusPending | ||||
|  | ||||
| 	if err := store.CreateBuild(c, build, build.Procs...); err != nil { | ||||
| 	if repo.IsGated { | ||||
| 		allowed, _ := Config.Services.Senders.SenderAllowed(user, repo, build) | ||||
| 		if !allowed { | ||||
| 			build.Status = model.StatusBlocked | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	err = store.CreateBuild(c, build, build.Procs...) | ||||
| 	if err != nil { | ||||
| 		logrus.Errorf("failure to save commit for %s. %s", repo.FullName, err) | ||||
| 		c.AbortWithError(500, err) | ||||
| 		return | ||||
| @@ -234,9 +184,9 @@ func PostHook(c *gin.Context) { | ||||
|  | ||||
| 	c.JSON(200, build) | ||||
|  | ||||
| 	// if build.Status == model.StatusBlocked { | ||||
| 	// 	return | ||||
| 	// } | ||||
| 	if build.Status == model.StatusBlocked { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// get the previous build so that we can send | ||||
| 	// on status change notifications | ||||
| @@ -321,7 +271,7 @@ func PostHook(c *gin.Context) { | ||||
| 		Build: buildCopy, | ||||
| 	}) | ||||
| 	// TODO remove global reference | ||||
| 	config.pubsub.Publish(c, "topic/events", message) | ||||
| 	Config.Services.Pubsub.Publish(c, "topic/events", message) | ||||
| 	// | ||||
| 	// end publish topic | ||||
| 	// | ||||
| @@ -341,8 +291,8 @@ func PostHook(c *gin.Context) { | ||||
| 			Timeout: b.Repo.Timeout, | ||||
| 		}) | ||||
|  | ||||
| 		config.logger.Open(context.Background(), task.ID) | ||||
| 		config.queue.Push(context.Background(), task) | ||||
| 		Config.Services.Logs.Open(context.Background(), task.ID) | ||||
| 		Config.Services.Queue.Push(context.Background(), task) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -460,7 +410,7 @@ func (b *builder) Build() ([]*buildItem, error) { | ||||
|  | ||||
| 		var secrets []compiler.Secret | ||||
| 		for _, sec := range b.Secs { | ||||
| 			if !sec.MatchEvent(b.Curr.Event) { | ||||
| 			if !sec.Match(b.Curr.Event) { | ||||
| 				continue | ||||
| 			} | ||||
| 			secrets = append(secrets, compiler.Secret{ | ||||
|   | ||||
| @@ -5,7 +5,6 @@ import ( | ||||
|  | ||||
| 	"github.com/drone/drone/model" | ||||
| 	"github.com/drone/drone/router/middleware/session" | ||||
| 	"github.com/drone/drone/store" | ||||
|  | ||||
| 	"github.com/gin-gonic/gin" | ||||
| ) | ||||
| @@ -17,7 +16,7 @@ func GetRegistry(c *gin.Context) { | ||||
| 		repo = session.Repo(c) | ||||
| 		name = c.Param("registry") | ||||
| 	) | ||||
| 	registry, err := store.FromContext(c).RegistryFind(repo, name) | ||||
| 	registry, err := Config.Services.Registries.RegistryFind(repo, name) | ||||
| 	if err != nil { | ||||
| 		c.String(404, "Error getting registry %q. %s", name, err) | ||||
| 		return | ||||
| @@ -46,7 +45,7 @@ func PostRegistry(c *gin.Context) { | ||||
| 		c.String(400, "Error inserting registry. %s", err) | ||||
| 		return | ||||
| 	} | ||||
| 	if err := store.FromContext(c).RegistryCreate(registry); err != nil { | ||||
| 	if err := Config.Services.Registries.RegistryCreate(repo, registry); err != nil { | ||||
| 		c.String(500, "Error inserting registry %q. %s", in.Address, err) | ||||
| 		return | ||||
| 	} | ||||
| @@ -67,7 +66,7 @@ func PatchRegistry(c *gin.Context) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	registry, err := store.FromContext(c).RegistryFind(repo, name) | ||||
| 	registry, err := Config.Services.Registries.RegistryFind(repo, name) | ||||
| 	if err != nil { | ||||
| 		c.String(404, "Error getting registry %q. %s", name, err) | ||||
| 		return | ||||
| @@ -89,7 +88,7 @@ func PatchRegistry(c *gin.Context) { | ||||
| 		c.String(400, "Error updating registry. %s", err) | ||||
| 		return | ||||
| 	} | ||||
| 	if err := store.FromContext(c).RegistryUpdate(registry); err != nil { | ||||
| 	if err := Config.Services.Registries.RegistryUpdate(repo, registry); err != nil { | ||||
| 		c.String(500, "Error updating registry %q. %s", in.Address, err) | ||||
| 		return | ||||
| 	} | ||||
| @@ -100,7 +99,7 @@ func PatchRegistry(c *gin.Context) { | ||||
| // to the response in json format. | ||||
| func GetRegistryList(c *gin.Context) { | ||||
| 	repo := session.Repo(c) | ||||
| 	list, err := store.FromContext(c).RegistryList(repo) | ||||
| 	list, err := Config.Services.Registries.RegistryList(repo) | ||||
| 	if err != nil { | ||||
| 		c.String(500, "Error getting registry list. %s", err) | ||||
| 		return | ||||
| @@ -119,13 +118,7 @@ func DeleteRegistry(c *gin.Context) { | ||||
| 		repo = session.Repo(c) | ||||
| 		name = c.Param("registry") | ||||
| 	) | ||||
| 	registry, err := store.FromContext(c).RegistryFind(repo, name) | ||||
| 	if err != nil { | ||||
| 		c.String(404, "Error getting registry %q. %s", name, err) | ||||
| 		return | ||||
| 	} | ||||
| 	err = store.FromContext(c).RegistryDelete(registry) | ||||
| 	if err != nil { | ||||
| 	if err := Config.Services.Registries.RegistryDelete(repo, name); err != nil { | ||||
| 		c.String(500, "Error deleting registry %q. %s", name, err) | ||||
| 		return | ||||
| 	} | ||||
|   | ||||
| @@ -98,6 +98,7 @@ func PatchRepo(c *gin.Context) { | ||||
|  | ||||
| 	in := &struct { | ||||
| 		IsTrusted   *bool  `json:"trusted,omitempty"` | ||||
| 		IsGated     *bool  `json:"gated,omitempty"` | ||||
| 		Timeout     *int64 `json:"timeout,omitempty"` | ||||
| 		AllowPull   *bool  `json:"allow_pr,omitempty"` | ||||
| 		AllowPush   *bool  `json:"allow_push,omitempty"` | ||||
| @@ -109,6 +110,11 @@ func PatchRepo(c *gin.Context) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if (in.IsTrusted != nil || in.Timeout != nil || in.IsGated != nil) && !user.Admin { | ||||
| 		c.String(403, "Insufficient privileges") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if in.AllowPush != nil { | ||||
| 		repo.AllowPush = *in.AllowPush | ||||
| 	} | ||||
| @@ -121,10 +127,13 @@ func PatchRepo(c *gin.Context) { | ||||
| 	if in.AllowTag != nil { | ||||
| 		repo.AllowTag = *in.AllowTag | ||||
| 	} | ||||
| 	if in.IsTrusted != nil && user.Admin { | ||||
| 	if in.IsGated != nil { | ||||
| 		repo.IsGated = *in.IsGated | ||||
| 	} | ||||
| 	if in.IsTrusted != nil { | ||||
| 		repo.IsTrusted = *in.IsTrusted | ||||
| 	} | ||||
| 	if in.Timeout != nil && user.Admin { | ||||
| 	if in.Timeout != nil { | ||||
| 		repo.Timeout = *in.Timeout | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,6 @@ import ( | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/cncd/logging" | ||||
| @@ -22,23 +21,57 @@ import ( | ||||
| // This file is a complete disaster because I'm trying to wedge in some | ||||
| // experimental code. Please pardon our appearance during renovations. | ||||
|  | ||||
| var config = struct { | ||||
| 	pubsub pubsub.Publisher | ||||
| 	queue  queue.Queue | ||||
| 	logger logging.Log | ||||
| 	secret string | ||||
| 	host   string | ||||
| }{ | ||||
| 	pubsub.New(), | ||||
| 	queue.New(), | ||||
| 	logging.New(), | ||||
| 	os.Getenv("DRONE_SECRET"), | ||||
| 	os.Getenv("DRONE_HOST"), | ||||
| } | ||||
| // Config is an evil global configuration that will be used as we transition / | ||||
| // refactor the codebase to move away from storing these values in the Context. | ||||
| var Config = struct { | ||||
| 	Services struct { | ||||
| 		Pubsub     pubsub.Publisher | ||||
| 		Queue      queue.Queue | ||||
| 		Logs       logging.Log | ||||
| 		Senders    model.SenderService | ||||
| 		Secrets    model.SecretService | ||||
| 		Registries model.RegistryService | ||||
| 	} | ||||
| 	Storage struct { | ||||
| 		// Users  model.UserStore | ||||
| 		// Repos  model.RepoStore | ||||
| 		// Builds model.BuildStore | ||||
| 		// Logs   model.LogStore | ||||
| 		Files model.FileStore | ||||
| 		Procs model.ProcStore | ||||
| 		// Registries model.RegistryStore | ||||
| 		// Secrets model.SecretStore | ||||
| 	} | ||||
| 	Server struct { | ||||
| 		Key  string | ||||
| 		Cert string | ||||
| 		Host string | ||||
| 		Port string | ||||
| 		Pass string | ||||
| 		// Open bool | ||||
| 		// Orgs map[string]struct{} | ||||
| 		// Admins map[string]struct{} | ||||
| 	} | ||||
| 	Pipeline struct { | ||||
| 		Volumes    []string | ||||
| 		Networks   []string | ||||
| 		Privileged []string | ||||
| 	} | ||||
| }{} | ||||
|  | ||||
| func init() { | ||||
| 	config.pubsub.Create(context.Background(), "topic/events") | ||||
| } | ||||
| // var config = struct { | ||||
| // 	pubsub pubsub.Publisher | ||||
| // 	queue  queue.Queue | ||||
| // 	logger logging.Log | ||||
| // 	secret string | ||||
| // 	host   string | ||||
| // }{ | ||||
| // 	pubsub.New(), | ||||
| // 	queue.New(), | ||||
| // 	logging.New(), | ||||
| // 	os.Getenv("DRONE_SECRET"), | ||||
| // 	os.Getenv("DRONE_HOST"), | ||||
| // } | ||||
|  | ||||
| // func SetupRPC() gin.HandlerFunc { | ||||
| // 	return func(c *gin.Context) { | ||||
| @@ -48,18 +81,18 @@ func init() { | ||||
|  | ||||
| func RPCHandler(c *gin.Context) { | ||||
|  | ||||
| 	if secret := c.Request.Header.Get("Authorization"); secret != "Bearer "+config.secret { | ||||
| 		log.Printf("Unable to connect agent. Invalid authorization token %q does not match %q", secret, config.secret) | ||||
| 	if secret := c.Request.Header.Get("Authorization"); secret != "Bearer "+Config.Server.Pass { | ||||
| 		log.Printf("Unable to connect agent. Invalid authorization token %q does not match %q", secret, Config.Server.Pass) | ||||
| 		c.String(401, "Unable to connect agent. Invalid authorization token") | ||||
| 		return | ||||
| 	} | ||||
| 	peer := RPC{ | ||||
| 		remote: remote.FromContext(c), | ||||
| 		store:  store.FromContext(c), | ||||
| 		queue:  config.queue, | ||||
| 		pubsub: config.pubsub, | ||||
| 		logger: config.logger, | ||||
| 		host:   config.host, | ||||
| 		queue:  Config.Services.Queue, | ||||
| 		pubsub: Config.Services.Pubsub, | ||||
| 		logger: Config.Services.Logs, | ||||
| 		host:   Config.Server.Host, | ||||
| 	} | ||||
| 	rpc.NewServer(&peer).ServeHTTP(c.Writer, c.Request) | ||||
| } | ||||
| @@ -201,7 +234,7 @@ func (s *RPC) Upload(c context.Context, id string, file *rpc.File) error { | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	return s.store.FileCreate(&model.File{ | ||||
| 	return Config.Storage.Files.FileCreate(&model.File{ | ||||
| 		BuildID: proc.BuildID, | ||||
| 		ProcID:  proc.ID, | ||||
| 		Mime:    file.Mime, | ||||
|   | ||||
							
								
								
									
										229
									
								
								server/secret.go
									
									
									
									
									
								
							
							
						
						
									
										229
									
								
								server/secret.go
									
									
									
									
									
								
							| @@ -5,173 +5,118 @@ import ( | ||||
|  | ||||
| 	"github.com/drone/drone/model" | ||||
| 	"github.com/drone/drone/router/middleware/session" | ||||
| 	"github.com/drone/drone/store" | ||||
|  | ||||
| 	"github.com/gin-gonic/gin" | ||||
| ) | ||||
|  | ||||
| func GetGlobalSecrets(c *gin.Context) { | ||||
| 	secrets, err := store.GetGlobalSecretList(c) | ||||
|  | ||||
| // GetSecret gets the named secret from the database and writes | ||||
| // to the response in json format. | ||||
| func GetSecret(c *gin.Context) { | ||||
| 	var ( | ||||
| 		repo = session.Repo(c) | ||||
| 		name = c.Param("secret") | ||||
| 	) | ||||
| 	secret, err := Config.Services.Secrets.SecretFind(repo, name) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithStatus(http.StatusInternalServerError) | ||||
| 		c.String(404, "Error getting secret %q. %s", name, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	var list []*model.TeamSecret | ||||
|  | ||||
| 	for _, s := range secrets { | ||||
| 		list = append(list, s.Clone()) | ||||
| 	} | ||||
|  | ||||
| 	c.JSON(http.StatusOK, list) | ||||
| } | ||||
|  | ||||
| func PostGlobalSecret(c *gin.Context) { | ||||
| 	in := &model.TeamSecret{} | ||||
| 	err := c.Bind(in) | ||||
| 	if err != nil { | ||||
| 		c.String(http.StatusBadRequest, "Invalid JSON input. %s", err.Error()) | ||||
| 		return | ||||
| 	} | ||||
| 	in.ID = 0 | ||||
|  | ||||
| 	err = store.SetGlobalSecret(c, in) | ||||
| 	if err != nil { | ||||
| 		c.String(http.StatusInternalServerError, "Unable to persist global secret. %s", err.Error()) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	c.String(http.StatusOK, "") | ||||
| } | ||||
|  | ||||
| func DeleteGlobalSecret(c *gin.Context) { | ||||
| 	name := c.Param("secret") | ||||
|  | ||||
| 	secret, err := store.GetGlobalSecret(c, name) | ||||
| 	if err != nil { | ||||
| 		c.String(http.StatusNotFound, "Cannot find secret %s.", name) | ||||
| 		return | ||||
| 	} | ||||
| 	err = store.DeleteGlobalSecret(c, secret) | ||||
| 	if err != nil { | ||||
| 		c.String(http.StatusInternalServerError, "Unable to delete global secret. %s", err.Error()) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	c.String(http.StatusOK, "") | ||||
| } | ||||
|  | ||||
| func GetSecrets(c *gin.Context) { | ||||
| 	repo := session.Repo(c) | ||||
| 	secrets, err := store.GetSecretList(c, repo) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		c.AbortWithStatus(http.StatusInternalServerError) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	var list []*model.RepoSecret | ||||
|  | ||||
| 	for _, s := range secrets { | ||||
| 		list = append(list, s.Clone()) | ||||
| 	} | ||||
|  | ||||
| 	c.JSON(http.StatusOK, list) | ||||
| 	c.JSON(200, secret.Copy()) | ||||
| } | ||||
|  | ||||
| // PostSecret persists the secret to the database. | ||||
| func PostSecret(c *gin.Context) { | ||||
| 	repo := session.Repo(c) | ||||
|  | ||||
| 	in := &model.RepoSecret{} | ||||
| 	err := c.Bind(in) | ||||
| 	if err != nil { | ||||
| 		c.String(http.StatusBadRequest, "Invalid JSON input. %s", err.Error()) | ||||
| 	in := new(model.Secret) | ||||
| 	if err := c.Bind(in); err != nil { | ||||
| 		c.String(http.StatusBadRequest, "Error parsing secret. %s", err) | ||||
| 		return | ||||
| 	} | ||||
| 	in.ID = 0 | ||||
| 	in.RepoID = repo.ID | ||||
|  | ||||
| 	err = store.SetSecret(c, in) | ||||
| 	if err != nil { | ||||
| 		c.String(http.StatusInternalServerError, "Unable to persist secret. %s", err.Error()) | ||||
| 	secret := &model.Secret{ | ||||
| 		RepoID: repo.ID, | ||||
| 		Name:   in.Name, | ||||
| 		Value:  in.Value, | ||||
| 		Events: in.Events, | ||||
| 		Images: in.Images, | ||||
| 	} | ||||
| 	if err := secret.Validate(); err != nil { | ||||
| 		c.String(400, "Error inserting secret. %s", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	c.String(http.StatusOK, "") | ||||
| 	if err := Config.Services.Secrets.SecretCreate(repo, secret); err != nil { | ||||
| 		c.String(500, "Error inserting secret %q. %s", in.Name, err) | ||||
| 		return | ||||
| 	} | ||||
| 	c.JSON(200, secret.Copy()) | ||||
| } | ||||
|  | ||||
| func DeleteSecret(c *gin.Context) { | ||||
| // PatchSecret updates the secret in the database. | ||||
| func PatchSecret(c *gin.Context) { | ||||
| 	var ( | ||||
| 		repo = session.Repo(c) | ||||
| 		name = c.Param("secret") | ||||
| 	) | ||||
|  | ||||
| 	in := new(model.Secret) | ||||
| 	err := c.Bind(in) | ||||
| 	if err != nil { | ||||
| 		c.String(http.StatusBadRequest, "Error parsing secret. %s", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	secret, err := Config.Services.Secrets.SecretFind(repo, name) | ||||
| 	if err != nil { | ||||
| 		c.String(404, "Error getting secret %q. %s", name, err) | ||||
| 		return | ||||
| 	} | ||||
| 	if in.Value != "" { | ||||
| 		secret.Value = in.Value | ||||
| 	} | ||||
| 	if len(in.Events) != 0 { | ||||
| 		secret.Events = in.Events | ||||
| 	} | ||||
| 	if len(in.Images) != 0 { | ||||
| 		secret.Images = in.Images | ||||
| 	} | ||||
|  | ||||
| 	if err := secret.Validate(); err != nil { | ||||
| 		c.String(400, "Error updating secret. %s", err) | ||||
| 		return | ||||
| 	} | ||||
| 	if err := Config.Services.Secrets.SecretUpdate(repo, secret); err != nil { | ||||
| 		c.String(500, "Error updating secret %q. %s", in.Name, err) | ||||
| 		return | ||||
| 	} | ||||
| 	c.JSON(200, secret.Copy()) | ||||
| } | ||||
|  | ||||
| // GetSecretList gets the secret list from the database and writes | ||||
| // to the response in json format. | ||||
| func GetSecretList(c *gin.Context) { | ||||
| 	repo := session.Repo(c) | ||||
| 	name := c.Param("secret") | ||||
|  | ||||
| 	secret, err := store.GetSecret(c, repo, name) | ||||
| 	list, err := Config.Services.Secrets.SecretList(repo) | ||||
| 	if err != nil { | ||||
| 		c.String(http.StatusNotFound, "Cannot find secret %s.", name) | ||||
| 		c.String(500, "Error getting secret list. %s", err) | ||||
| 		return | ||||
| 	} | ||||
| 	err = store.DeleteSecret(c, secret) | ||||
| 	if err != nil { | ||||
| 		c.String(http.StatusInternalServerError, "Unable to delete secret. %s", err.Error()) | ||||
| 		return | ||||
| 	// copy the secret detail to remove the sensitive | ||||
| 	// password and token fields. | ||||
| 	for i, secret := range list { | ||||
| 		list[i] = secret.Copy() | ||||
| 	} | ||||
|  | ||||
| 	c.String(http.StatusOK, "") | ||||
| 	c.JSON(200, list) | ||||
| } | ||||
|  | ||||
| func GetTeamSecrets(c *gin.Context) { | ||||
| 	team := c.Param("team") | ||||
| 	secrets, err := store.GetTeamSecretList(c, team) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		c.AbortWithStatus(http.StatusInternalServerError) | ||||
| // DeleteSecret deletes the named secret from the database. | ||||
| func DeleteSecret(c *gin.Context) { | ||||
| 	var ( | ||||
| 		repo = session.Repo(c) | ||||
| 		name = c.Param("secret") | ||||
| 	) | ||||
| 	if err := Config.Services.Secrets.SecretDelete(repo, name); err != nil { | ||||
| 		c.String(500, "Error deleting secret %q. %s", name, err) | ||||
| 		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, "") | ||||
| 	c.String(204, "") | ||||
| } | ||||
|   | ||||
| @@ -102,7 +102,7 @@ func LogStream(c *gin.Context) { | ||||
|  | ||||
| 	go func() { | ||||
| 		// TODO remove global variable | ||||
| 		config.logger.Tail(ctx, fmt.Sprint(proc.ID), func(entries ...*logging.Entry) { | ||||
| 		Config.Services.Logs.Tail(ctx, fmt.Sprint(proc.ID), func(entries ...*logging.Entry) { | ||||
| 			for _, entry := range entries { | ||||
| 				select { | ||||
| 				case <-ctx.Done(): | ||||
| @@ -167,7 +167,7 @@ func EventStream(c *gin.Context) { | ||||
|  | ||||
| 	go func() { | ||||
| 		// TODO remove this from global config | ||||
| 		config.pubsub.Subscribe(c, "topic/events", func(m pubsub.Message) { | ||||
| 		Config.Services.Pubsub.Subscribe(c, "topic/events", func(m pubsub.Message) { | ||||
| 			name := m.Labels["repo"] | ||||
| 			priv := m.Labels["private"] | ||||
| 			if repo[name] || priv == "false" { | ||||
|   | ||||
							
								
								
									
										22
									
								
								store/datastore/ddl/mysql/14.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								store/datastore/ddl/mysql/14.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| -- +migrate Up | ||||
|  | ||||
| ALTER TABLE repos ADD COLUMN repo_gated BOOLEAN; | ||||
| UPDATE repos SET repo_gated = false; | ||||
|  | ||||
| CREATE TABLE senders ( | ||||
|  sender_id      INTEGER PRIMARY KEY AUTO_INCREMENT | ||||
| ,sender_repo_id INTEGER | ||||
| ,sender_login   VARCHAR(250) | ||||
| ,sender_allow   BOOLEAN | ||||
| ,sender_block   BOOLEAN | ||||
|  | ||||
| ,UNIQUE(sender_repo_id,sender_login) | ||||
| ); | ||||
|  | ||||
| CREATE INDEX sender_repo_ix ON senders (sender_repo_id); | ||||
|  | ||||
| -- +migrate Down | ||||
|  | ||||
| ALTER TABLE repos DROP COLUMN repo_gated; | ||||
| DROP INDEX sender_repo_ix; | ||||
| DROP TABLE senders; | ||||
							
								
								
									
										22
									
								
								store/datastore/ddl/postgres/14.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								store/datastore/ddl/postgres/14.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| -- +migrate Up | ||||
|  | ||||
| ALTER TABLE repos ADD COLUMN repo_gated BOOLEAN; | ||||
| UPDATE repos SET repo_gated = false; | ||||
|  | ||||
| CREATE TABLE senders ( | ||||
|  sender_id      SERIAL PRIMARY KEY | ||||
| ,sender_repo_id INTEGER | ||||
| ,sender_login   VARCHAR(250) | ||||
| ,sender_allow   BOOLEAN | ||||
| ,sender_block   BOOLEAN | ||||
|  | ||||
| ,UNIQUE(sender_repo_id,sender_login) | ||||
| ); | ||||
|  | ||||
| CREATE INDEX sender_repo_ix ON senders (sender_repo_id); | ||||
|  | ||||
| -- +migrate Down | ||||
|  | ||||
| ALTER TABLE repos DROP COLUMN repo_gated; | ||||
| DROP INDEX sender_repo_ix; | ||||
| DROP TABLE senders; | ||||
							
								
								
									
										22
									
								
								store/datastore/ddl/sqlite3/14.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								store/datastore/ddl/sqlite3/14.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| -- +migrate Up | ||||
|  | ||||
| ALTER TABLE repos ADD COLUMN repo_gated BOOLEAN; | ||||
| UPDATE repos SET repo_gated = 0; | ||||
|  | ||||
| CREATE TABLE senders ( | ||||
|  sender_id      INTEGER PRIMARY KEY AUTOINCREMENT | ||||
| ,sender_repo_id INTEGER | ||||
| ,sender_login   BOOLEAN | ||||
| ,sender_allow   BOOLEAN | ||||
| ,sender_block   BOOLEAN | ||||
|  | ||||
| ,UNIQUE(sender_repo_id,sender_login) | ||||
| ); | ||||
|  | ||||
| CREATE INDEX sender_repo_ix ON senders (sender_repo_id); | ||||
|  | ||||
| -- +migrate Down | ||||
|  | ||||
| ALTER TABLE repos DROP COLUMN repo_gated; | ||||
| DROP INDEX sender_repo_ix; | ||||
| DROP TABLE senders; | ||||
| @@ -1,53 +0,0 @@ | ||||
| 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 = ? | ||||
| ` | ||||
| @@ -1,98 +0,0 @@ | ||||
| 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"}, | ||||
| 				SkipVerify: true, | ||||
| 				Conceal:    true, | ||||
| 			} | ||||
| 			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.Assert(got.SkipVerify).Equal(secret.SkipVerify) | ||||
| 			g.Assert(got.Conceal).Equal(secret.Conceal) | ||||
| 		}) | ||||
|  | ||||
| 		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") | ||||
| 		}) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										35
									
								
								store/datastore/secret.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								store/datastore/secret.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| package datastore | ||||
|  | ||||
| import ( | ||||
| 	"github.com/drone/drone/model" | ||||
| 	"github.com/drone/drone/store/datastore/sql" | ||||
| 	"github.com/russross/meddler" | ||||
| ) | ||||
|  | ||||
| func (db *datastore) SecretFind(repo *model.Repo, name string) (*model.Secret, error) { | ||||
| 	stmt := sql.Lookup(db.driver, "secret-find-repo-name") | ||||
| 	data := new(model.Secret) | ||||
| 	err := meddler.QueryRow(db, data, stmt, repo.ID, name) | ||||
| 	return data, err | ||||
| } | ||||
|  | ||||
| func (db *datastore) SecretList(repo *model.Repo) ([]*model.Secret, error) { | ||||
| 	stmt := sql.Lookup(db.driver, "secret-find-repo") | ||||
| 	data := []*model.Secret{} | ||||
| 	err := meddler.QueryAll(db, &data, stmt, repo.ID) | ||||
| 	return data, err | ||||
| } | ||||
|  | ||||
| func (db *datastore) SecretCreate(secret *model.Secret) error { | ||||
| 	return meddler.Insert(db, "secrets", secret) | ||||
| } | ||||
|  | ||||
| func (db *datastore) SecretUpdate(secret *model.Secret) error { | ||||
| 	return meddler.Update(db, "secrets", secret) | ||||
| } | ||||
|  | ||||
| func (db *datastore) SecretDelete(secret *model.Secret) error { | ||||
| 	stmt := sql.Lookup(db.driver, "secret-delete") | ||||
| 	_, err := db.Exec(stmt, secret.ID) | ||||
| 	return err | ||||
| } | ||||
							
								
								
									
										139
									
								
								store/datastore/secret_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								store/datastore/secret_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | ||||
| package datastore | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/drone/drone/model" | ||||
| ) | ||||
|  | ||||
| func TestSecretFind(t *testing.T) { | ||||
| 	s := newTest() | ||||
| 	defer func() { | ||||
| 		s.Exec("delete from secrets") | ||||
| 		s.Close() | ||||
| 	}() | ||||
|  | ||||
| 	err := s.SecretCreate(&model.Secret{ | ||||
| 		RepoID: 1, | ||||
| 		Name:   "password", | ||||
| 		Value:  "correct-horse-battery-staple", | ||||
| 		Images: []string{"golang", "node"}, | ||||
| 		Events: []string{"push", "tag"}, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Unexpected error: insert secret: %s", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	secret, err := s.SecretFind(&model.Repo{ID: 1}, "password") | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 		return | ||||
| 	} | ||||
| 	if got, want := secret.RepoID, int64(1); got != want { | ||||
| 		t.Errorf("Want repo id %d, got %d", want, got) | ||||
| 	} | ||||
| 	if got, want := secret.Name, "password"; got != want { | ||||
| 		t.Errorf("Want secret name %s, got %s", want, got) | ||||
| 	} | ||||
| 	if got, want := secret.Value, "correct-horse-battery-staple"; got != want { | ||||
| 		t.Errorf("Want secret value %s, got %s", want, got) | ||||
| 	} | ||||
| 	if got, want := secret.Events[0], "push"; got != want { | ||||
| 		t.Errorf("Want secret event %s, got %s", want, got) | ||||
| 	} | ||||
| 	if got, want := secret.Events[1], "tag"; got != want { | ||||
| 		t.Errorf("Want secret event %s, got %s", want, got) | ||||
| 	} | ||||
| 	if got, want := secret.Images[0], "golang"; got != want { | ||||
| 		t.Errorf("Want secret image %s, got %s", want, got) | ||||
| 	} | ||||
| 	if got, want := secret.Images[1], "node"; got != want { | ||||
| 		t.Errorf("Want secret image %s, got %s", want, got) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSecretList(t *testing.T) { | ||||
| 	s := newTest() | ||||
| 	defer func() { | ||||
| 		s.Exec("delete from secrets") | ||||
| 		s.Close() | ||||
| 	}() | ||||
|  | ||||
| 	s.SecretCreate(&model.Secret{ | ||||
| 		RepoID: 1, | ||||
| 		Name:   "foo", | ||||
| 		Value:  "bar", | ||||
| 	}) | ||||
| 	s.SecretCreate(&model.Secret{ | ||||
| 		RepoID: 1, | ||||
| 		Name:   "baz", | ||||
| 		Value:  "qux", | ||||
| 	}) | ||||
|  | ||||
| 	list, err := s.SecretList(&model.Repo{ID: 1}) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 		return | ||||
| 	} | ||||
| 	if got, want := len(list), 2; got != want { | ||||
| 		t.Errorf("Want %d registries, got %d", want, got) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSecretUpdate(t *testing.T) { | ||||
| 	s := newTest() | ||||
| 	defer func() { | ||||
| 		s.Exec("delete from secrets") | ||||
| 		s.Close() | ||||
| 	}() | ||||
|  | ||||
| 	secret := &model.Secret{ | ||||
| 		RepoID: 1, | ||||
| 		Name:   "foo", | ||||
| 		Value:  "baz", | ||||
| 	} | ||||
| 	if err := s.SecretCreate(secret); err != nil { | ||||
| 		t.Errorf("Unexpected error: insert secret: %s", err) | ||||
| 		return | ||||
| 	} | ||||
| 	secret.Value = "qux" | ||||
| 	if err := s.SecretUpdate(secret); err != nil { | ||||
| 		t.Errorf("Unexpected error: update secret: %s", err) | ||||
| 		return | ||||
| 	} | ||||
| 	updated, err := s.SecretFind(&model.Repo{ID: 1}, "foo") | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 		return | ||||
| 	} | ||||
| 	if got, want := updated.Value, "qux"; got != want { | ||||
| 		t.Errorf("Want secret value %s, got %s", want, got) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSecretIndexes(t *testing.T) { | ||||
| 	s := newTest() | ||||
| 	defer func() { | ||||
| 		s.Exec("delete from secrets") | ||||
| 		s.Close() | ||||
| 	}() | ||||
|  | ||||
| 	if err := s.SecretCreate(&model.Secret{ | ||||
| 		RepoID: 1, | ||||
| 		Name:   "foo", | ||||
| 		Value:  "bar", | ||||
| 	}); err != nil { | ||||
| 		t.Errorf("Unexpected error: insert secret: %s", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// fail due to duplicate name | ||||
| 	if err := s.SecretCreate(&model.Secret{ | ||||
| 		RepoID: 1, | ||||
| 		Name:   "foo", | ||||
| 		Value:  "baz", | ||||
| 	}); err == nil { | ||||
| 		t.Errorf("Unexpected error: dupliate name") | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										35
									
								
								store/datastore/sender.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								store/datastore/sender.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| package datastore | ||||
|  | ||||
| import ( | ||||
| 	"github.com/drone/drone/model" | ||||
| 	"github.com/drone/drone/store/datastore/sql" | ||||
| 	"github.com/russross/meddler" | ||||
| ) | ||||
|  | ||||
| func (db *datastore) SenderFind(repo *model.Repo, login string) (*model.Sender, error) { | ||||
| 	stmt := sql.Lookup(db.driver, "sender-find-repo-login") | ||||
| 	data := new(model.Sender) | ||||
| 	err := meddler.QueryRow(db, data, stmt, repo.ID, login) | ||||
| 	return data, err | ||||
| } | ||||
|  | ||||
| func (db *datastore) SenderList(repo *model.Repo) ([]*model.Sender, error) { | ||||
| 	stmt := sql.Lookup(db.driver, "sender-find-repo") | ||||
| 	data := []*model.Sender{} | ||||
| 	err := meddler.QueryAll(db, &data, stmt, repo.ID) | ||||
| 	return data, err | ||||
| } | ||||
|  | ||||
| func (db *datastore) SenderCreate(sender *model.Sender) error { | ||||
| 	return meddler.Insert(db, "senders", sender) | ||||
| } | ||||
|  | ||||
| func (db *datastore) SenderUpdate(sender *model.Sender) error { | ||||
| 	return meddler.Update(db, "senders", sender) | ||||
| } | ||||
|  | ||||
| func (db *datastore) SenderDelete(sender *model.Sender) error { | ||||
| 	stmt := sql.Lookup(db.driver, "sender-delete") | ||||
| 	_, err := db.Exec(stmt, sender.ID) | ||||
| 	return err | ||||
| } | ||||
							
								
								
									
										131
									
								
								store/datastore/sender_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								store/datastore/sender_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,131 @@ | ||||
| package datastore | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/drone/drone/model" | ||||
| ) | ||||
|  | ||||
| func TestSenderFind(t *testing.T) { | ||||
| 	s := newTest() | ||||
| 	defer func() { | ||||
| 		s.Exec("delete from senders") | ||||
| 		s.Close() | ||||
| 	}() | ||||
|  | ||||
| 	err := s.SenderCreate(&model.Sender{ | ||||
| 		RepoID: 1, | ||||
| 		Login:  "octocat", | ||||
| 		Allow:  true, | ||||
| 		Block:  false, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Unexpected error: insert secret: %s", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	sender, err := s.SenderFind(&model.Repo{ID: 1}, "octocat") | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 		return | ||||
| 	} | ||||
| 	if got, want := sender.RepoID, int64(1); got != want { | ||||
| 		t.Errorf("Want repo id %d, got %d", want, got) | ||||
| 	} | ||||
| 	if got, want := sender.Login, "octocat"; got != want { | ||||
| 		t.Errorf("Want sender login %s, got %s", want, got) | ||||
| 	} | ||||
| 	if got, want := sender.Allow, true; got != want { | ||||
| 		t.Errorf("Want sender allow %v, got %v", want, got) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSenderList(t *testing.T) { | ||||
| 	s := newTest() | ||||
| 	defer func() { | ||||
| 		s.Exec("delete from senders") | ||||
| 		s.Close() | ||||
| 	}() | ||||
|  | ||||
| 	s.SenderCreate(&model.Sender{ | ||||
| 		RepoID: 1, | ||||
| 		Login:  "octocat", | ||||
| 		Allow:  true, | ||||
| 		Block:  false, | ||||
| 	}) | ||||
| 	s.SenderCreate(&model.Sender{ | ||||
| 		RepoID: 1, | ||||
| 		Login:  "defunkt", | ||||
| 		Allow:  true, | ||||
| 		Block:  false, | ||||
| 	}) | ||||
|  | ||||
| 	list, err := s.SenderList(&model.Repo{ID: 1}) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 		return | ||||
| 	} | ||||
| 	if got, want := len(list), 2; got != want { | ||||
| 		t.Errorf("Want %d senders, got %d", want, got) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSenderUpdate(t *testing.T) { | ||||
| 	s := newTest() | ||||
| 	defer func() { | ||||
| 		s.Exec("delete from senders") | ||||
| 		s.Close() | ||||
| 	}() | ||||
|  | ||||
| 	sender := &model.Sender{ | ||||
| 		RepoID: 1, | ||||
| 		Login:  "octocat", | ||||
| 		Allow:  true, | ||||
| 		Block:  false, | ||||
| 	} | ||||
| 	if err := s.SenderCreate(sender); err != nil { | ||||
| 		t.Errorf("Unexpected error: insert sender: %s", err) | ||||
| 		return | ||||
| 	} | ||||
| 	sender.Allow = false | ||||
| 	if err := s.SenderUpdate(sender); err != nil { | ||||
| 		t.Errorf("Unexpected error: update sender: %s", err) | ||||
| 		return | ||||
| 	} | ||||
| 	updated, err := s.SenderFind(&model.Repo{ID: 1}, "octocat") | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 		return | ||||
| 	} | ||||
| 	if got, want := updated.Allow, false; got != want { | ||||
| 		t.Errorf("Want allow value %v, got %v", want, got) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSenderIndexes(t *testing.T) { | ||||
| 	s := newTest() | ||||
| 	defer func() { | ||||
| 		s.Exec("delete from senders") | ||||
| 		s.Close() | ||||
| 	}() | ||||
|  | ||||
| 	if err := s.SenderCreate(&model.Sender{ | ||||
| 		RepoID: 1, | ||||
| 		Login:  "octocat", | ||||
| 		Allow:  true, | ||||
| 		Block:  false, | ||||
| 	}); err != nil { | ||||
| 		t.Errorf("Unexpected error: insert sender: %s", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// fail due to duplicate name | ||||
| 	if err := s.SenderCreate(&model.Sender{ | ||||
| 		RepoID: 1, | ||||
| 		Login:  "octocat", | ||||
| 		Allow:  true, | ||||
| 		Block:  false, | ||||
| 	}); err == nil { | ||||
| 		t.Errorf("Unexpected error: dupliate login") | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										32
									
								
								store/datastore/sql/postgres/files/secret.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								store/datastore/sql/postgres/files/secret.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| -- name: secret-find-repo | ||||
|  | ||||
| SELECT | ||||
|  secret_id | ||||
| ,secret_repo_id | ||||
| ,secret_name | ||||
| ,secret_value | ||||
| ,secret_images | ||||
| ,secret_events | ||||
| ,secret_conceal | ||||
| ,secret_skip_verify | ||||
| FROM secrets | ||||
| WHERE secret_repo_id = $1 | ||||
|  | ||||
| -- name: secret-find-repo-name | ||||
|  | ||||
| SELECT | ||||
| secret_id | ||||
| ,secret_repo_id | ||||
| ,secret_name | ||||
| ,secret_value | ||||
| ,secret_images | ||||
| ,secret_events | ||||
| ,secret_conceal | ||||
| ,secret_skip_verify | ||||
| FROM secrets | ||||
| WHERE secret_repo_id = $1 | ||||
|   AND secret_name = $2 | ||||
|  | ||||
| -- name: secret-delete | ||||
|  | ||||
| DELETE FROM secrets WHERE secret_id = $1 | ||||
							
								
								
									
										30
									
								
								store/datastore/sql/postgres/files/sender.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								store/datastore/sql/postgres/files/sender.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| -- name: sender-find-repo | ||||
|  | ||||
| SELECT | ||||
|  sender_id | ||||
| ,sender_repo_id | ||||
| ,sender_login | ||||
| ,sender_allow | ||||
| ,sender_block | ||||
| FROM senders | ||||
| WHERE sender_repo_id = $1 | ||||
|  | ||||
| -- name: sender-find-repo-login | ||||
|  | ||||
| SELECT | ||||
|  sender_id | ||||
| ,sender_repo_id | ||||
| ,sender_login | ||||
| ,sender_allow | ||||
| ,sender_block | ||||
| FROM senders | ||||
| WHERE sender_repo_id = $1 | ||||
|   AND sender_login = $2 | ||||
|  | ||||
| -- name: sender-delete-repo | ||||
|  | ||||
| DELETE FROM senders WHERE sender_repo_id = $1 | ||||
|  | ||||
| -- name: sender-delete | ||||
|  | ||||
| DELETE FROM senders WHERE sender_id = $1 | ||||
| @@ -19,6 +19,13 @@ var index = map[string]string{ | ||||
| 	"registry-find-repo-addr":   registryFindRepoAddr, | ||||
| 	"registry-delete-repo":      registryDeleteRepo, | ||||
| 	"registry-delete":           registryDelete, | ||||
| 	"secret-find-repo":          secretFindRepo, | ||||
| 	"secret-find-repo-name":     secretFindRepoName, | ||||
| 	"secret-delete":             secretDelete, | ||||
| 	"sender-find-repo":          senderFindRepo, | ||||
| 	"sender-find-repo-login":    senderFindRepoLogin, | ||||
| 	"sender-delete-repo":        senderDeleteRepo, | ||||
| 	"sender-delete":             senderDelete, | ||||
| } | ||||
|  | ||||
| var filesFindBuild = ` | ||||
| @@ -188,3 +195,67 @@ DELETE FROM registry WHERE registry_repo_id = $1 | ||||
| var registryDelete = ` | ||||
| DELETE FROM registry WHERE registry_id = $1 | ||||
| ` | ||||
|  | ||||
| var secretFindRepo = ` | ||||
| SELECT | ||||
|  secret_id | ||||
| ,secret_repo_id | ||||
| ,secret_name | ||||
| ,secret_value | ||||
| ,secret_images | ||||
| ,secret_events | ||||
| ,secret_conceal | ||||
| ,secret_skip_verify | ||||
| FROM secrets | ||||
| WHERE secret_repo_id = $1 | ||||
| ` | ||||
|  | ||||
| var secretFindRepoName = ` | ||||
| SELECT | ||||
| secret_id | ||||
| ,secret_repo_id | ||||
| ,secret_name | ||||
| ,secret_value | ||||
| ,secret_images | ||||
| ,secret_events | ||||
| ,secret_conceal | ||||
| ,secret_skip_verify | ||||
| FROM secrets | ||||
| WHERE secret_repo_id = $1 | ||||
|   AND secret_name = $2 | ||||
| ` | ||||
|  | ||||
| var secretDelete = ` | ||||
| DELETE FROM secrets WHERE secret_id = $1 | ||||
| ` | ||||
|  | ||||
| var senderFindRepo = ` | ||||
| SELECT | ||||
|  sender_id | ||||
| ,sender_repo_id | ||||
| ,sender_login | ||||
| ,sender_allow | ||||
| ,sender_block | ||||
| FROM senders | ||||
| WHERE sender_repo_id = $1 | ||||
| ` | ||||
|  | ||||
| var senderFindRepoLogin = ` | ||||
| SELECT | ||||
|  sender_id | ||||
| ,sender_repo_id | ||||
| ,sender_login | ||||
| ,sender_allow | ||||
| ,sender_block | ||||
| FROM senders | ||||
| WHERE sender_repo_id = $1 | ||||
|   AND sender_login = $2 | ||||
| ` | ||||
|  | ||||
| var senderDeleteRepo = ` | ||||
| DELETE FROM senders WHERE sender_repo_id = $1 | ||||
| ` | ||||
|  | ||||
| var senderDelete = ` | ||||
| DELETE FROM senders WHERE sender_id = $1 | ||||
| ` | ||||
|   | ||||
							
								
								
									
										32
									
								
								store/datastore/sql/sqlite/files/secret.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								store/datastore/sql/sqlite/files/secret.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| -- name: secret-find-repo | ||||
|  | ||||
| SELECT | ||||
|  secret_id | ||||
| ,secret_repo_id | ||||
| ,secret_name | ||||
| ,secret_value | ||||
| ,secret_images | ||||
| ,secret_events | ||||
| ,secret_conceal | ||||
| ,secret_skip_verify | ||||
| FROM secrets | ||||
| WHERE secret_repo_id = ? | ||||
|  | ||||
| -- name: secret-find-repo-name | ||||
|  | ||||
| SELECT | ||||
| secret_id | ||||
| ,secret_repo_id | ||||
| ,secret_name | ||||
| ,secret_value | ||||
| ,secret_images | ||||
| ,secret_events | ||||
| ,secret_conceal | ||||
| ,secret_skip_verify | ||||
| FROM secrets | ||||
| WHERE secret_repo_id = ? | ||||
|   AND secret_name = ? | ||||
|  | ||||
| -- name: secret-delete | ||||
|  | ||||
| DELETE FROM secrets WHERE secret_id = ? | ||||
							
								
								
									
										30
									
								
								store/datastore/sql/sqlite/files/sender.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								store/datastore/sql/sqlite/files/sender.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| -- name: sender-find-repo | ||||
|  | ||||
| SELECT | ||||
|  sender_id | ||||
| ,sender_repo_id | ||||
| ,sender_login | ||||
| ,sender_allow | ||||
| ,sender_block | ||||
| FROM senders | ||||
| WHERE sender_repo_id = ? | ||||
|  | ||||
| -- name: sender-find-repo-login | ||||
|  | ||||
| SELECT | ||||
|  sender_id | ||||
| ,sender_repo_id | ||||
| ,sender_login | ||||
| ,sender_allow | ||||
| ,sender_block | ||||
| FROM senders | ||||
| WHERE sender_repo_id = ? | ||||
|   AND sender_login = ? | ||||
|  | ||||
| -- name: sender-delete-repo | ||||
|  | ||||
| DELETE FROM senders WHERE sender_repo_id = ? | ||||
|  | ||||
| -- name: sender-delete | ||||
|  | ||||
| DELETE FROM senders WHERE sender_id = ? | ||||
| @@ -19,6 +19,13 @@ var index = map[string]string{ | ||||
| 	"registry-find-repo-addr":   registryFindRepoAddr, | ||||
| 	"registry-delete-repo":      registryDeleteRepo, | ||||
| 	"registry-delete":           registryDelete, | ||||
| 	"secret-find-repo":          secretFindRepo, | ||||
| 	"secret-find-repo-name":     secretFindRepoName, | ||||
| 	"secret-delete":             secretDelete, | ||||
| 	"sender-find-repo":          senderFindRepo, | ||||
| 	"sender-find-repo-login":    senderFindRepoLogin, | ||||
| 	"sender-delete-repo":        senderDeleteRepo, | ||||
| 	"sender-delete":             senderDelete, | ||||
| } | ||||
|  | ||||
| var filesFindBuild = ` | ||||
| @@ -188,3 +195,67 @@ DELETE FROM registry WHERE registry_repo_id = ? | ||||
| var registryDelete = ` | ||||
| DELETE FROM registry WHERE registry_id = ? | ||||
| ` | ||||
|  | ||||
| var secretFindRepo = ` | ||||
| SELECT | ||||
|  secret_id | ||||
| ,secret_repo_id | ||||
| ,secret_name | ||||
| ,secret_value | ||||
| ,secret_images | ||||
| ,secret_events | ||||
| ,secret_conceal | ||||
| ,secret_skip_verify | ||||
| FROM secrets | ||||
| WHERE secret_repo_id = ? | ||||
| ` | ||||
|  | ||||
| var secretFindRepoName = ` | ||||
| SELECT | ||||
| secret_id | ||||
| ,secret_repo_id | ||||
| ,secret_name | ||||
| ,secret_value | ||||
| ,secret_images | ||||
| ,secret_events | ||||
| ,secret_conceal | ||||
| ,secret_skip_verify | ||||
| FROM secrets | ||||
| WHERE secret_repo_id = ? | ||||
|   AND secret_name = ? | ||||
| ` | ||||
|  | ||||
| var secretDelete = ` | ||||
| DELETE FROM secrets WHERE secret_id = ? | ||||
| ` | ||||
|  | ||||
| var senderFindRepo = ` | ||||
| SELECT | ||||
|  sender_id | ||||
| ,sender_repo_id | ||||
| ,sender_login | ||||
| ,sender_allow | ||||
| ,sender_block | ||||
| FROM senders | ||||
| WHERE sender_repo_id = ? | ||||
| ` | ||||
|  | ||||
| var senderFindRepoLogin = ` | ||||
| SELECT | ||||
|  sender_id | ||||
| ,sender_repo_id | ||||
| ,sender_login | ||||
| ,sender_allow | ||||
| ,sender_block | ||||
| FROM senders | ||||
| WHERE sender_repo_id = ? | ||||
|   AND sender_login = ? | ||||
| ` | ||||
|  | ||||
| var senderDeleteRepo = ` | ||||
| DELETE FROM senders WHERE sender_repo_id = ? | ||||
| ` | ||||
|  | ||||
| var senderDelete = ` | ||||
| DELETE FROM senders WHERE sender_id = ? | ||||
| ` | ||||
|   | ||||
| @@ -1,53 +0,0 @@ | ||||
| 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 = ? | ||||
| ` | ||||
| @@ -1,98 +0,0 @@ | ||||
| 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"}, | ||||
| 				SkipVerify: true, | ||||
| 				Conceal:    true, | ||||
| 			} | ||||
| 			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.Assert(got.SkipVerify).Equal(secret.SkipVerify) | ||||
| 			g.Assert(got.Conceal).Equal(secret.Conceal) | ||||
| 		}) | ||||
|  | ||||
| 		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") | ||||
| 		}) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										207
									
								
								store/store.go
									
									
									
									
									
								
							
							
						
						
									
										207
									
								
								store/store.go
									
									
									
									
									
								
							| @@ -58,30 +58,6 @@ type Store interface { | ||||
| 	// DeleteRepo deletes a user repository. | ||||
| 	DeleteRepo(*model.Repo) error | ||||
|  | ||||
| 	// GetSecretList gets a list of repository secrets | ||||
| 	GetSecretList(*model.Repo) ([]*model.RepoSecret, error) | ||||
|  | ||||
| 	// GetSecret gets the named repository secret. | ||||
| 	GetSecret(*model.Repo, string) (*model.RepoSecret, error) | ||||
|  | ||||
| 	// SetSecret sets the named repository secret. | ||||
| 	SetSecret(*model.RepoSecret) error | ||||
|  | ||||
| 	// DeleteSecret deletes the named repository secret. | ||||
| 	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 | ||||
|  | ||||
| 	// GetBuild gets a build by unique ID. | ||||
| 	GetBuild(int64) (*model.Build, error) | ||||
|  | ||||
| @@ -112,38 +88,21 @@ type Store interface { | ||||
| 	// UpdateBuild updates a build. | ||||
| 	UpdateBuild(*model.Build) error | ||||
|  | ||||
| 	// // GetJob gets a job by unique ID. | ||||
| 	// GetJob(int64) (*model.Job, error) | ||||
| 	// | ||||
| 	// // GetJobNumber gets a job by number. | ||||
| 	// GetJobNumber(*model.Build, int) (*model.Job, error) | ||||
| 	// new functions | ||||
| 	// | ||||
| 	// // GetJobList gets a list of all users in the system. | ||||
| 	// GetJobList(*model.Build) ([]*model.Job, error) | ||||
| 	// | ||||
| 	// // CreateJob creates a job. | ||||
| 	// CreateJob(*model.Job) error | ||||
| 	// | ||||
| 	// // UpdateJob updates a job. | ||||
| 	// UpdateJob(*model.Job) error | ||||
| 	// | ||||
| 	// // ReadLog reads the Job logs from the datastore. | ||||
| 	// ReadLog(*model.Job) (io.ReadCloser, error) | ||||
| 	// | ||||
| 	// // WriteLog writes the job logs to the datastore. | ||||
| 	// WriteLog(*model.Job, io.Reader) error | ||||
|  | ||||
| 	// GetAgent(int64) (*model.Agent, error) | ||||
| 	// | ||||
| 	// GetAgentAddr(string) (*model.Agent, error) | ||||
| 	// | ||||
| 	// GetAgentList() ([]*model.Agent, error) | ||||
| 	// | ||||
| 	// CreateAgent(*model.Agent) error | ||||
| 	// | ||||
| 	// UpdateAgent(*model.Agent) error | ||||
| 	// | ||||
| 	// DeleteAgent(*model.Agent) error | ||||
| 	SenderFind(*model.Repo, string) (*model.Sender, error) | ||||
| 	SenderList(*model.Repo) ([]*model.Sender, error) | ||||
| 	SenderCreate(*model.Sender) error | ||||
| 	SenderUpdate(*model.Sender) error | ||||
| 	SenderDelete(*model.Sender) error | ||||
|  | ||||
| 	SecretFind(*model.Repo, string) (*model.Secret, error) | ||||
| 	SecretList(*model.Repo) ([]*model.Secret, error) | ||||
| 	SecretCreate(*model.Secret) error | ||||
| 	SecretUpdate(*model.Secret) error | ||||
| 	SecretDelete(*model.Secret) error | ||||
|  | ||||
| 	RegistryFind(*model.Repo, string) (*model.Registry, error) | ||||
| 	RegistryList(*model.Repo) ([]*model.Registry, error) | ||||
| @@ -168,8 +127,6 @@ type Store interface { | ||||
| 	FileCreate(*model.File, io.Reader) error | ||||
| } | ||||
|  | ||||
| const globalTeamName = "__global__" | ||||
|  | ||||
| // GetUser gets a user by unique ID. | ||||
| func GetUser(c context.Context, id int64) (*model.User, error) { | ||||
| 	return FromContext(c).GetUser(id) | ||||
| @@ -238,94 +195,6 @@ func DeleteRepo(c context.Context, repo *model.Repo) error { | ||||
| 	return FromContext(c).DeleteRepo(repo) | ||||
| } | ||||
|  | ||||
| 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.RepoSecret, error) { | ||||
| 	return FromContext(c).GetSecret(r, name) | ||||
| } | ||||
|  | ||||
| func SetSecret(c context.Context, s *model.RepoSecret) error { | ||||
| 	return FromContext(c).SetSecret(s) | ||||
| } | ||||
|  | ||||
| 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 GetGlobalSecretList(c context.Context) ([]*model.TeamSecret, error) { | ||||
| 	return GetTeamSecretList(c, globalTeamName) | ||||
| } | ||||
|  | ||||
| func GetGlobalSecret(c context.Context, name string) (*model.TeamSecret, error) { | ||||
| 	return GetTeamSecret(c, globalTeamName, name) | ||||
| } | ||||
|  | ||||
| func SetGlobalSecret(c context.Context, s *model.TeamSecret) error { | ||||
| 	s.Key = globalTeamName | ||||
| 	return SetTeamSecret(c, s) | ||||
| } | ||||
|  | ||||
| func DeleteGlobalSecret(c context.Context, s *model.TeamSecret) error { | ||||
| 	s.Key = globalTeamName | ||||
| 	return DeleteTeamSecret(c, s) | ||||
| } | ||||
|  | ||||
| func GetMergedSecretList(c context.Context, r *model.Repo) ([]*model.Secret, error) { | ||||
| 	var ( | ||||
| 		secrets []*model.Secret | ||||
| 	) | ||||
|  | ||||
| 	globalSecs, err := GetGlobalSecretList(c) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	for _, secret := range globalSecs { | ||||
| 		secrets = append(secrets, secret.Secret()) | ||||
| 	} | ||||
|  | ||||
| 	teamSecs, err := GetTeamSecretList(c, r.Owner) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	for _, secret := range teamSecs { | ||||
| 		secrets = append(secrets, secret.Secret()) | ||||
| 	} | ||||
|  | ||||
| 	repoSecs, err := GetSecretList(c, r) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	for _, secret := range repoSecs { | ||||
| 		secrets = append(secrets, secret.Secret()) | ||||
| 	} | ||||
|  | ||||
| 	return secrets, nil | ||||
| } | ||||
|  | ||||
| func GetBuild(c context.Context, id int64) (*model.Build, error) { | ||||
| 	return FromContext(c).GetBuild(id) | ||||
| } | ||||
| @@ -365,55 +234,3 @@ func CreateBuild(c context.Context, build *model.Build, procs ...*model.Proc) er | ||||
| func UpdateBuild(c context.Context, build *model.Build) error { | ||||
| 	return FromContext(c).UpdateBuild(build) | ||||
| } | ||||
|  | ||||
| // func GetJob(c context.Context, id int64) (*model.Job, error) { | ||||
| // 	return FromContext(c).GetJob(id) | ||||
| // } | ||||
| // | ||||
| // func GetJobNumber(c context.Context, build *model.Build, num int) (*model.Job, error) { | ||||
| // 	return FromContext(c).GetJobNumber(build, num) | ||||
| // } | ||||
| // | ||||
| // func GetJobList(c context.Context, build *model.Build) ([]*model.Job, error) { | ||||
| // 	return FromContext(c).GetJobList(build) | ||||
| // } | ||||
| // | ||||
| // func CreateJob(c context.Context, job *model.Job) error { | ||||
| // 	return FromContext(c).CreateJob(job) | ||||
| // } | ||||
| // | ||||
| // func UpdateJob(c context.Context, job *model.Job) error { | ||||
| // 	return FromContext(c).UpdateJob(job) | ||||
| // } | ||||
| // | ||||
| // func ReadLog(c context.Context, job *model.Job) (io.ReadCloser, error) { | ||||
| // 	return FromContext(c).ReadLog(job) | ||||
| // } | ||||
| // | ||||
| // func WriteLog(c context.Context, job *model.Job, r io.Reader) error { | ||||
| // 	return FromContext(c).WriteLog(job, r) | ||||
| // } | ||||
|  | ||||
| // func GetAgent(c context.Context, id int64) (*model.Agent, error) { | ||||
| // 	return FromContext(c).GetAgent(id) | ||||
| // } | ||||
| // | ||||
| // func GetAgentAddr(c context.Context, addr string) (*model.Agent, error) { | ||||
| // 	return FromContext(c).GetAgentAddr(addr) | ||||
| // } | ||||
| // | ||||
| // func GetAgentList(c context.Context) ([]*model.Agent, error) { | ||||
| // 	return FromContext(c).GetAgentList() | ||||
| // } | ||||
| // | ||||
| // func CreateAgent(c context.Context, agent *model.Agent) error { | ||||
| // 	return FromContext(c).CreateAgent(agent) | ||||
| // } | ||||
| // | ||||
| // func UpdateAgent(c context.Context, agent *model.Agent) error { | ||||
| // 	return FromContext(c).UpdateAgent(agent) | ||||
| // } | ||||
| // | ||||
| // func DeleteAgent(c context.Context, agent *model.Agent) error { | ||||
| // 	return FromContext(c).DeleteAgent(agent) | ||||
| // } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user