provides a way to white-list plugins at a global config level

This commit is contained in:
Brad Rydzewski 2015-05-19 23:19:59 -07:00
parent f3c06a8fc3
commit 8c655d600d
7 changed files with 139 additions and 31 deletions

View file

@ -13,14 +13,15 @@ import (
type Context struct {
// Links *common.Link
Clone *common.Clone `json:"clone"`
Repo *common.Repo `json:"repo"`
Commit *common.Commit `json:"commit"`
Build *common.Build `json:"build"`
Keys *common.Keypair `json:"keys"`
Netrc *common.Netrc `json:"netrc"`
Yaml []byte `json:"yaml"`
Env []string `json:"env"`
Clone *common.Clone `json:"clone"`
Repo *common.Repo `json:"repo"`
Commit *common.Commit `json:"commit"`
Build *common.Build `json:"build"`
Keys *common.Keypair `json:"keys"`
Netrc *common.Netrc `json:"netrc"`
Yaml []byte `json:"yaml"`
Env []string `json:"environment"`
Plugins []string `json:"plugins"`
Conf *common.Config `json:"-"`
infos []*dockerclient.ContainerInfo
@ -29,12 +30,19 @@ type Context struct {
func setup(c *Context) error {
var err error
var opts = parser.DefaultOpts
var opts = parser.Opts{
Network: true,
Privileged: true,
Volumes: true,
Whitelist: c.Plugins,
}
// if repository is trusted the build may specify
// custom volumes, networking and run in trusted mode.
if c.Repo.Trusted {
opts = &parser.Opts{Network: true, Privileged: true, Volumes: true}
opts.Network = true
opts.Privileged = true
opts.Volumes = true
}
// inject the matrix parameters into the yaml

View file

@ -9,13 +9,14 @@ import (
// Work represents an item for work to be
// processed by a worker.
type Work struct {
User *common.User `json:"user"`
Repo *common.Repo `json:"repo"`
Commit *common.Commit `json:"commit"`
Keys *common.Keypair `json:"keypair"`
Netrc *common.Netrc `json:"netrc"`
Yaml []byte `json:"yaml"`
Env []string `json:"env"`
User *common.User `json:"user"`
Repo *common.Repo `json:"repo"`
Commit *common.Commit `json:"commit"`
Keys *common.Keypair `json:"keypair"`
Netrc *common.Netrc `json:"netrc"`
Yaml []byte `json:"yaml"`
Env []string `json:"environment"`
Plugins []string `json:"plugins"`
}
// represents a worker that has connected

View file

@ -112,13 +112,14 @@ func (r *Runner) Run(w *queue.Work) error {
}
work := &work{
Repo: w.Repo,
Commit: w.Commit,
Keys: w.Keys,
Netrc: w.Netrc,
Yaml: w.Yaml,
Build: task,
Env: w.Env,
Repo: w.Repo,
Commit: w.Commit,
Keys: w.Keys,
Netrc: w.Netrc,
Yaml: w.Yaml,
Build: task,
Env: w.Env,
Plugins: w.Plugins,
}
in, err := json.Marshal(work)
if err != nil {

View file

@ -52,13 +52,14 @@ var (
)
type work struct {
Repo *common.Repo `json:"repo"`
Commit *common.Commit `json:"commit"`
Build *common.Build `json:"build"`
Keys *common.Keypair `json:"keys"`
Netrc *common.Netrc `json:"netrc"`
Yaml []byte `json:"yaml"`
Env []string `json:"env"`
Repo *common.Repo `json:"repo"`
Commit *common.Commit `json:"commit"`
Build *common.Build `json:"build"`
Keys *common.Keypair `json:"keys"`
Netrc *common.Netrc `json:"netrc"`
Yaml []byte `json:"yaml"`
Env []string `json:"environment"`
Plugins []string `json:"plugins"`
}
type worker struct {

View file

@ -2,6 +2,7 @@ package parser
import (
"fmt"
"path/filepath"
"strings"
common "github.com/drone/drone/pkg/types"
@ -103,3 +104,42 @@ func expectTrustedNotify(c *common.Config) error {
}
return nil
}
func LintPlugins(c *common.Config, opts *Opts) error {
if len(opts.Whitelist) == 0 {
return nil
}
var images []string
images = append(images, c.Setup.Image)
images = append(images, c.Clone.Image)
c.Clone.Image = imageName(c.Clone.Image)
for _, step := range c.Publish {
images = append(images, step.Image)
}
for _, step := range c.Deploy {
images = append(images, step.Image)
}
for _, step := range c.Notify {
images = append(images, step.Image)
}
for _, image := range images {
match := false
for _, pattern := range opts.Whitelist {
if pattern == image {
match = true
break
}
ok, err := filepath.Match(pattern, image)
if ok && err == nil {
match = true
break
}
}
if !match {
return fmt.Errorf("Cannot use un-trusted image %s", image)
}
}
return nil
}

View file

@ -90,3 +90,58 @@ func Test_Linter(t *testing.T) {
})
}
func Test_LintPlugins(t *testing.T) {
g := goblin.Goblin(t)
g.Describe("Plugin Linter", func() {
g.It("Should fail un-trusted plugin", func() {
c := &common.Config{
Setup: &common.Step{Image: "foo/baz"},
Clone: &common.Step{Image: "foo/bar"},
Notify: map[string]*common.Step{},
Deploy: map[string]*common.Step{},
Publish: map[string]*common.Step{},
}
o := &Opts{Whitelist: []string{"plugins/*"}}
g.Assert(LintPlugins(c, o) != nil).IsTrue()
})
g.It("Should pass when empty whitelist", func() {
c := &common.Config{
Setup: &common.Step{Image: "foo/baz"},
Clone: &common.Step{Image: "foo/bar"},
Notify: map[string]*common.Step{},
Deploy: map[string]*common.Step{},
Publish: map[string]*common.Step{},
}
o := &Opts{Whitelist: []string{}}
g.Assert(LintPlugins(c, o) == nil).IsTrue()
})
g.It("Should pass wildcard", func() {
c := &common.Config{
Setup: &common.Step{Image: "plugins/drone-setup"},
Clone: &common.Step{Image: "plugins/drone-build"},
Notify: map[string]*common.Step{},
Deploy: map[string]*common.Step{},
Publish: map[string]*common.Step{},
}
o := &Opts{Whitelist: []string{"plugins/*"}}
g.Assert(LintPlugins(c, o) == nil).IsTrue()
})
g.It("Should pass itemized", func() {
c := &common.Config{
Setup: &common.Step{Image: "plugins/drone-setup"},
Clone: &common.Step{Image: "plugins/drone-build"},
Notify: map[string]*common.Step{},
Deploy: map[string]*common.Step{},
Publish: map[string]*common.Step{},
}
o := &Opts{Whitelist: []string{"plugins/drone-setup", "plugins/drone-build"}}
g.Assert(LintPlugins(c, o) == nil).IsTrue()
})
})
}

View file

@ -14,12 +14,14 @@ type Opts struct {
Volumes bool
Network bool
Privileged bool
Whitelist []string
}
var DefaultOpts = &Opts{
Volumes: false,
Network: false,
Privileged: false,
Whitelist: []string{"plugins/*"},
}
// Parse parses a build matrix and returns