github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/creds/ssm/ssm_test.go (about)

     1  package ssm_test
     2  
     3  import (
     4  	"errors"
     5  	"strconv"
     6  
     7  	"code.cloudfoundry.org/lager/lagertest"
     8  
     9  	"github.com/pf-qiu/concourse/v6/atc/creds"
    10  
    11  	"github.com/aws/aws-sdk-go/aws"
    12  	"github.com/aws/aws-sdk-go/aws/awserr"
    13  	"github.com/aws/aws-sdk-go/service/ssm"
    14  	"github.com/aws/aws-sdk-go/service/ssm/ssmiface"
    15  	. "github.com/pf-qiu/concourse/v6/atc/creds/ssm"
    16  	"github.com/pf-qiu/concourse/v6/vars"
    17  
    18  	. "github.com/onsi/ginkgo"
    19  	. "github.com/onsi/gomega"
    20  	. "github.com/onsi/gomega/gstruct"
    21  )
    22  
    23  type mockPathResultPage struct {
    24  	params map[string]string
    25  	err    error
    26  }
    27  
    28  func (page mockPathResultPage) ToGetParametersByPathOutput() (*ssm.GetParametersByPathOutput, error) {
    29  	if page.err != nil {
    30  		return nil, page.err
    31  	}
    32  	params := make([]*ssm.Parameter, 0, len(page.params))
    33  	for name, value := range page.params {
    34  		params = append(params, &ssm.Parameter{
    35  			Name:  aws.String(name),
    36  			Value: aws.String(value),
    37  		})
    38  	}
    39  	return &ssm.GetParametersByPathOutput{Parameters: params}, nil
    40  }
    41  
    42  type MockSsmService struct {
    43  	ssmiface.SSMAPI
    44  
    45  	stubGetParameter             func(name string) (string, error)
    46  	stubGetParametersByPathPages func(path string) []mockPathResultPage
    47  }
    48  
    49  func (mock *MockSsmService) GetParameter(input *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) {
    50  	if mock.stubGetParameter == nil {
    51  		return nil, errors.New("stubGetParameter is not defined")
    52  	}
    53  	Expect(input).ToNot(BeNil())
    54  	Expect(input.Name).ToNot(BeNil())
    55  	Expect(input.WithDecryption).To(PointTo(Equal(true)))
    56  	value, err := mock.stubGetParameter(*input.Name)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  	return &ssm.GetParameterOutput{Parameter: &ssm.Parameter{Value: &value}}, nil
    61  }
    62  
    63  func (mock *MockSsmService) GetParametersByPathPages(input *ssm.GetParametersByPathInput, fn func(*ssm.GetParametersByPathOutput, bool) bool) error {
    64  	if mock.stubGetParametersByPathPages == nil {
    65  		return errors.New("stubGetParametersByPathPages is not defined")
    66  	}
    67  	Expect(input).NotTo(BeNil())
    68  	Expect(input.Path).NotTo(BeNil())
    69  	Expect(input.Recursive).To(PointTo(Equal(true)))
    70  	Expect(input.WithDecryption).To(PointTo(Equal(true)))
    71  	Expect(input.MaxResults).To(PointTo(BeEquivalentTo(10)))
    72  	allPages := mock.stubGetParametersByPathPages(*input.Path)
    73  	for n, page := range allPages {
    74  		params, err := page.ToGetParametersByPathOutput()
    75  		if err != nil {
    76  			return err
    77  		}
    78  		params.NextToken = aws.String(strconv.Itoa(n + 1))
    79  		lastPage := (n == len(allPages)-1)
    80  		if !fn(params, lastPage) {
    81  			break
    82  		}
    83  	}
    84  	return nil
    85  }
    86  
    87  var _ = Describe("Ssm", func() {
    88  	var ssmAccess *Ssm
    89  	var variables vars.Variables
    90  	var varRef vars.Reference
    91  	var mockService MockSsmService
    92  
    93  	JustBeforeEach(func() {
    94  		varRef = vars.Reference{Path: "cheery"}
    95  		t1, err := creds.BuildSecretTemplate("t1", DefaultPipelineSecretTemplate)
    96  		Expect(t1).NotTo(BeNil())
    97  		Expect(err).To(BeNil())
    98  		t2, err := creds.BuildSecretTemplate("t2", DefaultTeamSecretTemplate)
    99  		Expect(t2).NotTo(BeNil())
   100  		Expect(err).To(BeNil())
   101  		ssmAccess = NewSsm(lagertest.NewTestLogger("ssm_test"), &mockService, []*creds.SecretTemplate{t1, t2})
   102  		variables = creds.NewVariables(ssmAccess, "alpha", "bogus", false)
   103  		Expect(ssmAccess).NotTo(BeNil())
   104  		mockService.stubGetParameter = func(input string) (string, error) {
   105  			if input == "/concourse/alpha/bogus/cheery" {
   106  				return "ssm decrypted value", nil
   107  			}
   108  			return "", awserr.New(ssm.ErrCodeParameterNotFound, "", nil)
   109  		}
   110  		mockService.stubGetParametersByPathPages = func(path string) []mockPathResultPage {
   111  			return []mockPathResultPage{}
   112  		}
   113  	})
   114  
   115  	Describe("Get()", func() {
   116  		It("should get parameter if exists", func() {
   117  			value, found, err := variables.Get(varRef)
   118  			Expect(value).To(BeEquivalentTo("ssm decrypted value"))
   119  			Expect(found).To(BeTrue())
   120  			Expect(err).To(BeNil())
   121  		})
   122  
   123  		It("should get complex paramter", func() {
   124  			mockService.stubGetParametersByPathPages = func(path string) []mockPathResultPage {
   125  				return []mockPathResultPage{
   126  					{
   127  						params: map[string]string{
   128  							"/concourse/alpha/bogus/user/name": "yours",
   129  							"/concourse/alpha/bogus/user/pass": "truely",
   130  						},
   131  						err: nil,
   132  					},
   133  				}
   134  			}
   135  			value, found, err := variables.Get(vars.Reference{Path: "user"})
   136  			Expect(value).To(BeEquivalentTo(map[string]interface{}{
   137  				"name": "yours",
   138  				"pass": "truely",
   139  			}))
   140  			Expect(found).To(BeTrue())
   141  			Expect(err).To(BeNil())
   142  		})
   143  
   144  		It("should return numbers as strings", func() {
   145  			mockService.stubGetParameter = func(input string) (string, error) {
   146  				return "101", nil
   147  			}
   148  			value, found, err := variables.Get(varRef)
   149  			Expect(value).To(BeEquivalentTo("101"))
   150  			Expect(found).To(BeTrue())
   151  			Expect(err).To(BeNil())
   152  		})
   153  
   154  		It("should get team parameter if exists", func() {
   155  			mockService.stubGetParameter = func(input string) (string, error) {
   156  				if input != "/concourse/alpha/cheery" {
   157  					return "", awserr.New(ssm.ErrCodeParameterNotFound, "", nil)
   158  				}
   159  				return "team decrypted value", nil
   160  			}
   161  			value, found, err := variables.Get(varRef)
   162  			Expect(value).To(BeEquivalentTo("team decrypted value"))
   163  			Expect(found).To(BeTrue())
   164  			Expect(err).To(BeNil())
   165  		})
   166  
   167  		It("should return not found on error", func() {
   168  			mockService.stubGetParameter = nil
   169  			value, found, err := variables.Get(varRef)
   170  			Expect(value).To(BeNil())
   171  			Expect(found).To(BeFalse())
   172  			Expect(err).NotTo(BeNil())
   173  		})
   174  
   175  		It("should allow empty pipeline name", func() {
   176  			variables := creds.NewVariables(ssmAccess, "alpha", "", false)
   177  			mockService.stubGetParameter = func(input string) (string, error) {
   178  				Expect(input).To(Equal("/concourse/alpha/cheery"))
   179  				return "team power", nil
   180  			}
   181  			value, found, err := variables.Get(varRef)
   182  			Expect(value).To(BeEquivalentTo("team power"))
   183  			Expect(found).To(BeTrue())
   184  			Expect(err).To(BeNil())
   185  		})
   186  	})
   187  })