client_test.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. /*
  2. Copyright © The ESO Authors
  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 store
  14. import (
  15. "bytes"
  16. "context"
  17. "errors"
  18. "testing"
  19. corev1 "k8s.io/api/core/v1"
  20. apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
  21. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  22. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  23. pb "github.com/external-secrets/external-secrets/proto/provider"
  24. )
  25. const (
  26. testProperty = "property"
  27. testSecretValue = "secret-value"
  28. testSourceNamespace = "tenant-a"
  29. testBarValue = "bar"
  30. testValue = "value"
  31. )
  32. type fakeV2Provider struct {
  33. getSecretResponse []byte
  34. getSecretErr error
  35. getSecretRef esv1.ExternalSecretDataRemoteRef
  36. getSecretProviderRef *pb.ProviderReference
  37. getSecretCompatibilityStore *pb.CompatibilityStore
  38. getSecretNamespace string
  39. getSecretMapResponse map[string][]byte
  40. getSecretMapErr error
  41. getSecretMapRef esv1.ExternalSecretDataRemoteRef
  42. getSecretMapCompatibilityStore *pb.CompatibilityStore
  43. getAllSecretsResponse map[string][]byte
  44. getAllSecretsErr error
  45. getAllSecretsFind esv1.ExternalSecretFind
  46. getAllSecretsCompatibilityStore *pb.CompatibilityStore
  47. pushSecretErr error
  48. pushSecretData map[string][]byte
  49. pushSecretSecret *corev1.Secret
  50. pushSecretPayload *pb.PushSecretData
  51. pushSecretProviderRef *pb.ProviderReference
  52. pushSecretCompatibilityStore *pb.CompatibilityStore
  53. pushSecretNamespace string
  54. deleteSecretErr error
  55. deleteSecretRemoteRef *pb.PushSecretRemoteRef
  56. deleteSecretProviderRef *pb.ProviderReference
  57. deleteSecretCompatibilityStore *pb.CompatibilityStore
  58. deleteSecretNamespace string
  59. secretExistsResponse bool
  60. secretExistsErr error
  61. secretExistsRemoteRef *pb.PushSecretRemoteRef
  62. secretExistsProviderRef *pb.ProviderReference
  63. secretExistsCompatibilityStore *pb.CompatibilityStore
  64. secretExistsNamespace string
  65. validateErr error
  66. validateProviderRef *pb.ProviderReference
  67. validateCompatibilityStore *pb.CompatibilityStore
  68. validateNamespace string
  69. validateCalled bool
  70. closeErr error
  71. closeCalled bool
  72. }
  73. func (f *fakeV2Provider) GetSecret(
  74. _ context.Context,
  75. ref esv1.ExternalSecretDataRemoteRef,
  76. providerRef *pb.ProviderReference,
  77. compatibilityStore *pb.CompatibilityStore,
  78. sourceNamespace string,
  79. ) ([]byte, error) {
  80. f.getSecretRef = ref
  81. f.getSecretProviderRef = providerRef
  82. f.getSecretCompatibilityStore = compatibilityStore
  83. f.getSecretNamespace = sourceNamespace
  84. return f.getSecretResponse, f.getSecretErr
  85. }
  86. func (f *fakeV2Provider) GetSecretMap(
  87. _ context.Context,
  88. ref esv1.ExternalSecretDataRemoteRef,
  89. providerRef *pb.ProviderReference,
  90. compatibilityStore *pb.CompatibilityStore,
  91. sourceNamespace string,
  92. ) (map[string][]byte, error) {
  93. f.getSecretMapRef = ref
  94. f.getSecretProviderRef = providerRef
  95. f.getSecretMapCompatibilityStore = compatibilityStore
  96. f.getSecretNamespace = sourceNamespace
  97. return f.getSecretMapResponse, f.getSecretMapErr
  98. }
  99. func (f *fakeV2Provider) GetAllSecrets(
  100. _ context.Context,
  101. find esv1.ExternalSecretFind,
  102. providerRef *pb.ProviderReference,
  103. compatibilityStore *pb.CompatibilityStore,
  104. sourceNamespace string,
  105. ) (map[string][]byte, error) {
  106. f.getAllSecretsFind = find
  107. f.getSecretProviderRef = providerRef
  108. f.getAllSecretsCompatibilityStore = compatibilityStore
  109. f.getSecretNamespace = sourceNamespace
  110. return f.getAllSecretsResponse, f.getAllSecretsErr
  111. }
  112. func (f *fakeV2Provider) PushSecret(
  113. _ context.Context,
  114. secret *corev1.Secret,
  115. pushSecretData *pb.PushSecretData,
  116. providerRef *pb.ProviderReference,
  117. compatibilityStore *pb.CompatibilityStore,
  118. sourceNamespace string,
  119. ) error {
  120. f.pushSecretData = secret.Data
  121. f.pushSecretSecret = secret.DeepCopy()
  122. f.pushSecretPayload = pushSecretData
  123. f.pushSecretProviderRef = providerRef
  124. f.pushSecretCompatibilityStore = compatibilityStore
  125. f.pushSecretNamespace = sourceNamespace
  126. return f.pushSecretErr
  127. }
  128. func (f *fakeV2Provider) DeleteSecret(
  129. _ context.Context,
  130. remoteRef *pb.PushSecretRemoteRef,
  131. providerRef *pb.ProviderReference,
  132. compatibilityStore *pb.CompatibilityStore,
  133. sourceNamespace string,
  134. ) error {
  135. f.deleteSecretRemoteRef = remoteRef
  136. f.deleteSecretProviderRef = providerRef
  137. f.deleteSecretCompatibilityStore = compatibilityStore
  138. f.deleteSecretNamespace = sourceNamespace
  139. return f.deleteSecretErr
  140. }
  141. func (f *fakeV2Provider) SecretExists(
  142. _ context.Context,
  143. remoteRef *pb.PushSecretRemoteRef,
  144. providerRef *pb.ProviderReference,
  145. compatibilityStore *pb.CompatibilityStore,
  146. sourceNamespace string,
  147. ) (bool, error) {
  148. f.secretExistsRemoteRef = remoteRef
  149. f.secretExistsProviderRef = providerRef
  150. f.secretExistsCompatibilityStore = compatibilityStore
  151. f.secretExistsNamespace = sourceNamespace
  152. return f.secretExistsResponse, f.secretExistsErr
  153. }
  154. func (f *fakeV2Provider) Validate(_ context.Context, providerRef *pb.ProviderReference, compatibilityStore *pb.CompatibilityStore, sourceNamespace string) error {
  155. f.validateCalled = true
  156. f.validateProviderRef = providerRef
  157. f.validateCompatibilityStore = compatibilityStore
  158. f.validateNamespace = sourceNamespace
  159. return f.validateErr
  160. }
  161. func (f *fakeV2Provider) Capabilities(context.Context, *pb.ProviderReference, string) (pb.SecretStoreCapabilities, error) {
  162. return pb.SecretStoreCapabilities_READ_WRITE, nil
  163. }
  164. func (f *fakeV2Provider) Close(context.Context) error {
  165. f.closeCalled = true
  166. return f.closeErr
  167. }
  168. type fakePushSecretData struct {
  169. property string
  170. secretKey string
  171. remoteKey string
  172. metadata *apiextensionsv1.JSON
  173. }
  174. func (f fakePushSecretData) GetProperty() string {
  175. return f.property
  176. }
  177. func (f fakePushSecretData) GetSecretKey() string {
  178. return f.secretKey
  179. }
  180. func (f fakePushSecretData) GetRemoteKey() string {
  181. return f.remoteKey
  182. }
  183. func (f fakePushSecretData) GetMetadata() *apiextensionsv1.JSON {
  184. return f.metadata
  185. }
  186. type fakePushSecretRemoteRef struct {
  187. remoteKey string
  188. property string
  189. }
  190. func (f fakePushSecretRemoteRef) GetRemoteKey() string {
  191. return f.remoteKey
  192. }
  193. func (f fakePushSecretRemoteRef) GetProperty() string {
  194. return f.property
  195. }
  196. func TestClientGetSecretDelegatesProviderReferenceAndNamespace(t *testing.T) {
  197. providerRef := &pb.ProviderReference{Name: "provider", Namespace: "config-ns"}
  198. provider := &fakeV2Provider{getSecretResponse: []byte(testSecretValue)}
  199. client := NewClient(provider, providerRef, testSourceNamespace)
  200. ref := esv1.ExternalSecretDataRemoteRef{Key: "sample", Version: "v1", Property: "password"}
  201. value, err := client.GetSecret(context.Background(), ref)
  202. if err != nil {
  203. t.Fatalf("GetSecret() error = %v", err)
  204. }
  205. if string(value) != testSecretValue {
  206. t.Fatalf("expected %s, got %q", testSecretValue, string(value))
  207. }
  208. if provider.getSecretRef != ref {
  209. t.Fatalf("unexpected ref: %#v", provider.getSecretRef)
  210. }
  211. if provider.getSecretProviderRef != providerRef {
  212. t.Fatalf("unexpected provider ref: %#v", provider.getSecretProviderRef)
  213. }
  214. if provider.getSecretNamespace != testSourceNamespace {
  215. t.Fatalf("unexpected source namespace: %q", provider.getSecretNamespace)
  216. }
  217. }
  218. func TestClientGetSecretMapDelegatesProviderReferenceAndNamespace(t *testing.T) {
  219. providerRef := &pb.ProviderReference{Name: "provider", Namespace: "config-ns"}
  220. expected := map[string][]byte{
  221. "foo": []byte(testBarValue),
  222. "baz": []byte("qux"),
  223. }
  224. provider := &fakeV2Provider{getSecretMapResponse: expected}
  225. client := NewClient(provider, providerRef, testSourceNamespace)
  226. ref := esv1.ExternalSecretDataRemoteRef{Key: "sample"}
  227. secretMap, err := client.GetSecretMap(context.Background(), ref)
  228. if err != nil {
  229. t.Fatalf("GetSecretMap() error = %v", err)
  230. }
  231. if string(secretMap["foo"]) != testBarValue || string(secretMap["baz"]) != "qux" {
  232. t.Fatalf("unexpected secret map: %#v", secretMap)
  233. }
  234. if provider.getSecretMapRef != ref {
  235. t.Fatalf("unexpected ref: %#v", provider.getSecretMapRef)
  236. }
  237. if provider.getSecretProviderRef != providerRef {
  238. t.Fatalf("unexpected provider ref: %#v", provider.getSecretProviderRef)
  239. }
  240. if provider.getSecretNamespace != testSourceNamespace {
  241. t.Fatalf("unexpected source namespace: %q", provider.getSecretNamespace)
  242. }
  243. }
  244. func TestClientGetAllSecretsDelegatesFindCriteria(t *testing.T) {
  245. providerRef := &pb.ProviderReference{Name: "provider", Namespace: "config-ns"}
  246. path := "/team-a"
  247. expected := map[string][]byte{"db-password": []byte(testValue)}
  248. provider := &fakeV2Provider{getAllSecretsResponse: expected}
  249. client := NewClient(provider, providerRef, testSourceNamespace)
  250. find := esv1.ExternalSecretFind{
  251. Tags: map[string]string{
  252. "team": "a",
  253. },
  254. Path: &path,
  255. Name: &esv1.FindName{RegExp: "db-.*"},
  256. }
  257. secrets, err := client.GetAllSecrets(context.Background(), find)
  258. if err != nil {
  259. t.Fatalf("GetAllSecrets() error = %v", err)
  260. }
  261. if string(secrets["db-password"]) != testValue {
  262. t.Fatalf("unexpected secret value: %#v", secrets)
  263. }
  264. if provider.getAllSecretsFind.Tags["team"] != "a" {
  265. t.Fatalf("unexpected find tags: %#v", provider.getAllSecretsFind)
  266. }
  267. if provider.getAllSecretsFind.Path == nil || *provider.getAllSecretsFind.Path != path {
  268. t.Fatalf("unexpected find path: %#v", provider.getAllSecretsFind.Path)
  269. }
  270. if provider.getAllSecretsFind.Name == nil || provider.getAllSecretsFind.Name.RegExp != "db-.*" {
  271. t.Fatalf("unexpected find name: %#v", provider.getAllSecretsFind.Name)
  272. }
  273. if provider.getSecretProviderRef != providerRef {
  274. t.Fatalf("unexpected provider ref: %#v", provider.getSecretProviderRef)
  275. }
  276. if provider.getSecretNamespace != testSourceNamespace {
  277. t.Fatalf("unexpected source namespace: %q", provider.getSecretNamespace)
  278. }
  279. }
  280. func TestCompatibilityClientGetSecretDelegatesCompatibilityStore(t *testing.T) {
  281. compatibilityStore := &pb.CompatibilityStore{
  282. StoreName: "compat-store",
  283. StoreNamespace: "config-ns",
  284. StoreKind: esv1.SecretStoreKind,
  285. StoreUid: "uid-1",
  286. StoreGeneration: 7,
  287. StoreSpecJson: []byte(`{"provider":{"fake":{"data":[{"key":"sample","value":"secret-value"}]}}}`),
  288. }
  289. provider := &fakeV2Provider{getSecretResponse: []byte(testSecretValue)}
  290. client := NewCompatibilityClient(provider, compatibilityStore, testSourceNamespace)
  291. value, err := client.GetSecret(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: "sample"})
  292. if err != nil {
  293. t.Fatalf("GetSecret() error = %v", err)
  294. }
  295. if string(value) != testSecretValue {
  296. t.Fatalf("expected %s, got %q", testSecretValue, string(value))
  297. }
  298. if provider.getSecretProviderRef != nil {
  299. t.Fatalf("expected provider ref to be nil, got %#v", provider.getSecretProviderRef)
  300. }
  301. if provider.getSecretCompatibilityStore != compatibilityStore {
  302. t.Fatalf("unexpected compatibility store: %#v", provider.getSecretCompatibilityStore)
  303. }
  304. }
  305. func TestCompatibilityClientGetSecretMapDelegatesCompatibilityStore(t *testing.T) {
  306. compatibilityStore := &pb.CompatibilityStore{
  307. StoreName: "compat-store",
  308. StoreNamespace: "config-ns",
  309. StoreKind: esv1.SecretStoreKind,
  310. StoreUid: "uid-1",
  311. StoreGeneration: 7,
  312. StoreSpecJson: []byte(`{"provider":{"fake":{"data":[{"key":"sample","value":"secret-value"}]}}}`),
  313. }
  314. provider := &fakeV2Provider{getSecretMapResponse: map[string][]byte{"foo": []byte(testBarValue)}}
  315. client := NewCompatibilityClient(provider, compatibilityStore, testSourceNamespace)
  316. secretMap, err := client.GetSecretMap(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: "sample"})
  317. if err != nil {
  318. t.Fatalf("GetSecretMap() error = %v", err)
  319. }
  320. if string(secretMap["foo"]) != testBarValue {
  321. t.Fatalf("unexpected secret map: %#v", secretMap)
  322. }
  323. if provider.getSecretProviderRef != nil {
  324. t.Fatalf("expected provider ref to be nil, got %#v", provider.getSecretProviderRef)
  325. }
  326. if provider.getSecretMapCompatibilityStore != compatibilityStore {
  327. t.Fatalf("unexpected compatibility store: %#v", provider.getSecretMapCompatibilityStore)
  328. }
  329. }
  330. func TestCompatibilityClientGetAllSecretsDelegatesCompatibilityStore(t *testing.T) {
  331. compatibilityStore := &pb.CompatibilityStore{
  332. StoreName: "compat-store",
  333. StoreNamespace: "config-ns",
  334. StoreKind: esv1.SecretStoreKind,
  335. StoreUid: "uid-1",
  336. StoreGeneration: 7,
  337. StoreSpecJson: []byte(`{"provider":{"fake":{"data":[{"key":"sample","value":"secret-value"}]}}}`),
  338. }
  339. provider := &fakeV2Provider{getAllSecretsResponse: map[string][]byte{"db-password": []byte(testValue)}}
  340. client := NewCompatibilityClient(provider, compatibilityStore, testSourceNamespace)
  341. secrets, err := client.GetAllSecrets(context.Background(), esv1.ExternalSecretFind{})
  342. if err != nil {
  343. t.Fatalf("GetAllSecrets() error = %v", err)
  344. }
  345. if string(secrets["db-password"]) != testValue {
  346. t.Fatalf("unexpected secret value: %#v", secrets)
  347. }
  348. if provider.getSecretProviderRef != nil {
  349. t.Fatalf("expected provider ref to be nil, got %#v", provider.getSecretProviderRef)
  350. }
  351. if provider.getAllSecretsCompatibilityStore != compatibilityStore {
  352. t.Fatalf("unexpected compatibility store: %#v", provider.getAllSecretsCompatibilityStore)
  353. }
  354. }
  355. func TestCompatibilityClientPushSecretDelegatesCompatibilityStore(t *testing.T) {
  356. compatibilityStore := &pb.CompatibilityStore{
  357. StoreName: "compat-store",
  358. StoreNamespace: "config-ns",
  359. StoreKind: esv1.SecretStoreKind,
  360. StoreUid: "uid-1",
  361. StoreGeneration: 7,
  362. StoreSpecJson: []byte(`{"provider":{"fake":{"data":[{"key":"sample","value":"secret-value"}]}}}`),
  363. }
  364. provider := &fakeV2Provider{}
  365. client := NewCompatibilityClient(provider, compatibilityStore, testSourceNamespace)
  366. err := client.PushSecret(context.Background(), &corev1.Secret{
  367. Data: map[string][]byte{"token": []byte(testValue)},
  368. }, fakePushSecretData{remoteKey: serverTestRemoteKey, secretKey: "token"})
  369. if err != nil {
  370. t.Fatalf("PushSecret() error = %v", err)
  371. }
  372. if provider.pushSecretProviderRef != nil {
  373. t.Fatalf("expected provider ref to be nil, got %#v", provider.pushSecretProviderRef)
  374. }
  375. if provider.pushSecretCompatibilityStore != compatibilityStore {
  376. t.Fatalf("unexpected compatibility store: %#v", provider.pushSecretCompatibilityStore)
  377. }
  378. }
  379. func TestCompatibilityClientDeleteSecretDelegatesCompatibilityStore(t *testing.T) {
  380. compatibilityStore := &pb.CompatibilityStore{
  381. StoreName: "compat-store",
  382. StoreNamespace: "config-ns",
  383. StoreKind: esv1.SecretStoreKind,
  384. StoreUid: "uid-1",
  385. StoreGeneration: 7,
  386. StoreSpecJson: []byte(`{"provider":{"fake":{"data":[{"key":"sample","value":"secret-value"}]}}}`),
  387. }
  388. provider := &fakeV2Provider{}
  389. client := NewCompatibilityClient(provider, compatibilityStore, testSourceNamespace)
  390. err := client.DeleteSecret(context.Background(), fakePushSecretRemoteRef{
  391. remoteKey: serverTestRemoteKey,
  392. property: testProperty,
  393. })
  394. if err != nil {
  395. t.Fatalf("DeleteSecret() error = %v", err)
  396. }
  397. if provider.deleteSecretProviderRef != nil {
  398. t.Fatalf("expected provider ref to be nil, got %#v", provider.deleteSecretProviderRef)
  399. }
  400. if provider.deleteSecretCompatibilityStore != compatibilityStore {
  401. t.Fatalf("unexpected compatibility store: %#v", provider.deleteSecretCompatibilityStore)
  402. }
  403. }
  404. func TestCompatibilityClientSecretExistsDelegatesCompatibilityStore(t *testing.T) {
  405. compatibilityStore := &pb.CompatibilityStore{
  406. StoreName: "compat-store",
  407. StoreNamespace: "config-ns",
  408. StoreKind: esv1.SecretStoreKind,
  409. StoreUid: "uid-1",
  410. StoreGeneration: 7,
  411. StoreSpecJson: []byte(`{"provider":{"fake":{"data":[{"key":"sample","value":"secret-value"}]}}}`),
  412. }
  413. provider := &fakeV2Provider{secretExistsResponse: true}
  414. client := NewCompatibilityClient(provider, compatibilityStore, testSourceNamespace)
  415. exists, err := client.SecretExists(context.Background(), fakePushSecretRemoteRef{
  416. remoteKey: serverTestRemoteKey,
  417. property: testProperty,
  418. })
  419. if err != nil {
  420. t.Fatalf("SecretExists() error = %v", err)
  421. }
  422. if !exists {
  423. t.Fatal("expected secret to exist")
  424. }
  425. if provider.secretExistsProviderRef != nil {
  426. t.Fatalf("expected provider ref to be nil, got %#v", provider.secretExistsProviderRef)
  427. }
  428. if provider.secretExistsCompatibilityStore != compatibilityStore {
  429. t.Fatalf("unexpected compatibility store: %#v", provider.secretExistsCompatibilityStore)
  430. }
  431. }
  432. func TestClientPushSecretConvertsPayloadAndMetadata(t *testing.T) {
  433. providerRef := &pb.ProviderReference{Name: "provider", Namespace: "config-ns"}
  434. provider := &fakeV2Provider{}
  435. client := NewClient(provider, providerRef, testSourceNamespace)
  436. metadata := []byte(`{"owner":"eso"}`)
  437. secret := &corev1.Secret{
  438. Data: map[string][]byte{
  439. "token": []byte(testValue),
  440. },
  441. }
  442. pushData := fakePushSecretData{
  443. property: testProperty,
  444. secretKey: "token",
  445. remoteKey: serverTestRemoteKey,
  446. metadata: &apiextensionsv1.JSON{Raw: metadata},
  447. }
  448. err := client.PushSecret(context.Background(), secret, pushData)
  449. if err != nil {
  450. t.Fatalf("PushSecret() error = %v", err)
  451. }
  452. if string(provider.pushSecretData["token"]) != testValue {
  453. t.Fatalf("unexpected secret data: %#v", provider.pushSecretData)
  454. }
  455. if provider.pushSecretPayload == nil {
  456. t.Fatal("expected push payload to be recorded")
  457. }
  458. if provider.pushSecretPayload.RemoteKey != serverTestRemoteKey || provider.pushSecretPayload.SecretKey != "token" || provider.pushSecretPayload.Property != testProperty {
  459. t.Fatalf("unexpected push payload: %#v", provider.pushSecretPayload)
  460. }
  461. if !bytes.Equal(provider.pushSecretPayload.Metadata, metadata) {
  462. t.Fatalf("unexpected metadata: %q", string(provider.pushSecretPayload.Metadata))
  463. }
  464. if provider.pushSecretProviderRef != providerRef {
  465. t.Fatalf("unexpected provider ref: %#v", provider.pushSecretProviderRef)
  466. }
  467. if provider.pushSecretNamespace != testSourceNamespace {
  468. t.Fatalf("unexpected source namespace: %q", provider.pushSecretNamespace)
  469. }
  470. }
  471. func TestClientPushSecretForwardsKubernetesSecretShape(t *testing.T) {
  472. providerRef := &pb.ProviderReference{Name: "provider", Namespace: "config-ns"}
  473. provider := &fakeV2Provider{}
  474. client := NewClient(provider, providerRef, testSourceNamespace)
  475. metadata := []byte(`{"mergePolicy":"replace"}`)
  476. secret := &corev1.Secret{
  477. Type: corev1.SecretTypeDockerConfigJson,
  478. ObjectMeta: metav1.ObjectMeta{
  479. Labels: map[string]string{"team": "platform"},
  480. Annotations: map[string]string{"owner": "app-team"},
  481. },
  482. Data: map[string][]byte{
  483. ".dockerconfigjson": []byte("payload"),
  484. },
  485. }
  486. pushData := fakePushSecretData{
  487. property: testProperty,
  488. secretKey: ".dockerconfigjson",
  489. remoteKey: serverTestRemoteKey,
  490. metadata: &apiextensionsv1.JSON{Raw: metadata},
  491. }
  492. err := client.PushSecret(context.Background(), secret, pushData)
  493. if err != nil {
  494. t.Fatalf("PushSecret() error = %v", err)
  495. }
  496. if provider.pushSecretSecret == nil {
  497. t.Fatal("expected pushed secret to be recorded")
  498. }
  499. if provider.pushSecretSecret.Type != corev1.SecretTypeDockerConfigJson {
  500. t.Errorf("expected secret type %q, got %q", corev1.SecretTypeDockerConfigJson, provider.pushSecretSecret.Type)
  501. }
  502. if got, want := provider.pushSecretSecret.Labels["team"], "platform"; got != want {
  503. t.Errorf("expected secret label team=%q, got %q", want, got)
  504. }
  505. if got, want := provider.pushSecretSecret.Annotations["owner"], "app-team"; got != want {
  506. t.Errorf("expected secret annotation owner=%q, got %q", want, got)
  507. }
  508. if got, want := string(provider.pushSecretSecret.Data[".dockerconfigjson"]), "payload"; got != want {
  509. t.Errorf("expected secret payload %q, got %q", want, got)
  510. }
  511. if provider.pushSecretPayload == nil {
  512. t.Fatal("expected push payload to be recorded")
  513. }
  514. if !bytes.Equal(provider.pushSecretPayload.Metadata, metadata) {
  515. t.Fatalf("unexpected metadata: %q", string(provider.pushSecretPayload.Metadata))
  516. }
  517. }
  518. func TestClientDeleteSecretConvertsRemoteRef(t *testing.T) {
  519. providerRef := &pb.ProviderReference{Name: "provider", Namespace: "config-ns"}
  520. provider := &fakeV2Provider{}
  521. client := NewClient(provider, providerRef, testSourceNamespace)
  522. err := client.DeleteSecret(context.Background(), fakePushSecretRemoteRef{
  523. remoteKey: serverTestRemoteKey,
  524. property: testProperty,
  525. })
  526. if err != nil {
  527. t.Fatalf("DeleteSecret() error = %v", err)
  528. }
  529. if provider.deleteSecretRemoteRef == nil {
  530. t.Fatal("expected delete remote ref to be recorded")
  531. }
  532. if provider.deleteSecretRemoteRef.RemoteKey != serverTestRemoteKey || provider.deleteSecretRemoteRef.Property != testProperty {
  533. t.Fatalf("unexpected remote ref: %#v", provider.deleteSecretRemoteRef)
  534. }
  535. if provider.deleteSecretProviderRef != providerRef {
  536. t.Fatalf("unexpected provider ref: %#v", provider.deleteSecretProviderRef)
  537. }
  538. if provider.deleteSecretNamespace != testSourceNamespace {
  539. t.Fatalf("unexpected source namespace: %q", provider.deleteSecretNamespace)
  540. }
  541. }
  542. func TestClientSecretExistsConvertsRemoteRef(t *testing.T) {
  543. providerRef := &pb.ProviderReference{Name: "provider", Namespace: "config-ns"}
  544. provider := &fakeV2Provider{secretExistsResponse: true}
  545. client := NewClient(provider, providerRef, testSourceNamespace)
  546. exists, err := client.SecretExists(context.Background(), fakePushSecretRemoteRef{
  547. remoteKey: serverTestRemoteKey,
  548. property: testProperty,
  549. })
  550. if err != nil {
  551. t.Fatalf("SecretExists() error = %v", err)
  552. }
  553. if !exists {
  554. t.Fatal("expected secret to exist")
  555. }
  556. if provider.secretExistsRemoteRef == nil {
  557. t.Fatal("expected exists remote ref to be recorded")
  558. }
  559. if provider.secretExistsRemoteRef.RemoteKey != serverTestRemoteKey || provider.secretExistsRemoteRef.Property != testProperty {
  560. t.Fatalf("unexpected remote ref: %#v", provider.secretExistsRemoteRef)
  561. }
  562. if provider.secretExistsProviderRef != providerRef {
  563. t.Fatalf("unexpected provider ref: %#v", provider.secretExistsProviderRef)
  564. }
  565. if provider.secretExistsNamespace != testSourceNamespace {
  566. t.Fatalf("unexpected source namespace: %q", provider.secretExistsNamespace)
  567. }
  568. }
  569. func TestClientValidateMapsProviderErrors(t *testing.T) {
  570. t.Run("success", func(t *testing.T) {
  571. providerRef := &pb.ProviderReference{
  572. Name: "provider",
  573. Namespace: "config-ns",
  574. StoreRefKind: esv1.ProviderStoreKindStr,
  575. }
  576. provider := &fakeV2Provider{}
  577. client := NewClient(provider, providerRef, testSourceNamespace)
  578. result, err := client.Validate()
  579. if err != nil {
  580. t.Fatalf("Validate() error = %v", err)
  581. }
  582. if result != esv1.ValidationResultReady {
  583. t.Fatalf("expected ValidationResultReady, got %q", result)
  584. }
  585. if provider.validateProviderRef != providerRef {
  586. t.Fatalf("unexpected provider ref: %#v", provider.validateProviderRef)
  587. }
  588. if provider.validateProviderRef.StoreRefKind != esv1.ProviderStoreKindStr {
  589. t.Fatalf("unexpected store_ref_kind: %q", provider.validateProviderRef.StoreRefKind)
  590. }
  591. if provider.validateNamespace != testSourceNamespace {
  592. t.Fatalf("unexpected source namespace: %q", provider.validateNamespace)
  593. }
  594. })
  595. t.Run("error", func(t *testing.T) {
  596. validateErr := errors.New("invalid credentials")
  597. provider := &fakeV2Provider{validateErr: validateErr}
  598. client := NewClient(provider, &pb.ProviderReference{Name: "provider"}, testSourceNamespace)
  599. result, err := client.Validate()
  600. if !errors.Is(err, validateErr) {
  601. t.Fatalf("expected %v, got %v", validateErr, err)
  602. }
  603. if result != esv1.ValidationResultError {
  604. t.Fatalf("expected ValidationResultError, got %q", result)
  605. }
  606. })
  607. }
  608. func TestCompatibilityClientValidateUsesCompatibilityStore(t *testing.T) {
  609. provider := &fakeV2Provider{}
  610. compatibilityStore := &pb.CompatibilityStore{
  611. StoreName: "runtime-store",
  612. StoreNamespace: "tenant-a",
  613. StoreKind: esv1.SecretStoreKind,
  614. StoreUid: "uid-1",
  615. StoreGeneration: 7,
  616. StoreSpecJson: []byte(`{"provider":{"fake":{"data":[{"key":"db","value":"secret"}]}}}`),
  617. }
  618. client := NewCompatibilityClient(provider, compatibilityStore, testSourceNamespace)
  619. result, err := client.Validate()
  620. if err != nil {
  621. t.Fatalf("Validate() error = %v", err)
  622. }
  623. if result != esv1.ValidationResultReady {
  624. t.Fatalf("expected ValidationResultReady, got %q", result)
  625. }
  626. if !provider.validateCalled {
  627. t.Fatal("expected provider Validate to be called")
  628. }
  629. if provider.validateProviderRef != nil {
  630. t.Fatalf("expected provider ref to be nil, got %#v", provider.validateProviderRef)
  631. }
  632. if provider.validateCompatibilityStore != compatibilityStore {
  633. t.Fatalf("unexpected compatibility store: %#v", provider.validateCompatibilityStore)
  634. }
  635. }
  636. func TestCompatibilityClientValidateReturnsErrorWhenValidationHookFails(t *testing.T) {
  637. validateErr := errors.New("runtime not serving")
  638. client := NewCompatibilityClient(&fakeV2Provider{validateErr: validateErr}, &pb.CompatibilityStore{
  639. StoreName: "runtime-store",
  640. StoreNamespace: "tenant-a",
  641. StoreKind: esv1.SecretStoreKind,
  642. StoreUid: "uid-1",
  643. StoreGeneration: 7,
  644. StoreSpecJson: []byte(`{"provider":{"fake":{"data":[{"key":"db","value":"secret"}]}}}`),
  645. }, testSourceNamespace)
  646. result, err := client.Validate()
  647. if !errors.Is(err, validateErr) {
  648. t.Fatalf("expected %v, got %v", validateErr, err)
  649. }
  650. if result != esv1.ValidationResultError {
  651. t.Fatalf("expected ValidationResultError, got %q", result)
  652. }
  653. }
  654. func TestClientCloseDelegates(t *testing.T) {
  655. closeErr := errors.New("close failed")
  656. provider := &fakeV2Provider{closeErr: closeErr}
  657. client := NewClient(provider, &pb.ProviderReference{Name: "provider"}, testSourceNamespace)
  658. err := client.Close(context.Background())
  659. if !errors.Is(err, closeErr) {
  660. t.Fatalf("expected %v, got %v", closeErr, err)
  661. }
  662. if !provider.closeCalled {
  663. t.Fatal("expected provider close to be called")
  664. }
  665. }