mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-18 14:36:30 +00:00
wip enable pluggable secret and registry backends
This commit is contained in:
parent
6e244be920
commit
8348c858ba
78 changed files with 1770 additions and 1611 deletions
|
@ -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)
|
||||
// }
|
||||
|
|
Loading…
Reference in a new issue