mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-26 20:01:02 +00:00
Merge pull request #2000 from bradrydzewski/master
pluggable secrets, registry, approval backends
This commit is contained in:
commit
b15e9bab6f
76 changed files with 1680 additions and 1611 deletions
|
@ -26,9 +26,6 @@ type Client interface {
|
||||||
// UserDel deletes a user account.
|
// UserDel deletes a user account.
|
||||||
UserDel(string) error
|
UserDel(string) error
|
||||||
|
|
||||||
// // UserFeed returns the user's activity feed.
|
|
||||||
// UserFeed() ([]*Activity, error)
|
|
||||||
|
|
||||||
// Repo returns a repository by name.
|
// Repo returns a repository by name.
|
||||||
Repo(string, string) (*model.Repo, error)
|
Repo(string, string) (*model.Repo, error)
|
||||||
|
|
||||||
|
@ -48,36 +45,6 @@ type Client interface {
|
||||||
// RepoDel deletes a repository.
|
// RepoDel deletes a repository.
|
||||||
RepoDel(string, string) error
|
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 returns a repository build by number.
|
||||||
Build(string, string, int) (*model.Build, error)
|
Build(string, string, int) (*model.Build, error)
|
||||||
|
|
||||||
|
@ -129,4 +96,19 @@ type Client interface {
|
||||||
|
|
||||||
// RegistryDelete deletes a registry.
|
// RegistryDelete deletes a registry.
|
||||||
RegistryDelete(owner, name, hostname string) error
|
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"
|
pathRepos = "%s/api/user/repos"
|
||||||
pathRepo = "%s/api/repos/%s/%s"
|
pathRepo = "%s/api/repos/%s/%s"
|
||||||
pathChown = "%s/api/repos/%s/%s/chown"
|
pathChown = "%s/api/repos/%s/%s/chown"
|
||||||
pathEncrypt = "%s/api/repos/%s/%s/encrypt"
|
|
||||||
pathBuilds = "%s/api/repos/%s/%s/builds"
|
pathBuilds = "%s/api/repos/%s/%s/builds"
|
||||||
pathBuild = "%s/api/repos/%s/%s/builds/%v"
|
pathBuild = "%s/api/repos/%s/%s/builds/%v"
|
||||||
pathApprove = "%s/api/repos/%s/%s/builds/%d/approve"
|
pathApprove = "%s/api/repos/%s/%s/builds/%d/approve"
|
||||||
pathDecline = "%s/api/repos/%s/%s/builds/%d/decline"
|
pathDecline = "%s/api/repos/%s/%s/builds/%d/decline"
|
||||||
pathJob = "%s/api/repos/%s/%s/builds/%d/%d"
|
pathJob = "%s/api/repos/%s/%s/builds/%d/%d"
|
||||||
pathLog = "%s/api/repos/%s/%s/logs/%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"
|
pathRepoSecrets = "%s/api/repos/%s/%s/secrets"
|
||||||
pathRepoSecret = "%s/api/repos/%s/%s/secrets/%s"
|
pathRepoSecret = "%s/api/repos/%s/%s/secrets/%s"
|
||||||
pathRepoRegistries = "%s/api/repos/%s/%s/registry"
|
pathRepoRegistries = "%s/api/repos/%s/%s/registry"
|
||||||
pathRepoRegistry = "%s/api/repos/%s/%s/registry/%s"
|
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"
|
pathUsers = "%s/api/users"
|
||||||
pathUser = "%s/api/users/%s"
|
pathUser = "%s/api/users/%s"
|
||||||
pathBuildQueue = "%s/api/builds"
|
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
|
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.
|
// Registry returns a registry by hostname.
|
||||||
func (c *client) Registry(owner, name, hostname string) (*model.Registry, error) {
|
func (c *client) Registry(owner, name, hostname string) (*model.Registry, error) {
|
||||||
out := new(model.Registry)
|
out := new(model.Registry)
|
||||||
|
@ -404,6 +324,44 @@ func (c *client) RegistryDelete(owner, name, hostname string) error {
|
||||||
return c.delete(uri)
|
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
|
// 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,
|
registryCmd,
|
||||||
secretCmd,
|
secretCmd,
|
||||||
serverCmd,
|
serverCmd,
|
||||||
signCmd,
|
|
||||||
repoCmd,
|
repoCmd,
|
||||||
userCmd,
|
userCmd,
|
||||||
orgCmd,
|
|
||||||
globalCmd,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
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{
|
cli.StringFlag{
|
||||||
Name: "format",
|
Name: "format",
|
||||||
Usage: "repository name (e.g. octocat/hello-world)",
|
Usage: "format output",
|
||||||
Value: tmplRegistryList,
|
Value: tmplRegistryList,
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,7 +18,7 @@ var registryListCmd = cli.Command{
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "format",
|
Name: "format",
|
||||||
Usage: "repository name (e.g. octocat/hello-world)",
|
Usage: "format output",
|
||||||
Value: tmplRegistryList,
|
Value: tmplRegistryList,
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
},
|
},
|
||||||
|
@ -58,6 +58,5 @@ func registryList(c *cli.Context) error {
|
||||||
// template for build list information
|
// template for build list information
|
||||||
var tmplRegistryList = "\x1b[33m{{ .Address }} \x1b[0m" + `
|
var tmplRegistryList = "\x1b[33m{{ .Address }} \x1b[0m" + `
|
||||||
Username: {{ .Username }}
|
Username: {{ .Username }}
|
||||||
Password: ********
|
|
||||||
Email: {{ .Email }}
|
Email: {{ .Email }}
|
||||||
`
|
`
|
||||||
|
|
131
drone/secret.go
131
drone/secret.go
|
@ -1,136 +1,15 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import "github.com/urfave/cli"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/drone/drone/model"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
var secretCmd = cli.Command{
|
var secretCmd = cli.Command{
|
||||||
Name: "secret",
|
Name: "secret",
|
||||||
Usage: "manage secrets",
|
Usage: "manage secrets",
|
||||||
Subcommands: []cli.Command{
|
Subcommands: []cli.Command{
|
||||||
secretAddCmd,
|
secretCreateCmd,
|
||||||
secretRemoveCmd,
|
secretDeleteCmd,
|
||||||
|
secretUpdateCmd,
|
||||||
|
secretInfoCmd,
|
||||||
secretListCmd,
|
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
|
package main
|
||||||
|
|
||||||
import "github.com/urfave/cli"
|
import (
|
||||||
|
"github.com/drone/drone/model"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
var secretAddCmd = cli.Command{
|
var secretCreateCmd = cli.Command{
|
||||||
Name: "add",
|
Name: "add",
|
||||||
Usage: "adds a secret",
|
Usage: "adds a secret",
|
||||||
ArgsUsage: "[repo] [key] [value]",
|
Action: secretCreate,
|
||||||
Action: secretAdd,
|
Flags: []cli.Flag{
|
||||||
Flags: secretAddFlags(),
|
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 {
|
func secretCreate(c *cli.Context) error {
|
||||||
repo := c.Args().First()
|
reponame := c.String("repository")
|
||||||
owner, name, err := parseRepo(repo)
|
if reponame == "" {
|
||||||
|
reponame = c.Args().First()
|
||||||
|
}
|
||||||
|
owner, name, err := parseRepo(reponame)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
client, err := newClient(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
secret := &model.Secret{
|
||||||
return client.SecretPost(owner, name, 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
|
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
|
package main
|
||||||
|
|
||||||
import "github.com/urfave/cli"
|
import (
|
||||||
|
"html/template"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
var secretListCmd = cli.Command{
|
var secretListCmd = cli.Command{
|
||||||
Name: "ls",
|
Name: "ls",
|
||||||
Usage: "list all secrets",
|
Usage: "list secrets",
|
||||||
Action: secretList,
|
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 {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := newClient(c)
|
client, err := newClient(c)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
list, err := client.SecretList(owner, name)
|
||||||
secrets, err := client.SecretList(owner, name)
|
if err != nil {
|
||||||
|
|
||||||
if err != nil || len(secrets) == 0 {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
|
||||||
return secretDisplayList(secrets, c)
|
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"
|
import "github.com/urfave/cli"
|
||||||
|
|
||||||
var secretRemoveCmd = cli.Command{
|
var secretDeleteCmd = cli.Command{
|
||||||
Name: "rm",
|
Name: "rm",
|
||||||
Usage: "remove a secret",
|
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 {
|
func secretDelete(c *cli.Context) error {
|
||||||
repo := c.Args().First()
|
var (
|
||||||
owner, name, err := parseRepo(repo)
|
secret = c.String("name")
|
||||||
|
reponame = c.String("repository")
|
||||||
|
)
|
||||||
|
if reponame == "" {
|
||||||
|
reponame = c.Args().First()
|
||||||
|
}
|
||||||
|
owner, name, err := parseRepo(reponame)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
secret := c.Args().Get(1)
|
|
||||||
|
|
||||||
client, err := newClient(c)
|
client, err := newClient(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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",
|
Name: "debug",
|
||||||
Usage: "start the server in debug mode",
|
Usage: "start the server in debug mode",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.StringFlag{
|
||||||
EnvVar: "DRONE_BROKER_DEBUG",
|
EnvVar: "DRONE_SERVER_HOST",
|
||||||
Name: "broker-debug",
|
Name: "server-host",
|
||||||
Usage: "start the broker in debug mode",
|
Usage: "server host",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
EnvVar: "DRONE_SERVER_ADDR",
|
EnvVar: "DRONE_SERVER_ADDR",
|
||||||
|
@ -58,12 +58,6 @@ var serverCmd = cli.Command{
|
||||||
Name: "open",
|
Name: "open",
|
||||||
Usage: "open user registration",
|
Usage: "open user registration",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
|
||||||
EnvVar: "DRONE_YAML",
|
|
||||||
Name: "yaml",
|
|
||||||
Usage: "build configuraton file name",
|
|
||||||
Value: ".drone.yml",
|
|
||||||
},
|
|
||||||
cli.DurationFlag{
|
cli.DurationFlag{
|
||||||
EnvVar: "DRONE_CACHE_TTL",
|
EnvVar: "DRONE_CACHE_TTL",
|
||||||
Name: "cache-ttl",
|
Name: "cache-ttl",
|
||||||
|
@ -75,6 +69,21 @@ var serverCmd = cli.Command{
|
||||||
Name: "agent-secret",
|
Name: "agent-secret",
|
||||||
Usage: "agent secret passcode",
|
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{
|
cli.StringFlag{
|
||||||
EnvVar: "DRONE_DATABASE_DRIVER,DATABASE_DRIVER",
|
EnvVar: "DRONE_DATABASE_DRIVER,DATABASE_DRIVER",
|
||||||
Name: "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")
|
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.
|
// RegistryStore persists registry information to storage.
|
||||||
type RegistryStore interface {
|
type RegistryStore interface {
|
||||||
RegistryFind(*Repo, string) (*Registry, error)
|
RegistryFind(*Repo, string) (*Registry, error)
|
||||||
|
|
|
@ -25,6 +25,7 @@ type Repo struct {
|
||||||
IsPrivate bool `json:"private,omitempty" meddler:"repo_private"`
|
IsPrivate bool `json:"private,omitempty" meddler:"repo_private"`
|
||||||
IsTrusted bool `json:"trusted" meddler:"repo_trusted"`
|
IsTrusted bool `json:"trusted" meddler:"repo_trusted"`
|
||||||
IsStarred bool `json:"starred,omitempty" meddler:"-"`
|
IsStarred bool `json:"starred,omitempty" meddler:"-"`
|
||||||
|
IsGated bool `json:"gated" meddler:"repo_gated"`
|
||||||
AllowPull bool `json:"allow_pr" meddler:"repo_allow_pr"`
|
AllowPull bool `json:"allow_pr" meddler:"repo_allow_pr"`
|
||||||
AllowPush bool `json:"allow_push" meddler:"repo_allow_push"`
|
AllowPush bool `json:"allow_push" meddler:"repo_allow_push"`
|
||||||
AllowDeploy bool `json:"allow_deploys" meddler:"repo_allow_deploys"`
|
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
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"path/filepath"
|
"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 {
|
type Secret struct {
|
||||||
// the name of the secret which will be used as the environment variable
|
ID int64 `json:"id" meddler:"secret_id,pk"`
|
||||||
// name at runtime.
|
RepoID int64 `json:"-" meddler:"secret_repo_id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name" meddler:"secret_name"`
|
||||||
|
Value string `json:"value,omitempty" meddler:"secret_value"`
|
||||||
// the value of the secret which will be provided to the runtime environment
|
Images []string `json:"image" meddler:"secret_images,json"`
|
||||||
// as a named environment variable.
|
Events []string `json:"event" meddler:"secret_events,json"`
|
||||||
Value string `json:"value"`
|
SkipVerify bool `json:"-" meddler:"secret_skip_verify"`
|
||||||
|
Conceal bool `json:"-" meddler:"secret_conceal"`
|
||||||
// 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"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match returns true if an image and event match the restricted list.
|
// Match returns true if an image and event match the restricted list.
|
||||||
func (s *Secret) Match(image, event string) bool {
|
func (s *Secret) Match(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 {
|
|
||||||
for _, pattern := range s.Events {
|
for _, pattern := range s.Events {
|
||||||
if match, _ := filepath.Match(pattern, event); match {
|
if match, _ := filepath.Match(pattern, event); match {
|
||||||
return true
|
return true
|
||||||
|
@ -55,5 +53,23 @@ func (s *Secret) MatchEvent(event string) bool {
|
||||||
|
|
||||||
// Validate validates the required fields and formats.
|
// Validate validates the required fields and formats.
|
||||||
func (s *Secret) Validate() error {
|
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 := goblin.Goblin(t)
|
||||||
g.Describe("Secret", func() {
|
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() {
|
g.It("should match event", func() {
|
||||||
secret := Secret{}
|
secret := Secret{}
|
||||||
secret.Events = []string{"pull_request"}
|
secret.Events = []string{"pull_request"}
|
||||||
g.Assert(secret.MatchEvent("pull_request")).IsTrue()
|
g.Assert(secret.Match("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.It("should not match event", func() {
|
g.It("should not match event", func() {
|
||||||
secret := Secret{}
|
secret := Secret{}
|
||||||
secret.Events = []string{"pull_request"}
|
secret.Events = []string{"pull_request"}
|
||||||
g.Assert(secret.MatchEvent("push")).IsFalse()
|
g.Assert(secret.Match("push")).IsFalse()
|
||||||
})
|
})
|
||||||
g.It("should pass validation")
|
g.It("should pass validation")
|
||||||
g.Describe("should fail validation", func() {
|
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
|
||||||
|
}
|
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
|
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{
|
return &model.Config{
|
||||||
Open: c.Bool("open"),
|
Open: c.Bool("open"),
|
||||||
Secret: c.String("agent-secret"),
|
Secret: c.String("agent-secret"),
|
||||||
Admins: sliceToMap(c.StringSlice("admin")),
|
Admins: sliceToMap2(c.StringSlice("admin")),
|
||||||
Orgs: sliceToMap(c.StringSlice("orgs")),
|
Orgs: sliceToMap2(c.StringSlice("orgs")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function to convert a string slice to a map.
|
// 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{}
|
v := map[string]bool{}
|
||||||
for _, ss := range s {
|
for _, ss := range s {
|
||||||
v[ss] = true
|
v[ss] = true
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
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"
|
||||||
"github.com/drone/drone/store/datastore"
|
"github.com/drone/drone/store/datastore"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
@ -12,6 +21,40 @@ import (
|
||||||
// the context of every http.Request.
|
// the context of every http.Request.
|
||||||
func Store(cli *cli.Context) gin.HandlerFunc {
|
func Store(cli *cli.Context) gin.HandlerFunc {
|
||||||
v := setupStore(cli)
|
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) {
|
return func(c *gin.Context) {
|
||||||
store.ToContext(c, v)
|
store.ToContext(c, v)
|
||||||
c.Next()
|
c.Next()
|
||||||
|
@ -25,3 +68,12 @@ func setupStore(c *cli.Context) store.Store {
|
||||||
c.String("datasource"),
|
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)
|
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 := e.Group("/api/repos/:owner/:name")
|
||||||
{
|
{
|
||||||
repos.POST("", server.PostRepo)
|
repos.POST("", server.PostRepo)
|
||||||
|
@ -107,8 +86,11 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
|
||||||
repo.GET("/logs/:number/:ppid/:proc", server.GetBuildLogs)
|
repo.GET("/logs/:number/:ppid/:proc", server.GetBuildLogs)
|
||||||
repo.POST("/sign", session.MustPush, server.Sign)
|
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.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)
|
repo.DELETE("/secrets/:secret", session.MustPush, server.DeleteSecret)
|
||||||
|
|
||||||
// requires push permissions
|
// requires push permissions
|
||||||
|
|
|
@ -138,7 +138,7 @@ func DeleteBuild(c *gin.Context) {
|
||||||
// TODO cancel child procs
|
// TODO cancel child procs
|
||||||
store.FromContext(c).ProcUpdate(proc)
|
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, "")
|
c.String(204, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,11 +197,11 @@ func PostApproval(c *gin.Context) {
|
||||||
// get the previous build so that we can send
|
// get the previous build so that we can send
|
||||||
// on status change notifications
|
// on status change notifications
|
||||||
last, _ := store.GetBuildLastBefore(c, repo, build.Branch, build.ID)
|
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 {
|
if err != nil {
|
||||||
logrus.Debugf("Error getting secrets for %s#%d. %s", repo.FullName, build.Number, err)
|
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 {
|
if err != nil {
|
||||||
logrus.Debugf("Error getting registry credentials for %s#%d. %s", repo.FullName, build.Number, err)
|
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,
|
Build: buildCopy,
|
||||||
})
|
})
|
||||||
// TODO remove global reference
|
// TODO remove global reference
|
||||||
config.pubsub.Publish(c, "topic/events", message)
|
Config.Services.Pubsub.Publish(c, "topic/events", message)
|
||||||
|
|
||||||
//
|
//
|
||||||
// end publish topic
|
// end publish topic
|
||||||
|
@ -298,8 +298,8 @@ func PostApproval(c *gin.Context) {
|
||||||
Timeout: b.Repo.Timeout,
|
Timeout: b.Repo.Timeout,
|
||||||
})
|
})
|
||||||
|
|
||||||
config.logger.Open(context.Background(), task.ID)
|
Config.Services.Logs.Open(context.Background(), task.ID)
|
||||||
config.queue.Push(context.Background(), task)
|
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
|
// get the previous build so that we can send
|
||||||
// on status change notifications
|
// on status change notifications
|
||||||
last, _ := store.GetBuildLastBefore(c, repo, build.Branch, build.ID)
|
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 {
|
if err != nil {
|
||||||
logrus.Debugf("Error getting secrets for %s#%d. %s", repo.FullName, build.Number, err)
|
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 {
|
if err != nil {
|
||||||
logrus.Debugf("Error getting registry credentials for %s#%d. %s", repo.FullName, build.Number, err)
|
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,
|
Build: buildCopy,
|
||||||
})
|
})
|
||||||
// TODO remove global reference
|
// TODO remove global reference
|
||||||
config.pubsub.Publish(c, "topic/events", message)
|
Config.Services.Pubsub.Publish(c, "topic/events", message)
|
||||||
//
|
//
|
||||||
// end publish topic
|
// end publish topic
|
||||||
//
|
//
|
||||||
|
@ -581,7 +581,7 @@ func PostBuild(c *gin.Context) {
|
||||||
Timeout: b.Repo.Timeout,
|
Timeout: b.Repo.Timeout,
|
||||||
})
|
})
|
||||||
|
|
||||||
config.logger.Open(context.Background(), task.ID)
|
Config.Services.Logs.Open(context.Background(), task.ID)
|
||||||
config.queue.Push(context.Background(), task)
|
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) {
|
func GetQueueInfo(c *gin.Context) {
|
||||||
c.IndentedJSON(200,
|
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 {
|
if err != nil {
|
||||||
logrus.Debugf("Error getting secrets for %s#%d. %s", repo.FullName, build.Number, err)
|
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 {
|
if err != nil {
|
||||||
logrus.Debugf("Error getting registry credentials for %s#%d. %s", repo.FullName, build.Number, err)
|
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
|
// update some build fields
|
||||||
build.RepoID = repo.ID
|
build.RepoID = repo.ID
|
||||||
build.Verified = true
|
build.Verified = true
|
||||||
build.Status = model.StatusPending
|
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)
|
logrus.Errorf("failure to save commit for %s. %s", repo.FullName, err)
|
||||||
c.AbortWithError(500, err)
|
c.AbortWithError(500, err)
|
||||||
return
|
return
|
||||||
|
@ -234,9 +184,9 @@ func PostHook(c *gin.Context) {
|
||||||
|
|
||||||
c.JSON(200, build)
|
c.JSON(200, build)
|
||||||
|
|
||||||
// if build.Status == model.StatusBlocked {
|
if build.Status == model.StatusBlocked {
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
|
|
||||||
// get the previous build so that we can send
|
// get the previous build so that we can send
|
||||||
// on status change notifications
|
// on status change notifications
|
||||||
|
@ -321,7 +271,7 @@ func PostHook(c *gin.Context) {
|
||||||
Build: buildCopy,
|
Build: buildCopy,
|
||||||
})
|
})
|
||||||
// TODO remove global reference
|
// TODO remove global reference
|
||||||
config.pubsub.Publish(c, "topic/events", message)
|
Config.Services.Pubsub.Publish(c, "topic/events", message)
|
||||||
//
|
//
|
||||||
// end publish topic
|
// end publish topic
|
||||||
//
|
//
|
||||||
|
@ -341,8 +291,8 @@ func PostHook(c *gin.Context) {
|
||||||
Timeout: b.Repo.Timeout,
|
Timeout: b.Repo.Timeout,
|
||||||
})
|
})
|
||||||
|
|
||||||
config.logger.Open(context.Background(), task.ID)
|
Config.Services.Logs.Open(context.Background(), task.ID)
|
||||||
config.queue.Push(context.Background(), task)
|
Config.Services.Queue.Push(context.Background(), task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,7 +410,7 @@ func (b *builder) Build() ([]*buildItem, error) {
|
||||||
|
|
||||||
var secrets []compiler.Secret
|
var secrets []compiler.Secret
|
||||||
for _, sec := range b.Secs {
|
for _, sec := range b.Secs {
|
||||||
if !sec.MatchEvent(b.Curr.Event) {
|
if !sec.Match(b.Curr.Event) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
secrets = append(secrets, compiler.Secret{
|
secrets = append(secrets, compiler.Secret{
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
|
|
||||||
"github.com/drone/drone/model"
|
"github.com/drone/drone/model"
|
||||||
"github.com/drone/drone/router/middleware/session"
|
"github.com/drone/drone/router/middleware/session"
|
||||||
"github.com/drone/drone/store"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
@ -17,7 +16,7 @@ func GetRegistry(c *gin.Context) {
|
||||||
repo = session.Repo(c)
|
repo = session.Repo(c)
|
||||||
name = c.Param("registry")
|
name = c.Param("registry")
|
||||||
)
|
)
|
||||||
registry, err := store.FromContext(c).RegistryFind(repo, name)
|
registry, err := Config.Services.Registries.RegistryFind(repo, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(404, "Error getting registry %q. %s", name, err)
|
c.String(404, "Error getting registry %q. %s", name, err)
|
||||||
return
|
return
|
||||||
|
@ -46,7 +45,7 @@ func PostRegistry(c *gin.Context) {
|
||||||
c.String(400, "Error inserting registry. %s", err)
|
c.String(400, "Error inserting registry. %s", err)
|
||||||
return
|
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)
|
c.String(500, "Error inserting registry %q. %s", in.Address, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -67,7 +66,7 @@ func PatchRegistry(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
registry, err := store.FromContext(c).RegistryFind(repo, name)
|
registry, err := Config.Services.Registries.RegistryFind(repo, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(404, "Error getting registry %q. %s", name, err)
|
c.String(404, "Error getting registry %q. %s", name, err)
|
||||||
return
|
return
|
||||||
|
@ -89,7 +88,7 @@ func PatchRegistry(c *gin.Context) {
|
||||||
c.String(400, "Error updating registry. %s", err)
|
c.String(400, "Error updating registry. %s", err)
|
||||||
return
|
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)
|
c.String(500, "Error updating registry %q. %s", in.Address, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -100,7 +99,7 @@ func PatchRegistry(c *gin.Context) {
|
||||||
// to the response in json format.
|
// to the response in json format.
|
||||||
func GetRegistryList(c *gin.Context) {
|
func GetRegistryList(c *gin.Context) {
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
list, err := store.FromContext(c).RegistryList(repo)
|
list, err := Config.Services.Registries.RegistryList(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(500, "Error getting registry list. %s", err)
|
c.String(500, "Error getting registry list. %s", err)
|
||||||
return
|
return
|
||||||
|
@ -119,13 +118,7 @@ func DeleteRegistry(c *gin.Context) {
|
||||||
repo = session.Repo(c)
|
repo = session.Repo(c)
|
||||||
name = c.Param("registry")
|
name = c.Param("registry")
|
||||||
)
|
)
|
||||||
registry, err := store.FromContext(c).RegistryFind(repo, name)
|
if err := Config.Services.Registries.RegistryDelete(repo, name); err != nil {
|
||||||
if err != nil {
|
|
||||||
c.String(404, "Error getting registry %q. %s", name, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = store.FromContext(c).RegistryDelete(registry)
|
|
||||||
if err != nil {
|
|
||||||
c.String(500, "Error deleting registry %q. %s", name, err)
|
c.String(500, "Error deleting registry %q. %s", name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,7 @@ func PatchRepo(c *gin.Context) {
|
||||||
|
|
||||||
in := &struct {
|
in := &struct {
|
||||||
IsTrusted *bool `json:"trusted,omitempty"`
|
IsTrusted *bool `json:"trusted,omitempty"`
|
||||||
|
IsGated *bool `json:"gated,omitempty"`
|
||||||
Timeout *int64 `json:"timeout,omitempty"`
|
Timeout *int64 `json:"timeout,omitempty"`
|
||||||
AllowPull *bool `json:"allow_pr,omitempty"`
|
AllowPull *bool `json:"allow_pr,omitempty"`
|
||||||
AllowPush *bool `json:"allow_push,omitempty"`
|
AllowPush *bool `json:"allow_push,omitempty"`
|
||||||
|
@ -109,6 +110,11 @@ func PatchRepo(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (in.IsTrusted != nil || in.Timeout != nil) && !user.Admin {
|
||||||
|
c.String(403, "Insufficient privileges")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if in.AllowPush != nil {
|
if in.AllowPush != nil {
|
||||||
repo.AllowPush = *in.AllowPush
|
repo.AllowPush = *in.AllowPush
|
||||||
}
|
}
|
||||||
|
@ -121,10 +127,13 @@ func PatchRepo(c *gin.Context) {
|
||||||
if in.AllowTag != nil {
|
if in.AllowTag != nil {
|
||||||
repo.AllowTag = *in.AllowTag
|
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
|
repo.IsTrusted = *in.IsTrusted
|
||||||
}
|
}
|
||||||
if in.Timeout != nil && user.Admin {
|
if in.Timeout != nil {
|
||||||
repo.Timeout = *in.Timeout
|
repo.Timeout = *in.Timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/cncd/logging"
|
"github.com/cncd/logging"
|
||||||
|
@ -22,23 +21,57 @@ import (
|
||||||
// This file is a complete disaster because I'm trying to wedge in some
|
// This file is a complete disaster because I'm trying to wedge in some
|
||||||
// experimental code. Please pardon our appearance during renovations.
|
// experimental code. Please pardon our appearance during renovations.
|
||||||
|
|
||||||
var config = struct {
|
// Config is an evil global configuration that will be used as we transition /
|
||||||
pubsub pubsub.Publisher
|
// refactor the codebase to move away from storing these values in the Context.
|
||||||
queue queue.Queue
|
var Config = struct {
|
||||||
logger logging.Log
|
Services struct {
|
||||||
secret string
|
Pubsub pubsub.Publisher
|
||||||
host string
|
Queue queue.Queue
|
||||||
}{
|
Logs logging.Log
|
||||||
pubsub.New(),
|
Senders model.SenderService
|
||||||
queue.New(),
|
Secrets model.SecretService
|
||||||
logging.New(),
|
Registries model.RegistryService
|
||||||
os.Getenv("DRONE_SECRET"),
|
}
|
||||||
os.Getenv("DRONE_HOST"),
|
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() {
|
// var config = struct {
|
||||||
config.pubsub.Create(context.Background(), "topic/events")
|
// 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 {
|
// func SetupRPC() gin.HandlerFunc {
|
||||||
// return func(c *gin.Context) {
|
// return func(c *gin.Context) {
|
||||||
|
@ -48,18 +81,18 @@ func init() {
|
||||||
|
|
||||||
func RPCHandler(c *gin.Context) {
|
func RPCHandler(c *gin.Context) {
|
||||||
|
|
||||||
if secret := c.Request.Header.Get("Authorization"); secret != "Bearer "+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.secret)
|
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")
|
c.String(401, "Unable to connect agent. Invalid authorization token")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
peer := RPC{
|
peer := RPC{
|
||||||
remote: remote.FromContext(c),
|
remote: remote.FromContext(c),
|
||||||
store: store.FromContext(c),
|
store: store.FromContext(c),
|
||||||
queue: config.queue,
|
queue: Config.Services.Queue,
|
||||||
pubsub: config.pubsub,
|
pubsub: Config.Services.Pubsub,
|
||||||
logger: config.logger,
|
logger: Config.Services.Logs,
|
||||||
host: config.host,
|
host: Config.Server.Host,
|
||||||
}
|
}
|
||||||
rpc.NewServer(&peer).ServeHTTP(c.Writer, c.Request)
|
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,
|
BuildID: proc.BuildID,
|
||||||
ProcID: proc.ID,
|
ProcID: proc.ID,
|
||||||
Mime: file.Mime,
|
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/model"
|
||||||
"github.com/drone/drone/router/middleware/session"
|
"github.com/drone/drone/router/middleware/session"
|
||||||
"github.com/drone/drone/store"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetGlobalSecrets(c *gin.Context) {
|
// GetSecret gets the named secret from the database and writes
|
||||||
secrets, err := store.GetGlobalSecretList(c)
|
// 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 {
|
if err != nil {
|
||||||
c.AbortWithStatus(http.StatusInternalServerError)
|
c.String(404, "Error getting secret %q. %s", name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
c.JSON(200, secret.Copy())
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PostSecret persists the secret to the database.
|
||||||
func PostSecret(c *gin.Context) {
|
func PostSecret(c *gin.Context) {
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
|
|
||||||
in := &model.RepoSecret{}
|
in := new(model.Secret)
|
||||||
err := c.Bind(in)
|
if err := c.Bind(in); err != nil {
|
||||||
if err != nil {
|
c.String(http.StatusBadRequest, "Error parsing secret. %s", err)
|
||||||
c.String(http.StatusBadRequest, "Invalid JSON input. %s", err.Error())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
in.ID = 0
|
secret := &model.Secret{
|
||||||
in.RepoID = repo.ID
|
RepoID: repo.ID,
|
||||||
|
Name: in.Name,
|
||||||
err = store.SetSecret(c, in)
|
Value: in.Value,
|
||||||
if err != nil {
|
Events: in.Events,
|
||||||
c.String(http.StatusInternalServerError, "Unable to persist secret. %s", err.Error())
|
Images: in.Images,
|
||||||
|
}
|
||||||
|
if err := secret.Validate(); err != nil {
|
||||||
|
c.String(400, "Error inserting secret. %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if err := Config.Services.Secrets.SecretCreate(repo, secret); err != nil {
|
||||||
c.String(http.StatusOK, "")
|
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)
|
repo := session.Repo(c)
|
||||||
name := c.Param("secret")
|
list, err := Config.Services.Secrets.SecretList(repo)
|
||||||
|
|
||||||
secret, err := store.GetSecret(c, repo, name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusNotFound, "Cannot find secret %s.", name)
|
c.String(500, "Error getting secret list. %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = store.DeleteSecret(c, secret)
|
// copy the secret detail to remove the sensitive
|
||||||
if err != nil {
|
// password and token fields.
|
||||||
c.String(http.StatusInternalServerError, "Unable to delete secret. %s", err.Error())
|
for i, secret := range list {
|
||||||
return
|
list[i] = secret.Copy()
|
||||||
}
|
}
|
||||||
|
c.JSON(200, list)
|
||||||
c.String(http.StatusOK, "")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTeamSecrets(c *gin.Context) {
|
// DeleteSecret deletes the named secret from the database.
|
||||||
team := c.Param("team")
|
func DeleteSecret(c *gin.Context) {
|
||||||
secrets, err := store.GetTeamSecretList(c, team)
|
var (
|
||||||
|
repo = session.Repo(c)
|
||||||
if err != nil {
|
name = c.Param("secret")
|
||||||
c.AbortWithStatus(http.StatusInternalServerError)
|
)
|
||||||
|
if err := Config.Services.Secrets.SecretDelete(repo, name); err != nil {
|
||||||
|
c.String(500, "Error deleting secret %q. %s", name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
c.String(204, "")
|
||||||
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, "")
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ func LogStream(c *gin.Context) {
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
// TODO remove global variable
|
// 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 {
|
for _, entry := range entries {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
@ -167,7 +167,7 @@ func EventStream(c *gin.Context) {
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
// TODO remove this from global config
|
// 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"]
|
name := m.Labels["repo"]
|
||||||
priv := m.Labels["private"]
|
priv := m.Labels["private"]
|
||||||
if repo[name] || priv == "false" {
|
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-find-repo-addr": registryFindRepoAddr,
|
||||||
"registry-delete-repo": registryDeleteRepo,
|
"registry-delete-repo": registryDeleteRepo,
|
||||||
"registry-delete": registryDelete,
|
"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 = `
|
var filesFindBuild = `
|
||||||
|
@ -188,3 +195,67 @@ DELETE FROM registry WHERE registry_repo_id = $1
|
||||||
var registryDelete = `
|
var registryDelete = `
|
||||||
DELETE FROM registry WHERE registry_id = $1
|
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-find-repo-addr": registryFindRepoAddr,
|
||||||
"registry-delete-repo": registryDeleteRepo,
|
"registry-delete-repo": registryDeleteRepo,
|
||||||
"registry-delete": registryDelete,
|
"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 = `
|
var filesFindBuild = `
|
||||||
|
@ -188,3 +195,67 @@ DELETE FROM registry WHERE registry_repo_id = ?
|
||||||
var registryDelete = `
|
var registryDelete = `
|
||||||
DELETE FROM registry WHERE registry_id = ?
|
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 deletes a user repository.
|
||||||
DeleteRepo(*model.Repo) error
|
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 gets a build by unique ID.
|
||||||
GetBuild(int64) (*model.Build, error)
|
GetBuild(int64) (*model.Build, error)
|
||||||
|
|
||||||
|
@ -112,38 +88,21 @@ type Store interface {
|
||||||
// UpdateBuild updates a build.
|
// UpdateBuild updates a build.
|
||||||
UpdateBuild(*model.Build) error
|
UpdateBuild(*model.Build) error
|
||||||
|
|
||||||
// // GetJob gets a job by unique ID.
|
|
||||||
// GetJob(int64) (*model.Job, error)
|
|
||||||
//
|
//
|
||||||
// // GetJobNumber gets a job by number.
|
// new functions
|
||||||
// GetJobNumber(*model.Build, int) (*model.Job, error)
|
|
||||||
//
|
//
|
||||||
// // 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)
|
SenderFind(*model.Repo, string) (*model.Sender, error)
|
||||||
//
|
SenderList(*model.Repo) ([]*model.Sender, error)
|
||||||
// GetAgentAddr(string) (*model.Agent, error)
|
SenderCreate(*model.Sender) error
|
||||||
//
|
SenderUpdate(*model.Sender) error
|
||||||
// GetAgentList() ([]*model.Agent, error)
|
SenderDelete(*model.Sender) error
|
||||||
//
|
|
||||||
// CreateAgent(*model.Agent) error
|
SecretFind(*model.Repo, string) (*model.Secret, error)
|
||||||
//
|
SecretList(*model.Repo) ([]*model.Secret, error)
|
||||||
// UpdateAgent(*model.Agent) error
|
SecretCreate(*model.Secret) error
|
||||||
//
|
SecretUpdate(*model.Secret) error
|
||||||
// DeleteAgent(*model.Agent) error
|
SecretDelete(*model.Secret) error
|
||||||
|
|
||||||
RegistryFind(*model.Repo, string) (*model.Registry, error)
|
RegistryFind(*model.Repo, string) (*model.Registry, error)
|
||||||
RegistryList(*model.Repo) ([]*model.Registry, error)
|
RegistryList(*model.Repo) ([]*model.Registry, error)
|
||||||
|
@ -168,8 +127,6 @@ type Store interface {
|
||||||
FileCreate(*model.File, io.Reader) error
|
FileCreate(*model.File, io.Reader) error
|
||||||
}
|
}
|
||||||
|
|
||||||
const globalTeamName = "__global__"
|
|
||||||
|
|
||||||
// GetUser gets a user by unique ID.
|
// GetUser gets a user by unique ID.
|
||||||
func GetUser(c context.Context, id int64) (*model.User, error) {
|
func GetUser(c context.Context, id int64) (*model.User, error) {
|
||||||
return FromContext(c).GetUser(id)
|
return FromContext(c).GetUser(id)
|
||||||
|
@ -238,94 +195,6 @@ func DeleteRepo(c context.Context, repo *model.Repo) error {
|
||||||
return FromContext(c).DeleteRepo(repo)
|
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) {
|
func GetBuild(c context.Context, id int64) (*model.Build, error) {
|
||||||
return FromContext(c).GetBuild(id)
|
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 {
|
func UpdateBuild(c context.Context, build *model.Build) error {
|
||||||
return FromContext(c).UpdateBuild(build)
|
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