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 { type Context struct {
// Links *common.Link // Links *common.Link
Clone *common.Clone `json:"clone"` Clone *common.Clone `json:"clone"`
Repo *common.Repo `json:"repo"` Repo *common.Repo `json:"repo"`
Commit *common.Commit `json:"commit"` Commit *common.Commit `json:"commit"`
Build *common.Build `json:"build"` Build *common.Build `json:"build"`
Keys *common.Keypair `json:"keys"` Keys *common.Keypair `json:"keys"`
Netrc *common.Netrc `json:"netrc"` Netrc *common.Netrc `json:"netrc"`
Yaml []byte `json:"yaml"` Yaml []byte `json:"yaml"`
Env []string `json:"env"` Env []string `json:"environment"`
Plugins []string `json:"plugins"`
Conf *common.Config `json:"-"` Conf *common.Config `json:"-"`
infos []*dockerclient.ContainerInfo infos []*dockerclient.ContainerInfo
@ -29,12 +30,19 @@ type Context struct {
func setup(c *Context) error { func setup(c *Context) error {
var err 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 // if repository is trusted the build may specify
// custom volumes, networking and run in trusted mode. // custom volumes, networking and run in trusted mode.
if c.Repo.Trusted { 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 // inject the matrix parameters into the yaml

View file

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

View file

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

View file

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

View file

@ -2,6 +2,7 @@ package parser
import ( import (
"fmt" "fmt"
"path/filepath"
"strings" "strings"
common "github.com/drone/drone/pkg/types" common "github.com/drone/drone/pkg/types"
@ -103,3 +104,42 @@ func expectTrustedNotify(c *common.Config) error {
} }
return nil 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 Volumes bool
Network bool Network bool
Privileged bool Privileged bool
Whitelist []string
} }
var DefaultOpts = &Opts{ var DefaultOpts = &Opts{
Volumes: false, Volumes: false,
Network: false, Network: false,
Privileged: false, Privileged: false,
Whitelist: []string{"plugins/*"},
} }
// Parse parses a build matrix and returns // Parse parses a build matrix and returns