mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-26 20:01:02 +00:00
Merge pull request #1593 from bradrydzewski/master
implemented 0.5 in-memory stream multiplexer
This commit is contained in:
commit
8dc3c452e0
45 changed files with 6147 additions and 182 deletions
|
@ -1,12 +1,6 @@
|
|||
# Build the drone executable on a x64 Linux host:
|
||||
#
|
||||
# go build --ldflags '-extldflags "-static"' -o drone_static
|
||||
#
|
||||
#
|
||||
# Alternate command for Go 1.4 and older:
|
||||
#
|
||||
# go build -a -tags netgo --ldflags '-extldflags "-static"' -o drone_static
|
||||
#
|
||||
# go build --ldflags '-extldflags "-static"' -o drone
|
||||
#
|
||||
# Build the docker image:
|
||||
#
|
||||
|
|
23
api/build.go
23
api/build.go
|
@ -35,7 +35,7 @@ func init() {
|
|||
}
|
||||
droneSec = fmt.Sprintf("%s.sec", strings.TrimSuffix(droneYml, filepath.Ext(droneYml)))
|
||||
if os.Getenv("CANARY") == "true" {
|
||||
droneSec = fmt.Sprintf("%s.sig", strings.TrimSuffix(droneYml, filepath.Ext(droneYml)))
|
||||
droneSec = fmt.Sprintf("%s.sig", droneYml)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -291,7 +291,10 @@ func PostBuild(c *gin.Context) {
|
|||
// get the previous build so that we can send
|
||||
// on status change notifications
|
||||
last, _ := store.GetBuildLastBefore(c, repo, build.Branch, build.ID)
|
||||
secs, _ := store.GetSecretList(c, repo)
|
||||
secs, err := store.GetSecretList(c, repo)
|
||||
if err != nil {
|
||||
log.Errorf("Error getting secrets for %s#%d. %s", repo.FullName, build.Number, err)
|
||||
}
|
||||
|
||||
// IMPORTANT. PLEASE READ
|
||||
//
|
||||
|
@ -305,14 +308,24 @@ func PostBuild(c *gin.Context) {
|
|||
var verified bool
|
||||
|
||||
signature, err := jose.ParseSigned(string(sec))
|
||||
if err == nil && len(sec) != 0 {
|
||||
if err != nil {
|
||||
log.Debugf("cannot parse .drone.yml.sig file. %s", err)
|
||||
} else if len(sec) == 0 {
|
||||
log.Debugf("cannot parse .drone.yml.sig file. empty file")
|
||||
} else {
|
||||
signed = true
|
||||
output, err := signature.Verify(repo.Hash)
|
||||
if err == nil && string(output) == string(raw) {
|
||||
output, err := signature.Verify([]byte(repo.Hash))
|
||||
if err != nil {
|
||||
log.Debugf("cannot verify .drone.yml.sig file. %s", err)
|
||||
} else if string(output) != string(raw) {
|
||||
log.Debugf("cannot verify .drone.yml.sig file. no match. %q <> %q", string(output), string(raw))
|
||||
} else {
|
||||
verified = true
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugf(".drone.yml is signed=%v and verified=%v", signed, verified)
|
||||
|
||||
bus.Publish(c, bus.NewBuildEvent(bus.Enqueued, repo, build))
|
||||
for _, job := range jobs {
|
||||
queue.Publish(c, &queue.Work{
|
||||
|
|
37
api/queue.go
37
api/queue.go
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/drone/drone/bus"
|
||||
|
@ -96,6 +97,13 @@ func Update(c *gin.Context) {
|
|||
store.UpdateBuild(c, build)
|
||||
}
|
||||
|
||||
if job.Status == model.StatusRunning {
|
||||
err := stream.Create(c, stream.ToKey(job.ID))
|
||||
if err != nil {
|
||||
logrus.Errorf("Unable to create stream. %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
ok, err := store.UpdateBuildJob(c, build, job)
|
||||
if err != nil {
|
||||
c.String(500, "Unable to update job. %s", err)
|
||||
|
@ -132,32 +140,39 @@ func Stream(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
key := stream.ToKey(id)
|
||||
rc, wc, err := stream.Create(c, key)
|
||||
key := c.Param("id")
|
||||
logrus.Infof("Agent %s creating stream %s.", c.ClientIP(), key)
|
||||
|
||||
wc, err := stream.Writer(c, key)
|
||||
if err != nil {
|
||||
logrus.Errorf("Agent %s failed to create stream. %s.", c.ClientIP(), err)
|
||||
c.String(500, "Failed to create stream writer. %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
wc.Close()
|
||||
rc.Close()
|
||||
stream.Remove(c, key)
|
||||
stream.Delete(c, key)
|
||||
}()
|
||||
|
||||
io.Copy(wc, c.Request.Body)
|
||||
wc.Close()
|
||||
|
||||
rcc, _, err := stream.Open(c, key)
|
||||
rc, err := stream.Reader(c, key)
|
||||
if err != nil {
|
||||
logrus.Errorf("Agent %s failed to read cache. %s.", c.ClientIP(), err)
|
||||
c.String(500, "Failed to create stream reader. %s", err)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
rcc.Close()
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer recover()
|
||||
store.WriteLog(c, &model.Job{ID: id}, rc)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
store.WriteLog(c, &model.Job{ID: id}, rcc)
|
||||
wc.Close()
|
||||
wg.Wait()
|
||||
c.String(200, "")
|
||||
|
||||
logrus.Debugf("Agent %s wrote stream to database", c.ClientIP())
|
||||
|
|
|
@ -3,11 +3,21 @@ package client
|
|||
import (
|
||||
"io"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/queue"
|
||||
)
|
||||
|
||||
// Client is used to communicate with a Drone server.
|
||||
type Client interface {
|
||||
// Sign returns a cryptographic signature for the input string.
|
||||
Sign(string, string, []byte) ([]byte, 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
|
||||
|
||||
// Pull pulls work from the server queue.
|
||||
Pull(os, arch string) (*queue.Work, error)
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package client
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -22,6 +23,24 @@ const (
|
|||
pathWait = "%s/api/queue/wait/%d"
|
||||
pathStream = "%s/api/queue/stream/%d"
|
||||
pathPush = "%s/api/queue/status/%d"
|
||||
|
||||
pathSelf = "%s/api/user"
|
||||
pathFeed = "%s/api/user/feed"
|
||||
pathRepos = "%s/api/user/repos"
|
||||
pathRepo = "%s/api/repos/%s/%s"
|
||||
pathEncrypt = "%s/api/repos/%s/%s/encrypt"
|
||||
pathBuilds = "%s/api/repos/%s/%s/builds"
|
||||
pathBuild = "%s/api/repos/%s/%s/builds/%v"
|
||||
pathJob = "%s/api/repos/%s/%s/builds/%d/%d"
|
||||
pathLog = "%s/api/repos/%s/%s/logs/%d/%d"
|
||||
pathKey = "%s/api/repos/%s/%s/key"
|
||||
pathSign = "%s/api/repos/%s/%s/sign"
|
||||
pathSecrets = "%s/api/repos/%s/%s/secrets"
|
||||
pathSecret = "%s/api/repos/%s/%s/secrets/%s"
|
||||
pathNodes = "%s/api/nodes"
|
||||
pathNode = "%s/api/nodes/%d"
|
||||
pathUsers = "%s/api/users"
|
||||
pathUser = "%s/api/users/%s"
|
||||
)
|
||||
|
||||
type client struct {
|
||||
|
@ -34,14 +53,50 @@ func NewClient(uri string) Client {
|
|||
return &client{http.DefaultClient, uri}
|
||||
}
|
||||
|
||||
// NewClientToken returns a client at the specified url that
|
||||
// authenticates all outbound requests with the given token.
|
||||
// NewClientToken returns a client at the specified url that authenticates all
|
||||
// outbound requests with the given token.
|
||||
func NewClientToken(uri, token string) Client {
|
||||
config := new(oauth2.Config)
|
||||
auther := config.Client(oauth2.NoContext, &oauth2.Token{AccessToken: token})
|
||||
return &client{auther, uri}
|
||||
}
|
||||
|
||||
// NewClientTokenTLS returns a client at the specified url that authenticates
|
||||
// all outbound requests with the given token and tls.Config if provided.
|
||||
func NewClientTokenTLS(uri, token string, c *tls.Config) Client {
|
||||
config := new(oauth2.Config)
|
||||
auther := config.Client(oauth2.NoContext, &oauth2.Token{AccessToken: token})
|
||||
if c != nil {
|
||||
if trans, ok := auther.Transport.(*oauth2.Transport); ok {
|
||||
trans.Base = &http.Transport{TLSClientConfig: c}
|
||||
}
|
||||
}
|
||||
return &client{auther, uri}
|
||||
}
|
||||
|
||||
// SecretPost create or updates a repository secret.
|
||||
func (c *client) SecretPost(owner, name string, secret *model.Secret) error {
|
||||
uri := fmt.Sprintf(pathSecrets, c.base, owner, name)
|
||||
return c.post(uri, secret, nil)
|
||||
}
|
||||
|
||||
// SecretDel deletes a named repository secret.
|
||||
func (c *client) SecretDel(owner, name, secret string) error {
|
||||
uri := fmt.Sprintf(pathSecret, c.base, owner, name, secret)
|
||||
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)
|
||||
}
|
||||
|
||||
// Pull pulls work from the server queue.
|
||||
func (c *client) Pull(os, arch string) (*queue.Work, error) {
|
||||
out := new(queue.Work)
|
||||
|
|
61
client/http.go
Normal file
61
client/http.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// helper function to stream an http request
|
||||
func stream(client *http.Client, rawurl, method string, in, out interface{}) (io.ReadCloser, error) {
|
||||
uri, err := url.Parse(rawurl)
|
||||
if err != nil {
|
||||
return nil, 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 {
|
||||
// nothing
|
||||
} else if rw, ok := in.(io.ReadWriter); ok {
|
||||
buf = rw
|
||||
} else if b, ok := in.([]byte); ok {
|
||||
buf = new(bytes.Buffer)
|
||||
buf.Write(b)
|
||||
} else {
|
||||
buf = new(bytes.Buffer)
|
||||
err := json.NewEncoder(buf).Encode(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// creates a new http request to bitbucket.
|
||||
req, err := http.NewRequest(method, uri.String(), buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if in == nil {
|
||||
// nothing
|
||||
} else if _, ok := in.(io.ReadWriter); ok {
|
||||
req.Header.Set("Content-Type", "plain/text")
|
||||
} else {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode > http.StatusPartialContent {
|
||||
defer resp.Body.Close()
|
||||
out, _ := ioutil.ReadAll(resp.Body)
|
||||
return nil, fmt.Errorf(string(out))
|
||||
}
|
||||
return resp.Body, nil
|
||||
}
|
|
@ -83,7 +83,16 @@ var AgentCmd = cli.Command{
|
|||
EnvVar: "DRONE_PLUGIN_NETRC",
|
||||
Name: "netrc-plugin",
|
||||
Usage: "plugins that receive the netrc file",
|
||||
Value: &cli.StringSlice{"git", "hg"},
|
||||
Value: &cli.StringSlice{
|
||||
"git",
|
||||
"git:*",
|
||||
"hg",
|
||||
"hg:*",
|
||||
"plugins/hg",
|
||||
"plugins/hg:*",
|
||||
"plugins/git",
|
||||
"plugins/git:*",
|
||||
},
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
EnvVar: "DRONE_PLUGIN_PRIVILEGED",
|
||||
|
|
|
@ -66,25 +66,25 @@ func (r *pipeline) run() error {
|
|||
secrets = append(secrets, &model.Secret{
|
||||
Name: "DRONE_NETRC_USERNAME",
|
||||
Value: w.Netrc.Login,
|
||||
Images: []string{"git", "hg"}, // TODO(bradrydzewski) use the command line parameters here
|
||||
Events: []string{model.EventDeploy, model.EventPull, model.EventPush, model.EventTag},
|
||||
Images: []string{"*"},
|
||||
Events: []string{"*"},
|
||||
})
|
||||
secrets = append(secrets, &model.Secret{
|
||||
Name: "DRONE_NETRC_PASSWORD",
|
||||
Value: w.Netrc.Password,
|
||||
Images: []string{"git", "hg"},
|
||||
Events: []string{model.EventDeploy, model.EventPull, model.EventPush, model.EventTag},
|
||||
Images: []string{"*"},
|
||||
Events: []string{"*"},
|
||||
})
|
||||
secrets = append(secrets, &model.Secret{
|
||||
Name: "DRONE_NETRC_MACHINE",
|
||||
Value: w.Netrc.Machine,
|
||||
Images: []string{"git", "hg"},
|
||||
Events: []string{model.EventDeploy, model.EventPull, model.EventPush, model.EventTag},
|
||||
Images: []string{"*"},
|
||||
Events: []string{"*"},
|
||||
})
|
||||
}
|
||||
|
||||
trans := []compiler.Transform{
|
||||
builtin.NewCloneOp("plugins/git:latest", true),
|
||||
builtin.NewCloneOp("git", true),
|
||||
builtin.NewCacheOp(
|
||||
"plugins/cache:latest",
|
||||
"/var/lib/drone/cache/"+w.Repo.FullName,
|
||||
|
@ -195,10 +195,11 @@ func (r *pipeline) run() error {
|
|||
w.Job.Status = model.StatusFailure
|
||||
}
|
||||
|
||||
pushRetry(r.drone, w)
|
||||
|
||||
logrus.Infof("Finished build %s/%s#%d.%d",
|
||||
w.Repo.Owner, w.Repo.Name, w.Build.Number, w.Job.Number)
|
||||
|
||||
pushRetry(r.drone, w)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -19,10 +19,25 @@ func main2() {
|
|||
app.Name = "drone"
|
||||
app.Version = version.Version
|
||||
app.Usage = "command line utility"
|
||||
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "t, token",
|
||||
Value: "",
|
||||
Usage: "server auth token",
|
||||
EnvVar: "DRONE_TOKEN",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "s, server",
|
||||
Value: "",
|
||||
Usage: "server location",
|
||||
EnvVar: "DRONE_SERVER",
|
||||
},
|
||||
}
|
||||
app.Commands = []cli.Command{
|
||||
agent.AgentCmd,
|
||||
server.ServeCmd,
|
||||
SignCmd,
|
||||
SecretCmd,
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
|
|
103
drone/secret.go
Normal file
103
drone/secret.go
Normal file
|
@ -0,0 +1,103 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
// SecretCmd is the exported command for managing secrets.
|
||||
var SecretCmd = cli.Command{
|
||||
Name: "secret",
|
||||
Usage: "manage secrets",
|
||||
Subcommands: []cli.Command{
|
||||
// Secret Add
|
||||
{
|
||||
Name: "add",
|
||||
Usage: "add a secret",
|
||||
ArgsUsage: "[repo] [key] [value]",
|
||||
Action: func(c *cli.Context) {
|
||||
if err := secretAdd(c); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringSliceFlag{
|
||||
Name: "event",
|
||||
Usage: "inject the secret for these event types",
|
||||
Value: &cli.StringSlice{
|
||||
model.EventPush,
|
||||
model.EventTag,
|
||||
model.EventDeploy,
|
||||
},
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "image",
|
||||
Usage: "inject the secret for these image types",
|
||||
Value: &cli.StringSlice{},
|
||||
},
|
||||
},
|
||||
},
|
||||
// Secret Delete
|
||||
{
|
||||
Name: "rm",
|
||||
Usage: "remove a secret",
|
||||
Action: func(c *cli.Context) {
|
||||
if err := secretDel(c); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func secretAdd(c *cli.Context) error {
|
||||
|
||||
repo := c.Args().First()
|
||||
owner, name, err := parseRepo(repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tail := c.Args().Tail()
|
||||
if len(tail) != 2 {
|
||||
cli.ShowSubcommandHelp(c)
|
||||
return nil
|
||||
}
|
||||
|
||||
secret := &model.Secret{}
|
||||
secret.Name = tail[0]
|
||||
secret.Value = tail[1]
|
||||
secret.Images = c.StringSlice("image")
|
||||
secret.Events = c.StringSlice("event")
|
||||
|
||||
if len(secret.Images) == 0 {
|
||||
return fmt.Errorf("Please specify the --image parameter")
|
||||
}
|
||||
|
||||
client, err := newClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return client.SecretPost(owner, name, secret)
|
||||
}
|
||||
|
||||
func secretDel(c *cli.Context) error {
|
||||
repo := c.Args().First()
|
||||
owner, name, err := parseRepo(repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secret := c.Args().Get(1)
|
||||
|
||||
client, err := newClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return client.SecretDel(owner, name, secret)
|
||||
}
|
56
drone/sign.go
Normal file
56
drone/sign.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
// SignCmd is the exported command for signing the yaml.
|
||||
var SignCmd = cli.Command{
|
||||
Name: "sign",
|
||||
Usage: "creates a secure yaml file",
|
||||
Action: func(c *cli.Context) {
|
||||
if err := sign(c); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
},
|
||||
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)
|
||||
}
|
53
drone/util.go
Normal file
53
drone/util.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone/client"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/jackspirou/syscerts"
|
||||
)
|
||||
|
||||
func newClient(c *cli.Context) (client.Client, error) {
|
||||
var token = c.GlobalString("token")
|
||||
var server = c.GlobalString("server")
|
||||
|
||||
// if no server url is provided we can default
|
||||
// to the hosted Drone service.
|
||||
if len(server) == 0 {
|
||||
return nil, fmt.Errorf("Error: you must provide the Drone server address.")
|
||||
}
|
||||
if len(token) == 0 {
|
||||
return nil, fmt.Errorf("Error: you must provide your Drone access token.")
|
||||
}
|
||||
|
||||
// attempt to find system CA certs
|
||||
certs := syscerts.SystemRootsPool()
|
||||
tlsConfig := &tls.Config{RootCAs: certs}
|
||||
|
||||
// create the drone client with TLS options
|
||||
return client.NewClientTokenTLS(server, token, tlsConfig), nil
|
||||
}
|
||||
|
||||
func parseRepo(str string) (user, repo string, err error) {
|
||||
var parts = strings.Split(str, "/")
|
||||
if len(parts) != 2 {
|
||||
err = fmt.Errorf("Error: Invalid or missing repository. eg octocat/hello-world.")
|
||||
return
|
||||
}
|
||||
user = parts[0]
|
||||
repo = parts[1]
|
||||
return
|
||||
}
|
||||
|
||||
func readInput(in string) ([]byte, error) {
|
||||
if in == "-" {
|
||||
return ioutil.ReadAll(os.Stdin)
|
||||
}
|
||||
return ioutil.ReadFile(in)
|
||||
}
|
|
@ -79,7 +79,7 @@ func argsToEnv(from map[string]interface{}, to map[string]string) error {
|
|||
} else {
|
||||
out, err = json.YAMLToJSON(out)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
// return err TODO(bradrydzewski) unit test coverage for possible errors
|
||||
}
|
||||
to[k] = string(out)
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ func (v *podOp) VisitRoot(node *parse.RootNode) error {
|
|||
service.Container = runner.Container{
|
||||
Name: v.name,
|
||||
Alias: "ambassador",
|
||||
Image: "busybox",
|
||||
Image: "busybox:latest",
|
||||
Entrypoint: []string{"/bin/sleep"},
|
||||
Command: []string{"86400"},
|
||||
Volumes: []string{node.Path, node.Base},
|
||||
|
|
|
@ -36,14 +36,14 @@ func (v *shellOp) VisitContainer(node *parse.ContainerNode) error {
|
|||
"/bin/sh", "-c",
|
||||
}
|
||||
node.Container.Command = []string{
|
||||
"echo $CI_CMDS | base64 -d | /bin/sh -e",
|
||||
"echo $DRONE_SCRIPT | base64 -d | /bin/sh -e",
|
||||
}
|
||||
if node.Container.Environment == nil {
|
||||
node.Container.Environment = map[string]string{}
|
||||
}
|
||||
node.Container.Environment["HOME"] = "/root"
|
||||
node.Container.Environment["SHELL"] = "/bin/sh"
|
||||
node.Container.Environment["CI_CMDS"] = toScript(
|
||||
node.Container.Environment["DRONE_SCRIPT"] = toScript(
|
||||
node.Root().Path,
|
||||
node.Commands,
|
||||
)
|
||||
|
@ -72,7 +72,17 @@ func toScript(base string, commands []string) string {
|
|||
// setupScript is a helper script this is added to the build to ensure
|
||||
// a minimum set of environment variables are set correctly.
|
||||
const setupScript = `
|
||||
echo $DRONE_NETRC > $HOME/.netrc
|
||||
if [ -n "$DRONE_NETRC_MACHINE" ]; then
|
||||
cat <<EOF > $HOME/.netrc
|
||||
machine $DRONE_NETRC_MACHINE
|
||||
login $DRONE_NETRC_USERNAME
|
||||
password $DRONE_NETRC_PASSWORD
|
||||
EOF
|
||||
fi
|
||||
|
||||
unset DRONE_NETRC_USERNAME
|
||||
unset DRONE_NETRC_PASSWORD
|
||||
unset DRONE_SCRIPT
|
||||
|
||||
%s
|
||||
`
|
||||
|
|
|
@ -23,7 +23,7 @@ func Test_shell(t *testing.T) {
|
|||
|
||||
g.Assert(len(c.Container.Entrypoint)).Equal(0)
|
||||
g.Assert(len(c.Container.Command)).Equal(0)
|
||||
g.Assert(c.Container.Environment["CI_CMDS"]).Equal("")
|
||||
g.Assert(c.Container.Environment["DRONE_SCRIPT"]).Equal("")
|
||||
})
|
||||
|
||||
g.It("should set entrypoint, command and environment variables", func() {
|
||||
|
@ -37,8 +37,8 @@ func Test_shell(t *testing.T) {
|
|||
ops.VisitContainer(c)
|
||||
|
||||
g.Assert(c.Container.Entrypoint).Equal([]string{"/bin/sh", "-c"})
|
||||
g.Assert(c.Container.Command).Equal([]string{"echo $CI_CMDS | base64 -d | /bin/sh -e"})
|
||||
g.Assert(c.Container.Environment["CI_CMDS"] != "").IsTrue()
|
||||
g.Assert(c.Container.Command).Equal([]string{"echo $DRONE_SCRIPT | base64 -d | /bin/sh -e"})
|
||||
g.Assert(c.Container.Environment["DRONE_SCRIPT"] != "").IsTrue()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ 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
|
||||
|
|
|
@ -29,7 +29,7 @@ func TestSecret(t *testing.T) {
|
|||
g.It("should match any image", func() {
|
||||
secret := Secret{}
|
||||
secret.Images = []string{"*"}
|
||||
g.Assert(secret.MatchImage("golang")).IsTrue()
|
||||
g.Assert(secret.MatchImage("custom/golang")).IsTrue()
|
||||
})
|
||||
g.It("should match any event", func() {
|
||||
secret := Secret{}
|
||||
|
|
|
@ -16,6 +16,6 @@ type Work struct {
|
|||
Netrc *model.Netrc `json:"netrc"`
|
||||
Keys *model.Key `json:"keys"`
|
||||
System *model.System `json:"system"`
|
||||
Secrets []*model.Secret `json:"secret"`
|
||||
Secrets []*model.Secret `json:"secrets"`
|
||||
User *model.User `json:"user"`
|
||||
}
|
||||
|
|
|
@ -164,12 +164,14 @@ func Load(middlewares ...gin.HandlerFunc) http.Handler {
|
|||
|
||||
queue := e.Group("/api/queue")
|
||||
{
|
||||
queue.Use(middleware.AgentMust())
|
||||
queue.POST("/pull", api.Pull)
|
||||
queue.POST("/pull/:os/:arch", api.Pull)
|
||||
queue.POST("/wait/:id", api.Wait)
|
||||
queue.POST("/stream/:id", api.Stream)
|
||||
queue.POST("/status/:id", api.Update)
|
||||
if os.Getenv("CANARY") == "true" {
|
||||
queue.Use(middleware.AgentMust())
|
||||
queue.POST("/pull", api.Pull)
|
||||
queue.POST("/pull/:os/:arch", api.Pull)
|
||||
queue.POST("/wait/:id", api.Wait)
|
||||
queue.POST("/stream/:id", api.Stream)
|
||||
queue.POST("/status/:id", api.Update)
|
||||
}
|
||||
}
|
||||
|
||||
gitlab := e.Group("/gitlab/:owner/:name")
|
||||
|
|
|
@ -33,10 +33,7 @@ func TestRepos(t *testing.T) {
|
|||
err1 := s.CreateRepo(&repo)
|
||||
err2 := s.UpdateRepo(&repo)
|
||||
getrepo, err3 := s.GetRepo(repo.ID)
|
||||
if err3 != nil {
|
||||
println("Get Repo Error")
|
||||
println(err3.Error())
|
||||
}
|
||||
|
||||
g.Assert(err1 == nil).IsTrue()
|
||||
g.Assert(err2 == nil).IsTrue()
|
||||
g.Assert(err3 == nil).IsTrue()
|
||||
|
|
|
@ -9,13 +9,13 @@ type Setter interface {
|
|||
Set(string, interface{})
|
||||
}
|
||||
|
||||
// FromContext returns the Mux associated with this context.
|
||||
func FromContext(c context.Context) Mux {
|
||||
return c.Value(key).(Mux)
|
||||
// FromContext returns the Stream associated with this context.
|
||||
func FromContext(c context.Context) Stream {
|
||||
return c.Value(key).(Stream)
|
||||
}
|
||||
|
||||
// ToContext adds the Mux to this context if it supports
|
||||
// the Setter interface.
|
||||
func ToContext(c Setter, m Mux) {
|
||||
c.Set(key, m)
|
||||
// ToContext adds the Stream to this context if it supports the
|
||||
// Setter interface.
|
||||
func ToContext(c Setter, s Stream) {
|
||||
c.Set(key, s)
|
||||
}
|
||||
|
|
54
stream/reader.go
Normal file
54
stream/reader.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package stream
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type reader struct {
|
||||
w *writer
|
||||
off int
|
||||
closed uint32
|
||||
}
|
||||
|
||||
// Read reads from the Buffer
|
||||
func (r *reader) Read(p []byte) (n int, err error) {
|
||||
r.w.RLock()
|
||||
defer r.w.RUnlock()
|
||||
|
||||
var m int
|
||||
|
||||
for len(p) > 0 {
|
||||
|
||||
m, _ = bytes.NewReader(r.w.buffer.Bytes()[r.off:]).Read(p)
|
||||
n += m
|
||||
r.off += n
|
||||
|
||||
if n > 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if r.w.Closed() {
|
||||
err = io.EOF
|
||||
break
|
||||
}
|
||||
if r.Closed() {
|
||||
err = io.EOF
|
||||
break
|
||||
}
|
||||
|
||||
r.w.Wait()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *reader) Close() error {
|
||||
atomic.StoreUint32(&r.closed, 1)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *reader) Closed() bool {
|
||||
return atomic.LoadUint32(&r.closed) != 0
|
||||
}
|
7
stream/reader_test.go
Normal file
7
stream/reader_test.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package stream
|
||||
|
||||
import "testing"
|
||||
|
||||
func TetsReader(t *testing.T) {
|
||||
t.Skip() //TODO(bradrydzewski) implement reader tests
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
package stream
|
||||
|
||||
//go:generate mockery -name Mux -output mock -case=underscore
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
|
@ -10,43 +8,32 @@ import (
|
|||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Mux defines a stream multiplexer
|
||||
type Mux interface {
|
||||
// Create creates and returns a new stream identified by
|
||||
// the specified key.
|
||||
Create(key string) (io.ReadCloser, io.WriteCloser, error)
|
||||
|
||||
// Open returns the existing stream by key. If the stream
|
||||
// does not exist an error is returned.
|
||||
Open(key string) (io.ReadCloser, io.WriteCloser, error)
|
||||
|
||||
// Remove deletes the stream by key.
|
||||
Remove(key string) error
|
||||
|
||||
// Exists return true if the stream exists.
|
||||
Exists(key string) bool
|
||||
// Stream manages the stream of build logs.
|
||||
type Stream interface {
|
||||
Create(string) error
|
||||
Delete(string) error
|
||||
Reader(string) (io.ReadCloser, error)
|
||||
Writer(string) (io.WriteCloser, error)
|
||||
}
|
||||
|
||||
// Create creates and returns a new stream identified
|
||||
// by the specified key.
|
||||
func Create(c context.Context, key string) (io.ReadCloser, io.WriteCloser, error) {
|
||||
// Create creates a new stream.
|
||||
func Create(c context.Context, key string) error {
|
||||
return FromContext(c).Create(key)
|
||||
}
|
||||
|
||||
// Open returns the existing stream by key. If the stream does
|
||||
// not exist an error is returned.
|
||||
func Open(c context.Context, key string) (io.ReadCloser, io.WriteCloser, error) {
|
||||
return FromContext(c).Open(key)
|
||||
// Reader opens the stream for reading.
|
||||
func Reader(c context.Context, key string) (io.ReadCloser, error) {
|
||||
return FromContext(c).Reader(key)
|
||||
}
|
||||
|
||||
// Exists return true if the stream exists.
|
||||
func Exists(c context.Context, key string) bool {
|
||||
return FromContext(c).Exists(key)
|
||||
// Writer opens the stream for writing.
|
||||
func Writer(c context.Context, key string) (io.WriteCloser, error) {
|
||||
return FromContext(c).Writer(key)
|
||||
}
|
||||
|
||||
// Remove deletes the stream by key.
|
||||
func Remove(c context.Context, key string) error {
|
||||
return FromContext(c).Remove(key)
|
||||
// Delete deletes the stream by key.
|
||||
func Delete(c context.Context, key string) error {
|
||||
return FromContext(c).Delete(key)
|
||||
}
|
||||
|
||||
// ToKey is a helper function that converts a unique identifier
|
||||
|
@ -55,9 +42,9 @@ func ToKey(i int64) string {
|
|||
return strconv.FormatInt(i, 10)
|
||||
}
|
||||
|
||||
// Copy copies the stream from the source to the destination in
|
||||
// valid JSON format. This converts the logs, which are per-line
|
||||
// JSON objects, to a JSON array.
|
||||
// Copy copies the stream from the source to the destination in valid JSON
|
||||
// format. This converts the logs, which are per-line JSON objects, to a
|
||||
// proper JSON array.
|
||||
func Copy(dest io.Writer, src io.Reader) error {
|
||||
io.WriteString(dest, "[")
|
||||
|
||||
|
|
|
@ -1,96 +1,72 @@
|
|||
package stream
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/djherbis/fscache"
|
||||
)
|
||||
|
||||
var noexp fscache.Reaper
|
||||
type stream struct {
|
||||
sync.Mutex
|
||||
writers map[string]*writer
|
||||
}
|
||||
|
||||
// New creates a new Mux using an in-memory filesystem.
|
||||
func New() Mux {
|
||||
fs := fscache.NewMemFs()
|
||||
c, err := fscache.NewCache(fs, noexp)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
// New returns a new in-memory implementation of Stream.
|
||||
func New() Stream {
|
||||
return &stream{
|
||||
writers: map[string]*writer{},
|
||||
}
|
||||
return &mux{c}
|
||||
}
|
||||
|
||||
// New creates a new Mux using a persistent filesystem.
|
||||
func NewFileSystem(path string) Mux {
|
||||
fs, err := fscache.NewFs(path, 0777)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
// Reader returns an io.Reader for reading from to the stream.
|
||||
func (s *stream) Reader(name string) (io.ReadCloser, error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if !s.exists(name) {
|
||||
return nil, fmt.Errorf("stream: cannot read stream %s, not found", name)
|
||||
}
|
||||
c, err := fscache.NewCache(fs, noexp)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return s.writers[name].Reader()
|
||||
}
|
||||
|
||||
// Writer returns an io.WriteCloser for writing to the stream.
|
||||
func (s *stream) Writer(name string) (io.WriteCloser, error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if !s.exists(name) {
|
||||
return nil, fmt.Errorf("stream: cannot write stream %s, not found", name)
|
||||
}
|
||||
return &mux{c}
|
||||
return s.writers[name], nil
|
||||
}
|
||||
|
||||
// mux wraps the default fscache.Cache to match the
|
||||
// defined interface and to wrap the ReadCloser and
|
||||
// WriteCloser to avoid panics when we over-aggressively
|
||||
// close streams.
|
||||
type mux struct {
|
||||
cache fscache.Cache
|
||||
}
|
||||
// Create creates a new stream.
|
||||
func (s *stream) Create(name string) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
func (m *mux) Create(key string) (io.ReadCloser, io.WriteCloser, error) {
|
||||
rc, wc, err := m.cache.Get(key)
|
||||
if rc != nil {
|
||||
rc = &closeOnceReader{ReaderAt: rc, ReadCloser: rc}
|
||||
if s.exists(name) {
|
||||
return fmt.Errorf("stream: cannot create stream %s, already exists", name)
|
||||
}
|
||||
if wc != nil {
|
||||
wc = &closeOnceWriter{WriteCloser: wc}
|
||||
}
|
||||
return rc, wc, err
|
||||
}
|
||||
|
||||
func (m *mux) Open(key string) (io.ReadCloser, io.WriteCloser, error) {
|
||||
return m.Create(key)
|
||||
}
|
||||
|
||||
func (m *mux) Exists(key string) bool {
|
||||
return m.cache.Exists(key)
|
||||
}
|
||||
func (m *mux) Remove(key string) error {
|
||||
return m.cache.Remove(key)
|
||||
}
|
||||
|
||||
// closeOnceReader is a helper function that ensures
|
||||
// the reader is only closed once. This is because
|
||||
// attempting to close the fscache reader more than
|
||||
// once results in a panic.
|
||||
type closeOnceReader struct {
|
||||
io.ReaderAt
|
||||
io.ReadCloser
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func (c *closeOnceReader) Close() error {
|
||||
c.once.Do(func() {
|
||||
c.ReadCloser.Close()
|
||||
})
|
||||
s.writers[name] = newWriter()
|
||||
return nil
|
||||
}
|
||||
|
||||
// closeOnceWriter is a helper function that ensures
|
||||
// the writer is only closed once. This is because
|
||||
// attempting to close the fscache writer more than
|
||||
// once results in a panic.
|
||||
type closeOnceWriter struct {
|
||||
io.WriteCloser
|
||||
once sync.Once
|
||||
// Delete deletes the stream by key.
|
||||
func (s *stream) Delete(name string) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if !s.exists(name) {
|
||||
return fmt.Errorf("stream: cannot delete stream %s, not found", name)
|
||||
}
|
||||
w := s.writers[name]
|
||||
delete(s.writers, name)
|
||||
return w.Close()
|
||||
}
|
||||
|
||||
func (c *closeOnceWriter) Close() error {
|
||||
c.once.Do(func() {
|
||||
c.WriteCloser.Close()
|
||||
})
|
||||
return nil
|
||||
func (s *stream) exists(name string) bool {
|
||||
_, exists := s.writers[name]
|
||||
return exists
|
||||
}
|
||||
|
|
|
@ -1 +1,7 @@
|
|||
package stream
|
||||
|
||||
import "testing"
|
||||
|
||||
func TetsStream(t *testing.T) {
|
||||
t.Skip() //TODO(bradrydzewski) implement stream tests
|
||||
}
|
||||
|
|
52
stream/writer.go
Normal file
52
stream/writer.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
package stream
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type writer struct {
|
||||
sync.RWMutex
|
||||
*sync.Cond
|
||||
|
||||
buffer bytes.Buffer
|
||||
closed uint32
|
||||
}
|
||||
|
||||
func newWriter() *writer {
|
||||
var w writer
|
||||
w.Cond = sync.NewCond(w.RWMutex.RLocker())
|
||||
return &w
|
||||
}
|
||||
|
||||
func (w *writer) Write(p []byte) (n int, err error) {
|
||||
defer w.Broadcast()
|
||||
w.Lock()
|
||||
defer w.Unlock()
|
||||
if w.Closed() {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return w.buffer.Write(p)
|
||||
}
|
||||
|
||||
func (w *writer) Reader() (io.ReadCloser, error) {
|
||||
return &reader{w: w}, nil
|
||||
}
|
||||
|
||||
func (w *writer) Wait() {
|
||||
if !w.Closed() {
|
||||
w.Cond.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
func (w *writer) Close() error {
|
||||
atomic.StoreUint32(&w.closed, 1)
|
||||
w.Cond.Broadcast()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *writer) Closed() bool {
|
||||
return atomic.LoadUint32(&w.closed) != 0
|
||||
}
|
7
stream/writer_test.go
Normal file
7
stream/writer_test.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package stream
|
||||
|
||||
import "testing"
|
||||
|
||||
func TetsWriter(t *testing.T) {
|
||||
t.Skip() //TODO(bradrydzewski) implement writer tests
|
||||
}
|
201
vendor/github.com/jackspirou/syscerts/LICENSE
generated
vendored
Normal file
201
vendor/github.com/jackspirou/syscerts/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
42
vendor/github.com/jackspirou/syscerts/README.md
generated
vendored
Normal file
42
vendor/github.com/jackspirou/syscerts/README.md
generated
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
# syscerts
|
||||
Gather local system certificates in Go via a public `SystemRootsPool` method.
|
||||
|
||||
#### What does this do?
|
||||
Provide a way to gather local system certificates
|
||||
on different OS platforms.
|
||||
|
||||
#### How does it do it?
|
||||
It uses the `crypto/x509` package and provides a single public method called
|
||||
`SystemRootsPool()` to return a `*x509.CertPool` object.
|
||||
|
||||
#### How do you use it?
|
||||
```Go
|
||||
// gather CA certs
|
||||
certpool := syscerts.SystemRootsPool()
|
||||
|
||||
// place them in an HTTP client for trusted SSL/TLS connections
|
||||
tlsConfig := &tls.Config{RootCAs: certpool}
|
||||
transport := &http.Transport{TLSClientConfig: tlsConfig}
|
||||
client := &http.Client{Transport: transport}
|
||||
|
||||
// make a request
|
||||
resp, err := client.Do(req)
|
||||
```
|
||||
|
||||
#### Why even do it?
|
||||
The `crypto/x509` package already has a `systemRootsPool` method.
|
||||
The `crypto/x509.systemRootsPool` method is almost the same as
|
||||
`github.com/jackspirou/syscerts.SystemRootsPool`.
|
||||
The difference? The `crypto/x509.systemRootsPool` method is private so you
|
||||
cannot access it. :(
|
||||
|
||||
There are plans for the `crypto/x509.systemRootsPool` method to become public
|
||||
in Go 1.7. When this happens you might no longer need `github.com/jackspirou/syscerts.SystemRootsPool`.
|
||||
|
||||
The only reason you may still use this package after the Go 1.7 release might
|
||||
be for the Mac OSX System Keychain certs which are not included in the
|
||||
`crypto/x509` package. Relevant lines below:
|
||||
|
||||
* https://github.com/jackspirou/syscerts/blob/master/root_darwin.go#L24-L32
|
||||
|
||||
Find more about this Go issue here: https://github.com/golang/go/issues/13335
|
22
vendor/github.com/jackspirou/syscerts/root.go
generated
vendored
Normal file
22
vendor/github.com/jackspirou/syscerts/root.go
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscerts
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
systemRoots *x509.CertPool
|
||||
)
|
||||
|
||||
// SystemRootsPool attempts to find and return a pool of all all installed
|
||||
// system certificates.
|
||||
func SystemRootsPool() *x509.CertPool {
|
||||
once.Do(initSystemRoots)
|
||||
return systemRoots
|
||||
}
|
14
vendor/github.com/jackspirou/syscerts/root_bsd.go
generated
vendored
Normal file
14
vendor/github.com/jackspirou/syscerts/root_bsd.go
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build dragonfly freebsd netbsd openbsd
|
||||
|
||||
package syscerts
|
||||
|
||||
// Possible certificate files; stop after finding one.
|
||||
var certFiles = []string{
|
||||
"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly
|
||||
"/etc/ssl/cert.pem", // OpenBSD
|
||||
"/etc/openssl/certs/ca-certificates.crt", // NetBSD
|
||||
}
|
85
vendor/github.com/jackspirou/syscerts/root_cgo_darwin.go
generated
vendored
Normal file
85
vendor/github.com/jackspirou/syscerts/root_cgo_darwin.go
generated
vendored
Normal file
|
@ -0,0 +1,85 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build cgo,darwin,!arm,!arm64,!ios
|
||||
|
||||
package syscerts
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
|
||||
#cgo LDFLAGS: -framework CoreFoundation -framework Security
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Security/Security.h>
|
||||
|
||||
// FetchPEMRootsC fetches the system's list of trusted X.509 root certificates.
|
||||
//
|
||||
// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
|
||||
// certificates of the system. On failure, the function returns -1.
|
||||
//
|
||||
// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
|
||||
// we've consumed its content.
|
||||
int FetchPEMRootsC(CFDataRef *pemRoots) {
|
||||
if (pemRoots == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CFArrayRef certs = NULL;
|
||||
OSStatus err = SecTrustCopyAnchorCertificates(&certs);
|
||||
if (err != noErr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
||||
int i, ncerts = CFArrayGetCount(certs);
|
||||
for (i = 0; i < ncerts; i++) {
|
||||
CFDataRef data = NULL;
|
||||
SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
|
||||
if (cert == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
|
||||
// Once we support weak imports via cgo we should prefer that, and fall back to this
|
||||
// for older systems.
|
||||
err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
|
||||
if (err != noErr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data != NULL) {
|
||||
CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
|
||||
CFRelease(data);
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(certs);
|
||||
|
||||
*pemRoots = combinedData;
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
import "C"
|
||||
import (
|
||||
"crypto/x509"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func initSystemRoots() {
|
||||
roots := x509.NewCertPool()
|
||||
|
||||
var data C.CFDataRef = nil
|
||||
err := C.FetchPEMRootsC(&data)
|
||||
if err == -1 {
|
||||
return
|
||||
}
|
||||
|
||||
defer C.CFRelease(C.CFTypeRef(data))
|
||||
buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
|
||||
roots.AppendCertsFromPEM(buf)
|
||||
systemRoots = roots
|
||||
}
|
||||
*/
|
39
vendor/github.com/jackspirou/syscerts/root_darwin.go
generated
vendored
Normal file
39
vendor/github.com/jackspirou/syscerts/root_darwin.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run root_darwin_arm_gen.go -output root_darwin_armx.go
|
||||
|
||||
package syscerts
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func execSecurityRoots() (*x509.CertPool, error) {
|
||||
roots := x509.NewCertPool()
|
||||
cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
|
||||
data, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
roots.AppendCertsFromPEM(data)
|
||||
|
||||
// if available add the Mac OSX System Keychain
|
||||
if _, err := os.Stat("/Library/Keychains/System.keychain"); err == nil {
|
||||
cmd = exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/Library/Keychains/System.keychain")
|
||||
data, err = cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
roots.AppendCertsFromPEM(data)
|
||||
}
|
||||
|
||||
return roots, nil
|
||||
}
|
||||
|
||||
func initSystemRoots() {
|
||||
systemRoots, _ = execSecurityRoots()
|
||||
}
|
4909
vendor/github.com/jackspirou/syscerts/root_darwin_armx.go
generated
vendored
Normal file
4909
vendor/github.com/jackspirou/syscerts/root_darwin_armx.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
13
vendor/github.com/jackspirou/syscerts/root_linux.go
generated
vendored
Normal file
13
vendor/github.com/jackspirou/syscerts/root_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscerts
|
||||
|
||||
// Possible certificate files; stop after finding one.
|
||||
var certFiles = []string{
|
||||
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
|
||||
"/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL
|
||||
"/etc/ssl/ca-bundle.pem", // OpenSUSE
|
||||
"/etc/pki/tls/cacert.pem", // OpenELEC
|
||||
}
|
8
vendor/github.com/jackspirou/syscerts/root_nacl.go
generated
vendored
Normal file
8
vendor/github.com/jackspirou/syscerts/root_nacl.go
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscerts
|
||||
|
||||
// Possible certificate files; stop after finding one.
|
||||
var certFiles = []string{}
|
32
vendor/github.com/jackspirou/syscerts/root_plan9.go
generated
vendored
Normal file
32
vendor/github.com/jackspirou/syscerts/root_plan9.go
generated
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build plan9
|
||||
|
||||
package syscerts
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// Possible certificate files; stop after finding one.
|
||||
var certFiles = []string{
|
||||
"/sys/lib/tls/ca.pem",
|
||||
}
|
||||
|
||||
func initSystemRoots() {
|
||||
roots := x509.NewCertPool()
|
||||
for _, file := range certFiles {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err == nil {
|
||||
roots.AppendCertsFromPEM(data)
|
||||
systemRoots = roots
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// All of the files failed to load. systemRoots will be nil which will
|
||||
// trigger a specific error at verification time.
|
||||
}
|
12
vendor/github.com/jackspirou/syscerts/root_solaris.go
generated
vendored
Normal file
12
vendor/github.com/jackspirou/syscerts/root_solaris.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscerts
|
||||
|
||||
// Possible certificate files; stop after finding one.
|
||||
var certFiles = []string{
|
||||
"/etc/certs/ca-certificates.crt", // Solaris 11.2+
|
||||
"/etc/ssl/certs/ca-certificates.crt", // Joyent SmartOS
|
||||
"/etc/ssl/cacert.pem", // OmniOS
|
||||
}
|
52
vendor/github.com/jackspirou/syscerts/root_unix.go
generated
vendored
Normal file
52
vendor/github.com/jackspirou/syscerts/root_unix.go
generated
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build dragonfly freebsd linux nacl netbsd openbsd solaris
|
||||
|
||||
package syscerts
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// Possible directories with certificate files; stop after successfully
|
||||
// reading at least one file from a directory.
|
||||
var certDirectories = []string{
|
||||
"/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139
|
||||
"/system/etc/security/cacerts", // Android
|
||||
}
|
||||
|
||||
func initSystemRoots() {
|
||||
roots := x509.NewCertPool()
|
||||
for _, file := range certFiles {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err == nil {
|
||||
roots.AppendCertsFromPEM(data)
|
||||
systemRoots = roots
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, directory := range certDirectories {
|
||||
fis, err := ioutil.ReadDir(directory)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
rootsAdded := false
|
||||
for _, fi := range fis {
|
||||
data, err := ioutil.ReadFile(directory + "/" + fi.Name())
|
||||
if err == nil && roots.AppendCertsFromPEM(data) {
|
||||
rootsAdded = true
|
||||
}
|
||||
}
|
||||
if rootsAdded {
|
||||
systemRoots = roots
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// All of the files failed to load. systemRoots will be nil which will
|
||||
// trigger a specific error at verification time.
|
||||
}
|
40
vendor/github.com/jackspirou/syscerts/root_windows.go
generated
vendored
Normal file
40
vendor/github.com/jackspirou/syscerts/root_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscerts
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// extractSimpleChain extracts the final certificate chain from a CertSimpleChain.
|
||||
func extractSimpleChain(simpleChain **syscall.CertSimpleChain, count int) (chain []*x509.Certificate, err error) {
|
||||
if simpleChain == nil || count == 0 {
|
||||
return nil, errors.New("x509: invalid simple chain")
|
||||
}
|
||||
|
||||
simpleChains := (*[1 << 20]*syscall.CertSimpleChain)(unsafe.Pointer(simpleChain))[:]
|
||||
lastChain := simpleChains[count-1]
|
||||
elements := (*[1 << 20]*syscall.CertChainElement)(unsafe.Pointer(lastChain.Elements))[:]
|
||||
for i := 0; i < int(lastChain.NumElements); i++ {
|
||||
// Copy the buf, since ParseCertificate does not create its own copy.
|
||||
cert := elements[i].CertContext
|
||||
encodedCert := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:]
|
||||
buf := make([]byte, cert.Length)
|
||||
copy(buf, encodedCert[:])
|
||||
parsedCert, err := x509.ParseCertificate(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
chain = append(chain, parsedCert)
|
||||
}
|
||||
|
||||
return chain, nil
|
||||
}
|
||||
|
||||
func initSystemRoots() {
|
||||
}
|
5
vendor/vendor.json
vendored
5
vendor/vendor.json
vendored
|
@ -133,6 +133,11 @@
|
|||
"revision": "9111d830d133f952887a936367fb0211c3134f0d",
|
||||
"revisionTime": "2014-07-20T15:03:42-06:00"
|
||||
},
|
||||
{
|
||||
"path": "github.com/jackspirou/syscerts",
|
||||
"revision": "5ecaea8f7ec96a0826ced1ff106d30083066bf35",
|
||||
"revisionTime": "2016-03-18T16:00:26-05:00"
|
||||
},
|
||||
{
|
||||
"path": "github.com/joho/godotenv",
|
||||
"revision": "4ed13390c0acd2ff4e371e64d8b97c8954138243",
|
||||
|
|
23
web/hook.go
23
web/hook.go
|
@ -33,7 +33,7 @@ func init() {
|
|||
}
|
||||
droneSec = fmt.Sprintf("%s.sec", strings.TrimSuffix(droneYml, filepath.Ext(droneYml)))
|
||||
if os.Getenv("CANARY") == "true" {
|
||||
droneSec = fmt.Sprintf("%s.sig", strings.TrimSuffix(droneYml, filepath.Ext(droneYml)))
|
||||
droneSec = fmt.Sprintf("%s.sig", droneYml)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,7 +209,10 @@ func PostHook(c *gin.Context) {
|
|||
// get the previous build so that we can send
|
||||
// on status change notifications
|
||||
last, _ := store.GetBuildLastBefore(c, repo, build.Branch, build.ID)
|
||||
secs, _ := store.GetSecretList(c, repo)
|
||||
secs, err := store.GetSecretList(c, repo)
|
||||
if err != nil {
|
||||
log.Errorf("Error getting secrets for %s#%d. %s", repo.FullName, build.Number, err)
|
||||
}
|
||||
|
||||
// IMPORTANT. PLEASE READ
|
||||
//
|
||||
|
@ -223,14 +226,24 @@ func PostHook(c *gin.Context) {
|
|||
var verified bool
|
||||
|
||||
signature, err := jose.ParseSigned(string(sec))
|
||||
if err == nil && len(sec) != 0 {
|
||||
if err != nil {
|
||||
log.Debugf("cannot parse .drone.yml.sig file. %s", err)
|
||||
} else if len(sec) == 0 {
|
||||
log.Debugf("cannot parse .drone.yml.sig file. empty file")
|
||||
} else {
|
||||
signed = true
|
||||
output, err := signature.Verify(repo.Hash)
|
||||
if err == nil && string(output) == string(raw) {
|
||||
output, err := signature.Verify([]byte(repo.Hash))
|
||||
if err != nil {
|
||||
log.Debugf("cannot verify .drone.yml.sig file. %s", err)
|
||||
} else if string(output) != string(raw) {
|
||||
log.Debugf("cannot verify .drone.yml.sig file. no match")
|
||||
} else {
|
||||
verified = true
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugf(".drone.yml is signed=%v and verified=%v", signed, verified)
|
||||
|
||||
bus.Publish(c, bus.NewBuildEvent(bus.Enqueued, repo, build))
|
||||
for _, job := range jobs {
|
||||
queue.Publish(c, &queue.Work{
|
||||
|
|
|
@ -91,21 +91,12 @@ func GetStream2(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
rc, wc, err := stream.Open(c, stream.ToKey(job.ID))
|
||||
rc, err := stream.Reader(c, stream.ToKey(job.ID))
|
||||
if err != nil {
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if wc != nil {
|
||||
wc.Close()
|
||||
}
|
||||
if rc != nil {
|
||||
rc.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
<-c.Writer.CloseNotify()
|
||||
rc.Close()
|
||||
|
@ -125,4 +116,6 @@ func GetStream2(c *gin.Context) {
|
|||
}
|
||||
c.Writer.Flush()
|
||||
}
|
||||
|
||||
log.Debugf("Closed stream %s#%d", repo.FullName, build.Number)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue