support environment masking

pull/3/head
Brad Rydzewski 4 years ago
parent 6f725b3b9f
commit a238edf7e8

@ -4,11 +4,7 @@
package provider package provider
import ( import "context"
"context"
"github.com/drone/runner-go/environ"
)
// Combine returns a new combined environment provider, // Combine returns a new combined environment provider,
// capable of sourcing environment variables from multiple // capable of sourcing environment variables from multiple
@ -21,16 +17,14 @@ type combined struct {
sources []Provider sources []Provider
} }
func (p *combined) List(ctx context.Context, in *Request) (map[string]string, error) { func (p *combined) List(ctx context.Context, in *Request) ([]*Variable, error) {
out := map[string]string{} var out []*Variable
for _, source := range p.sources { for _, source := range p.sources {
got, err := source.List(ctx, in) got, err := source.List(ctx, in)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if got != nil { out = append(out, got...)
out = environ.Combine(got, out)
}
} }
return out, nil return out, nil
} }

@ -7,6 +7,8 @@ package provider
import ( import (
"errors" "errors"
"testing" "testing"
"github.com/google/go-cmp/cmp"
) )
func TestCombine(t *testing.T) { func TestCombine(t *testing.T) {
@ -15,20 +17,29 @@ func TestCombine(t *testing.T) {
aa := Static(a) aa := Static(a)
bb := Static(b) bb := Static(b)
p := Combine(aa, bb) p := Combine(aa, bb)
out, err := p.List(noContext, nil) got, err := p.List(noContext, nil)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
if len(out) != 2 { if len(got) != 2 {
t.Errorf("Expect combined variable output") t.Errorf("Expect combined variable output")
return return
} }
if out["a"] != "b" { want := []*Variable{
t.Errorf("Missing variable") {
Name: "a",
Data: "b",
Mask: false,
},
{
Name: "c",
Data: "d",
Mask: false,
},
} }
if out["c"] != "d" { if diff := cmp.Diff(got, want); diff != "" {
t.Errorf("Missing variable") t.Errorf(diff)
} }
} }

@ -40,7 +40,7 @@ type external struct {
client environ.Plugin client environ.Plugin
} }
func (p *external) List(ctx context.Context, in *Request) (map[string]string, error) { func (p *external) List(ctx context.Context, in *Request) ([]*Variable, error) {
if p.client == nil { if p.client == nil {
return nil, nil return nil, nil
} }
@ -74,5 +74,13 @@ func (p *external) List(ctx context.Context, in *Request) (map[string]string, er
logger.Trace("environment: external: environment variable list returned") logger.Trace("environment: external: environment variable list returned")
return res, nil var out []*Variable
for _, v := range res {
out = append(out, &Variable{
Name: v.Name,
Data: v.Data,
Mask: v.Mask,
})
}
return out, nil
} }

@ -19,9 +19,17 @@ func TestExternal(t *testing.T) {
Build: &drone.Build{Event: drone.EventPush}, Build: &drone.Build{Event: drone.EventPush},
Repo: &drone.Repo{Private: false}, Repo: &drone.Repo{Private: false},
} }
want := map[string]string{"a": "b"} res := []*environ.Variable{
{
Name: "a",
Data: "b",
Mask: true,
},
}
want := []*Variable{{Name: "a", Data: "b", Mask: true}}
provider := External("http://localhost", "secret", false) provider := External("http://localhost", "secret", false)
provider.(*external).client = &mockPlugin{out: want} provider.(*external).client = &mockPlugin{out: res}
got, err := provider.List(noContext, req) got, err := provider.List(noContext, req)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -91,10 +99,10 @@ func TestMultiExternal(t *testing.T) {
} }
type mockPlugin struct { type mockPlugin struct {
out map[string]string out []*environ.Variable
err error err error
} }
func (m *mockPlugin) List(context.Context, *environ.Request) (map[string]string, error) { func (m *mockPlugin) List(context.Context, *environ.Request) ([]*environ.Variable, error) {
return m.out, m.err return m.out, m.err
} }

@ -19,9 +19,16 @@ type Request struct {
Build *drone.Build Build *drone.Build
} }
// Variable defines an environment variable.
type Variable struct {
Name string
Data string
Mask bool
}
// Provider is the interface that must be implemented by an // Provider is the interface that must be implemented by an
// environment provider. // environment provider.
type Provider interface { type Provider interface {
// List returns a list of environment variables. // List returns a list of environment variables.
List(context.Context, *Request) (map[string]string, error) List(context.Context, *Request) ([]*Variable, error)
} }

@ -11,10 +11,10 @@ import (
var noContext = context.Background() var noContext = context.Background()
type mockProvider struct { type mockProvider struct {
out map[string]string out []*Variable
err error err error
} }
func (p *mockProvider) List(context.Context, *Request) (map[string]string, error) { func (p *mockProvider) List(context.Context, *Request) ([]*Variable, error) {
return p.out, p.err return p.out, p.err
} }

@ -17,6 +17,6 @@ type static struct {
params map[string]string params map[string]string
} }
func (p *static) List(context.Context, *Request) (map[string]string, error) { func (p *static) List(context.Context, *Request) ([]*Variable, error) {
return p.params, nil return ToSlice(p.params), nil
} }

@ -5,19 +5,28 @@
package provider package provider
import ( import (
"reflect"
"testing" "testing"
"github.com/google/go-cmp/cmp"
) )
func TestStatic(t *testing.T) { func TestStatic(t *testing.T) {
a := map[string]string{"a": "b"} in := map[string]string{"a": "b"}
p := Static(a)
b, err := p.List(noContext, nil) got, err := Static(in).List(noContext, nil)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
if !reflect.DeepEqual(a, b) {
t.Errorf("Unexpected environment variable output") want := []*Variable{
{
Name: "a",
Data: "b",
},
}
if diff := cmp.Diff(got, want); diff != "" {
t.Errorf(diff)
} }
} }

@ -0,0 +1,52 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package provider
// ToMap is a helper function that converts a list of
// variables to a map.
func ToMap(src []*Variable) map[string]string {
dst := map[string]string{}
for _, v := range src {
dst[v.Name] = v.Data
}
return dst
}
// ToSlice is a helper function that converts a map of
// environment variables to a slice.
func ToSlice(src map[string]string) []*Variable {
var dst []*Variable
for k, v := range src {
dst = append(dst, &Variable{
Name: k,
Data: v,
})
}
return dst
}
// FilterMasked is a helper function that filters a list of
// variable to return a list of masked variables only.
func FilterMasked(v []*Variable) []*Variable {
var filtered []*Variable
for _, vv := range v {
if vv.Mask {
filtered = append(filtered, vv)
}
}
return filtered
}
// FilterUnmasked is a helper function that filters a list of
// variable to return a list of masked variables only.
func FilterUnmasked(v []*Variable) []*Variable {
var filtered []*Variable
for _, vv := range v {
if vv.Mask == false {
filtered = append(filtered, vv)
}
}
return filtered
}

@ -0,0 +1,87 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package provider
import (
"testing"
"github.com/google/go-cmp/cmp"
)
func TestToMap(t *testing.T) {
in := []*Variable{
{
Name: "foo",
Data: "bar",
},
}
want := map[string]string{
"foo": "bar",
}
got := ToMap(in)
if diff := cmp.Diff(want, got); diff != "" {
t.Log(diff)
t.Errorf("Unexpected map value")
}
}
func TestFromMap(t *testing.T) {
in := map[string]string{
"foo": "bar",
}
want := []*Variable{
{
Name: "foo",
Data: "bar",
},
}
got := ToSlice(in)
if diff := cmp.Diff(want, got); diff != "" {
t.Log(diff)
t.Errorf("Unexpected variable list")
}
}
func TestFilterMasked(t *testing.T) {
in := []*Variable{
{
Name: "foo",
Data: "bar",
Mask: false,
},
{
Name: "baz",
Data: "qux",
Mask: true,
},
}
want := in[1:]
got := FilterMasked(in)
if diff := cmp.Diff(want, got); diff != "" {
t.Log(diff)
t.Errorf("Unexpected variable list")
}
}
func TestFilterUnmasked(t *testing.T) {
in := []*Variable{
{
Name: "foo",
Data: "bar",
Mask: true,
},
{
Name: "baz",
Data: "qux",
Mask: false,
},
}
want := in[1:]
got := FilterUnmasked(in)
if diff := cmp.Diff(want, got); diff != "" {
t.Log(diff)
t.Errorf("Unexpected variable list")
}
}

@ -8,7 +8,7 @@ require (
github.com/buildkite/yaml v2.1.0+incompatible github.com/buildkite/yaml v2.1.0+incompatible
github.com/coreos/go-semver v0.3.0 github.com/coreos/go-semver v0.3.0
github.com/docker/go-units v0.4.0 github.com/docker/go-units v0.4.0
github.com/drone/drone-go v1.1.1-0.20191119212130-1d2e07e87e79 github.com/drone/drone-go v1.2.1-0.20200326064413-195394da1018
github.com/drone/envsubst v1.0.2 github.com/drone/envsubst v1.0.2
github.com/google/go-cmp v0.3.0 github.com/google/go-cmp v0.3.0
github.com/hashicorp/go-multierror v1.0.0 github.com/hashicorp/go-multierror v1.0.0

@ -13,6 +13,11 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/drone/drone-go v1.1.1-0.20191119212130-1d2e07e87e79 h1:jW+dJ8HrZ1CbazlsYoriOOCQnVJ2NkfNczLHs6UMU6I= github.com/drone/drone-go v1.1.1-0.20191119212130-1d2e07e87e79 h1:jW+dJ8HrZ1CbazlsYoriOOCQnVJ2NkfNczLHs6UMU6I=
github.com/drone/drone-go v1.1.1-0.20191119212130-1d2e07e87e79/go.mod h1:GxyeGClYohaKNYJv/ZpsmVHtMJ7WhoT+uDaJNcDIrk4= github.com/drone/drone-go v1.1.1-0.20191119212130-1d2e07e87e79/go.mod h1:GxyeGClYohaKNYJv/ZpsmVHtMJ7WhoT+uDaJNcDIrk4=
github.com/drone/drone-go v1.2.1-0.20200326061744-0158580ce4ea h1:bMFm53oPjGvjpdO7+mfK6Qak4+O5ri5UlmlvN6J/qvo=
github.com/drone/drone-go v1.2.1-0.20200326061744-0158580ce4ea/go.mod h1:GxyeGClYohaKNYJv/ZpsmVHtMJ7WhoT+uDaJNcDIrk4=
github.com/drone/drone-go v1.2.1-0.20200326064413-195394da1018 h1:aHRv4GohqzHXZEGks/Qyrd8kI7hkCdLhJO1QoYtQMjU=
github.com/drone/drone-go v1.2.1-0.20200326064413-195394da1018/go.mod h1:GxyeGClYohaKNYJv/ZpsmVHtMJ7WhoT+uDaJNcDIrk4=
github.com/drone/drone-go v1.3.1 h1:D4KXbauJtbT/zXk19TcMpu36F8GPOUcndIw7pOWsX6k=
github.com/drone/envsubst v1.0.2 h1:dpYLMAspQHW0a8dZpLRKe9jCNvIGZPhCPrycZzIHdqo= github.com/drone/envsubst v1.0.2 h1:dpYLMAspQHW0a8dZpLRKe9jCNvIGZPhCPrycZzIHdqo=
github.com/drone/envsubst v1.0.2/go.mod h1:bkZbnc/2vh1M12Ecn7EYScpI4YGYU0etwLJICOWi8Z0= github.com/drone/envsubst v1.0.2/go.mod h1:bkZbnc/2vh1M12Ecn7EYScpI4YGYU0etwLJICOWi8Z0=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=

Loading…
Cancel
Save