From 9781e160a4c4591d7fa8eec33054bf127a994616 Mon Sep 17 00:00:00 2001 From: Don Date: Wed, 16 Nov 2016 18:33:48 -0800 Subject: [PATCH] Hide secrets --- agent/agent.go | 2 ++ agent/secret.go | 50 ++++++++++++++++++++++++++++++++++++++++++++ agent/secret_test.go | 39 ++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 agent/secret.go create mode 100644 agent/secret_test.go diff --git a/agent/agent.go b/agent/agent.go index 02aac61df..72e793510 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -188,6 +188,7 @@ func (a *Agent) exec(spec *yaml.Config, payload *model.Work, cancel <-chan bool) return err } + replacer := NewSecretReplacer(payload.Secrets) timeout := time.After(time.Duration(payload.Repo.Timeout) * time.Minute) for { @@ -227,6 +228,7 @@ func (a *Agent) exec(spec *yaml.Config, payload *model.Work, cancel <-chan bool) pipeline.Exec() } case line := <-pipeline.Pipe(): + line.Out = replacer.Replace(line.Out) a.Logger(line) } } diff --git a/agent/secret.go b/agent/secret.go new file mode 100644 index 000000000..4f6e4575f --- /dev/null +++ b/agent/secret.go @@ -0,0 +1,50 @@ +package agent + +import ( + "strings" + + "github.com/drone/drone/model" +) + +// SecretReplacer hides secrets from being exposed by the build output. +type SecretReplacer interface { + // Replace conceals instances of secrets found in s. + Replace(s string) string +} + +// NewSecretReplacer creates a SecretReplacer based on whether any value in +// secrets requests it be hidden. +func NewSecretReplacer(secrets []*model.Secret) SecretReplacer { + var r []string + for _, s := range secrets { + if s.Conceal { + r = append(r, s.Value, "*****") + } + } + + var replacer SecretReplacer + + if len(r) > 0 { + replacer = &secretReplacer{ + replacer: strings.NewReplacer(r...), + } + } else { + replacer = &noopReplacer{} + } + + return replacer +} + +type noopReplacer struct{} + +func (*noopReplacer) Replace(s string) string { + return s +} + +type secretReplacer struct { + replacer *strings.Replacer +} + +func (r *secretReplacer) Replace(s string) string { + return r.replacer.Replace(s) +} diff --git a/agent/secret_test.go b/agent/secret_test.go new file mode 100644 index 000000000..a88b523c0 --- /dev/null +++ b/agent/secret_test.go @@ -0,0 +1,39 @@ +package agent + +import ( + "testing" + + "github.com/drone/drone/model" + "github.com/franela/goblin" +) + +const testString = "This is SECRET: secret_value" + +func TestSecret(t *testing.T) { + g := goblin.Goblin(t) + g.Describe("SecretReplacer", func() { + g.It("Should conceal secret", func() { + secrets := []*model.Secret{ + { + Name: "SECRET", + Value: "secret_value", + Conceal: true, + }, + } + r := NewSecretReplacer(secrets) + g.Assert(r.Replace(testString)).Equal("This is SECRET: *****") + }) + + g.It("Should not conceal secret", func() { + secrets := []*model.Secret{ + { + Name: "SECRET", + Value: "secret_value", + Conceal: false, + }, + } + r := NewSecretReplacer(secrets) + g.Assert(r.Replace(testString)).Equal(testString) + }) + }) +}