gitlab_test.go 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  1. /*
  2. Copyright © 2025 ESO Maintainer Team
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. https://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package gitlab
  14. import (
  15. "context"
  16. "encoding/json"
  17. "errors"
  18. "fmt"
  19. "net/http"
  20. "reflect"
  21. "strings"
  22. "testing"
  23. "github.com/google/uuid"
  24. tassert "github.com/stretchr/testify/assert"
  25. "github.com/yandex-cloud/go-sdk/iamkey"
  26. gitlab "gitlab.com/gitlab-org/api/client-go"
  27. corev1 "k8s.io/api/core/v1"
  28. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  29. k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
  30. clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
  31. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  32. esv1meta "github.com/external-secrets/external-secrets/apis/meta/v1"
  33. fakegitlab "github.com/external-secrets/external-secrets/providers/v1/gitlab/fake"
  34. )
  35. const (
  36. project = "my-Project"
  37. username = "user-name"
  38. userkey = "user-key"
  39. environment = "prod"
  40. environmentTest = "test"
  41. projectvalue = "projectvalue"
  42. groupvalue = "groupvalue"
  43. groupid = "groupId"
  44. defaultErrorMessage = "[%d] unexpected error: [%s], expected: [%s]"
  45. errMissingCredentials = "cannot get Kubernetes secret \"\" from namespace \"namespace\": secrets \"\" not found"
  46. testKey = "testKey"
  47. findTestPrefix = "test.*"
  48. )
  49. type secretManagerTestCase struct {
  50. mockProjectsClient *fakegitlab.GitlabMockProjectsClient
  51. mockProjectVarClient *fakegitlab.GitlabMockProjectVariablesClient
  52. mockGroupVarClient *fakegitlab.GitlabMockGroupVariablesClient
  53. apiInputProjectID string
  54. apiInputKey string
  55. apiInputEnv string
  56. projectAPIOutput *gitlab.ProjectVariable
  57. projectAPIResponse *gitlab.Response
  58. projectAPIOutputs []*fakegitlab.APIResponse[[]*gitlab.ProjectVariable]
  59. projectGroupsAPIOutput []*gitlab.ProjectGroup
  60. projectGroupsAPIResponse *gitlab.Response
  61. groupAPIOutputs []*fakegitlab.APIResponse[[]*gitlab.GroupVariable]
  62. groupAPIOutput *gitlab.GroupVariable
  63. groupAPIResponse *gitlab.Response
  64. ref *esv1.ExternalSecretDataRemoteRef
  65. refFind *esv1.ExternalSecretFind
  66. projectID string
  67. groupIDs []string
  68. inheritFromGroups bool
  69. apiErr error
  70. expectError string
  71. expectedSecret string
  72. expectedValidationResult esv1.ValidationResult
  73. // for testing secretmap
  74. expectedData map[string][]byte
  75. }
  76. func makeValidSecretManagerTestCase() *secretManagerTestCase {
  77. smtc := secretManagerTestCase{
  78. mockProjectsClient: &fakegitlab.GitlabMockProjectsClient{},
  79. mockProjectVarClient: &fakegitlab.GitlabMockProjectVariablesClient{},
  80. mockGroupVarClient: &fakegitlab.GitlabMockGroupVariablesClient{},
  81. apiInputProjectID: makeValidAPIInputProjectID(),
  82. apiInputKey: makeValidAPIInputKey(),
  83. //apiInputEnv: makeValidEnvironment(),
  84. ref: makeValidRef(),
  85. refFind: makeValidFindRef(),
  86. projectID: makeValidProjectID(),
  87. groupIDs: makeEmptyGroupIds(),
  88. projectAPIOutput: makeValidProjectAPIOutput(),
  89. projectAPIResponse: makeValidProjectAPIResponse(),
  90. projectGroupsAPIOutput: makeValidProjectGroupsAPIOutput(),
  91. projectGroupsAPIResponse: makeValidProjectGroupsAPIResponse(),
  92. groupAPIOutput: makeValidGroupAPIOutput(),
  93. groupAPIResponse: makeValidGroupAPIResponse(),
  94. apiErr: nil,
  95. expectError: "",
  96. expectedSecret: "",
  97. expectedValidationResult: esv1.ValidationResultReady,
  98. expectedData: map[string][]byte{},
  99. }
  100. prepareMockProjectVarClient(&smtc)
  101. prepareMockGroupVarClient(&smtc)
  102. return &smtc
  103. }
  104. func makeValidRef() *esv1.ExternalSecretDataRemoteRef {
  105. return &esv1.ExternalSecretDataRemoteRef{
  106. Key: testKey,
  107. Version: "default",
  108. }
  109. }
  110. func makeValidFindRef() *esv1.ExternalSecretFind {
  111. return &esv1.ExternalSecretFind{}
  112. }
  113. func makeValidProjectID() string {
  114. return "projectId"
  115. }
  116. func makeEmptyGroupIds() []string {
  117. return []string{}
  118. }
  119. func makeFindName(regexp string) *esv1.FindName {
  120. return &esv1.FindName{
  121. RegExp: regexp,
  122. }
  123. }
  124. func makeValidAPIInputProjectID() string {
  125. return "testID"
  126. }
  127. func makeValidAPIInputKey() string {
  128. return testKey
  129. }
  130. func makeValidProjectAPIResponse() *gitlab.Response {
  131. return &gitlab.Response{
  132. Response: &http.Response{
  133. StatusCode: http.StatusOK,
  134. },
  135. CurrentPage: 1,
  136. TotalPages: 1,
  137. }
  138. }
  139. func make404GitlabAPIResponse() *gitlab.Response {
  140. return &gitlab.Response{
  141. Response: &http.Response{
  142. StatusCode: http.StatusNotFound,
  143. },
  144. CurrentPage: 1,
  145. TotalPages: 1,
  146. }
  147. }
  148. func makeValidProjectGroupsAPIResponse() *gitlab.Response {
  149. return &gitlab.Response{
  150. Response: &http.Response{
  151. StatusCode: http.StatusOK,
  152. },
  153. CurrentPage: 1,
  154. TotalPages: 1,
  155. }
  156. }
  157. func makeValidGroupAPIResponse() *gitlab.Response {
  158. return &gitlab.Response{
  159. Response: &http.Response{
  160. StatusCode: http.StatusOK,
  161. },
  162. CurrentPage: 1,
  163. TotalPages: 1,
  164. }
  165. }
  166. func makeValidProjectAPIOutput() *gitlab.ProjectVariable {
  167. return &gitlab.ProjectVariable{
  168. Key: testKey,
  169. Value: "",
  170. EnvironmentScope: environment,
  171. }
  172. }
  173. func makeValidProjectGroupsAPIOutput() []*gitlab.ProjectGroup {
  174. return []*gitlab.ProjectGroup{{
  175. ID: 1,
  176. Name: "Group (1)",
  177. FullPath: "foo",
  178. }, {
  179. ID: 100,
  180. Name: "Group (100)",
  181. FullPath: "foo/bar/baz",
  182. }, {
  183. ID: 10,
  184. Name: "Group (10)",
  185. FullPath: "foo/bar",
  186. }}
  187. }
  188. func make404ProjectAPIOutput(numResponses ...int) []*fakegitlab.APIResponse[[]*gitlab.ProjectVariable] {
  189. count := 1
  190. if len(numResponses) > 0 && numResponses[0] > 0 {
  191. count = numResponses[0]
  192. }
  193. responses := make([]*fakegitlab.APIResponse[[]*gitlab.ProjectVariable], count)
  194. for i := 0; i < count; i++ {
  195. responses[i] = &fakegitlab.APIResponse[[]*gitlab.ProjectVariable]{
  196. Response: make404GitlabAPIResponse(),
  197. Error: gitlab.ErrNotFound,
  198. }
  199. }
  200. return responses
  201. }
  202. func makeValidGroupAPIOutput() *gitlab.GroupVariable {
  203. return &gitlab.GroupVariable{
  204. Key: "groupKey",
  205. Value: "",
  206. EnvironmentScope: environment,
  207. }
  208. }
  209. func makeValidSecretManagerTestCaseCustom(tweaks ...func(smtc *secretManagerTestCase)) *secretManagerTestCase {
  210. smtc := makeValidSecretManagerTestCase()
  211. for _, fn := range tweaks {
  212. fn(smtc)
  213. }
  214. smtc.mockProjectsClient.WithValue(smtc.projectGroupsAPIOutput, smtc.projectGroupsAPIResponse, smtc.apiErr)
  215. prepareMockProjectVarClient(smtc)
  216. prepareMockGroupVarClient(smtc)
  217. return smtc
  218. }
  219. func makeValidSecretManagerGetAllTestCaseCustom(tweaks ...func(smtc *secretManagerTestCase)) *secretManagerTestCase {
  220. smtc := makeValidSecretManagerTestCase()
  221. smtc.ref = nil
  222. smtc.refFind.Name = makeFindName(".*")
  223. for _, fn := range tweaks {
  224. fn(smtc)
  225. }
  226. prepareMockProjectVarClient(smtc)
  227. prepareMockGroupVarClient(smtc)
  228. return smtc
  229. }
  230. func prepareMockProjectVarClient(smtc *secretManagerTestCase) {
  231. responses := make([]fakegitlab.APIResponse[[]*gitlab.ProjectVariable], 0)
  232. if smtc.projectAPIOutput != nil {
  233. responses = append(
  234. responses,
  235. fakegitlab.APIResponse[[]*gitlab.ProjectVariable]{Output: []*gitlab.ProjectVariable{smtc.projectAPIOutput}, Response: smtc.projectAPIResponse, Error: smtc.apiErr},
  236. )
  237. }
  238. for _, response := range smtc.projectAPIOutputs {
  239. responses = append(responses, *response)
  240. }
  241. smtc.mockProjectVarClient.WithValues(responses)
  242. }
  243. func prepareMockGroupVarClient(smtc *secretManagerTestCase) {
  244. responses := make([]fakegitlab.APIResponse[[]*gitlab.GroupVariable], 0)
  245. if smtc.groupAPIOutput != nil {
  246. responses = append(responses, fakegitlab.APIResponse[[]*gitlab.GroupVariable]{Output: []*gitlab.GroupVariable{smtc.groupAPIOutput}, Response: smtc.groupAPIResponse, Error: smtc.apiErr})
  247. }
  248. for _, response := range smtc.groupAPIOutputs {
  249. responses = append(responses, *response)
  250. }
  251. smtc.mockGroupVarClient.WithValues(responses)
  252. }
  253. // This case can be shared by both GetSecret and GetSecretMap tests.
  254. // bad case: set apiErr.
  255. var setAPIErr = func(smtc *secretManagerTestCase) {
  256. smtc.apiErr = errors.New("oh no")
  257. smtc.expectError = "oh no"
  258. smtc.projectAPIResponse.Response.StatusCode = http.StatusInternalServerError
  259. smtc.expectedValidationResult = esv1.ValidationResultError
  260. }
  261. var setListAPIErr = func(smtc *secretManagerTestCase) {
  262. err := errors.New("oh no")
  263. smtc.apiErr = err
  264. smtc.expectError = fmt.Errorf(errList, err).Error()
  265. smtc.expectedValidationResult = esv1.ValidationResultError
  266. }
  267. var setProjectListAPIRespNil = func(smtc *secretManagerTestCase) {
  268. smtc.projectAPIResponse = nil
  269. smtc.expectError = fmt.Errorf(errProjectAuth, smtc.projectID).Error()
  270. smtc.expectedValidationResult = esv1.ValidationResultError
  271. }
  272. var setGroupListAPIRespNil = func(smtc *secretManagerTestCase) {
  273. smtc.groupIDs = []string{groupid}
  274. smtc.groupAPIResponse = nil
  275. smtc.expectError = fmt.Errorf(errGroupAuth, groupid).Error()
  276. smtc.expectedValidationResult = esv1.ValidationResultError
  277. }
  278. var setProjectAndGroup = func(smtc *secretManagerTestCase) {
  279. smtc.groupIDs = []string{groupid}
  280. }
  281. var setProjectAndInheritFromGroups = func(smtc *secretManagerTestCase) {
  282. smtc.groupIDs = nil
  283. smtc.inheritFromGroups = true
  284. }
  285. var setProjectListAPIRespBadCode = func(smtc *secretManagerTestCase) {
  286. smtc.projectAPIResponse.StatusCode = http.StatusUnauthorized
  287. smtc.expectError = fmt.Errorf(errProjectAuth, smtc.projectID).Error()
  288. smtc.expectedValidationResult = esv1.ValidationResultError
  289. }
  290. var setGroupListAPIRespBadCode = func(smtc *secretManagerTestCase) {
  291. smtc.groupIDs = []string{groupid}
  292. smtc.groupAPIResponse.StatusCode = http.StatusUnauthorized
  293. smtc.expectError = fmt.Errorf(errGroupAuth, groupid).Error()
  294. smtc.expectedValidationResult = esv1.ValidationResultError
  295. }
  296. var setNilMockClient = func(smtc *secretManagerTestCase) {
  297. smtc.mockProjectVarClient = nil
  298. smtc.mockGroupVarClient = nil
  299. smtc.expectError = errUninitializedGitlabProvider
  300. }
  301. func TestNewClient(t *testing.T) {
  302. ctx := context.Background()
  303. const namespace = "namespace"
  304. store := &esv1.SecretStore{
  305. ObjectMeta: metav1.ObjectMeta{
  306. Namespace: namespace,
  307. },
  308. Spec: esv1.SecretStoreSpec{
  309. Provider: &esv1.SecretStoreProvider{
  310. Gitlab: &esv1.GitlabProvider{},
  311. },
  312. },
  313. }
  314. esv1.Register(NewProvider(), ProviderSpec(), MaintenanceStatus())
  315. provider, err := esv1.GetProvider(store)
  316. tassert.Nil(t, err)
  317. k8sClient := clientfake.NewClientBuilder().Build()
  318. secretClient, err := provider.NewClient(context.Background(), store, k8sClient, namespace)
  319. tassert.EqualError(t, err, errMissingCredentials)
  320. tassert.Nil(t, secretClient)
  321. store.Spec.Provider.Gitlab.Auth = esv1.GitlabAuth{}
  322. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  323. tassert.EqualError(t, err, errMissingCredentials)
  324. tassert.Nil(t, secretClient)
  325. store.Spec.Provider.Gitlab.Auth.SecretRef = esv1.GitlabSecretRef{}
  326. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  327. tassert.EqualError(t, err, errMissingCredentials)
  328. tassert.Nil(t, secretClient)
  329. store.Spec.Provider.Gitlab.Auth.SecretRef.AccessToken = esv1meta.SecretKeySelector{}
  330. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  331. tassert.EqualError(t, err, errMissingCredentials)
  332. tassert.Nil(t, secretClient)
  333. const authorizedKeySecretName = "authorizedKeySecretName"
  334. const authorizedKeySecretKey = "authorizedKeySecretKey"
  335. store.Spec.Provider.Gitlab.Auth.SecretRef.AccessToken.Name = authorizedKeySecretName
  336. store.Spec.Provider.Gitlab.Auth.SecretRef.AccessToken.Key = authorizedKeySecretKey
  337. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  338. tassert.EqualError(t, err, "cannot get Kubernetes secret \"authorizedKeySecretName\" from namespace \"namespace\": secrets \"authorizedKeySecretName\" not found")
  339. tassert.Nil(t, secretClient)
  340. err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, newFakeAuthorizedKey()))
  341. tassert.Nil(t, err)
  342. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  343. tassert.Nil(t, err)
  344. tassert.NotNil(t, secretClient)
  345. }
  346. func toJSON(t *testing.T, v any) []byte {
  347. jsonBytes, err := json.Marshal(v)
  348. tassert.Nil(t, err)
  349. return jsonBytes
  350. }
  351. func createK8sSecret(ctx context.Context, t *testing.T, k8sClient k8sclient.Client, namespace, secretName, secretKey string, secretValue []byte) error {
  352. err := k8sClient.Create(ctx, &corev1.Secret{
  353. ObjectMeta: metav1.ObjectMeta{
  354. Namespace: namespace,
  355. Name: secretName,
  356. },
  357. Data: map[string][]byte{secretKey: secretValue},
  358. })
  359. tassert.Nil(t, err)
  360. return nil
  361. }
  362. func newFakeAuthorizedKey() *iamkey.Key {
  363. uniqueLabel := uuid.NewString()
  364. return &iamkey.Key{
  365. Id: uniqueLabel,
  366. Subject: &iamkey.Key_ServiceAccountId{
  367. ServiceAccountId: uniqueLabel,
  368. },
  369. PrivateKey: uniqueLabel,
  370. }
  371. }
  372. // test the sm<->gcp interface
  373. // make sure correct values are passed and errors are handled accordingly.
  374. func TestGetSecret(t *testing.T) {
  375. // good case: default version is set
  376. // key is passed in, output is sent back
  377. onlyProjectSecret := func(smtc *secretManagerTestCase) {
  378. smtc.projectAPIOutput.Value = projectvalue
  379. smtc.groupAPIResponse = nil
  380. smtc.groupAPIOutput = nil
  381. smtc.expectedSecret = smtc.projectAPIOutput.Value
  382. }
  383. groupSecretProjectOverride := func(smtc *secretManagerTestCase) {
  384. // given a secre t in the project and a group with the same key
  385. // the project secret should override the group secret
  386. smtc.projectAPIOutput.Value = projectvalue
  387. smtc.groupAPIOutput.Key = testKey
  388. smtc.groupAPIOutput.Value = groupvalue
  389. smtc.expectedSecret = smtc.projectAPIOutput.Value
  390. }
  391. groupWithoutProjectOverride := func(smtc *secretManagerTestCase) {
  392. // given a group secret without a project secret
  393. // the group secret should be returned
  394. smtc.groupIDs = []string{groupid}
  395. smtc.projectAPIOutput = nil
  396. smtc.projectAPIOutputs = make404ProjectAPIOutput()
  397. smtc.groupAPIOutput.Key = testKey
  398. smtc.groupAPIOutput.Value = groupvalue
  399. smtc.expectedSecret = smtc.groupAPIOutput.Value
  400. }
  401. successCases := []*secretManagerTestCase{
  402. makeValidSecretManagerTestCaseCustom(onlyProjectSecret),
  403. makeValidSecretManagerTestCaseCustom(groupSecretProjectOverride),
  404. makeValidSecretManagerTestCaseCustom(groupWithoutProjectOverride),
  405. makeValidSecretManagerTestCaseCustom(setGroupWildcardVariable),
  406. makeValidSecretManagerTestCaseCustom(setGroupWildcardVariableWithEnvironment),
  407. makeValidSecretManagerTestCaseCustom(setGroupWildcardVariableNotFoundThenFound),
  408. makeValidSecretManagerTestCaseCustom(setAPIErr),
  409. makeValidSecretManagerTestCaseCustom(setNilMockClient),
  410. }
  411. sm := gitlabBase{}
  412. sm.store = &esv1.GitlabProvider{}
  413. for k, v := range successCases {
  414. sm.projectVariablesClient = v.mockProjectVarClient
  415. sm.groupVariablesClient = v.mockGroupVarClient
  416. sm.store.ProjectID = v.projectID
  417. sm.store.GroupIDs = v.groupIDs
  418. sm.store.Environment = v.apiInputEnv
  419. out, err := sm.GetSecret(context.Background(), *v.ref)
  420. if !ErrorContains(err, v.expectError) {
  421. t.Errorf(defaultErrorMessage, k, err.Error(), v.expectError)
  422. }
  423. if string(out) != v.expectedSecret {
  424. t.Errorf("[%d] unexpected secret: [%s], expected [%s]", k, string(out), v.expectedSecret)
  425. }
  426. }
  427. }
  428. // TestResolveGroupIDs tests the resolving of group IDs for a GitLab store.
  429. func TestResolveGroupIDs(t *testing.T) {
  430. v := makeValidSecretManagerTestCaseCustom()
  431. sm := gitlabBase{}
  432. sm.store = &esv1.GitlabProvider{}
  433. sm.projectsClient = v.mockProjectsClient
  434. sm.store.ProjectID = v.projectID
  435. sm.store.InheritFromGroups = true
  436. err := sm.ResolveGroupIDs()
  437. if err != nil {
  438. t.Errorf(defaultErrorMessage, 0, err.Error(), "")
  439. }
  440. if !reflect.DeepEqual(sm.store.GroupIDs, []string{"1", "10", "100"}) {
  441. t.Errorf("unexpected groupIDs: %s, expected %s", sm.store.GroupIDs, []string{"1", "10", "100"})
  442. }
  443. }
  444. func TestGetAllSecrets(t *testing.T) {
  445. // good case: default version is set
  446. // key is passed in, output is sent back
  447. setMissingFindRegex := func(smtc *secretManagerTestCase) {
  448. smtc.refFind.Name = nil
  449. smtc.expectError = "'find.name' is mandatory"
  450. }
  451. setUnsupportedFindPath := func(smtc *secretManagerTestCase) {
  452. path := "path"
  453. smtc.refFind.Path = &path
  454. smtc.expectError = "'find.path' is not implemented in the GitLab provider"
  455. }
  456. setUnsupportedFindTag := func(smtc *secretManagerTestCase) {
  457. smtc.expectError = "'find.tags' only supports 'environment_scope"
  458. smtc.refFind.Tags = map[string]string{"foo": ""}
  459. }
  460. setMatchingSecretFindString := func(smtc *secretManagerTestCase) {
  461. smtc.projectAPIOutput = &gitlab.ProjectVariable{
  462. Key: testKey,
  463. Value: projectvalue,
  464. EnvironmentScope: environment,
  465. }
  466. smtc.expectedSecret = projectvalue
  467. smtc.refFind.Name = makeFindName(findTestPrefix)
  468. }
  469. setNoMatchingRegexpFindString := func(smtc *secretManagerTestCase) {
  470. smtc.projectAPIOutput = &gitlab.ProjectVariable{
  471. Key: testKey,
  472. Value: projectvalue,
  473. EnvironmentScope: environmentTest,
  474. }
  475. smtc.expectedSecret = ""
  476. smtc.refFind.Name = makeFindName("foo.*")
  477. }
  478. setUnmatchedEnvironmentFindString := func(smtc *secretManagerTestCase) {
  479. smtc.apiInputEnv = environment
  480. smtc.projectAPIOutput = &gitlab.ProjectVariable{
  481. Key: testKey,
  482. Value: projectvalue,
  483. EnvironmentScope: environmentTest,
  484. }
  485. smtc.expectedSecret = ""
  486. smtc.refFind.Name = makeFindName(findTestPrefix)
  487. }
  488. setMatchingSecretFindTags := func(smtc *secretManagerTestCase) {
  489. smtc.projectAPIOutput = &gitlab.ProjectVariable{
  490. Key: testKey,
  491. Value: projectvalue,
  492. EnvironmentScope: environment,
  493. }
  494. smtc.apiInputEnv = "*"
  495. smtc.expectedSecret = projectvalue
  496. smtc.refFind.Tags = map[string]string{"environment_scope": environment}
  497. }
  498. setEnvironmentConstrainedByStore := func(smtc *secretManagerTestCase) {
  499. smtc.apiInputEnv = environment
  500. smtc.expectedSecret = projectvalue
  501. smtc.expectError = "'find.tags' is constrained by 'environment_scope' of the store"
  502. smtc.refFind.Tags = map[string]string{"environment_scope": environment}
  503. }
  504. setWildcardDoesntOverwriteEnvironmentValue := func(smtc *secretManagerTestCase) {
  505. var1 := gitlab.ProjectVariable{
  506. Key: testKey,
  507. Value: "wildcardValue",
  508. EnvironmentScope: "*",
  509. }
  510. var2 := gitlab.ProjectVariable{
  511. Key: testKey,
  512. Value: "expectedValue",
  513. EnvironmentScope: environmentTest,
  514. }
  515. var3 := gitlab.ProjectVariable{
  516. Key: testKey,
  517. Value: "wildcardValue",
  518. EnvironmentScope: "*",
  519. }
  520. vars := []*gitlab.ProjectVariable{&var1, &var2, &var3}
  521. smtc.projectAPIOutputs = []*fakegitlab.APIResponse[[]*gitlab.ProjectVariable]{{Output: vars, Response: smtc.projectAPIResponse, Error: nil}}
  522. smtc.projectAPIOutput = nil
  523. smtc.apiInputEnv = environmentTest
  524. smtc.expectedSecret = "expectedValue"
  525. smtc.refFind.Name = makeFindName(findTestPrefix)
  526. }
  527. setFilterByEnvironmentWithWildcard := func(smtc *secretManagerTestCase) {
  528. var1 := gitlab.ProjectVariable{
  529. Key: testKey,
  530. Value: projectvalue,
  531. EnvironmentScope: "*",
  532. }
  533. var2 := gitlab.ProjectVariable{
  534. Key: "testKey2",
  535. Value: "value2",
  536. EnvironmentScope: environment,
  537. }
  538. var3 := gitlab.ProjectVariable{
  539. Key: "testKey3",
  540. Value: "value3",
  541. EnvironmentScope: environmentTest,
  542. }
  543. var4 := gitlab.ProjectVariable{
  544. Key: "anotherKey4",
  545. Value: "value4",
  546. EnvironmentScope: environment,
  547. }
  548. vars := []*gitlab.ProjectVariable{&var1, &var2, &var3, &var4}
  549. smtc.projectAPIOutput = nil
  550. smtc.projectAPIOutputs = []*fakegitlab.APIResponse[[]*gitlab.ProjectVariable]{{Output: vars, Response: smtc.projectAPIResponse, Error: nil}}
  551. smtc.apiInputEnv = environment
  552. smtc.expectedData = map[string][]byte{testKey: []byte(projectvalue), "testKey2": []byte("value2")}
  553. smtc.refFind.Name = makeFindName(findTestPrefix)
  554. }
  555. setPaginationInGroupAndProjectVars := func(smtc *secretManagerTestCase) {
  556. smtc.groupIDs = []string{groupid}
  557. gvar1 := gitlab.GroupVariable{
  558. Key: testKey + "Group",
  559. Value: "groupValue1",
  560. EnvironmentScope: environmentTest,
  561. }
  562. gvar2 := gitlab.GroupVariable{
  563. Key: testKey,
  564. Value: "groupValue2",
  565. EnvironmentScope: environmentTest,
  566. }
  567. pvar1 := gitlab.ProjectVariable{
  568. Key: testKey,
  569. Value: "testValue1",
  570. EnvironmentScope: environmentTest,
  571. }
  572. pvar2a := gitlab.ProjectVariable{
  573. Key: testKey + "2a",
  574. Value: "testValue2a",
  575. EnvironmentScope: environmentTest,
  576. }
  577. pvar2b := gitlab.ProjectVariable{
  578. Key: testKey + "2b",
  579. Value: "testValue2b",
  580. EnvironmentScope: environmentTest,
  581. }
  582. gPage1 := []*gitlab.GroupVariable{&gvar1}
  583. gResponsePage1 := makeValidGroupAPIResponse()
  584. gResponsePage1.TotalPages = 2
  585. gResponsePage1.CurrentPage = 1
  586. gPage2 := []*gitlab.GroupVariable{&gvar2}
  587. gResponsePage2 := makeValidGroupAPIResponse()
  588. gResponsePage2.TotalPages = 2
  589. gResponsePage2.CurrentPage = 1
  590. pPage1 := []*gitlab.ProjectVariable{&pvar1}
  591. pResponsePage1 := makeValidProjectAPIResponse()
  592. pResponsePage1.TotalPages = 2
  593. pResponsePage1.CurrentPage = 1
  594. pPage2 := []*gitlab.ProjectVariable{&pvar2a, &pvar2b}
  595. pResponsePage2 := makeValidProjectAPIResponse()
  596. pResponsePage2.TotalPages = 2
  597. pResponsePage2.CurrentPage = 2
  598. smtc.groupAPIOutputs = []*fakegitlab.APIResponse[[]*gitlab.GroupVariable]{{Output: gPage1, Response: gResponsePage1, Error: nil}, {Output: gPage2, Response: gResponsePage2, Error: nil}}
  599. smtc.groupAPIOutput = nil
  600. smtc.projectAPIOutputs = []*fakegitlab.APIResponse[[]*gitlab.ProjectVariable]{{Output: pPage1, Response: pResponsePage1, Error: nil}, {Output: pPage2, Response: pResponsePage2, Error: nil}}
  601. smtc.projectAPIOutput = nil
  602. smtc.apiInputEnv = environmentTest
  603. smtc.expectedData = map[string][]byte{testKey: []byte("testValue1"), "testKey2a": []byte("testValue2a"), "testKey2b": []byte("testValue2b"), "testKeyGroup": []byte("groupValue1")}
  604. smtc.refFind.Name = makeFindName(findTestPrefix)
  605. }
  606. setGroupWildcardVariableInGetAllSecrets := func(smtc *secretManagerTestCase) {
  607. smtc.groupIDs = []string{groupid}
  608. smtc.projectAPIOutput = &gitlab.ProjectVariable{
  609. Key: testKey,
  610. Value: projectvalue,
  611. EnvironmentScope: environment,
  612. }
  613. smtc.groupAPIOutput = &gitlab.GroupVariable{
  614. Key: testKey,
  615. Value: groupvalue,
  616. EnvironmentScope: "*",
  617. }
  618. // Project variable should override group wildcard variable
  619. smtc.expectedData = map[string][]byte{testKey: []byte(projectvalue)}
  620. smtc.refFind.Name = makeFindName(findTestPrefix)
  621. }
  622. setGroupWildcardVariableOnlyInGetAllSecrets := func(smtc *secretManagerTestCase) {
  623. smtc.groupIDs = []string{groupid}
  624. smtc.projectAPIOutput = &gitlab.ProjectVariable{
  625. Key: testKey,
  626. Value: projectvalue,
  627. EnvironmentScope: environmentTest, // Different environment
  628. }
  629. smtc.groupAPIOutput = &gitlab.GroupVariable{
  630. Key: testKey,
  631. Value: groupvalue,
  632. EnvironmentScope: "*",
  633. }
  634. // Group wildcard variable should be used when project variable doesn't match environment
  635. smtc.apiInputEnv = environment
  636. smtc.expectedData = map[string][]byte{testKey: []byte(groupvalue)}
  637. smtc.refFind.Name = makeFindName(findTestPrefix)
  638. }
  639. setGroupWildcardVariableWithCollision := func(smtc *secretManagerTestCase) {
  640. smtc.groupIDs = []string{groupid}
  641. smtc.projectAPIOutput = &gitlab.ProjectVariable{
  642. Key: testKey,
  643. Value: projectvalue,
  644. EnvironmentScope: "*",
  645. }
  646. smtc.groupAPIOutput = &gitlab.GroupVariable{
  647. Key: testKey,
  648. Value: groupvalue,
  649. EnvironmentScope: "*",
  650. }
  651. // Project wildcard variable should override group wildcard variable
  652. smtc.expectedData = map[string][]byte{testKey: []byte(projectvalue)}
  653. smtc.refFind.Name = makeFindName(findTestPrefix)
  654. }
  655. cases := []*secretManagerTestCase{
  656. makeValidSecretManagerGetAllTestCaseCustom(setUnmatchedEnvironmentFindString),
  657. ///
  658. makeValidSecretManagerGetAllTestCaseCustom(setMissingFindRegex),
  659. makeValidSecretManagerGetAllTestCaseCustom(setUnsupportedFindPath),
  660. makeValidSecretManagerGetAllTestCaseCustom(setUnsupportedFindTag),
  661. makeValidSecretManagerGetAllTestCaseCustom(setMatchingSecretFindString),
  662. makeValidSecretManagerGetAllTestCaseCustom(setNoMatchingRegexpFindString),
  663. makeValidSecretManagerGetAllTestCaseCustom(setUnmatchedEnvironmentFindString),
  664. makeValidSecretManagerGetAllTestCaseCustom(setMatchingSecretFindTags),
  665. makeValidSecretManagerGetAllTestCaseCustom(setWildcardDoesntOverwriteEnvironmentValue),
  666. makeValidSecretManagerGetAllTestCaseCustom(setEnvironmentConstrainedByStore),
  667. makeValidSecretManagerGetAllTestCaseCustom(setFilterByEnvironmentWithWildcard),
  668. makeValidSecretManagerGetAllTestCaseCustom(setPaginationInGroupAndProjectVars),
  669. makeValidSecretManagerGetAllTestCaseCustom(setGroupWildcardVariableInGetAllSecrets),
  670. makeValidSecretManagerGetAllTestCaseCustom(setGroupWildcardVariableOnlyInGetAllSecrets),
  671. makeValidSecretManagerGetAllTestCaseCustom(setGroupWildcardVariableWithCollision),
  672. makeValidSecretManagerGetAllTestCaseCustom(setAPIErr),
  673. makeValidSecretManagerGetAllTestCaseCustom(setNilMockClient),
  674. }
  675. sm := gitlabBase{}
  676. sm.store = &esv1.GitlabProvider{}
  677. for k, v := range cases {
  678. sm.projectVariablesClient = v.mockProjectVarClient
  679. sm.groupVariablesClient = v.mockGroupVarClient
  680. sm.store.Environment = v.apiInputEnv
  681. sm.store.GroupIDs = v.groupIDs
  682. if v.expectedSecret != "" {
  683. v.expectedData = map[string][]byte{testKey: []byte(v.expectedSecret)}
  684. }
  685. out, err := sm.GetAllSecrets(context.Background(), *v.refFind)
  686. if !ErrorContains(err, v.expectError) {
  687. t.Errorf(defaultErrorMessage, k, err.Error(), v.expectError)
  688. }
  689. if err == nil && !reflect.DeepEqual(out, v.expectedData) {
  690. t.Errorf("[%d] unexpected secret data: [%#v], expected [%#v]", k, out, v.expectedData)
  691. }
  692. }
  693. }
  694. func TestGetAllSecretsWithGroups(t *testing.T) {
  695. onlyProjectSecret := func(smtc *secretManagerTestCase) {
  696. smtc.projectAPIOutput.Value = projectvalue
  697. smtc.refFind.Name = makeFindName(findTestPrefix)
  698. smtc.groupAPIResponse = nil
  699. smtc.groupAPIOutput = nil
  700. smtc.expectedSecret = smtc.projectAPIOutput.Value
  701. }
  702. groupAndProjectSecrets := func(smtc *secretManagerTestCase) {
  703. smtc.groupIDs = []string{groupid}
  704. smtc.projectAPIOutput.Value = projectvalue
  705. smtc.groupAPIOutput.Value = groupvalue
  706. smtc.expectedData = map[string][]byte{testKey: []byte(projectvalue), "groupKey": []byte(groupvalue)}
  707. smtc.refFind.Name = makeFindName(".*Key")
  708. }
  709. groupAndOverrideProjectSecrets := func(smtc *secretManagerTestCase) {
  710. smtc.groupIDs = []string{groupid}
  711. smtc.projectAPIOutput.Value = projectvalue
  712. smtc.groupAPIOutput.Key = smtc.projectAPIOutput.Key
  713. smtc.groupAPIOutput.Value = groupvalue
  714. smtc.expectedData = map[string][]byte{testKey: []byte(projectvalue)}
  715. smtc.refFind.Name = makeFindName(".*Key")
  716. }
  717. groupAndProjectWithDifferentEnvSecrets := func(smtc *secretManagerTestCase) {
  718. smtc.groupIDs = []string{groupid}
  719. smtc.projectAPIOutput.Value = projectvalue
  720. smtc.projectAPIOutput.EnvironmentScope = environmentTest
  721. smtc.groupAPIOutput.Key = smtc.projectAPIOutput.Key
  722. smtc.groupAPIOutput.Value = groupvalue
  723. smtc.expectedData = map[string][]byte{testKey: []byte(groupvalue)}
  724. smtc.refFind.Name = makeFindName(".*Key")
  725. }
  726. cases := []*secretManagerTestCase{
  727. makeValidSecretManagerGetAllTestCaseCustom(onlyProjectSecret),
  728. makeValidSecretManagerGetAllTestCaseCustom(groupAndProjectSecrets),
  729. makeValidSecretManagerGetAllTestCaseCustom(groupAndOverrideProjectSecrets),
  730. makeValidSecretManagerGetAllTestCaseCustom(groupAndProjectWithDifferentEnvSecrets),
  731. }
  732. sm := gitlabBase{}
  733. sm.store = &esv1.GitlabProvider{}
  734. sm.store.Environment = environment
  735. for k, v := range cases {
  736. sm.projectVariablesClient = v.mockProjectVarClient
  737. sm.groupVariablesClient = v.mockGroupVarClient
  738. sm.store.ProjectID = v.projectID
  739. sm.store.GroupIDs = v.groupIDs
  740. out, err := sm.GetAllSecrets(context.Background(), *v.refFind)
  741. if !ErrorContains(err, v.expectError) {
  742. t.Errorf(defaultErrorMessage, k, err.Error(), v.expectError)
  743. }
  744. if v.expectError == "" {
  745. if len(v.expectedData) > 0 {
  746. if !reflect.DeepEqual(v.expectedData, out) {
  747. t.Errorf("[%d] unexpected secrets: [%s], expected [%s]", k, out, v.expectedData)
  748. }
  749. } else if string(out[v.projectAPIOutput.Key]) != v.expectedSecret {
  750. t.Errorf("[%d] unexpected secret: [%s], expected [%s]", k, string(out[v.projectAPIOutput.Key]), v.expectedSecret)
  751. }
  752. }
  753. }
  754. }
  755. func TestValidate(t *testing.T) {
  756. successCases := []*secretManagerTestCase{
  757. makeValidSecretManagerTestCaseCustom(),
  758. makeValidSecretManagerTestCaseCustom(setProjectAndInheritFromGroups),
  759. makeValidSecretManagerTestCaseCustom(setProjectAndGroup),
  760. makeValidSecretManagerTestCaseCustom(setListAPIErr),
  761. makeValidSecretManagerTestCaseCustom(setProjectListAPIRespNil),
  762. makeValidSecretManagerTestCaseCustom(setProjectListAPIRespBadCode),
  763. makeValidSecretManagerTestCaseCustom(setGroupListAPIRespNil),
  764. makeValidSecretManagerTestCaseCustom(setGroupListAPIRespBadCode),
  765. }
  766. sm := gitlabBase{}
  767. sm.store = &esv1.GitlabProvider{}
  768. for k, v := range successCases {
  769. sm.projectsClient = v.mockProjectsClient
  770. sm.projectVariablesClient = v.mockProjectVarClient
  771. sm.groupVariablesClient = v.mockGroupVarClient
  772. sm.store.ProjectID = v.projectID
  773. sm.store.GroupIDs = v.groupIDs
  774. sm.store.InheritFromGroups = v.inheritFromGroups
  775. t.Logf("%+v", v)
  776. validationResult, err := sm.Validate()
  777. if !ErrorContains(err, v.expectError) {
  778. t.Errorf(defaultErrorMessage, k, err.Error(), v.expectError)
  779. }
  780. if validationResult != v.expectedValidationResult {
  781. t.Errorf("[%d], unexpected validationResult: [%s], expected: [%s]", k, validationResult, v.expectedValidationResult)
  782. }
  783. if sm.store.InheritFromGroups && sm.store.GroupIDs[0] != "1" {
  784. t.Errorf("[%d], unexpected groupID: [%s], expected [1]", k, sm.store.GroupIDs[0])
  785. }
  786. }
  787. }
  788. func TestGetSecretMap(t *testing.T) {
  789. // good case: default version & deserialization
  790. setDeserialization := func(smtc *secretManagerTestCase) {
  791. smtc.projectAPIOutput.Value = `{"foo":"bar"}`
  792. smtc.expectedData["foo"] = []byte("bar")
  793. }
  794. // bad case: invalid json
  795. setInvalidJSON := func(smtc *secretManagerTestCase) {
  796. smtc.projectAPIOutput.Value = `-----------------`
  797. smtc.expectError = "unable to unmarshal secret"
  798. }
  799. successCases := []*secretManagerTestCase{
  800. makeValidSecretManagerTestCaseCustom(setDeserialization),
  801. makeValidSecretManagerTestCaseCustom(setInvalidJSON),
  802. makeValidSecretManagerTestCaseCustom(setNilMockClient),
  803. makeValidSecretManagerTestCaseCustom(setAPIErr),
  804. }
  805. sm := gitlabBase{}
  806. sm.store = &esv1.GitlabProvider{}
  807. for k, v := range successCases {
  808. sm.projectVariablesClient = v.mockProjectVarClient
  809. sm.groupVariablesClient = v.mockGroupVarClient
  810. out, err := sm.GetSecretMap(context.Background(), *v.ref)
  811. if !ErrorContains(err, v.expectError) {
  812. t.Errorf(defaultErrorMessage, k, err.Error(), v.expectError)
  813. }
  814. if err == nil && !reflect.DeepEqual(out, v.expectedData) {
  815. t.Errorf("[%d] unexpected secret data: [%#v], expected [%#v]", k, out, v.expectedData)
  816. }
  817. }
  818. }
  819. func makeSecretStore(projectID, environment string, fn ...storeModifier) *esv1.SecretStore {
  820. store := &esv1.SecretStore{
  821. Spec: esv1.SecretStoreSpec{
  822. Provider: &esv1.SecretStoreProvider{
  823. Gitlab: &esv1.GitlabProvider{
  824. Auth: esv1.GitlabAuth{},
  825. ProjectID: projectID,
  826. Environment: environment,
  827. },
  828. },
  829. },
  830. }
  831. for _, f := range fn {
  832. store = f(store)
  833. }
  834. return store
  835. }
  836. func withAccessToken(name, key string, namespace *string) storeModifier {
  837. return func(store *esv1.SecretStore) *esv1.SecretStore {
  838. store.Spec.Provider.Gitlab.Auth.SecretRef.AccessToken = esv1meta.SecretKeySelector{
  839. Name: name,
  840. Key: key,
  841. Namespace: namespace,
  842. }
  843. return store
  844. }
  845. }
  846. func withGroups(ids []string, inherit bool) storeModifier {
  847. return func(store *esv1.SecretStore) *esv1.SecretStore {
  848. store.Spec.Provider.Gitlab.GroupIDs = ids
  849. store.Spec.Provider.Gitlab.InheritFromGroups = inherit
  850. return store
  851. }
  852. }
  853. type ValidateStoreTestCase struct {
  854. store *esv1.SecretStore
  855. err error
  856. }
  857. func TestValidateStore(t *testing.T) {
  858. namespace := "my-namespace"
  859. testCases := []ValidateStoreTestCase{
  860. {
  861. store: makeSecretStore("", environment),
  862. err: errors.New("projectID and groupIDs must not both be empty"),
  863. },
  864. {
  865. store: makeSecretStore(project, environment, withGroups([]string{"group1"}, true)),
  866. err: errors.New("defining groupIDs and inheritFromGroups = true is not allowed"),
  867. },
  868. {
  869. store: makeSecretStore(project, environment, withAccessToken("", userkey, nil)),
  870. err: errors.New("accessToken.name cannot be empty"),
  871. },
  872. {
  873. store: makeSecretStore(project, environment, withAccessToken(username, "", nil)),
  874. err: errors.New("accessToken.key cannot be empty"),
  875. },
  876. {
  877. store: makeSecretStore(project, environment, withAccessToken("userName", "userKey", &namespace)),
  878. err: errors.New("namespace should either be empty or match the namespace of the SecretStore for a namespaced SecretStore"),
  879. },
  880. {
  881. store: makeSecretStore(project, environment, withAccessToken("userName", "userKey", nil)),
  882. err: nil,
  883. },
  884. {
  885. store: makeSecretStore("", environment, withGroups([]string{"group1"}, false), withAccessToken("userName", "userKey", nil)),
  886. err: nil,
  887. },
  888. }
  889. p := Provider{}
  890. for _, tc := range testCases {
  891. _, err := p.ValidateStore(tc.store)
  892. if tc.err != nil && err != nil && err.Error() != tc.err.Error() {
  893. t.Errorf("test failed! want %v, got %v", tc.err, err)
  894. } else if tc.err == nil && err != nil {
  895. t.Errorf("want nil got err %v", err)
  896. } else if tc.err != nil && err == nil {
  897. t.Errorf("want err %v got nil", tc.err)
  898. }
  899. }
  900. }
  901. func ErrorContains(out error, want string) bool {
  902. if out == nil {
  903. return want == ""
  904. }
  905. if want == "" {
  906. return false
  907. }
  908. return strings.Contains(out.Error(), want)
  909. }
  910. type storeModifier func(*esv1.SecretStore) *esv1.SecretStore
  911. func setGroupWildcardVariable(smtc *secretManagerTestCase) {
  912. // Given a group variable with a wildcard environment scope
  913. // and a provider with no environment,
  914. // the group variable should be returned
  915. smtc.groupIDs = []string{groupid}
  916. smtc.projectAPIOutput = nil
  917. smtc.projectAPIOutputs = make404ProjectAPIOutput(2)
  918. smtc.groupAPIOutput.Key = testKey
  919. smtc.groupAPIOutput.Value = groupvalue
  920. smtc.groupAPIOutput.EnvironmentScope = "*"
  921. smtc.expectedSecret = smtc.groupAPIOutput.Value
  922. }
  923. func setGroupWildcardVariableWithEnvironment(smtc *secretManagerTestCase) {
  924. // Given a group variable with a wildcard environment scope
  925. // and a provider with a specific environment,
  926. // the group variable should be returned
  927. // todo: verify that the flow for wildcard is observed. Have some doubts
  928. smtc.groupIDs = []string{groupid}
  929. smtc.projectAPIOutput = nil
  930. smtc.projectAPIOutputs = make404ProjectAPIOutput(2)
  931. smtc.groupAPIOutput.Key = testKey
  932. smtc.groupAPIOutput.Value = groupvalue
  933. smtc.groupAPIOutput.EnvironmentScope = "*"
  934. smtc.apiInputEnv = environment
  935. smtc.expectedSecret = smtc.groupAPIOutput.Value
  936. }
  937. func setGroupWildcardVariableNotFoundThenFound(smtc *secretManagerTestCase) {
  938. // Given a group variable with a wildcard environment scope
  939. // and a provider with a specific environment,
  940. // the group variable should be returned
  941. smtc.groupIDs = []string{groupid}
  942. smtc.projectAPIOutput = nil
  943. smtc.projectAPIOutputs = make404ProjectAPIOutput(2)
  944. smtc.groupAPIOutput = nil
  945. smtc.groupAPIOutputs = []*fakegitlab.APIResponse[[]*gitlab.GroupVariable]{
  946. {Response: make404GitlabAPIResponse(), Error: gitlab.ErrNotFound},
  947. {Output: []*gitlab.GroupVariable{
  948. {
  949. Key: testKey,
  950. Value: groupvalue,
  951. EnvironmentScope: "*",
  952. },
  953. }, Response: makeValidGroupAPIResponse(), Error: nil},
  954. }
  955. smtc.apiInputEnv = environment
  956. smtc.expectedSecret = groupvalue
  957. }