From cf953f19d31797fdebff4a9527bca7adc850e7ec Mon Sep 17 00:00:00 2001 From: Brad Rydzewski Date: Tue, 8 Sep 2015 19:18:30 -0700 Subject: [PATCH] removed yaml functions that were pushed down to the build layer --- pkg/remote/client/client.go | 118 +++++----- pkg/yaml/inject/inject.go | 54 ----- pkg/yaml/inject/inject_test.go | 67 ------ pkg/yaml/lint.go | 142 ------------ pkg/yaml/lint_test.go | 177 --------------- pkg/yaml/parse.go | 104 +-------- pkg/yaml/transform/transform.go | 314 --------------------------- pkg/yaml/transform/transform_test.go | 220 ------------------- 8 files changed, 62 insertions(+), 1134 deletions(-) delete mode 100644 pkg/yaml/inject/inject.go delete mode 100644 pkg/yaml/inject/inject_test.go delete mode 100644 pkg/yaml/lint.go delete mode 100644 pkg/yaml/lint_test.go delete mode 100644 pkg/yaml/transform/transform.go delete mode 100644 pkg/yaml/transform/transform_test.go diff --git a/pkg/remote/client/client.go b/pkg/remote/client/client.go index be3a096a2..6d3c18ab6 100644 --- a/pkg/remote/client/client.go +++ b/pkg/remote/client/client.go @@ -1,74 +1,74 @@ package client -import ( - "net" - "net/http" - "net/rpc" +// import ( +// "net" +// "net/http" +// "net/rpc" - common "github.com/drone/drone/pkg/types" -) +// common "github.com/drone/drone/pkg/types" +// ) -// Client communicates with a Remote plugin using the -// net/rpc protocol. -type Client struct { - *rpc.Client -} +// // Client communicates with a Remote plugin using the +// // net/rpc protocol. +// type Client struct { +// *rpc.Client +// } -// New returns a new, remote datastore backend that connects -// via tcp and exchanges data using Go's RPC mechanism. -func New(conf *config.Config) (*Client, error) { - // conn, err := net.Dial("tcp", conf.Server.Addr) - // if err != nil { - // return nil, err - // } - // client := &Client{ - // rpc.NewClient(conn), - // } - // return client, nil - return nil, nil -} +// // New returns a new, remote datastore backend that connects +// // via tcp and exchanges data using Go's RPC mechanism. +// func New(conf *config.Config) (*Client, error) { +// // conn, err := net.Dial("tcp", conf.Server.Addr) +// // if err != nil { +// // return nil, err +// // } +// // client := &Client{ +// // rpc.NewClient(conn), +// // } +// // return client, nil +// return nil, nil +// } -func (c *Client) Login(token, secret string) (*common.User, error) { - return nil, nil -} +// func (c *Client) Login(token, secret string) (*common.User, error) { +// return nil, nil +// } -// Repo fetches the named repository from the remote system. -func (c *Client) Repo(u *common.User, owner, repo string) (*common.Repo, error) { - return nil, nil -} +// // Repo fetches the named repository from the remote system. +// func (c *Client) Repo(u *common.User, owner, repo string) (*common.Repo, error) { +// return nil, nil +// } -func (c *Client) Perm(u *common.User, owner, repo string) (*common.Perm, error) { - return nil, nil -} +// func (c *Client) Perm(u *common.User, owner, repo string) (*common.Perm, error) { +// return nil, nil +// } -func (c *Client) Script(u *common.User, r *common.Repo, b *common.Build) ([]byte, error) { - return nil, nil -} +// func (c *Client) Script(u *common.User, r *common.Repo, b *common.Build) ([]byte, error) { +// return nil, nil +// } -func (c *Client) Status(u *common.User, r *common.Repo, b *common.Build, link string) error { - return nil -} +// func (c *Client) Status(u *common.User, r *common.Repo, b *common.Build, link string) error { +// return nil +// } -func (c *Client) Activate(u *common.User, r *common.Repo, k *common.Keypair, link string) error { - return nil -} +// func (c *Client) Activate(u *common.User, r *common.Repo, k *common.Keypair, link string) error { +// return nil +// } -func (c *Client) Deactivate(u *common.User, r *common.Repo, link string) error { - return nil -} +// func (c *Client) Deactivate(u *common.User, r *common.Repo, link string) error { +// return nil +// } -func (c *Client) Hook(r *http.Request) (*common.Hook, error) { - hook := new(common.Hook) - header := make(http.Header) - copyHeader(r.Header, header) +// func (c *Client) Hook(r *http.Request) (*common.Hook, error) { +// hook := new(common.Hook) +// header := make(http.Header) +// copyHeader(r.Header, header) - return hook, nil -} +// return hook, nil +// } -func copyHeader(dst, src http.Header) { - for k, vv := range src { - for _, v := range vv { - dst.Add(k, v) - } - } -} +// func copyHeader(dst, src http.Header) { +// for k, vv := range src { +// for _, v := range vv { +// dst.Add(k, v) +// } +// } +// } diff --git a/pkg/yaml/inject/inject.go b/pkg/yaml/inject/inject.go deleted file mode 100644 index 8d1784872..000000000 --- a/pkg/yaml/inject/inject.go +++ /dev/null @@ -1,54 +0,0 @@ -package inject - -import ( - "sort" - "strings" - - "github.com/drone/drone/Godeps/_workspace/src/gopkg.in/yaml.v2" - "github.com/drone/drone/pkg/types" -) - -// Inject injects a map of parameters into a raw string and returns -// the resulting string. -// -// Parameters are represented in the string using $$ notation, similar -// to how environment variables are defined in Makefiles. -func Inject(raw string, params map[string]string) string { - if params == nil { - return raw - } - keys := []string{} - for k := range params { - keys = append(keys, k) - } - sort.Sort(sort.Reverse(sort.StringSlice(keys))) - injected := raw - for _, k := range keys { - v := params[k] - injected = strings.Replace(injected, "$$"+k, v, -1) - } - return injected -} - -// InjectSafe attempts to safely inject parameters without leaking -// parameters in the Build or Compose section of the yaml file. -// -// The intended use case for this function are public pull requests. -// We want to avoid a malicious pull request that allows someone -// to inject and print private variables. -func InjectSafe(raw string, params map[string]string) string { - before, _ := parse(raw) - after, _ := parse(Inject(raw, params)) - before.Notify = after.Notify - before.Publish = after.Publish - before.Deploy = after.Deploy - result, _ := yaml.Marshal(before) - return string(result) -} - -// helper funtion to parse a yaml configuration file. -func parse(raw string) (*types.Config, error) { - cfg := types.Config{} - err := yaml.Unmarshal([]byte(raw), &cfg) - return &cfg, err -} diff --git a/pkg/yaml/inject/inject_test.go b/pkg/yaml/inject/inject_test.go deleted file mode 100644 index b130f6505..000000000 --- a/pkg/yaml/inject/inject_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package inject - -import ( - "testing" - - "github.com/drone/drone/Godeps/_workspace/src/github.com/franela/goblin" -) - -func Test_Inject(t *testing.T) { - - g := goblin.Goblin(t) - g.Describe("Inject params", func() { - - g.It("Should replace vars with $$", func() { - s := "echo $$FOO $BAR" - m := map[string]string{} - m["FOO"] = "BAZ" - g.Assert("echo BAZ $BAR").Equal(Inject(s, m)) - }) - - g.It("Should not replace vars with single $", func() { - s := "echo $FOO $BAR" - m := map[string]string{} - m["FOO"] = "BAZ" - g.Assert(s).Equal(Inject(s, m)) - }) - - g.It("Should not replace vars in nil map", func() { - s := "echo $$FOO $BAR" - g.Assert(s).Equal(Inject(s, nil)) - }) - }) -} - -func Test_InjectSafe(t *testing.T) { - - g := goblin.Goblin(t) - g.Describe("Safely Inject params", func() { - - m := map[string]string{} - m["TOKEN"] = "FOO" - m["SECRET"] = "BAR" - c, _ := parse(InjectSafe(yml, m)) - - g.It("Should replace vars in notify section", func() { - g.Assert(c.Deploy["digital_ocean"].Config["token"]).Equal("FOO") - g.Assert(c.Deploy["digital_ocean"].Config["secret"]).Equal("BAR") - }) - - g.It("Should not replace vars in script section", func() { - g.Assert(c.Build.Config["commands"].([]interface{})[0]).Equal("echo $$TOKEN") - g.Assert(c.Build.Config["commands"].([]interface{})[1]).Equal("echo $$SECRET") - }) - }) -} - -var yml = ` -build: - image: foo - commands: - - echo $$TOKEN - - echo $$SECRET -deploy: - digital_ocean: - token: $$TOKEN - secret: $$SECRET -` diff --git a/pkg/yaml/lint.go b/pkg/yaml/lint.go deleted file mode 100644 index 750f1ff47..000000000 --- a/pkg/yaml/lint.go +++ /dev/null @@ -1,142 +0,0 @@ -package parser - -import ( - "fmt" - "path/filepath" - "strings" - - common "github.com/drone/drone/pkg/types" -) - -// lintRule defines a function that runs lint -// checks against a Yaml Config file. If the rule -// fails it should return an error message. -type lintRule func(*common.Config) error - -var lintRules = []lintRule{ - expectBuild, - expectImage, - expectCommand, - expectCloneInWorkspace, - expectCacheInWorkspace, -} - -// Lint runs all lint rules against the Yaml Config. -func Lint(c *common.Config) error { - for _, rule := range lintRules { - err := rule(c) - if err != nil { - return err - } - } - return nil -} - -// lint rule that fails when no build is defined -func expectBuild(c *common.Config) error { - if c.Build == nil { - return fmt.Errorf("Yaml must define a build section") - } - return nil -} - -// lint rule that fails when no build image is defined -func expectImage(c *common.Config) error { - if len(c.Build.Image) == 0 { - return fmt.Errorf("Yaml must define a build image") - } - return nil -} - -// lint rule that fails when no build commands are defined -func expectCommand(c *common.Config) error { - if c.Setup.Config == nil || c.Setup.Config["commands"] == nil { - return fmt.Errorf("Yaml must define build / setup commands") - } - return nil -} - -// lint rule that fails if the clone directory is not contained -// in the root workspace. -func expectCloneInWorkspace(c *common.Config) error { - pathv, ok := c.Clone.Config["path"] - var path string - - if ok { - path, _ = pathv.(string) - } - if len(path) == 0 { - // This should only happen if the transformer was not run - return fmt.Errorf("No workspace specified") - } - - relative, relOk := filepath.Rel("/drone/src", path) - if relOk != nil { - return fmt.Errorf("Path is not relative to root") - } - - cleaned := filepath.Clean(relative) - if strings.Index(cleaned, "../") != -1 { - return fmt.Errorf("Cannot clone above the root") - } - - return nil -} - -// lint rule that fails if the cache directories are not contained -// in the workspace. -func expectCacheInWorkspace(c *common.Config) error { - for _, step := range c.Build.Cache { - if strings.Index(step, ":") != -1 { - return fmt.Errorf("Cache cannot contain : in the path") - } - - cleaned := filepath.Clean(step) - - if strings.Index(cleaned, "../") != -1 { - return fmt.Errorf("Cache must point to a path in the workspace") - } else if cleaned == "." { - return fmt.Errorf("Cannot cache the workspace") - } - } - - 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) - 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 -} diff --git a/pkg/yaml/lint_test.go b/pkg/yaml/lint_test.go deleted file mode 100644 index a7d1afdbc..000000000 --- a/pkg/yaml/lint_test.go +++ /dev/null @@ -1,177 +0,0 @@ -package parser - -import ( - "testing" - - "github.com/drone/drone/Godeps/_workspace/src/github.com/franela/goblin" - common "github.com/drone/drone/pkg/types" -) - -func Test_Linter(t *testing.T) { - - g := goblin.Goblin(t) - g.Describe("Linter", func() { - - g.It("Should fail when nil build", func() { - c := &common.Config{} - g.Assert(expectBuild(c) != nil).IsTrue() - }) - - g.It("Should fail when no image", func() { - c := &common.Config{ - Build: &common.Step{}, - } - g.Assert(expectImage(c) != nil).IsTrue() - }) - - g.It("Should fail when no commands", func() { - c := &common.Config{ - Setup: &common.Step{}, - } - g.Assert(expectCommand(c) != nil).IsTrue() - }) - - g.It("Should pass when proper Build provided", func() { - c := &common.Config{ - Build: &common.Step{ - Config: map[string]interface{}{ - "commands": []string{"echo hi"}, - }, - }, - } - g.Assert(expectImage(c) != nil).IsTrue() - }) - - g.It("Should pass linter when build properly setup", func() { - c := &common.Config{} - c.Build = &common.Step{} - c.Build.Image = "golang" - c.Setup = &common.Step{} - c.Setup.Config = map[string]interface{}{} - c.Setup.Config["commands"] = []string{"go build", "go test"} - c.Clone = &common.Step{} - c.Clone.Config = map[string]interface{}{} - c.Clone.Config["path"] = "/drone/src/foo/bar" - c.Publish = map[string]*common.Step{} - c.Publish["docker"] = &common.Step{Image: "docker"} - c.Deploy = map[string]*common.Step{} - c.Deploy["kubernetes"] = &common.Step{Image: "kubernetes"} - c.Notify = map[string]*common.Step{} - c.Notify["email"] = &common.Step{Image: "email"} - g.Assert(Lint(c) == nil).IsTrue() - }) - - g.It("Should pass with clone path inside workspace", func() { - c := &common.Config{ - Clone: &common.Step{ - Config: map[string]interface{}{ - "path": "/drone/src/foo/bar", - }, - }, - } - g.Assert(expectCloneInWorkspace(c) == nil).IsTrue() - }) - - g.It("Should fail with clone path outside workspace", func() { - c := &common.Config{ - Clone: &common.Step{ - Config: map[string]interface{}{ - "path": "/foo/bar", - }, - }, - } - g.Assert(expectCloneInWorkspace(c) != nil).IsTrue() - }) - - g.It("Should pass with cache path inside workspace", func() { - c := &common.Config{ - Build: &common.Step{ - Cache: []string{".git", "/.git", "/.git/../.git/../.git"}, - }, - } - g.Assert(expectCacheInWorkspace(c) == nil).IsTrue() - }) - - g.It("Should fail with cache path outside workspace", func() { - c := &common.Config{ - Build: &common.Step{ - Cache: []string{".git", "/.git", "../../.git"}, - }, - } - g.Assert(expectCacheInWorkspace(c) != nil).IsTrue() - }) - - g.It("Should fail when caching workspace directory", func() { - c := &common.Config{ - Build: &common.Step{ - Cache: []string{".git", ".git/../"}, - }, - } - g.Assert(expectCacheInWorkspace(c) != nil).IsTrue() - }) - - g.It("Should fail when : is in the cache path", func() { - c := &common.Config{ - Build: &common.Step{ - Cache: []string{".git", ".git:/../"}, - }, - } - g.Assert(expectCacheInWorkspace(c) != nil).IsTrue() - }) - }) -} - -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() - }) - }) -} diff --git a/pkg/yaml/parse.go b/pkg/yaml/parse.go index c37354067..6908743bd 100644 --- a/pkg/yaml/parse.go +++ b/pkg/yaml/parse.go @@ -1,112 +1,14 @@ package parser import ( - common "github.com/drone/drone/pkg/types" - "github.com/drone/drone/pkg/yaml/inject" - "github.com/drone/drone/pkg/yaml/matrix" - "github.com/drone/drone/pkg/yaml/transform" + "github.com/drone/drone/pkg/types" "github.com/drone/drone/Godeps/_workspace/src/gopkg.in/yaml.v2" ) -// Opts specifies parser options that will permit -// or deny certain Yaml settings. -type Opts struct { - Volumes bool - Network bool - Privileged bool - Caching bool - Whitelist []string -} - -var DefaultOpts = &Opts{ - Volumes: false, - Network: false, - Privileged: false, - Caching: true, - Whitelist: []string{"plugins/*"}, -} - -// Parse parses a build matrix and returns -// a list of build configurations for each axis -// using the default parsing options. -func Parse(raw string, r *common.Repo) ([]*common.Config, error) { - return ParseOpts(raw, DefaultOpts, r) -} - -// ParseOpts parses a build matrix and returns -// a list of build configurations for each axis -// using the provided parsing options. -func ParseOpts(raw string, opts *Opts, r *common.Repo) ([]*common.Config, error) { - axis, err := matrix.Parse(raw) - if err != nil { - return nil, err - } - confs := []*common.Config{} - - // when no matrix values exist we should return - // a single config value with an empty label. - if len(axis) == 0 { - conf, err := ParseSingle(raw, opts, r) - if err != nil { - return nil, err - } - confs = append(confs, conf) - } - - for _, ax := range axis { - // inject the matrix values into the raw script - injected := inject.Inject(raw, ax) - conf, err := ParseSingle(injected, opts, r) - if err != nil { - return nil, err - } - conf.Axis = common.Axis(ax) - confs = append(confs, conf) - } - - return confs, nil -} - -// helper funtion to parse a yaml configuration file. -func ParseSingle(raw string, opts *Opts, r *common.Repo) (*common.Config, error) { - conf := &common.Config{} - err := yaml.Unmarshal([]byte(raw), conf) - if err != nil { - return nil, err - } - - // apply rules / transforms - transform.Defaults(conf) - if !opts.Network { - transform.RemoveNetwork(conf) - } - if !opts.Volumes { - transform.RemoveVolumes(conf) - } - if !opts.Privileged { - transform.RemovePrivileged(conf) - } - transform.Repo(conf, r) - if !opts.Caching { - transform.RemoveVolumes(conf) - } - - // lint the yaml file - err = Lint(conf) - if err != nil { - return nil, err - } - err = LintPlugins(conf, opts) - if err != nil { - return nil, err - } - return conf, err -} - -func ParseCondition(raw string) (*common.Condition, error) { +func ParseCondition(raw string) (*types.Condition, error) { c := struct { - Condition *common.Condition `yaml:"when"` + Condition *types.Condition `yaml:"when"` }{} err := yaml.Unmarshal([]byte(raw), c) return c.Condition, err diff --git a/pkg/yaml/transform/transform.go b/pkg/yaml/transform/transform.go deleted file mode 100644 index c14864fa1..000000000 --- a/pkg/yaml/transform/transform.go +++ /dev/null @@ -1,314 +0,0 @@ -package transform - -import ( - "fmt" - "net/url" - "path/filepath" - "strings" - - common "github.com/drone/drone/pkg/types" -) - -// buildRoot is the root build directory. -// -// If this changes then the matching value in lint.go needs -// to be modified as well. -const buildRoot = "/drone/src" - -// transformRule applies a check or transformation rule -// to the build configuration. -type transformRule func(*common.Config) - -var transformRules = []transformRule{ - transformSetup, - transformClone, - transformBuild, - transformImages, - transformDockerPlugin, -} - -var rmPrivilegedRules = []transformRule{ - rmPrivileged, - rmVolumes, - rmNetwork, -} - -// Default executes the default transformers that -// ensure the minimal Yaml configuration is in place -// and correctly configured. -func Defaults(c *common.Config) { - for _, rule := range transformRules { - rule(c) - } -} - -// Safe executes all transformers that remove privileged -// options from the Yaml. -func Safe(c *common.Config) { - for _, rule := range rmPrivilegedRules { - rule(c) - } -} - -// RemoveNetwork executes all transformers that remove -// network options from the Yaml. -func RemoveNetwork(c *common.Config) { - rmNetwork(c) -} - -// TransformRemoveVolumes executes all transformers that -// remove volume options from the Yaml. -func RemoveVolumes(c *common.Config) { - rmVolumes(c) -} - -// RemovePrivileged executes all transformers that remove -// privileged options from the Yaml. -func RemovePrivileged(c *common.Config) { - rmPrivileged(c) -} - -// Repo executes all transformers that rely on repository -// information. -func Repo(c *common.Config, r *common.Repo) { - transformWorkspace(c, r) - transformCache(c, r) -} - -// transformSetup is a transformer that adds a default -// setup step if none exists. -func transformSetup(c *common.Config) { - c.Setup = &common.Step{} - c.Setup.Image = "plugins/drone-build" - - // TODO move below code to separate transform - if c.Build == nil { - c.Build = &common.Step{} - } - if c.Build.Config == nil { - c.Build.Config = map[string]interface{}{} - } - //// - - c.Setup.Config = c.Build.Config -} - -// transformClone is a transformer that adds a default -// clone step if none exists. -func transformClone(c *common.Config) { - if c.Clone == nil { - c.Clone = &common.Step{} - } - if len(c.Clone.Image) == 0 { - c.Clone.Image = "plugins/drone-git" - c.Clone.Volumes = nil - c.Clone.NetworkMode = "" - } - if c.Clone.Config == nil { - c.Clone.Config = map[string]interface{}{} - c.Clone.Config["depth"] = 50 - c.Clone.Config["recursive"] = true - } -} - -// transformBuild is a transformer that removes the -// build configuration vargs. They should have -// already been transferred to the Setup step. -func transformBuild(c *common.Config) { - c.Build.Config = nil - c.Build.Entrypoint = []string{"/bin/bash", "-e"} - c.Build.Command = []string{"/drone/bin/build.sh"} -} - -// transformImages is a transformer that ensures every -// step has an image and uses a fully-qualified -// image name. -func transformImages(c *common.Config) { - c.Setup.Image = imageName(c.Setup.Image) - c.Clone.Image = imageName(c.Clone.Image) - for name, step := range c.Publish { - step.Image = imageNameDefault(step.Image, name) - } - for name, step := range c.Deploy { - step.Image = imageNameDefault(step.Image, name) - } - for name, step := range c.Notify { - step.Image = imageNameDefault(step.Image, name) - } -} - -// transformDockerPlugin is a transformer that ensures the -// official Docker plugin can run in privileged mode. It -// will disable volumes and network mode for added protection. -func transformDockerPlugin(c *common.Config) { - for _, step := range c.Publish { - if step.Image == "plugins/drone-docker" { - step.Privileged = true - step.Volumes = nil - step.NetworkMode = "" - step.Entrypoint = []string{} - break - } - } -} - -// rmPrivileged is a transformer that ensures every -// step is executed in non-privileged mode. -func rmPrivileged(c *common.Config) { - c.Setup.Privileged = false - c.Clone.Privileged = false - c.Build.Privileged = false - for _, step := range c.Publish { - if step.Image == "plugins/drone-docker" { - continue // the official docker plugin is the only exception here - } - step.Privileged = false - } - for _, step := range c.Deploy { - step.Privileged = false - } - for _, step := range c.Notify { - step.Privileged = false - } - for _, step := range c.Compose { - step.Privileged = false - } -} - -// rmVolumes is a transformer that ensures every -// step is executed without volumes. -func rmVolumes(c *common.Config) { - c.Setup.Volumes = nil - c.Clone.Volumes = nil - c.Build.Volumes = nil - for _, step := range c.Publish { - step.Volumes = nil - } - for _, step := range c.Deploy { - step.Volumes = nil - } - for _, step := range c.Notify { - step.Volumes = nil - } - for _, step := range c.Compose { - step.Volumes = nil - } -} - -// rmNetwork is a transformer that ensures every -// step is executed with default bridge networking. -func rmNetwork(c *common.Config) { - c.Setup.NetworkMode = "" - c.Clone.NetworkMode = "" - c.Build.NetworkMode = "" - for _, step := range c.Publish { - step.NetworkMode = "" - } - for _, step := range c.Deploy { - step.NetworkMode = "" - } - for _, step := range c.Notify { - step.NetworkMode = "" - } - for _, step := range c.Compose { - step.NetworkMode = "" - } -} - -// transformWorkspace is a transformer that adds the workspace -// directory to the configuration based on the repository -// information. -func transformWorkspace(c *common.Config, r *common.Repo) { - pathv, ok := c.Clone.Config["path"] - var path string - - if ok { - path, _ = pathv.(string) - } - if len(path) == 0 { - path = repoPath(r) - } - - c.Clone.Config["path"] = filepath.Join(buildRoot, path) -} - -// transformCache is a transformer that adds volumes -// to the configuration based on the cache. -func transformCache(c *common.Config, r *common.Repo) { - cacheCount := len(c.Build.Cache) - - if cacheCount == 0 { - return - } - - volumes := make([]string, cacheCount) - - cache := cacheRoot(r) - workspace := c.Clone.Config["path"].(string) - - for i, dir := range c.Build.Cache { - cacheDir := filepath.Join(cache, dir) - workspaceDir := filepath.Join(workspace, dir) - - volumes[i] = fmt.Sprintf("%s:%s", cacheDir, workspaceDir) - } - - c.Setup.Volumes = append(c.Setup.Volumes, volumes...) - c.Clone.Volumes = append(c.Clone.Volumes, volumes...) - c.Build.Volumes = append(c.Build.Volumes, volumes...) - - for _, step := range c.Publish { - step.Volumes = append(step.Volumes, volumes...) - } - for _, step := range c.Deploy { - step.Volumes = append(step.Volumes, volumes...) - } - for _, step := range c.Notify { - step.Volumes = append(step.Volumes, volumes...) - } - for _, step := range c.Compose { - step.Volumes = append(step.Volumes, volumes...) - } -} - -// imageName is a helper function that resolves the -// image name. When using official drone plugins it -// is possible to use an alias name. This converts to -// the fully qualified name. -func imageName(name string) string { - if strings.Contains(name, "/") { - return name - } - name = strings.Replace(name, "_", "-", -1) - name = "plugins/drone-" + name - return name -} - -// imageNameDefault is a helper function that resolves -// the image name. If the image name is blank the -// default name is used instead. -func imageNameDefault(name, defaultName string) string { - if len(name) == 0 { - name = defaultName - } - return imageName(name) -} - -// workspaceRoot is a helper function that determines the -// default workspace the build runs in. -func workspaceRoot(r *common.Repo) string { - return filepath.Join(buildRoot, repoPath(r)) -} - -// cacheRoot is a helper function that deteremines the -// default caching root. -func cacheRoot(r *common.Repo) string { - return filepath.Join("/tmp/drone/cache", repoPath(r)) -} - -// repoPath is a helper function that creates a path based -// on the host and repository name. -func repoPath(r *common.Repo) string { - parsed, _ := url.Parse(r.Link) - return filepath.Join(parsed.Host, r.FullName) -} diff --git a/pkg/yaml/transform/transform_test.go b/pkg/yaml/transform/transform_test.go deleted file mode 100644 index a01214c18..000000000 --- a/pkg/yaml/transform/transform_test.go +++ /dev/null @@ -1,220 +0,0 @@ -package transform - -import ( - "path/filepath" - "testing" - - "github.com/drone/drone/Godeps/_workspace/src/github.com/franela/goblin" - common "github.com/drone/drone/pkg/types" -) - -func Test_Transform(t *testing.T) { - - g := goblin.Goblin(t) - g.Describe("Transform", func() { - - g.It("Should transform setup step", func() { - c := &common.Config{} - c.Build = &common.Step{} - c.Build.Config = map[string]interface{}{} - transformSetup(c) - g.Assert(c.Setup != nil).IsTrue() - g.Assert(c.Setup.Image).Equal("plugins/drone-build") - g.Assert(c.Setup.Config).Equal(c.Build.Config) - }) - - g.It("Should transform clone step", func() { - c := &common.Config{} - transformClone(c) - g.Assert(c.Clone != nil).IsTrue() - g.Assert(c.Clone.Image).Equal("plugins/drone-git") - }) - - g.It("Should transform build", func() { - c := &common.Config{} - c.Build = &common.Step{} - c.Build.Config = map[string]interface{}{} - c.Build.Config["commands"] = []string{"echo hello"} - transformBuild(c) - g.Assert(len(c.Build.Config)).Equal(0) - g.Assert(c.Build.Entrypoint[0]).Equal("/bin/bash") - g.Assert(c.Build.Command[0]).Equal("/drone/bin/build.sh") - }) - - g.It("Should transform images", func() { - c := &common.Config{} - c.Setup = &common.Step{Image: "foo"} - c.Clone = &common.Step{Image: "foo/bar"} - c.Build = &common.Step{Image: "golang"} - c.Publish = map[string]*common.Step{"google_compute": &common.Step{}} - c.Deploy = map[string]*common.Step{"amazon": &common.Step{}} - c.Notify = map[string]*common.Step{"slack": &common.Step{}} - transformImages(c) - - g.Assert(c.Setup.Image).Equal("plugins/drone-foo") - g.Assert(c.Clone.Image).Equal("foo/bar") - g.Assert(c.Build.Image).Equal("golang") - g.Assert(c.Publish["google_compute"].Image).Equal("plugins/drone-google-compute") - g.Assert(c.Deploy["amazon"].Image).Equal("plugins/drone-amazon") - g.Assert(c.Notify["slack"].Image).Equal("plugins/drone-slack") - }) - - g.It("Should transform docker plugin", func() { - c := &common.Config{} - c.Publish = map[string]*common.Step{} - c.Publish["docker"] = &common.Step{Image: "plugins/drone-docker"} - transformDockerPlugin(c) - g.Assert(c.Publish["docker"].Privileged).Equal(true) - }) - - g.It("Should remove privileged flag", func() { - c := &common.Config{} - c.Setup = &common.Step{Privileged: true} - c.Clone = &common.Step{Privileged: true} - c.Build = &common.Step{Privileged: true} - c.Compose = map[string]*common.Step{"postgres": &common.Step{Privileged: true}} - c.Publish = map[string]*common.Step{"google": &common.Step{Privileged: true}} - c.Deploy = map[string]*common.Step{"amazon": &common.Step{Privileged: true}} - c.Notify = map[string]*common.Step{"slack": &common.Step{Privileged: true}} - rmPrivileged(c) - - g.Assert(c.Setup.Privileged).Equal(false) - g.Assert(c.Clone.Privileged).Equal(false) - g.Assert(c.Build.Privileged).Equal(false) - g.Assert(c.Compose["postgres"].Privileged).Equal(false) - g.Assert(c.Publish["google"].Privileged).Equal(false) - g.Assert(c.Deploy["amazon"].Privileged).Equal(false) - g.Assert(c.Notify["slack"].Privileged).Equal(false) - }) - - g.It("Should not remove docker plugin privileged flag", func() { - c := &common.Config{} - c.Setup = &common.Step{} - c.Clone = &common.Step{} - c.Build = &common.Step{} - c.Publish = map[string]*common.Step{} - c.Publish["docker"] = &common.Step{Image: "plugins/drone-docker"} - transformDockerPlugin(c) - g.Assert(c.Publish["docker"].Privileged).Equal(true) - }) - - g.It("Should remove volumes", func() { - c := &common.Config{} - c.Setup = &common.Step{Volumes: []string{"/:/tmp"}} - c.Clone = &common.Step{Volumes: []string{"/:/tmp"}} - c.Build = &common.Step{Volumes: []string{"/:/tmp"}} - c.Compose = map[string]*common.Step{"postgres": &common.Step{Volumes: []string{"/:/tmp"}}} - c.Publish = map[string]*common.Step{"google": &common.Step{Volumes: []string{"/:/tmp"}}} - c.Deploy = map[string]*common.Step{"amazon": &common.Step{Volumes: []string{"/:/tmp"}}} - c.Notify = map[string]*common.Step{"slack": &common.Step{Volumes: []string{"/:/tmp"}}} - rmVolumes(c) - - g.Assert(len(c.Setup.Volumes)).Equal(0) - g.Assert(len(c.Clone.Volumes)).Equal(0) - g.Assert(len(c.Build.Volumes)).Equal(0) - g.Assert(len(c.Compose["postgres"].Volumes)).Equal(0) - g.Assert(len(c.Publish["google"].Volumes)).Equal(0) - g.Assert(len(c.Deploy["amazon"].Volumes)).Equal(0) - g.Assert(len(c.Notify["slack"].Volumes)).Equal(0) - }) - - g.It("Should remove network", func() { - c := &common.Config{} - c.Setup = &common.Step{NetworkMode: "host"} - c.Clone = &common.Step{NetworkMode: "host"} - c.Build = &common.Step{NetworkMode: "host"} - c.Compose = map[string]*common.Step{"postgres": &common.Step{NetworkMode: "host"}} - c.Publish = map[string]*common.Step{"google": &common.Step{NetworkMode: "host"}} - c.Deploy = map[string]*common.Step{"amazon": &common.Step{NetworkMode: "host"}} - c.Notify = map[string]*common.Step{"slack": &common.Step{NetworkMode: "host"}} - rmNetwork(c) - - g.Assert(c.Setup.NetworkMode).Equal("") - g.Assert(c.Clone.NetworkMode).Equal("") - g.Assert(c.Build.NetworkMode).Equal("") - g.Assert(c.Compose["postgres"].NetworkMode).Equal("") - g.Assert(c.Publish["google"].NetworkMode).Equal("") - g.Assert(c.Deploy["amazon"].NetworkMode).Equal("") - g.Assert(c.Notify["slack"].NetworkMode).Equal("") - }) - - g.It("Should return full qualified image name", func() { - g.Assert(imageName("microsoft/azure")).Equal("microsoft/azure") - g.Assert(imageName("azure")).Equal("plugins/drone-azure") - g.Assert(imageName("azure_storage")).Equal("plugins/drone-azure-storage") - }) - - g.It("Should have cached volumes", func() { - c := &common.Config{ - Setup: &common.Step{}, - Clone: &common.Step{ - Config: map[string]interface{}{}, - }, - Build: &common.Step{ - Cache: []string{".git", "foo", "bar"}, - }, - Notify: map[string]*common.Step{}, - Deploy: map[string]*common.Step{}, - Publish: map[string]*common.Step{}, - } - r := &common.Repo{ - Link: "https://github.com/drone/drone", - FullName: "drone/drone", - } - transformWorkspace(c, r) - transformCache(c, r) - - cacheCount := len(c.Build.Cache) - - test := func(s *common.Step) { - g.Assert(len(s.Volumes)).Equal(cacheCount) - } - - testRange := func(s map[string]*common.Step) { - for _, step := range s { - test(step) - } - } - - test(c.Setup) - test(c.Clone) - test(c.Build) - testRange(c.Publish) - testRange(c.Deploy) - testRange(c.Notify) - testRange(c.Compose) - }) - - g.It("Should have default workspace directory", func() { - c := &common.Config{ - Clone: &common.Step{ - Config: map[string]interface{}{}, - }, - } - r := &common.Repo{ - Link: "https://github.com/drone/drone", - FullName: "drone/drone", - } - transformWorkspace(c, r) - - g.Assert(c.Clone.Config["path"]).Equal(workspaceRoot(r)) - }) - - g.It("Should use path for working directory", func() { - c := &common.Config{ - Clone: &common.Step{ - Config: map[string]interface{}{ - "path": "foo/bar", - }, - }, - } - r := &common.Repo{ - Link: "https://github.com/drone/drone", - FullName: "drone/drone", - } - transformWorkspace(c, r) - - g.Assert(c.Clone.Config["path"]).Equal(filepath.Join(buildRoot, "foo/bar")) - }) - }) -}