gitlab_test.go 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034
  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(responses, fakegitlab.APIResponse[[]*gitlab.ProjectVariable]{Output: []*gitlab.ProjectVariable{smtc.projectAPIOutput}, Response: smtc.projectAPIResponse, Error: smtc.apiErr})
  234. }
  235. for _, response := range smtc.projectAPIOutputs {
  236. responses = append(responses, *response)
  237. }
  238. smtc.mockProjectVarClient.WithValues(responses)
  239. }
  240. func prepareMockGroupVarClient(smtc *secretManagerTestCase) {
  241. responses := make([]fakegitlab.APIResponse[[]*gitlab.GroupVariable], 0)
  242. if smtc.groupAPIOutput != nil {
  243. responses = append(responses, fakegitlab.APIResponse[[]*gitlab.GroupVariable]{Output: []*gitlab.GroupVariable{smtc.groupAPIOutput}, Response: smtc.groupAPIResponse, Error: smtc.apiErr})
  244. }
  245. for _, response := range smtc.groupAPIOutputs {
  246. responses = append(responses, *response)
  247. }
  248. smtc.mockGroupVarClient.WithValues(responses)
  249. }
  250. // This case can be shared by both GetSecret and GetSecretMap tests.
  251. // bad case: set apiErr.
  252. var setAPIErr = func(smtc *secretManagerTestCase) {
  253. smtc.apiErr = errors.New("oh no")
  254. smtc.expectError = "oh no"
  255. smtc.projectAPIResponse.Response.StatusCode = http.StatusInternalServerError
  256. smtc.expectedValidationResult = esv1.ValidationResultError
  257. }
  258. var setListAPIErr = func(smtc *secretManagerTestCase) {
  259. err := errors.New("oh no")
  260. smtc.apiErr = err
  261. smtc.expectError = fmt.Errorf(errList, err).Error()
  262. smtc.expectedValidationResult = esv1.ValidationResultError
  263. }
  264. var setProjectListAPIRespNil = func(smtc *secretManagerTestCase) {
  265. smtc.projectAPIResponse = nil
  266. smtc.expectError = fmt.Errorf(errProjectAuth, smtc.projectID).Error()
  267. smtc.expectedValidationResult = esv1.ValidationResultError
  268. }
  269. var setGroupListAPIRespNil = func(smtc *secretManagerTestCase) {
  270. smtc.groupIDs = []string{groupid}
  271. smtc.groupAPIResponse = nil
  272. smtc.expectError = fmt.Errorf(errGroupAuth, groupid).Error()
  273. smtc.expectedValidationResult = esv1.ValidationResultError
  274. }
  275. var setProjectAndGroup = func(smtc *secretManagerTestCase) {
  276. smtc.groupIDs = []string{groupid}
  277. }
  278. var setProjectAndInheritFromGroups = func(smtc *secretManagerTestCase) {
  279. smtc.groupIDs = nil
  280. smtc.inheritFromGroups = true
  281. }
  282. var setProjectListAPIRespBadCode = func(smtc *secretManagerTestCase) {
  283. smtc.projectAPIResponse.StatusCode = http.StatusUnauthorized
  284. smtc.expectError = fmt.Errorf(errProjectAuth, smtc.projectID).Error()
  285. smtc.expectedValidationResult = esv1.ValidationResultError
  286. }
  287. var setGroupListAPIRespBadCode = func(smtc *secretManagerTestCase) {
  288. smtc.groupIDs = []string{groupid}
  289. smtc.groupAPIResponse.StatusCode = http.StatusUnauthorized
  290. smtc.expectError = fmt.Errorf(errGroupAuth, groupid).Error()
  291. smtc.expectedValidationResult = esv1.ValidationResultError
  292. }
  293. var setNilMockClient = func(smtc *secretManagerTestCase) {
  294. smtc.mockProjectVarClient = nil
  295. smtc.mockGroupVarClient = nil
  296. smtc.expectError = errUninitializedGitlabProvider
  297. }
  298. func TestNewClient(t *testing.T) {
  299. ctx := context.Background()
  300. const namespace = "namespace"
  301. store := &esv1.SecretStore{
  302. ObjectMeta: metav1.ObjectMeta{
  303. Namespace: namespace,
  304. },
  305. Spec: esv1.SecretStoreSpec{
  306. Provider: &esv1.SecretStoreProvider{
  307. Gitlab: &esv1.GitlabProvider{},
  308. },
  309. },
  310. }
  311. esv1.Register(NewProvider(), ProviderSpec(), MaintenanceStatus())
  312. provider, err := esv1.GetProvider(store)
  313. tassert.Nil(t, err)
  314. k8sClient := clientfake.NewClientBuilder().Build()
  315. secretClient, err := provider.NewClient(context.Background(), store, k8sClient, namespace)
  316. tassert.EqualError(t, err, errMissingCredentials)
  317. tassert.Nil(t, secretClient)
  318. store.Spec.Provider.Gitlab.Auth = esv1.GitlabAuth{}
  319. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  320. tassert.EqualError(t, err, errMissingCredentials)
  321. tassert.Nil(t, secretClient)
  322. store.Spec.Provider.Gitlab.Auth.SecretRef = esv1.GitlabSecretRef{}
  323. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  324. tassert.EqualError(t, err, errMissingCredentials)
  325. tassert.Nil(t, secretClient)
  326. store.Spec.Provider.Gitlab.Auth.SecretRef.AccessToken = esv1meta.SecretKeySelector{}
  327. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  328. tassert.EqualError(t, err, errMissingCredentials)
  329. tassert.Nil(t, secretClient)
  330. const authorizedKeySecretName = "authorizedKeySecretName"
  331. const authorizedKeySecretKey = "authorizedKeySecretKey"
  332. store.Spec.Provider.Gitlab.Auth.SecretRef.AccessToken.Name = authorizedKeySecretName
  333. store.Spec.Provider.Gitlab.Auth.SecretRef.AccessToken.Key = authorizedKeySecretKey
  334. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  335. tassert.EqualError(t, err, "cannot get Kubernetes secret \"authorizedKeySecretName\" from namespace \"namespace\": secrets \"authorizedKeySecretName\" not found")
  336. tassert.Nil(t, secretClient)
  337. err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, newFakeAuthorizedKey()))
  338. tassert.Nil(t, err)
  339. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  340. tassert.Nil(t, err)
  341. tassert.NotNil(t, secretClient)
  342. }
  343. func toJSON(t *testing.T, v any) []byte {
  344. jsonBytes, err := json.Marshal(v)
  345. tassert.Nil(t, err)
  346. return jsonBytes
  347. }
  348. func createK8sSecret(ctx context.Context, t *testing.T, k8sClient k8sclient.Client, namespace, secretName, secretKey string, secretValue []byte) error {
  349. err := k8sClient.Create(ctx, &corev1.Secret{
  350. ObjectMeta: metav1.ObjectMeta{
  351. Namespace: namespace,
  352. Name: secretName,
  353. },
  354. Data: map[string][]byte{secretKey: secretValue},
  355. })
  356. tassert.Nil(t, err)
  357. return nil
  358. }
  359. func newFakeAuthorizedKey() *iamkey.Key {
  360. uniqueLabel := uuid.NewString()
  361. return &iamkey.Key{
  362. Id: uniqueLabel,
  363. Subject: &iamkey.Key_ServiceAccountId{
  364. ServiceAccountId: uniqueLabel,
  365. },
  366. PrivateKey: uniqueLabel,
  367. }
  368. }
  369. // test the sm<->gcp interface
  370. // make sure correct values are passed and errors are handled accordingly.
  371. func TestGetSecret(t *testing.T) {
  372. // good case: default version is set
  373. // key is passed in, output is sent back
  374. onlyProjectSecret := func(smtc *secretManagerTestCase) {
  375. smtc.projectAPIOutput.Value = projectvalue
  376. smtc.groupAPIResponse = nil
  377. smtc.groupAPIOutput = nil
  378. smtc.expectedSecret = smtc.projectAPIOutput.Value
  379. }
  380. groupSecretProjectOverride := func(smtc *secretManagerTestCase) {
  381. // given a secre t in the project and a group with the same key
  382. // the project secret should override the group secret
  383. smtc.projectAPIOutput.Value = projectvalue
  384. smtc.groupAPIOutput.Key = testKey
  385. smtc.groupAPIOutput.Value = groupvalue
  386. smtc.expectedSecret = smtc.projectAPIOutput.Value
  387. }
  388. groupWithoutProjectOverride := func(smtc *secretManagerTestCase) {
  389. // given a group secret without a project secret
  390. // the group secret should be returned
  391. smtc.groupIDs = []string{groupid}
  392. smtc.projectAPIOutput = nil
  393. smtc.projectAPIOutputs = make404ProjectAPIOutput()
  394. smtc.groupAPIOutput.Key = testKey
  395. smtc.groupAPIOutput.Value = groupvalue
  396. smtc.expectedSecret = smtc.groupAPIOutput.Value
  397. }
  398. successCases := []*secretManagerTestCase{
  399. makeValidSecretManagerTestCaseCustom(onlyProjectSecret),
  400. makeValidSecretManagerTestCaseCustom(groupSecretProjectOverride),
  401. makeValidSecretManagerTestCaseCustom(groupWithoutProjectOverride),
  402. makeValidSecretManagerTestCaseCustom(setGroupWildcardVariable),
  403. makeValidSecretManagerTestCaseCustom(setGroupWildcardVariableWithEnvironment),
  404. makeValidSecretManagerTestCaseCustom(setGroupWildcardVariableNotFoundThenFound),
  405. makeValidSecretManagerTestCaseCustom(setAPIErr),
  406. makeValidSecretManagerTestCaseCustom(setNilMockClient),
  407. }
  408. sm := gitlabBase{}
  409. sm.store = &esv1.GitlabProvider{}
  410. for k, v := range successCases {
  411. sm.projectVariablesClient = v.mockProjectVarClient
  412. sm.groupVariablesClient = v.mockGroupVarClient
  413. sm.store.ProjectID = v.projectID
  414. sm.store.GroupIDs = v.groupIDs
  415. sm.store.Environment = v.apiInputEnv
  416. out, err := sm.GetSecret(context.Background(), *v.ref)
  417. if !ErrorContains(err, v.expectError) {
  418. t.Errorf(defaultErrorMessage, k, err.Error(), v.expectError)
  419. }
  420. if string(out) != v.expectedSecret {
  421. t.Errorf("[%d] unexpected secret: [%s], expected [%s]", k, string(out), v.expectedSecret)
  422. }
  423. }
  424. }
  425. // TestResolveGroupIDs tests the resolving of group IDs for a GitLab store.
  426. func TestResolveGroupIDs(t *testing.T) {
  427. v := makeValidSecretManagerTestCaseCustom()
  428. sm := gitlabBase{}
  429. sm.store = &esv1.GitlabProvider{}
  430. sm.projectsClient = v.mockProjectsClient
  431. sm.store.ProjectID = v.projectID
  432. sm.store.InheritFromGroups = true
  433. err := sm.ResolveGroupIDs()
  434. if err != nil {
  435. t.Errorf(defaultErrorMessage, 0, err.Error(), "")
  436. }
  437. if !reflect.DeepEqual(sm.store.GroupIDs, []string{"1", "10", "100"}) {
  438. t.Errorf("unexpected groupIDs: %s, expected %s", sm.store.GroupIDs, []string{"1", "10", "100"})
  439. }
  440. }
  441. func TestGetAllSecrets(t *testing.T) {
  442. // good case: default version is set
  443. // key is passed in, output is sent back
  444. setMissingFindRegex := func(smtc *secretManagerTestCase) {
  445. smtc.refFind.Name = nil
  446. smtc.expectError = "'find.name' is mandatory"
  447. }
  448. setUnsupportedFindPath := func(smtc *secretManagerTestCase) {
  449. path := "path"
  450. smtc.refFind.Path = &path
  451. smtc.expectError = "'find.path' is not implemented in the GitLab provider"
  452. }
  453. setUnsupportedFindTag := func(smtc *secretManagerTestCase) {
  454. smtc.expectError = "'find.tags' only supports 'environment_scope"
  455. smtc.refFind.Tags = map[string]string{"foo": ""}
  456. }
  457. setMatchingSecretFindString := func(smtc *secretManagerTestCase) {
  458. smtc.projectAPIOutput = &gitlab.ProjectVariable{
  459. Key: testKey,
  460. Value: projectvalue,
  461. EnvironmentScope: environment,
  462. }
  463. smtc.expectedSecret = projectvalue
  464. smtc.refFind.Name = makeFindName(findTestPrefix)
  465. }
  466. setNoMatchingRegexpFindString := func(smtc *secretManagerTestCase) {
  467. smtc.projectAPIOutput = &gitlab.ProjectVariable{
  468. Key: testKey,
  469. Value: projectvalue,
  470. EnvironmentScope: environmentTest,
  471. }
  472. smtc.expectedSecret = ""
  473. smtc.refFind.Name = makeFindName("foo.*")
  474. }
  475. setUnmatchedEnvironmentFindString := func(smtc *secretManagerTestCase) {
  476. smtc.apiInputEnv = environment
  477. smtc.projectAPIOutput = &gitlab.ProjectVariable{
  478. Key: testKey,
  479. Value: projectvalue,
  480. EnvironmentScope: environmentTest,
  481. }
  482. smtc.expectedSecret = ""
  483. smtc.refFind.Name = makeFindName(findTestPrefix)
  484. }
  485. setMatchingSecretFindTags := func(smtc *secretManagerTestCase) {
  486. smtc.projectAPIOutput = &gitlab.ProjectVariable{
  487. Key: testKey,
  488. Value: projectvalue,
  489. EnvironmentScope: environment,
  490. }
  491. smtc.apiInputEnv = "*"
  492. smtc.expectedSecret = projectvalue
  493. smtc.refFind.Tags = map[string]string{"environment_scope": environment}
  494. }
  495. setEnvironmentConstrainedByStore := func(smtc *secretManagerTestCase) {
  496. smtc.apiInputEnv = environment
  497. smtc.expectedSecret = projectvalue
  498. smtc.expectError = "'find.tags' is constrained by 'environment_scope' of the store"
  499. smtc.refFind.Tags = map[string]string{"environment_scope": environment}
  500. }
  501. setWildcardDoesntOverwriteEnvironmentValue := func(smtc *secretManagerTestCase) {
  502. var1 := gitlab.ProjectVariable{
  503. Key: testKey,
  504. Value: "wildcardValue",
  505. EnvironmentScope: "*",
  506. }
  507. var2 := gitlab.ProjectVariable{
  508. Key: testKey,
  509. Value: "expectedValue",
  510. EnvironmentScope: environmentTest,
  511. }
  512. var3 := gitlab.ProjectVariable{
  513. Key: testKey,
  514. Value: "wildcardValue",
  515. EnvironmentScope: "*",
  516. }
  517. vars := []*gitlab.ProjectVariable{&var1, &var2, &var3}
  518. smtc.projectAPIOutputs = []*fakegitlab.APIResponse[[]*gitlab.ProjectVariable]{{Output: vars, Response: smtc.projectAPIResponse, Error: nil}}
  519. smtc.projectAPIOutput = nil
  520. smtc.apiInputEnv = environmentTest
  521. smtc.expectedSecret = "expectedValue"
  522. smtc.refFind.Name = makeFindName(findTestPrefix)
  523. }
  524. setFilterByEnvironmentWithWildcard := func(smtc *secretManagerTestCase) {
  525. var1 := gitlab.ProjectVariable{
  526. Key: testKey,
  527. Value: projectvalue,
  528. EnvironmentScope: "*",
  529. }
  530. var2 := gitlab.ProjectVariable{
  531. Key: "testKey2",
  532. Value: "value2",
  533. EnvironmentScope: environment,
  534. }
  535. var3 := gitlab.ProjectVariable{
  536. Key: "testKey3",
  537. Value: "value3",
  538. EnvironmentScope: environmentTest,
  539. }
  540. var4 := gitlab.ProjectVariable{
  541. Key: "anotherKey4",
  542. Value: "value4",
  543. EnvironmentScope: environment,
  544. }
  545. vars := []*gitlab.ProjectVariable{&var1, &var2, &var3, &var4}
  546. smtc.projectAPIOutput = nil
  547. smtc.projectAPIOutputs = []*fakegitlab.APIResponse[[]*gitlab.ProjectVariable]{{Output: vars, Response: smtc.projectAPIResponse, Error: nil}}
  548. smtc.apiInputEnv = environment
  549. smtc.expectedData = map[string][]byte{testKey: []byte(projectvalue), "testKey2": []byte("value2")}
  550. smtc.refFind.Name = makeFindName(findTestPrefix)
  551. }
  552. setPaginationInGroupAndProjectVars := func(smtc *secretManagerTestCase) {
  553. smtc.groupIDs = []string{groupid}
  554. gvar1 := gitlab.GroupVariable{
  555. Key: testKey + "Group",
  556. Value: "groupValue1",
  557. EnvironmentScope: environmentTest,
  558. }
  559. gvar2 := gitlab.GroupVariable{
  560. Key: testKey,
  561. Value: "groupValue2",
  562. EnvironmentScope: environmentTest,
  563. }
  564. pvar1 := gitlab.ProjectVariable{
  565. Key: testKey,
  566. Value: "testValue1",
  567. EnvironmentScope: environmentTest,
  568. }
  569. pvar2a := gitlab.ProjectVariable{
  570. Key: testKey + "2a",
  571. Value: "testValue2a",
  572. EnvironmentScope: environmentTest,
  573. }
  574. pvar2b := gitlab.ProjectVariable{
  575. Key: testKey + "2b",
  576. Value: "testValue2b",
  577. EnvironmentScope: environmentTest,
  578. }
  579. gPage1 := []*gitlab.GroupVariable{&gvar1}
  580. gResponsePage1 := makeValidGroupAPIResponse()
  581. gResponsePage1.TotalPages = 2
  582. gResponsePage1.CurrentPage = 1
  583. gPage2 := []*gitlab.GroupVariable{&gvar2}
  584. gResponsePage2 := makeValidGroupAPIResponse()
  585. gResponsePage2.TotalPages = 2
  586. gResponsePage2.CurrentPage = 1
  587. pPage1 := []*gitlab.ProjectVariable{&pvar1}
  588. pResponsePage1 := makeValidProjectAPIResponse()
  589. pResponsePage1.TotalPages = 2
  590. pResponsePage1.CurrentPage = 1
  591. pPage2 := []*gitlab.ProjectVariable{&pvar2a, &pvar2b}
  592. pResponsePage2 := makeValidProjectAPIResponse()
  593. pResponsePage2.TotalPages = 2
  594. pResponsePage2.CurrentPage = 2
  595. smtc.groupAPIOutputs = []*fakegitlab.APIResponse[[]*gitlab.GroupVariable]{{Output: gPage1, Response: gResponsePage1, Error: nil}, {Output: gPage2, Response: gResponsePage2, Error: nil}}
  596. smtc.groupAPIOutput = nil
  597. smtc.projectAPIOutputs = []*fakegitlab.APIResponse[[]*gitlab.ProjectVariable]{{Output: pPage1, Response: pResponsePage1, Error: nil}, {Output: pPage2, Response: pResponsePage2, Error: nil}}
  598. smtc.projectAPIOutput = nil
  599. smtc.apiInputEnv = environmentTest
  600. smtc.expectedData = map[string][]byte{testKey: []byte("testValue1"), "testKey2a": []byte("testValue2a"), "testKey2b": []byte("testValue2b"), "testKeyGroup": []byte("groupValue1")}
  601. smtc.refFind.Name = makeFindName(findTestPrefix)
  602. }
  603. setGroupWildcardVariableInGetAllSecrets := func(smtc *secretManagerTestCase) {
  604. smtc.groupIDs = []string{groupid}
  605. smtc.projectAPIOutput = &gitlab.ProjectVariable{
  606. Key: testKey,
  607. Value: projectvalue,
  608. EnvironmentScope: environment,
  609. }
  610. smtc.groupAPIOutput = &gitlab.GroupVariable{
  611. Key: testKey,
  612. Value: groupvalue,
  613. EnvironmentScope: "*",
  614. }
  615. // Project variable should override group wildcard variable
  616. smtc.expectedData = map[string][]byte{testKey: []byte(projectvalue)}
  617. smtc.refFind.Name = makeFindName(findTestPrefix)
  618. }
  619. setGroupWildcardVariableOnlyInGetAllSecrets := func(smtc *secretManagerTestCase) {
  620. smtc.groupIDs = []string{groupid}
  621. smtc.projectAPIOutput = &gitlab.ProjectVariable{
  622. Key: testKey,
  623. Value: projectvalue,
  624. EnvironmentScope: environmentTest, // Different environment
  625. }
  626. smtc.groupAPIOutput = &gitlab.GroupVariable{
  627. Key: testKey,
  628. Value: groupvalue,
  629. EnvironmentScope: "*",
  630. }
  631. // Group wildcard variable should be used when project variable doesn't match environment
  632. smtc.apiInputEnv = environment
  633. smtc.expectedData = map[string][]byte{testKey: []byte(groupvalue)}
  634. smtc.refFind.Name = makeFindName(findTestPrefix)
  635. }
  636. setGroupWildcardVariableWithCollision := func(smtc *secretManagerTestCase) {
  637. smtc.groupIDs = []string{groupid}
  638. smtc.projectAPIOutput = &gitlab.ProjectVariable{
  639. Key: testKey,
  640. Value: projectvalue,
  641. EnvironmentScope: "*",
  642. }
  643. smtc.groupAPIOutput = &gitlab.GroupVariable{
  644. Key: testKey,
  645. Value: groupvalue,
  646. EnvironmentScope: "*",
  647. }
  648. // Project wildcard variable should override group wildcard variable
  649. smtc.expectedData = map[string][]byte{testKey: []byte(projectvalue)}
  650. smtc.refFind.Name = makeFindName(findTestPrefix)
  651. }
  652. cases := []*secretManagerTestCase{
  653. makeValidSecretManagerGetAllTestCaseCustom(setUnmatchedEnvironmentFindString),
  654. ///
  655. makeValidSecretManagerGetAllTestCaseCustom(setMissingFindRegex),
  656. makeValidSecretManagerGetAllTestCaseCustom(setUnsupportedFindPath),
  657. makeValidSecretManagerGetAllTestCaseCustom(setUnsupportedFindTag),
  658. makeValidSecretManagerGetAllTestCaseCustom(setMatchingSecretFindString),
  659. makeValidSecretManagerGetAllTestCaseCustom(setNoMatchingRegexpFindString),
  660. makeValidSecretManagerGetAllTestCaseCustom(setUnmatchedEnvironmentFindString),
  661. makeValidSecretManagerGetAllTestCaseCustom(setMatchingSecretFindTags),
  662. makeValidSecretManagerGetAllTestCaseCustom(setWildcardDoesntOverwriteEnvironmentValue),
  663. makeValidSecretManagerGetAllTestCaseCustom(setEnvironmentConstrainedByStore),
  664. makeValidSecretManagerGetAllTestCaseCustom(setFilterByEnvironmentWithWildcard),
  665. makeValidSecretManagerGetAllTestCaseCustom(setPaginationInGroupAndProjectVars),
  666. makeValidSecretManagerGetAllTestCaseCustom(setGroupWildcardVariableInGetAllSecrets),
  667. makeValidSecretManagerGetAllTestCaseCustom(setGroupWildcardVariableOnlyInGetAllSecrets),
  668. makeValidSecretManagerGetAllTestCaseCustom(setGroupWildcardVariableWithCollision),
  669. makeValidSecretManagerGetAllTestCaseCustom(setAPIErr),
  670. makeValidSecretManagerGetAllTestCaseCustom(setNilMockClient),
  671. }
  672. sm := gitlabBase{}
  673. sm.store = &esv1.GitlabProvider{}
  674. for k, v := range cases {
  675. sm.projectVariablesClient = v.mockProjectVarClient
  676. sm.groupVariablesClient = v.mockGroupVarClient
  677. sm.store.Environment = v.apiInputEnv
  678. sm.store.GroupIDs = v.groupIDs
  679. if v.expectedSecret != "" {
  680. v.expectedData = map[string][]byte{testKey: []byte(v.expectedSecret)}
  681. }
  682. out, err := sm.GetAllSecrets(context.Background(), *v.refFind)
  683. if !ErrorContains(err, v.expectError) {
  684. t.Errorf(defaultErrorMessage, k, err.Error(), v.expectError)
  685. }
  686. if err == nil && !reflect.DeepEqual(out, v.expectedData) {
  687. t.Errorf("[%d] unexpected secret data: [%#v], expected [%#v]", k, out, v.expectedData)
  688. }
  689. }
  690. }
  691. func TestGetAllSecretsWithGroups(t *testing.T) {
  692. onlyProjectSecret := func(smtc *secretManagerTestCase) {
  693. smtc.projectAPIOutput.Value = projectvalue
  694. smtc.refFind.Name = makeFindName(findTestPrefix)
  695. smtc.groupAPIResponse = nil
  696. smtc.groupAPIOutput = nil
  697. smtc.expectedSecret = smtc.projectAPIOutput.Value
  698. }
  699. groupAndProjectSecrets := func(smtc *secretManagerTestCase) {
  700. smtc.groupIDs = []string{groupid}
  701. smtc.projectAPIOutput.Value = projectvalue
  702. smtc.groupAPIOutput.Value = groupvalue
  703. smtc.expectedData = map[string][]byte{testKey: []byte(projectvalue), "groupKey": []byte(groupvalue)}
  704. smtc.refFind.Name = makeFindName(".*Key")
  705. }
  706. groupAndOverrideProjectSecrets := func(smtc *secretManagerTestCase) {
  707. smtc.groupIDs = []string{groupid}
  708. smtc.projectAPIOutput.Value = projectvalue
  709. smtc.groupAPIOutput.Key = smtc.projectAPIOutput.Key
  710. smtc.groupAPIOutput.Value = groupvalue
  711. smtc.expectedData = map[string][]byte{testKey: []byte(projectvalue)}
  712. smtc.refFind.Name = makeFindName(".*Key")
  713. }
  714. groupAndProjectWithDifferentEnvSecrets := func(smtc *secretManagerTestCase) {
  715. smtc.groupIDs = []string{groupid}
  716. smtc.projectAPIOutput.Value = projectvalue
  717. smtc.projectAPIOutput.EnvironmentScope = environmentTest
  718. smtc.groupAPIOutput.Key = smtc.projectAPIOutput.Key
  719. smtc.groupAPIOutput.Value = groupvalue
  720. smtc.expectedData = map[string][]byte{testKey: []byte(groupvalue)}
  721. smtc.refFind.Name = makeFindName(".*Key")
  722. }
  723. cases := []*secretManagerTestCase{
  724. makeValidSecretManagerGetAllTestCaseCustom(onlyProjectSecret),
  725. makeValidSecretManagerGetAllTestCaseCustom(groupAndProjectSecrets),
  726. makeValidSecretManagerGetAllTestCaseCustom(groupAndOverrideProjectSecrets),
  727. makeValidSecretManagerGetAllTestCaseCustom(groupAndProjectWithDifferentEnvSecrets),
  728. }
  729. sm := gitlabBase{}
  730. sm.store = &esv1.GitlabProvider{}
  731. sm.store.Environment = environment
  732. for k, v := range cases {
  733. sm.projectVariablesClient = v.mockProjectVarClient
  734. sm.groupVariablesClient = v.mockGroupVarClient
  735. sm.store.ProjectID = v.projectID
  736. sm.store.GroupIDs = v.groupIDs
  737. out, err := sm.GetAllSecrets(context.Background(), *v.refFind)
  738. if !ErrorContains(err, v.expectError) {
  739. t.Errorf(defaultErrorMessage, k, err.Error(), v.expectError)
  740. }
  741. if v.expectError == "" {
  742. if len(v.expectedData) > 0 {
  743. if !reflect.DeepEqual(v.expectedData, out) {
  744. t.Errorf("[%d] unexpected secrets: [%s], expected [%s]", k, out, v.expectedData)
  745. }
  746. } else if string(out[v.projectAPIOutput.Key]) != v.expectedSecret {
  747. t.Errorf("[%d] unexpected secret: [%s], expected [%s]", k, string(out[v.projectAPIOutput.Key]), v.expectedSecret)
  748. }
  749. }
  750. }
  751. }
  752. func TestValidate(t *testing.T) {
  753. successCases := []*secretManagerTestCase{
  754. makeValidSecretManagerTestCaseCustom(),
  755. makeValidSecretManagerTestCaseCustom(setProjectAndInheritFromGroups),
  756. makeValidSecretManagerTestCaseCustom(setProjectAndGroup),
  757. makeValidSecretManagerTestCaseCustom(setListAPIErr),
  758. makeValidSecretManagerTestCaseCustom(setProjectListAPIRespNil),
  759. makeValidSecretManagerTestCaseCustom(setProjectListAPIRespBadCode),
  760. makeValidSecretManagerTestCaseCustom(setGroupListAPIRespNil),
  761. makeValidSecretManagerTestCaseCustom(setGroupListAPIRespBadCode),
  762. }
  763. sm := gitlabBase{}
  764. sm.store = &esv1.GitlabProvider{}
  765. for k, v := range successCases {
  766. sm.projectsClient = v.mockProjectsClient
  767. sm.projectVariablesClient = v.mockProjectVarClient
  768. sm.groupVariablesClient = v.mockGroupVarClient
  769. sm.store.ProjectID = v.projectID
  770. sm.store.GroupIDs = v.groupIDs
  771. sm.store.InheritFromGroups = v.inheritFromGroups
  772. t.Logf("%+v", v)
  773. validationResult, err := sm.Validate()
  774. if !ErrorContains(err, v.expectError) {
  775. t.Errorf(defaultErrorMessage, k, err.Error(), v.expectError)
  776. }
  777. if validationResult != v.expectedValidationResult {
  778. t.Errorf("[%d], unexpected validationResult: [%s], expected: [%s]", k, validationResult, v.expectedValidationResult)
  779. }
  780. if sm.store.InheritFromGroups && sm.store.GroupIDs[0] != "1" {
  781. t.Errorf("[%d], unexpected groupID: [%s], expected [1]", k, sm.store.GroupIDs[0])
  782. }
  783. }
  784. }
  785. func TestGetSecretMap(t *testing.T) {
  786. // good case: default version & deserialization
  787. setDeserialization := func(smtc *secretManagerTestCase) {
  788. smtc.projectAPIOutput.Value = `{"foo":"bar"}`
  789. smtc.expectedData["foo"] = []byte("bar")
  790. }
  791. // bad case: invalid json
  792. setInvalidJSON := func(smtc *secretManagerTestCase) {
  793. smtc.projectAPIOutput.Value = `-----------------`
  794. smtc.expectError = "unable to unmarshal secret"
  795. }
  796. successCases := []*secretManagerTestCase{
  797. makeValidSecretManagerTestCaseCustom(setDeserialization),
  798. makeValidSecretManagerTestCaseCustom(setInvalidJSON),
  799. makeValidSecretManagerTestCaseCustom(setNilMockClient),
  800. makeValidSecretManagerTestCaseCustom(setAPIErr),
  801. }
  802. sm := gitlabBase{}
  803. sm.store = &esv1.GitlabProvider{}
  804. for k, v := range successCases {
  805. sm.projectVariablesClient = v.mockProjectVarClient
  806. sm.groupVariablesClient = v.mockGroupVarClient
  807. out, err := sm.GetSecretMap(context.Background(), *v.ref)
  808. if !ErrorContains(err, v.expectError) {
  809. t.Errorf(defaultErrorMessage, k, err.Error(), v.expectError)
  810. }
  811. if err == nil && !reflect.DeepEqual(out, v.expectedData) {
  812. t.Errorf("[%d] unexpected secret data: [%#v], expected [%#v]", k, out, v.expectedData)
  813. }
  814. }
  815. }
  816. func makeSecretStore(projectID, environment string, fn ...storeModifier) *esv1.SecretStore {
  817. store := &esv1.SecretStore{
  818. Spec: esv1.SecretStoreSpec{
  819. Provider: &esv1.SecretStoreProvider{
  820. Gitlab: &esv1.GitlabProvider{
  821. Auth: esv1.GitlabAuth{},
  822. ProjectID: projectID,
  823. Environment: environment,
  824. },
  825. },
  826. },
  827. }
  828. for _, f := range fn {
  829. store = f(store)
  830. }
  831. return store
  832. }
  833. func withAccessToken(name, key string, namespace *string) storeModifier {
  834. return func(store *esv1.SecretStore) *esv1.SecretStore {
  835. store.Spec.Provider.Gitlab.Auth.SecretRef.AccessToken = esv1meta.SecretKeySelector{
  836. Name: name,
  837. Key: key,
  838. Namespace: namespace,
  839. }
  840. return store
  841. }
  842. }
  843. func withGroups(ids []string, inherit bool) storeModifier {
  844. return func(store *esv1.SecretStore) *esv1.SecretStore {
  845. store.Spec.Provider.Gitlab.GroupIDs = ids
  846. store.Spec.Provider.Gitlab.InheritFromGroups = inherit
  847. return store
  848. }
  849. }
  850. type ValidateStoreTestCase struct {
  851. store *esv1.SecretStore
  852. err error
  853. }
  854. func TestValidateStore(t *testing.T) {
  855. namespace := "my-namespace"
  856. testCases := []ValidateStoreTestCase{
  857. {
  858. store: makeSecretStore("", environment),
  859. err: errors.New("projectID and groupIDs must not both be empty"),
  860. },
  861. {
  862. store: makeSecretStore(project, environment, withGroups([]string{"group1"}, true)),
  863. err: errors.New("defining groupIDs and inheritFromGroups = true is not allowed"),
  864. },
  865. {
  866. store: makeSecretStore(project, environment, withAccessToken("", userkey, nil)),
  867. err: errors.New("accessToken.name cannot be empty"),
  868. },
  869. {
  870. store: makeSecretStore(project, environment, withAccessToken(username, "", nil)),
  871. err: errors.New("accessToken.key cannot be empty"),
  872. },
  873. {
  874. store: makeSecretStore(project, environment, withAccessToken("userName", "userKey", &namespace)),
  875. err: errors.New("namespace should either be empty or match the namespace of the SecretStore for a namespaced SecretStore"),
  876. },
  877. {
  878. store: makeSecretStore(project, environment, withAccessToken("userName", "userKey", nil)),
  879. err: nil,
  880. },
  881. {
  882. store: makeSecretStore("", environment, withGroups([]string{"group1"}, false), withAccessToken("userName", "userKey", nil)),
  883. err: nil,
  884. },
  885. }
  886. p := Provider{}
  887. for _, tc := range testCases {
  888. _, err := p.ValidateStore(tc.store)
  889. if tc.err != nil && err != nil && err.Error() != tc.err.Error() {
  890. t.Errorf("test failed! want %v, got %v", tc.err, err)
  891. } else if tc.err == nil && err != nil {
  892. t.Errorf("want nil got err %v", err)
  893. } else if tc.err != nil && err == nil {
  894. t.Errorf("want err %v got nil", tc.err)
  895. }
  896. }
  897. }
  898. func ErrorContains(out error, want string) bool {
  899. if out == nil {
  900. return want == ""
  901. }
  902. if want == "" {
  903. return false
  904. }
  905. return strings.Contains(out.Error(), want)
  906. }
  907. type storeModifier func(*esv1.SecretStore) *esv1.SecretStore
  908. func setGroupWildcardVariable(smtc *secretManagerTestCase) {
  909. // Given a group variable with a wildcard environment scope
  910. // and a provider with no environment,
  911. // the group variable should be returned
  912. smtc.groupIDs = []string{groupid}
  913. smtc.projectAPIOutput = nil
  914. smtc.projectAPIOutputs = make404ProjectAPIOutput(2)
  915. smtc.groupAPIOutput.Key = testKey
  916. smtc.groupAPIOutput.Value = groupvalue
  917. smtc.groupAPIOutput.EnvironmentScope = "*"
  918. smtc.expectedSecret = smtc.groupAPIOutput.Value
  919. }
  920. func setGroupWildcardVariableWithEnvironment(smtc *secretManagerTestCase) {
  921. // Given a group variable with a wildcard environment scope
  922. // and a provider with a specific environment,
  923. // the group variable should be returned
  924. // todo: verify that the flow for wildcard is observed. Have some doubts
  925. smtc.groupIDs = []string{groupid}
  926. smtc.projectAPIOutput = nil
  927. smtc.projectAPIOutputs = make404ProjectAPIOutput(2)
  928. smtc.groupAPIOutput.Key = testKey
  929. smtc.groupAPIOutput.Value = groupvalue
  930. smtc.groupAPIOutput.EnvironmentScope = "*"
  931. smtc.apiInputEnv = environment
  932. smtc.expectedSecret = smtc.groupAPIOutput.Value
  933. }
  934. func setGroupWildcardVariableNotFoundThenFound(smtc *secretManagerTestCase) {
  935. // Given a group variable with a wildcard environment scope
  936. // and a provider with a specific environment,
  937. // the group variable should be returned
  938. smtc.groupIDs = []string{groupid}
  939. smtc.projectAPIOutput = nil
  940. smtc.projectAPIOutputs = make404ProjectAPIOutput(2)
  941. smtc.groupAPIOutput = nil
  942. smtc.groupAPIOutputs = []*fakegitlab.APIResponse[[]*gitlab.GroupVariable]{
  943. {Response: make404GitlabAPIResponse(), Error: gitlab.ErrNotFound},
  944. {Output: []*gitlab.GroupVariable{
  945. {
  946. Key: testKey,
  947. Value: groupvalue,
  948. EnvironmentScope: "*",
  949. },
  950. }, Response: makeValidGroupAPIResponse(), Error: nil},
  951. }
  952. smtc.apiInputEnv = environment
  953. smtc.expectedSecret = groupvalue
  954. }