server_test.go 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168
  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. "context"
  16. "encoding/json"
  17. "errors"
  18. "strings"
  19. "testing"
  20. corev1 "k8s.io/api/core/v1"
  21. "k8s.io/apimachinery/pkg/runtime/schema"
  22. "sigs.k8s.io/controller-runtime/pkg/client"
  23. "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
  24. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  25. pb "github.com/external-secrets/external-secrets/proto/provider"
  26. )
  27. const (
  28. serverTestRemoteKey = "remote/path"
  29. serverTestProperty = "property"
  30. serverTestSourceNamespace = "tenant-a"
  31. serverTestValue = "value"
  32. )
  33. type fakeProviderInterface struct {
  34. newClient func(context.Context, esv1.GenericStore, client.Client, string) (esv1.SecretsClient, error)
  35. caps esv1.SecretStoreCapabilities
  36. }
  37. func (f *fakeProviderInterface) NewClient(ctx context.Context, store esv1.GenericStore, kube client.Client, namespace string) (esv1.SecretsClient, error) {
  38. return f.newClient(ctx, store, kube, namespace)
  39. }
  40. func (f *fakeProviderInterface) Capabilities() esv1.SecretStoreCapabilities {
  41. return f.caps
  42. }
  43. func (f *fakeProviderInterface) ValidateStore(esv1.GenericStore) (admission.Warnings, error) {
  44. return nil, nil
  45. }
  46. type fakeSecretsClient struct {
  47. getSecretResponse []byte
  48. getSecretErr error
  49. getSecretRef esv1.ExternalSecretDataRemoteRef
  50. getSecretMapResponse map[string][]byte
  51. getSecretMapErr error
  52. getSecretMapRef esv1.ExternalSecretDataRemoteRef
  53. getAllSecretsResponse map[string][]byte
  54. getAllSecretsErr error
  55. getAllSecretsFind esv1.ExternalSecretFind
  56. pushSecretErr error
  57. pushSecretSecret *corev1.Secret
  58. pushSecretData esv1.PushSecretData
  59. deleteSecretErr error
  60. deleteSecretRef esv1.PushSecretRemoteRef
  61. secretExistsResp bool
  62. secretExistsErr error
  63. secretExistsRef esv1.PushSecretRemoteRef
  64. validateResult esv1.ValidationResult
  65. validateErr error
  66. closeCalled bool
  67. }
  68. func (f *fakeSecretsClient) GetSecret(_ context.Context, ref esv1.ExternalSecretDataRemoteRef) ([]byte, error) {
  69. f.getSecretRef = ref
  70. return f.getSecretResponse, f.getSecretErr
  71. }
  72. func (f *fakeSecretsClient) GetSecretMap(_ context.Context, ref esv1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  73. f.getSecretMapRef = ref
  74. return f.getSecretMapResponse, f.getSecretMapErr
  75. }
  76. func (f *fakeSecretsClient) GetAllSecrets(_ context.Context, find esv1.ExternalSecretFind) (map[string][]byte, error) {
  77. f.getAllSecretsFind = find
  78. return f.getAllSecretsResponse, f.getAllSecretsErr
  79. }
  80. func (f *fakeSecretsClient) PushSecret(_ context.Context, secret *corev1.Secret, data esv1.PushSecretData) error {
  81. f.pushSecretSecret = secret
  82. f.pushSecretData = data
  83. return f.pushSecretErr
  84. }
  85. func (f *fakeSecretsClient) DeleteSecret(_ context.Context, remoteRef esv1.PushSecretRemoteRef) error {
  86. f.deleteSecretRef = remoteRef
  87. return f.deleteSecretErr
  88. }
  89. func (f *fakeSecretsClient) SecretExists(_ context.Context, remoteRef esv1.PushSecretRemoteRef) (bool, error) {
  90. f.secretExistsRef = remoteRef
  91. return f.secretExistsResp, f.secretExistsErr
  92. }
  93. func (f *fakeSecretsClient) Validate() (esv1.ValidationResult, error) {
  94. return f.validateResult, f.validateErr
  95. }
  96. func (f *fakeSecretsClient) Close(context.Context) error {
  97. f.closeCalled = true
  98. return nil
  99. }
  100. type specMapperRecorder struct {
  101. ref *pb.ProviderReference
  102. sourceNamespace string
  103. spec *esv1.SecretStoreSpec
  104. err error
  105. }
  106. func (r *specMapperRecorder) mapRef(ref *pb.ProviderReference, sourceNamespace string) (*esv1.SecretStoreSpec, error) {
  107. r.ref = ref
  108. r.sourceNamespace = sourceNamespace
  109. return r.spec, r.err
  110. }
  111. func mustCompatibilityStore(t *testing.T, spec *esv1.SecretStoreSpec) *pb.CompatibilityStore {
  112. t.Helper()
  113. specBytes, err := json.Marshal(spec)
  114. if err != nil {
  115. t.Fatalf("json.Marshal() error = %v", err)
  116. }
  117. return &pb.CompatibilityStore{
  118. StoreName: "compat-store",
  119. StoreNamespace: serverTestSourceNamespace,
  120. StoreKind: esv1.SecretStoreKind,
  121. StoreUid: "uid-1",
  122. StoreGeneration: 7,
  123. StoreSpecJson: specBytes,
  124. }
  125. }
  126. func TestCompatibilityStoreToSyntheticStoreRejectsInvalidPayloads(t *testing.T) {
  127. validSpec := &esv1.SecretStoreSpec{
  128. Provider: &esv1.SecretStoreProvider{
  129. Fake: &esv1.FakeProvider{},
  130. },
  131. }
  132. validSpecBytes, err := json.Marshal(validSpec)
  133. if err != nil {
  134. t.Fatalf("json.Marshal() error = %v", err)
  135. }
  136. testCases := []struct {
  137. name string
  138. store *pb.CompatibilityStore
  139. want string
  140. }{
  141. {
  142. name: "nil store",
  143. store: nil,
  144. want: "compatibility store is nil",
  145. },
  146. {
  147. name: "empty spec",
  148. store: &pb.CompatibilityStore{
  149. StoreKind: esv1.SecretStoreKind,
  150. },
  151. want: "compatibility store spec is empty",
  152. },
  153. {
  154. name: "bad json",
  155. store: &pb.CompatibilityStore{
  156. StoreKind: esv1.SecretStoreKind,
  157. StoreSpecJson: []byte(`{`),
  158. },
  159. want: "decode compatibility store spec:",
  160. },
  161. {
  162. name: "bad kind",
  163. store: &pb.CompatibilityStore{
  164. StoreKind: "UnknownStore",
  165. StoreSpecJson: validSpecBytes,
  166. },
  167. want: `unsupported compatibility store kind "UnknownStore"`,
  168. },
  169. {
  170. name: "missing provider",
  171. store: &pb.CompatibilityStore{
  172. StoreKind: esv1.SecretStoreKind,
  173. StoreSpecJson: []byte(`{"retrySettings":{"maxRetries":1}}`),
  174. },
  175. want: "compatibility store provider config is required",
  176. },
  177. }
  178. for _, tc := range testCases {
  179. t.Run(tc.name, func(t *testing.T) {
  180. _, err := CompatibilityStoreToSyntheticStore(tc.store)
  181. if err == nil || !strings.Contains(err.Error(), tc.want) {
  182. t.Fatalf("expected error containing %q, got %v", tc.want, err)
  183. }
  184. })
  185. }
  186. }
  187. func TestServerGetSecretMapsRemoteRefAndSyntheticStoreNamespace(t *testing.T) {
  188. mapper := &specMapperRecorder{
  189. spec: &esv1.SecretStoreSpec{
  190. Provider: &esv1.SecretStoreProvider{
  191. Fake: &esv1.FakeProvider{},
  192. },
  193. },
  194. }
  195. fakeClient := &fakeSecretsClient{getSecretResponse: []byte("secret-value")}
  196. var receivedStore esv1.GenericStore
  197. var receivedNamespace string
  198. server := NewServer(nil, ProviderMapping{
  199. schema.GroupVersionKind{Group: "provider.external-secrets.io", Version: "v2alpha1", Kind: "Fake"}: &fakeProviderInterface{
  200. caps: esv1.SecretStoreReadWrite,
  201. newClient: func(_ context.Context, store esv1.GenericStore, _ client.Client, namespace string) (esv1.SecretsClient, error) {
  202. receivedStore = store
  203. receivedNamespace = namespace
  204. return fakeClient, nil
  205. },
  206. },
  207. }, mapper.mapRef)
  208. req := &pb.GetSecretRequest{
  209. ProviderRef: &pb.ProviderReference{
  210. ApiVersion: "provider.external-secrets.io/v2alpha1",
  211. Kind: "Fake",
  212. Name: "backend",
  213. Namespace: "provider-config-ns",
  214. StoreRefKind: esv1.ProviderStoreKindStr,
  215. },
  216. SourceNamespace: serverTestSourceNamespace,
  217. RemoteRef: &pb.ExternalSecretDataRemoteRef{
  218. Key: "sample",
  219. Version: "v1",
  220. Property: "password",
  221. DecodingStrategy: string(esv1.ExternalSecretDecodeBase64),
  222. MetadataPolicy: string(esv1.ExternalSecretMetadataPolicyFetch),
  223. },
  224. }
  225. resp, err := server.GetSecret(context.Background(), req)
  226. if err != nil {
  227. t.Fatalf("GetSecret() error = %v", err)
  228. }
  229. if string(resp.Value) != "secret-value" {
  230. t.Fatalf("expected secret-value, got %q", string(resp.Value))
  231. }
  232. if mapper.ref != req.ProviderRef || mapper.sourceNamespace != serverTestSourceNamespace {
  233. t.Fatalf("unexpected spec mapper input: ref=%#v namespace=%q", mapper.ref, mapper.sourceNamespace)
  234. }
  235. if receivedNamespace != "provider-config-ns" {
  236. t.Fatalf("unexpected new client namespace: %q", receivedNamespace)
  237. }
  238. syntheticStore, ok := receivedStore.(*SyntheticStore)
  239. if !ok {
  240. t.Fatalf("expected SyntheticStore, got %T", receivedStore)
  241. }
  242. if syntheticStore.Namespace != "provider-config-ns" {
  243. t.Fatalf("unexpected synthetic store namespace: %q", syntheticStore.Namespace)
  244. }
  245. if syntheticStore.Kind != esv1.SecretStoreKind {
  246. t.Fatalf("unexpected synthetic store kind: %q", syntheticStore.Kind)
  247. }
  248. if syntheticStore.GetSpec() != mapper.spec {
  249. t.Fatalf("unexpected synthetic spec: %#v", syntheticStore.GetSpec())
  250. }
  251. if fakeClient.getSecretRef.Key != "sample" || fakeClient.getSecretRef.Version != "v1" || fakeClient.getSecretRef.Property != "password" {
  252. t.Fatalf("unexpected remote ref: %#v", fakeClient.getSecretRef)
  253. }
  254. if fakeClient.getSecretRef.DecodingStrategy != esv1.ExternalSecretDecodeBase64 {
  255. t.Fatalf("unexpected decoding strategy: %q", fakeClient.getSecretRef.DecodingStrategy)
  256. }
  257. if fakeClient.getSecretRef.MetadataPolicy != esv1.ExternalSecretMetadataPolicyFetch {
  258. t.Fatalf("unexpected metadata policy: %q", fakeClient.getSecretRef.MetadataPolicy)
  259. }
  260. if !fakeClient.closeCalled {
  261. t.Fatal("expected secrets client to be closed")
  262. }
  263. }
  264. func TestServerPushSecretMapsClusterProviderStoreKindToClusterSecretStore(t *testing.T) {
  265. mapper := &specMapperRecorder{
  266. spec: &esv1.SecretStoreSpec{
  267. Provider: &esv1.SecretStoreProvider{
  268. Fake: &esv1.FakeProvider{},
  269. },
  270. },
  271. }
  272. fakeClient := &fakeSecretsClient{}
  273. var receivedStore esv1.GenericStore
  274. server := NewServer(nil, ProviderMapping{
  275. schema.GroupVersionKind{Group: "provider.external-secrets.io", Version: "v2alpha1", Kind: "Fake"}: &fakeProviderInterface{
  276. caps: esv1.SecretStoreReadWrite,
  277. newClient: func(_ context.Context, store esv1.GenericStore, _ client.Client, _ string) (esv1.SecretsClient, error) {
  278. receivedStore = store
  279. return fakeClient, nil
  280. },
  281. },
  282. }, mapper.mapRef)
  283. _, err := server.PushSecret(context.Background(), &pb.PushSecretRequest{
  284. ProviderRef: &pb.ProviderReference{
  285. ApiVersion: "provider.external-secrets.io/v2alpha1",
  286. Kind: "Fake",
  287. Name: "backend",
  288. StoreRefKind: esv1.ClusterProviderStoreKindStr,
  289. },
  290. SourceNamespace: serverTestSourceNamespace,
  291. SecretData: map[string][]byte{
  292. serverTestValue: []byte("secret-value"),
  293. },
  294. PushSecretData: &pb.PushSecretData{
  295. RemoteKey: "remote-secret",
  296. SecretKey: serverTestValue,
  297. },
  298. })
  299. if err != nil {
  300. t.Fatalf("PushSecret() error = %v", err)
  301. }
  302. syntheticStore, ok := receivedStore.(*SyntheticStore)
  303. if !ok {
  304. t.Fatalf("expected SyntheticStore, got %T", receivedStore)
  305. }
  306. if syntheticStore.Kind != esv1.ClusterSecretStoreKind {
  307. t.Fatalf("unexpected synthetic store kind: %q", syntheticStore.Kind)
  308. }
  309. }
  310. func TestServerGetSecretMapDelegates(t *testing.T) {
  311. mapper := &specMapperRecorder{
  312. spec: &esv1.SecretStoreSpec{Provider: &esv1.SecretStoreProvider{Fake: &esv1.FakeProvider{}}},
  313. }
  314. fakeClient := &fakeSecretsClient{
  315. getSecretMapResponse: map[string][]byte{"foo": []byte("bar")},
  316. }
  317. server := NewServer(nil, ProviderMapping{
  318. schema.GroupVersionKind{Group: "provider.external-secrets.io", Version: "v2alpha1", Kind: "Fake"}: &fakeProviderInterface{
  319. caps: esv1.SecretStoreReadWrite,
  320. newClient: func(context.Context, esv1.GenericStore, client.Client, string) (esv1.SecretsClient, error) {
  321. return fakeClient, nil
  322. },
  323. },
  324. }, mapper.mapRef)
  325. resp, err := server.GetSecretMap(context.Background(), &pb.GetSecretMapRequest{
  326. ProviderRef: &pb.ProviderReference{
  327. ApiVersion: "provider.external-secrets.io/v2alpha1",
  328. Kind: "Fake",
  329. Name: "backend",
  330. },
  331. SourceNamespace: serverTestSourceNamespace,
  332. RemoteRef: &pb.ExternalSecretDataRemoteRef{Key: "sample"},
  333. })
  334. if err != nil {
  335. t.Fatalf("GetSecretMap() error = %v", err)
  336. }
  337. if string(resp.Secrets["foo"]) != "bar" {
  338. t.Fatalf("unexpected response: %#v", resp.Secrets)
  339. }
  340. if fakeClient.getSecretMapRef.Key != "sample" {
  341. t.Fatalf("unexpected ref: %#v", fakeClient.getSecretMapRef)
  342. }
  343. }
  344. func TestServerGetSecretUsesCompatibilityStore(t *testing.T) {
  345. mapper := &specMapperRecorder{err: errors.New("spec mapper should not be called")}
  346. fakeClient := &fakeSecretsClient{getSecretResponse: []byte("secret-value")}
  347. var receivedStore esv1.GenericStore
  348. provider := &fakeProviderInterface{
  349. caps: esv1.SecretStoreReadWrite,
  350. newClient: func(_ context.Context, store esv1.GenericStore, _ client.Client, _ string) (esv1.SecretsClient, error) {
  351. receivedStore = store
  352. return fakeClient, nil
  353. },
  354. }
  355. server := NewServerWithCompatibilityProvider(nil, ProviderMapping{
  356. schema.GroupVersionKind{Group: "provider.external-secrets.io", Version: "v2alpha1", Kind: "Fake"}: &fakeProviderInterface{
  357. caps: provider.caps,
  358. newClient: provider.newClient,
  359. },
  360. }, mapper.mapRef, provider)
  361. spec := &esv1.SecretStoreSpec{
  362. Provider: &esv1.SecretStoreProvider{
  363. Fake: &esv1.FakeProvider{
  364. Data: []esv1.FakeProviderData{
  365. {Key: "sample", Value: "secret-value"},
  366. },
  367. },
  368. },
  369. }
  370. resp, err := server.GetSecret(context.Background(), &pb.GetSecretRequest{
  371. ProviderRef: &pb.ProviderReference{
  372. ApiVersion: "provider.external-secrets.io/v2alpha1",
  373. Kind: "Fake",
  374. Name: "backend",
  375. },
  376. CompatibilityStore: mustCompatibilityStore(t, spec),
  377. SourceNamespace: serverTestSourceNamespace,
  378. RemoteRef: &pb.ExternalSecretDataRemoteRef{Key: "sample"},
  379. })
  380. if err != nil {
  381. t.Fatalf("GetSecret() error = %v", err)
  382. }
  383. if string(resp.Value) != "secret-value" {
  384. t.Fatalf("unexpected response: %q", string(resp.Value))
  385. }
  386. if mapper.ref != nil {
  387. t.Fatalf("expected spec mapper to be bypassed, got %#v", mapper.ref)
  388. }
  389. syntheticStore, ok := receivedStore.(*SyntheticStore)
  390. if !ok {
  391. t.Fatalf("expected SyntheticStore, got %T", receivedStore)
  392. }
  393. if syntheticStore.Name != "compat-store" || syntheticStore.Namespace != serverTestSourceNamespace {
  394. t.Fatalf("unexpected synthetic store metadata: %#v", syntheticStore.ObjectMeta)
  395. }
  396. if syntheticStore.GetSpec().Provider == nil || syntheticStore.GetSpec().Provider.Fake == nil {
  397. t.Fatalf("expected fake provider config, got %#v", syntheticStore.GetSpec().Provider)
  398. }
  399. }
  400. func TestServerCompatibilityReadsRequireExplicitCompatibilityProvider(t *testing.T) {
  401. server := NewServer(nil, ProviderMapping{}, (&specMapperRecorder{}).mapRef)
  402. _, err := server.GetSecret(context.Background(), &pb.GetSecretRequest{
  403. CompatibilityStore: &pb.CompatibilityStore{
  404. StoreName: "compat-store",
  405. StoreNamespace: serverTestSourceNamespace,
  406. StoreKind: esv1.SecretStoreKind,
  407. StoreSpecJson: []byte(`{"provider":{"fake":{}}}`),
  408. StoreGeneration: 1,
  409. },
  410. SourceNamespace: serverTestSourceNamespace,
  411. RemoteRef: &pb.ExternalSecretDataRemoteRef{Key: "sample"},
  412. })
  413. if err == nil || err.Error() != "failed to get client: compatibility provider is not configured" {
  414. t.Fatalf("unexpected error: %v", err)
  415. }
  416. }
  417. func TestServerReadRequestsRequireReadIdentity(t *testing.T) {
  418. server := NewServerWithCompatibilityProvider(nil, ProviderMapping{}, (&specMapperRecorder{}).mapRef, &fakeProviderInterface{})
  419. testCases := []struct {
  420. name string
  421. call func() error
  422. }{
  423. {
  424. name: "get secret",
  425. call: func() error {
  426. _, err := server.GetSecret(context.Background(), &pb.GetSecretRequest{
  427. SourceNamespace: serverTestSourceNamespace,
  428. RemoteRef: &pb.ExternalSecretDataRemoteRef{Key: "sample"},
  429. })
  430. return err
  431. },
  432. },
  433. {
  434. name: "get secret map",
  435. call: func() error {
  436. _, err := server.GetSecretMap(context.Background(), &pb.GetSecretMapRequest{
  437. SourceNamespace: serverTestSourceNamespace,
  438. RemoteRef: &pb.ExternalSecretDataRemoteRef{Key: "sample"},
  439. })
  440. return err
  441. },
  442. },
  443. {
  444. name: "get all secrets",
  445. call: func() error {
  446. _, err := server.GetAllSecrets(context.Background(), &pb.GetAllSecretsRequest{
  447. SourceNamespace: serverTestSourceNamespace,
  448. Find: &pb.ExternalSecretFind{},
  449. })
  450. return err
  451. },
  452. },
  453. }
  454. for _, tc := range testCases {
  455. t.Run(tc.name, func(t *testing.T) {
  456. err := tc.call()
  457. if err == nil || err.Error() != "provider reference or compatibility store is required for read operations" {
  458. t.Fatalf("unexpected error: %v", err)
  459. }
  460. })
  461. }
  462. }
  463. func TestServerGetSecretPrefersCompatibilityStoreOverProviderRef(t *testing.T) {
  464. mapper := &specMapperRecorder{
  465. spec: &esv1.SecretStoreSpec{
  466. Provider: &esv1.SecretStoreProvider{
  467. Fake: &esv1.FakeProvider{
  468. Data: []esv1.FakeProviderData{
  469. {Key: "sample", Value: "mapped-value"},
  470. },
  471. },
  472. },
  473. },
  474. }
  475. fakeClient := &fakeSecretsClient{getSecretResponse: []byte("compat-value")}
  476. provider := &fakeProviderInterface{
  477. caps: esv1.SecretStoreReadWrite,
  478. newClient: func(_ context.Context, _ esv1.GenericStore, _ client.Client, _ string) (esv1.SecretsClient, error) {
  479. return fakeClient, nil
  480. },
  481. }
  482. server := NewServerWithCompatibilityProvider(nil, ProviderMapping{
  483. schema.GroupVersionKind{Group: "provider.external-secrets.io", Version: "v2alpha1", Kind: "Fake"}: &fakeProviderInterface{
  484. caps: provider.caps,
  485. newClient: provider.newClient,
  486. },
  487. }, mapper.mapRef, provider)
  488. spec := &esv1.SecretStoreSpec{
  489. Provider: &esv1.SecretStoreProvider{
  490. Fake: &esv1.FakeProvider{
  491. Data: []esv1.FakeProviderData{
  492. {Key: "sample", Value: "compat-value"},
  493. },
  494. },
  495. },
  496. }
  497. resp, err := server.GetSecret(context.Background(), &pb.GetSecretRequest{
  498. ProviderRef: &pb.ProviderReference{
  499. ApiVersion: "provider.external-secrets.io/v2alpha1",
  500. Kind: "Fake",
  501. Name: "backend",
  502. },
  503. CompatibilityStore: mustCompatibilityStore(t, spec),
  504. SourceNamespace: serverTestSourceNamespace,
  505. RemoteRef: &pb.ExternalSecretDataRemoteRef{Key: "sample"},
  506. })
  507. if err != nil {
  508. t.Fatalf("GetSecret() error = %v", err)
  509. }
  510. if string(resp.Value) != "compat-value" {
  511. t.Fatalf("unexpected response: %q", string(resp.Value))
  512. }
  513. if mapper.ref != nil {
  514. t.Fatalf("expected compatibility store to bypass provider ref mapping, got %#v", mapper.ref)
  515. }
  516. }
  517. func TestServerGetSecretMapUsesCompatibilityStore(t *testing.T) {
  518. mapper := &specMapperRecorder{err: errors.New("spec mapper should not be called")}
  519. fakeClient := &fakeSecretsClient{
  520. getSecretMapResponse: map[string][]byte{"foo": []byte("bar")},
  521. }
  522. provider := &fakeProviderInterface{
  523. caps: esv1.SecretStoreReadWrite,
  524. newClient: func(_ context.Context, _ esv1.GenericStore, _ client.Client, _ string) (esv1.SecretsClient, error) {
  525. return fakeClient, nil
  526. },
  527. }
  528. server := NewServerWithCompatibilityProvider(nil, ProviderMapping{
  529. schema.GroupVersionKind{Group: "provider.external-secrets.io", Version: "v2alpha1", Kind: "Fake"}: &fakeProviderInterface{
  530. caps: provider.caps,
  531. newClient: provider.newClient,
  532. },
  533. }, mapper.mapRef, provider)
  534. spec := &esv1.SecretStoreSpec{
  535. Provider: &esv1.SecretStoreProvider{
  536. Fake: &esv1.FakeProvider{},
  537. },
  538. }
  539. resp, err := server.GetSecretMap(context.Background(), &pb.GetSecretMapRequest{
  540. CompatibilityStore: mustCompatibilityStore(t, spec),
  541. SourceNamespace: serverTestSourceNamespace,
  542. RemoteRef: &pb.ExternalSecretDataRemoteRef{Key: "sample"},
  543. })
  544. if err != nil {
  545. t.Fatalf("GetSecretMap() error = %v", err)
  546. }
  547. if string(resp.Secrets["foo"]) != "bar" {
  548. t.Fatalf("unexpected response: %#v", resp.Secrets)
  549. }
  550. if mapper.ref != nil {
  551. t.Fatalf("expected spec mapper to be bypassed, got %#v", mapper.ref)
  552. }
  553. }
  554. func TestServerGetAllSecretsUsesCompatibilityStore(t *testing.T) {
  555. mapper := &specMapperRecorder{err: errors.New("spec mapper should not be called")}
  556. fakeClient := &fakeSecretsClient{
  557. getAllSecretsResponse: map[string][]byte{"db-password": []byte(serverTestValue)},
  558. }
  559. provider := &fakeProviderInterface{
  560. caps: esv1.SecretStoreReadWrite,
  561. newClient: func(_ context.Context, _ esv1.GenericStore, _ client.Client, _ string) (esv1.SecretsClient, error) {
  562. return fakeClient, nil
  563. },
  564. }
  565. server := NewServerWithCompatibilityProvider(nil, ProviderMapping{
  566. schema.GroupVersionKind{Group: "provider.external-secrets.io", Version: "v2alpha1", Kind: "Fake"}: &fakeProviderInterface{
  567. caps: provider.caps,
  568. newClient: provider.newClient,
  569. },
  570. }, mapper.mapRef, provider)
  571. spec := &esv1.SecretStoreSpec{
  572. Provider: &esv1.SecretStoreProvider{
  573. Fake: &esv1.FakeProvider{},
  574. },
  575. }
  576. resp, err := server.GetAllSecrets(context.Background(), &pb.GetAllSecretsRequest{
  577. CompatibilityStore: mustCompatibilityStore(t, spec),
  578. SourceNamespace: serverTestSourceNamespace,
  579. Find: &pb.ExternalSecretFind{Tags: map[string]string{"team": "a"}},
  580. })
  581. if err != nil {
  582. t.Fatalf("GetAllSecrets() error = %v", err)
  583. }
  584. if string(resp.Secrets["db-password"]) != serverTestValue {
  585. t.Fatalf("unexpected response: %#v", resp.Secrets)
  586. }
  587. if mapper.ref != nil {
  588. t.Fatalf("expected spec mapper to be bypassed, got %#v", mapper.ref)
  589. }
  590. }
  591. func TestServerPushSecretUsesCompatibilityStore(t *testing.T) {
  592. mapper := &specMapperRecorder{err: errors.New("spec mapper should not be called")}
  593. fakeClient := &fakeSecretsClient{}
  594. provider := &fakeProviderInterface{
  595. caps: esv1.SecretStoreReadWrite,
  596. newClient: func(_ context.Context, _ esv1.GenericStore, _ client.Client, _ string) (esv1.SecretsClient, error) {
  597. return fakeClient, nil
  598. },
  599. }
  600. server := NewServerWithCompatibilityProvider(nil, ProviderMapping{}, mapper.mapRef, provider)
  601. spec := &esv1.SecretStoreSpec{
  602. Provider: &esv1.SecretStoreProvider{
  603. Fake: &esv1.FakeProvider{},
  604. },
  605. }
  606. _, err := server.PushSecret(context.Background(), &pb.PushSecretRequest{
  607. CompatibilityStore: mustCompatibilityStore(t, spec),
  608. SourceNamespace: serverTestSourceNamespace,
  609. SecretData: map[string][]byte{"token": []byte(serverTestValue)},
  610. PushSecretData: &pb.PushSecretData{RemoteKey: serverTestRemoteKey, SecretKey: "token"},
  611. })
  612. if err != nil {
  613. t.Fatalf("PushSecret() error = %v", err)
  614. }
  615. if mapper.ref != nil {
  616. t.Fatalf("expected spec mapper to be bypassed, got %#v", mapper.ref)
  617. }
  618. if fakeClient.pushSecretData.GetRemoteKey() != serverTestRemoteKey {
  619. t.Fatalf("unexpected push data: %#v", fakeClient.pushSecretData)
  620. }
  621. }
  622. func TestServerDeleteSecretUsesCompatibilityStore(t *testing.T) {
  623. mapper := &specMapperRecorder{err: errors.New("spec mapper should not be called")}
  624. fakeClient := &fakeSecretsClient{}
  625. provider := &fakeProviderInterface{
  626. caps: esv1.SecretStoreReadWrite,
  627. newClient: func(_ context.Context, _ esv1.GenericStore, _ client.Client, _ string) (esv1.SecretsClient, error) {
  628. return fakeClient, nil
  629. },
  630. }
  631. server := NewServerWithCompatibilityProvider(nil, ProviderMapping{}, mapper.mapRef, provider)
  632. spec := &esv1.SecretStoreSpec{
  633. Provider: &esv1.SecretStoreProvider{
  634. Fake: &esv1.FakeProvider{},
  635. },
  636. }
  637. _, err := server.DeleteSecret(context.Background(), &pb.DeleteSecretRequest{
  638. CompatibilityStore: mustCompatibilityStore(t, spec),
  639. SourceNamespace: serverTestSourceNamespace,
  640. RemoteRef: &pb.PushSecretRemoteRef{RemoteKey: serverTestRemoteKey, Property: serverTestProperty},
  641. })
  642. if err != nil {
  643. t.Fatalf("DeleteSecret() error = %v", err)
  644. }
  645. if mapper.ref != nil {
  646. t.Fatalf("expected spec mapper to be bypassed, got %#v", mapper.ref)
  647. }
  648. if fakeClient.deleteSecretRef.GetRemoteKey() != serverTestRemoteKey {
  649. t.Fatalf("unexpected delete ref: %#v", fakeClient.deleteSecretRef)
  650. }
  651. }
  652. func TestServerSecretExistsUsesCompatibilityStore(t *testing.T) {
  653. mapper := &specMapperRecorder{err: errors.New("spec mapper should not be called")}
  654. fakeClient := &fakeSecretsClient{secretExistsResp: true}
  655. provider := &fakeProviderInterface{
  656. caps: esv1.SecretStoreReadWrite,
  657. newClient: func(_ context.Context, _ esv1.GenericStore, _ client.Client, _ string) (esv1.SecretsClient, error) {
  658. return fakeClient, nil
  659. },
  660. }
  661. server := NewServerWithCompatibilityProvider(nil, ProviderMapping{}, mapper.mapRef, provider)
  662. spec := &esv1.SecretStoreSpec{
  663. Provider: &esv1.SecretStoreProvider{
  664. Fake: &esv1.FakeProvider{},
  665. },
  666. }
  667. resp, err := server.SecretExists(context.Background(), &pb.SecretExistsRequest{
  668. CompatibilityStore: mustCompatibilityStore(t, spec),
  669. SourceNamespace: serverTestSourceNamespace,
  670. RemoteRef: &pb.PushSecretRemoteRef{RemoteKey: serverTestRemoteKey, Property: serverTestProperty},
  671. })
  672. if err != nil {
  673. t.Fatalf("SecretExists() error = %v", err)
  674. }
  675. if !resp.Exists {
  676. t.Fatal("expected secret to exist")
  677. }
  678. if mapper.ref != nil {
  679. t.Fatalf("expected spec mapper to be bypassed, got %#v", mapper.ref)
  680. }
  681. if fakeClient.secretExistsRef.GetRemoteKey() != serverTestRemoteKey {
  682. t.Fatalf("unexpected secret exists ref: %#v", fakeClient.secretExistsRef)
  683. }
  684. }
  685. func TestServerValidateUsesCompatibilityStore(t *testing.T) {
  686. mapper := &specMapperRecorder{err: errors.New("spec mapper should not be called")}
  687. fakeClient := &fakeSecretsClient{validateResult: esv1.ValidationResultReady}
  688. provider := &fakeProviderInterface{
  689. caps: esv1.SecretStoreReadWrite,
  690. newClient: func(_ context.Context, _ esv1.GenericStore, _ client.Client, _ string) (esv1.SecretsClient, error) {
  691. return fakeClient, nil
  692. },
  693. }
  694. server := NewServerWithCompatibilityProvider(nil, ProviderMapping{}, mapper.mapRef, provider)
  695. spec := &esv1.SecretStoreSpec{
  696. Provider: &esv1.SecretStoreProvider{
  697. Fake: &esv1.FakeProvider{},
  698. },
  699. }
  700. resp, err := server.Validate(context.Background(), &pb.ValidateRequest{
  701. CompatibilityStore: mustCompatibilityStore(t, spec),
  702. SourceNamespace: serverTestSourceNamespace,
  703. })
  704. if err != nil {
  705. t.Fatalf("Validate() error = %v", err)
  706. }
  707. if !resp.Valid {
  708. t.Fatalf("expected validate response to be valid: %#v", resp)
  709. }
  710. if mapper.ref != nil {
  711. t.Fatalf("expected spec mapper to be bypassed, got %#v", mapper.ref)
  712. }
  713. }
  714. func TestServerGetAllSecretsMapsFindCriteria(t *testing.T) {
  715. mapper := &specMapperRecorder{
  716. spec: &esv1.SecretStoreSpec{Provider: &esv1.SecretStoreProvider{Fake: &esv1.FakeProvider{}}},
  717. }
  718. fakeClient := &fakeSecretsClient{
  719. getAllSecretsResponse: map[string][]byte{"db-password": []byte(serverTestValue)},
  720. }
  721. server := NewServer(nil, ProviderMapping{
  722. schema.GroupVersionKind{Group: "provider.external-secrets.io", Version: "v2alpha1", Kind: "Fake"}: &fakeProviderInterface{
  723. caps: esv1.SecretStoreReadWrite,
  724. newClient: func(context.Context, esv1.GenericStore, client.Client, string) (esv1.SecretsClient, error) {
  725. return fakeClient, nil
  726. },
  727. },
  728. }, mapper.mapRef)
  729. resp, err := server.GetAllSecrets(context.Background(), &pb.GetAllSecretsRequest{
  730. ProviderRef: &pb.ProviderReference{
  731. ApiVersion: "provider.external-secrets.io/v2alpha1",
  732. Kind: "Fake",
  733. Name: "backend",
  734. },
  735. SourceNamespace: serverTestSourceNamespace,
  736. Find: &pb.ExternalSecretFind{
  737. Tags: map[string]string{"team": "a"},
  738. Path: "/team-a",
  739. ConversionStrategy: string(esv1.ExternalSecretConversionDefault),
  740. DecodingStrategy: string(esv1.ExternalSecretDecodeBase64),
  741. Name: &pb.FindName{Regexp: "db-.*"},
  742. },
  743. })
  744. if err != nil {
  745. t.Fatalf("GetAllSecrets() error = %v", err)
  746. }
  747. if string(resp.Secrets["db-password"]) != serverTestValue {
  748. t.Fatalf("unexpected response: %#v", resp.Secrets)
  749. }
  750. if fakeClient.getAllSecretsFind.Tags["team"] != "a" {
  751. t.Fatalf("unexpected find tags: %#v", fakeClient.getAllSecretsFind)
  752. }
  753. if fakeClient.getAllSecretsFind.Path == nil || *fakeClient.getAllSecretsFind.Path != "/team-a" {
  754. t.Fatalf("unexpected find path: %#v", fakeClient.getAllSecretsFind.Path)
  755. }
  756. if fakeClient.getAllSecretsFind.Name == nil || fakeClient.getAllSecretsFind.Name.RegExp != "db-.*" {
  757. t.Fatalf("unexpected find name: %#v", fakeClient.getAllSecretsFind.Name)
  758. }
  759. }
  760. func TestServerPushDeleteAndExistsMapWriteRequests(t *testing.T) {
  761. mapper := &specMapperRecorder{
  762. spec: &esv1.SecretStoreSpec{Provider: &esv1.SecretStoreProvider{Fake: &esv1.FakeProvider{}}},
  763. }
  764. fakeClient := &fakeSecretsClient{secretExistsResp: true}
  765. server := NewServer(nil, ProviderMapping{
  766. schema.GroupVersionKind{Group: "provider.external-secrets.io", Version: "v2alpha1", Kind: "Fake"}: &fakeProviderInterface{
  767. caps: esv1.SecretStoreReadWrite,
  768. newClient: func(context.Context, esv1.GenericStore, client.Client, string) (esv1.SecretsClient, error) {
  769. return fakeClient, nil
  770. },
  771. },
  772. }, mapper.mapRef)
  773. _, err := server.PushSecret(context.Background(), &pb.PushSecretRequest{
  774. ProviderRef: &pb.ProviderReference{
  775. ApiVersion: "provider.external-secrets.io/v2alpha1",
  776. Kind: "Fake",
  777. Name: "backend",
  778. },
  779. SourceNamespace: serverTestSourceNamespace,
  780. SecretData: map[string][]byte{
  781. "token": []byte(serverTestValue),
  782. },
  783. PushSecretData: &pb.PushSecretData{
  784. RemoteKey: serverTestRemoteKey,
  785. SecretKey: "token",
  786. Property: serverTestProperty,
  787. Metadata: []byte(`{"owner":"eso"}`),
  788. },
  789. })
  790. if err != nil {
  791. t.Fatalf("PushSecret() error = %v", err)
  792. }
  793. if fakeClient.pushSecretSecret == nil || string(fakeClient.pushSecretSecret.Data["token"]) != serverTestValue {
  794. t.Fatalf("unexpected pushed secret: %#v", fakeClient.pushSecretSecret)
  795. }
  796. if fakeClient.pushSecretSecret.Type != "" {
  797. t.Fatalf("unexpected secret type: %q", fakeClient.pushSecretSecret.Type)
  798. }
  799. if fakeClient.pushSecretData.GetRemoteKey() != serverTestRemoteKey || fakeClient.pushSecretData.GetSecretKey() != "token" || fakeClient.pushSecretData.GetProperty() != serverTestProperty {
  800. t.Fatalf("unexpected push data: %#v", fakeClient.pushSecretData)
  801. }
  802. if got := fakeClient.pushSecretData.GetMetadata(); got == nil || string(got.Raw) != `{"owner":"eso"}` {
  803. t.Fatalf("unexpected metadata: %#v", got)
  804. }
  805. _, err = server.DeleteSecret(context.Background(), &pb.DeleteSecretRequest{
  806. ProviderRef: &pb.ProviderReference{
  807. ApiVersion: "provider.external-secrets.io/v2alpha1",
  808. Kind: "Fake",
  809. Name: "backend",
  810. },
  811. SourceNamespace: serverTestSourceNamespace,
  812. RemoteRef: &pb.PushSecretRemoteRef{
  813. RemoteKey: serverTestRemoteKey,
  814. Property: serverTestProperty,
  815. },
  816. })
  817. if err != nil {
  818. t.Fatalf("DeleteSecret() error = %v", err)
  819. }
  820. if fakeClient.deleteSecretRef.GetRemoteKey() != serverTestRemoteKey || fakeClient.deleteSecretRef.GetProperty() != serverTestProperty {
  821. t.Fatalf("unexpected delete ref: %#v", fakeClient.deleteSecretRef)
  822. }
  823. resp, err := server.SecretExists(context.Background(), &pb.SecretExistsRequest{
  824. ProviderRef: &pb.ProviderReference{
  825. ApiVersion: "provider.external-secrets.io/v2alpha1",
  826. Kind: "Fake",
  827. Name: "backend",
  828. },
  829. SourceNamespace: serverTestSourceNamespace,
  830. RemoteRef: &pb.PushSecretRemoteRef{
  831. RemoteKey: serverTestRemoteKey,
  832. Property: serverTestProperty,
  833. },
  834. })
  835. if err != nil {
  836. t.Fatalf("SecretExists() error = %v", err)
  837. }
  838. if !resp.Exists {
  839. t.Fatal("expected exists response to be true")
  840. }
  841. if fakeClient.secretExistsRef.GetRemoteKey() != serverTestRemoteKey || fakeClient.secretExistsRef.GetProperty() != serverTestProperty {
  842. t.Fatalf("unexpected exists ref: %#v", fakeClient.secretExistsRef)
  843. }
  844. }
  845. func TestServerPushSecretForwardsKubernetesSecretMetadata(t *testing.T) {
  846. mapper := &specMapperRecorder{
  847. spec: &esv1.SecretStoreSpec{Provider: &esv1.SecretStoreProvider{Fake: &esv1.FakeProvider{}}},
  848. }
  849. fakeClient := &fakeSecretsClient{}
  850. server := NewServer(nil, ProviderMapping{
  851. schema.GroupVersionKind{Group: "provider.external-secrets.io", Version: "v2alpha1", Kind: "Fake"}: &fakeProviderInterface{
  852. caps: esv1.SecretStoreReadWrite,
  853. newClient: func(context.Context, esv1.GenericStore, client.Client, string) (esv1.SecretsClient, error) {
  854. return fakeClient, nil
  855. },
  856. },
  857. }, mapper.mapRef)
  858. req := &pb.PushSecretRequest{
  859. ProviderRef: &pb.ProviderReference{
  860. ApiVersion: "provider.external-secrets.io/v2alpha1",
  861. Kind: "Fake",
  862. Name: "backend",
  863. },
  864. SourceNamespace: serverTestSourceNamespace,
  865. SecretData: map[string][]byte{
  866. ".dockerconfigjson": []byte("payload"),
  867. },
  868. SecretType: string(corev1.SecretTypeDockerConfigJson),
  869. SecretLabels: map[string]string{"team": "platform"},
  870. SecretAnnotations: map[string]string{"owner": "app-team"},
  871. PushSecretData: &pb.PushSecretData{
  872. RemoteKey: serverTestRemoteKey,
  873. SecretKey: ".dockerconfigjson",
  874. Property: serverTestProperty,
  875. Metadata: []byte(`{"mergePolicy":"replace"}`),
  876. },
  877. }
  878. _, err := server.PushSecret(context.Background(), req)
  879. if err != nil {
  880. t.Fatalf("PushSecret() error = %v", err)
  881. }
  882. if fakeClient.pushSecretSecret == nil {
  883. t.Fatal("expected pushed secret to be recorded")
  884. }
  885. if got, want := string(fakeClient.pushSecretSecret.Data[".dockerconfigjson"]), "payload"; got != want {
  886. t.Errorf("expected payload %q, got %q", want, got)
  887. }
  888. if got, want := fakeClient.pushSecretSecret.Type, corev1.SecretTypeDockerConfigJson; got != want {
  889. t.Errorf("expected secret type %q, got %q", want, got)
  890. }
  891. if got, want := fakeClient.pushSecretSecret.Labels["team"], "platform"; got != want {
  892. t.Errorf("expected secret label team=%q, got %q", want, got)
  893. }
  894. if got, want := fakeClient.pushSecretSecret.Annotations["owner"], "app-team"; got != want {
  895. t.Errorf("expected secret annotation owner=%q, got %q", want, got)
  896. }
  897. }
  898. func TestServerValidateMapsReadyUnknownAndErrorResults(t *testing.T) {
  899. t.Run("ready", func(t *testing.T) {
  900. resp := runValidateTest(t, esv1.ValidationResultReady, nil)
  901. if !resp.Valid {
  902. t.Fatalf("expected valid response, got %#v", resp)
  903. }
  904. })
  905. t.Run("unknown", func(t *testing.T) {
  906. resp := runValidateTest(t, esv1.ValidationResultUnknown, nil)
  907. if !resp.Valid {
  908. t.Fatalf("expected unknown to be treated as valid, got %#v", resp)
  909. }
  910. })
  911. t.Run("error_result", func(t *testing.T) {
  912. resp := runValidateTest(t, esv1.ValidationResultError, nil)
  913. if resp.Valid {
  914. t.Fatalf("expected invalid response, got %#v", resp)
  915. }
  916. })
  917. t.Run("error", func(t *testing.T) {
  918. validateErr := errors.New("invalid credentials")
  919. resp := runValidateTest(t, esv1.ValidationResultError, validateErr)
  920. if resp.Valid || resp.Error != "invalid credentials" {
  921. t.Fatalf("unexpected response: %#v", resp)
  922. }
  923. })
  924. }
  925. func TestServerCapabilitiesMapsProviderCapabilities(t *testing.T) {
  926. testCases := []struct {
  927. name string
  928. caps esv1.SecretStoreCapabilities
  929. expectedPB pb.SecretStoreCapabilities
  930. }{
  931. {name: "read_only", caps: esv1.SecretStoreReadOnly, expectedPB: pb.SecretStoreCapabilities_READ_ONLY},
  932. {name: "write_only", caps: esv1.SecretStoreWriteOnly, expectedPB: pb.SecretStoreCapabilities_WRITE_ONLY},
  933. {name: "read_write", caps: esv1.SecretStoreReadWrite, expectedPB: pb.SecretStoreCapabilities_READ_WRITE},
  934. }
  935. for _, tc := range testCases {
  936. t.Run(tc.name, func(t *testing.T) {
  937. server := NewServer(nil, ProviderMapping{
  938. schema.GroupVersionKind{Group: "provider.external-secrets.io", Version: "v2alpha1", Kind: "Fake"}: &fakeProviderInterface{
  939. caps: tc.caps,
  940. newClient: func(context.Context, esv1.GenericStore, client.Client, string) (esv1.SecretsClient, error) {
  941. return &fakeSecretsClient{}, nil
  942. },
  943. },
  944. }, (&specMapperRecorder{}).mapRef)
  945. resp, err := server.Capabilities(context.Background(), &pb.CapabilitiesRequest{
  946. ProviderRef: &pb.ProviderReference{
  947. ApiVersion: "provider.external-secrets.io/v2alpha1",
  948. Kind: "Fake",
  949. Name: "backend",
  950. },
  951. })
  952. if err != nil {
  953. t.Fatalf("Capabilities() error = %v", err)
  954. }
  955. if resp.Capabilities != tc.expectedPB {
  956. t.Fatalf("expected %v, got %v", tc.expectedPB, resp.Capabilities)
  957. }
  958. })
  959. }
  960. }
  961. func TestServerRejectsInvalidRequests(t *testing.T) {
  962. server := NewServer(nil, ProviderMapping{}, (&specMapperRecorder{}).mapRef)
  963. testCases := []struct {
  964. name string
  965. call func() error
  966. want string
  967. }{
  968. {
  969. name: "get_secret_nil_request",
  970. call: func() error {
  971. _, err := server.GetSecret(context.Background(), nil)
  972. return err
  973. },
  974. want: "request or remote ref is nil",
  975. },
  976. {
  977. name: "get_secret_empty_source_namespace",
  978. call: func() error {
  979. _, err := server.GetSecret(context.Background(), &pb.GetSecretRequest{
  980. RemoteRef: &pb.ExternalSecretDataRemoteRef{Key: "sample"},
  981. })
  982. return err
  983. },
  984. want: "source namespace is required",
  985. },
  986. {
  987. name: "push_secret_nil_payload",
  988. call: func() error {
  989. _, err := server.PushSecret(context.Background(), &pb.PushSecretRequest{
  990. SourceNamespace: serverTestSourceNamespace,
  991. })
  992. return err
  993. },
  994. want: "request or push secret data is nil",
  995. },
  996. {
  997. name: "validate_nil_request",
  998. call: func() error {
  999. _, err := server.Validate(context.Background(), nil)
  1000. return err
  1001. },
  1002. want: "request is nil",
  1003. },
  1004. {
  1005. name: "capabilities_nil_request",
  1006. call: func() error {
  1007. _, err := server.Capabilities(context.Background(), nil)
  1008. return err
  1009. },
  1010. want: "request is nil",
  1011. },
  1012. }
  1013. for _, tc := range testCases {
  1014. t.Run(tc.name, func(t *testing.T) {
  1015. err := tc.call()
  1016. if err == nil || err.Error() != tc.want {
  1017. t.Fatalf("expected %q, got %v", tc.want, err)
  1018. }
  1019. })
  1020. }
  1021. }
  1022. func runValidateTest(t *testing.T, result esv1.ValidationResult, validateErr error) *pb.ValidateResponse {
  1023. t.Helper()
  1024. server := NewServer(nil, ProviderMapping{
  1025. schema.GroupVersionKind{Group: "provider.external-secrets.io", Version: "v2alpha1", Kind: "Fake"}: &fakeProviderInterface{
  1026. caps: esv1.SecretStoreReadWrite,
  1027. newClient: func(context.Context, esv1.GenericStore, client.Client, string) (esv1.SecretsClient, error) {
  1028. return &fakeSecretsClient{
  1029. validateResult: result,
  1030. validateErr: validateErr,
  1031. }, nil
  1032. },
  1033. },
  1034. }, (&specMapperRecorder{
  1035. spec: &esv1.SecretStoreSpec{Provider: &esv1.SecretStoreProvider{Fake: &esv1.FakeProvider{}}},
  1036. }).mapRef)
  1037. resp, err := server.Validate(context.Background(), &pb.ValidateRequest{
  1038. ProviderRef: &pb.ProviderReference{
  1039. ApiVersion: "provider.external-secrets.io/v2alpha1",
  1040. Kind: "Fake",
  1041. Name: "backend",
  1042. },
  1043. SourceNamespace: "tenant-a",
  1044. })
  1045. if err != nil {
  1046. t.Fatalf("Validate() error = %v", err)
  1047. }
  1048. return resp
  1049. }