provider_test.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // /*
  2. // Licensed under the Apache License, Version 2.0 (the "License");
  3. // you may not use this file except in compliance with the License.
  4. // You may obtain a copy of the License at
  5. //
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. // */
  14. package gitlab
  15. import (
  16. "context"
  17. "encoding/pem"
  18. "net/http"
  19. "net/http/httptest"
  20. "testing"
  21. "github.com/stretchr/testify/assert"
  22. corev1 "k8s.io/api/core/v1"
  23. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  24. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  25. clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
  26. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  27. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  28. )
  29. func TestGetClientWithCABundle(t *testing.T) {
  30. // Create a mock TLS server that asserts a client certificate is present
  31. server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  32. // We expect a GET request to the variables API
  33. assert.Equal(t, "/api/v4/projects/1234/variables/test-secret", r.URL.Path)
  34. w.Header().Set("Content-Type", "application/json")
  35. w.WriteHeader(http.StatusOK)
  36. w.Write([]byte(`{}`))
  37. }))
  38. defer server.Close()
  39. // Define the GitLab provider with the CABundle
  40. provider := &esv1.GitlabProvider{
  41. URL: server.URL,
  42. ProjectID: "1234",
  43. CABundle: pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: server.Certificate().Raw}),
  44. Auth: esv1.GitlabAuth{
  45. SecretRef: esv1.GitlabSecretRef{
  46. AccessToken: esmeta.SecretKeySelector{
  47. Name: "gitlab-secret",
  48. Key: "token",
  49. },
  50. },
  51. },
  52. }
  53. // Create a fake Kubernetes client with the required secret
  54. secret := &corev1.Secret{
  55. ObjectMeta: metav1.ObjectMeta{
  56. Name: "gitlab-secret",
  57. Namespace: "default",
  58. },
  59. Data: map[string][]byte{
  60. "token": []byte("test-token"),
  61. },
  62. }
  63. fakeClient := clientfake.NewClientBuilder().WithObjects(secret).Build()
  64. // Create the gitlabBase struct
  65. gl := &gitlabBase{
  66. kube: fakeClient,
  67. store: provider,
  68. namespace: "default",
  69. }
  70. // We need to initialize the gitlab clients inside our gitlabBase struct
  71. client, err := gl.getClient(context.Background(), provider)
  72. assert.NoError(t, err)
  73. gl.projectsClient = client.Projects
  74. gl.projectVariablesClient = client.ProjectVariables
  75. gl.groupVariablesClient = client.GroupVariables
  76. // Call getVariables to trigger a network request to the mock server.
  77. // The request will only succeed if the custom CA is correctly configured.
  78. _, _, err = gl.getVariables(esv1.ExternalSecretDataRemoteRef{Key: "test-secret"}, nil)
  79. assert.NoError(t, err, "getVariables should succeed with the correct CA")
  80. }
  81. func TestGetClientWithInvalidCABundle(t *testing.T) {
  82. provider := &esv1.GitlabProvider{
  83. CABundle: []byte("invalid-ca-bundle"),
  84. Auth: esv1.GitlabAuth{
  85. SecretRef: esv1.GitlabSecretRef{
  86. AccessToken: esmeta.SecretKeySelector{
  87. Name: "gitlab-secret",
  88. Key: "token",
  89. },
  90. },
  91. },
  92. }
  93. secret := &corev1.Secret{
  94. ObjectMeta: metav1.ObjectMeta{
  95. Name: "gitlab-secret",
  96. Namespace: "default",
  97. },
  98. Data: map[string][]byte{
  99. "token": []byte("test-token"),
  100. },
  101. }
  102. fakeClient := clientfake.NewClientBuilder().WithObjects(secret).Build()
  103. gl := &gitlabBase{
  104. kube: fakeClient,
  105. store: provider,
  106. namespace: "default",
  107. }
  108. _, err := gl.getClient(context.Background(), provider)
  109. assert.Error(t, err)
  110. assert.Contains(t, err.Error(), "failed to read ca bundle")
  111. }
  112. func TestGetClientWithCAProviderSecret(t *testing.T) {
  113. // Create a mock TLS server
  114. server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  115. w.Header().Set("Content-Type", "application/json")
  116. w.WriteHeader(http.StatusOK)
  117. w.Write([]byte(`{}`))
  118. }))
  119. defer server.Close()
  120. certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: server.Certificate().Raw})
  121. caSecret := makeFakeCASource(t, "Secret", "ca-secret", "default", certPEM)
  122. // Define the GitLab provider with the CAProvider
  123. provider := &esv1.GitlabProvider{
  124. URL: server.URL,
  125. ProjectID: "1234",
  126. Auth: esv1.GitlabAuth{
  127. SecretRef: esv1.GitlabSecretRef{
  128. AccessToken: esmeta.SecretKeySelector{
  129. Name: "gitlab-secret",
  130. Key: "token",
  131. },
  132. },
  133. },
  134. CAProvider: &esv1.CAProvider{
  135. Type: esv1.CAProviderTypeSecret,
  136. Name: "ca-secret",
  137. Key: "tls.crt",
  138. },
  139. }
  140. // Create a fake Kubernetes client with the required secrets
  141. accessTokenSecret := &corev1.Secret{
  142. ObjectMeta: metav1.ObjectMeta{
  143. Name: "gitlab-secret",
  144. Namespace: "default",
  145. },
  146. Data: map[string][]byte{
  147. "token": []byte("test-token"),
  148. },
  149. }
  150. fakeClient := clientfake.NewClientBuilder().WithObjects(accessTokenSecret, caSecret).Build()
  151. // Create the gitlabBase struct
  152. gl := &gitlabBase{
  153. kube: fakeClient,
  154. store: provider,
  155. namespace: "default",
  156. }
  157. // We need to initialize the gitlab clients inside our gitlabBase struct
  158. client, err := gl.getClient(context.Background(), provider)
  159. assert.NoError(t, err)
  160. gl.projectsClient = client.Projects
  161. gl.projectVariablesClient = client.ProjectVariables
  162. gl.groupVariablesClient = client.GroupVariables
  163. // Call getVariables to trigger a network request to the mock server.
  164. _, _, err = gl.getVariables(esv1.ExternalSecretDataRemoteRef{Key: "test-secret"}, nil)
  165. assert.NoError(t, err, "getVariables should succeed with the correct CA from Secret")
  166. }
  167. func TestGetClientWithCAProviderConfigMap(t *testing.T) {
  168. // Create a mock TLS server
  169. server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  170. w.Header().Set("Content-Type", "application/json")
  171. w.WriteHeader(http.StatusOK)
  172. w.Write([]byte(`{}`))
  173. }))
  174. defer server.Close()
  175. certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: server.Certificate().Raw})
  176. caCM := makeFakeCASource(t, "ConfigMap", "ca-cm", "default", certPEM)
  177. // Define the GitLab provider with the CAProvider
  178. provider := &esv1.GitlabProvider{
  179. URL: server.URL,
  180. ProjectID: "1234",
  181. Auth: esv1.GitlabAuth{
  182. SecretRef: esv1.GitlabSecretRef{
  183. AccessToken: esmeta.SecretKeySelector{
  184. Name: "gitlab-secret",
  185. Key: "token",
  186. },
  187. },
  188. },
  189. CAProvider: &esv1.CAProvider{
  190. Type: esv1.CAProviderTypeConfigMap,
  191. Name: "ca-cm",
  192. Key: "ca.crt",
  193. },
  194. }
  195. // Create a fake Kubernetes client with the required secrets
  196. accessTokenSecret := &corev1.Secret{
  197. ObjectMeta: metav1.ObjectMeta{
  198. Name: "gitlab-secret",
  199. Namespace: "default",
  200. },
  201. Data: map[string][]byte{
  202. "token": []byte("test-token"),
  203. },
  204. }
  205. fakeClient := clientfake.NewClientBuilder().WithObjects(accessTokenSecret, caCM).Build()
  206. // Create the gitlabBase struct
  207. gl := &gitlabBase{
  208. kube: fakeClient,
  209. store: provider,
  210. namespace: "default",
  211. }
  212. // We need to initialize the gitlab clients inside our gitlabBase struct
  213. client, err := gl.getClient(context.Background(), provider)
  214. assert.NoError(t, err)
  215. gl.projectsClient = client.Projects
  216. gl.projectVariablesClient = client.ProjectVariables
  217. gl.groupVariablesClient = client.GroupVariables
  218. // Call getVariables to trigger a network request to the mock server.
  219. _, _, err = gl.getVariables(esv1.ExternalSecretDataRemoteRef{Key: "test-secret"}, nil)
  220. assert.NoError(t, err, "getVariables should succeed with the correct CA from ConfigMap")
  221. }
  222. func makeFakeCASource(t *testing.T, kind, name, namespace string, certData []byte) kclient.Object {
  223. t.Helper()
  224. switch kind {
  225. case "Secret":
  226. return &corev1.Secret{
  227. ObjectMeta: metav1.ObjectMeta{
  228. Name: name,
  229. Namespace: namespace,
  230. },
  231. Data: map[string][]byte{
  232. "tls.crt": certData,
  233. },
  234. }
  235. case "ConfigMap":
  236. return &corev1.ConfigMap{
  237. ObjectMeta: metav1.ObjectMeta{
  238. Name: name,
  239. Namespace: namespace,
  240. },
  241. Data: map[string]string{
  242. "ca.crt": string(certData),
  243. },
  244. }
  245. }
  246. return nil
  247. }