acr_test.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package acr
  13. import (
  14. "context"
  15. "fmt"
  16. "reflect"
  17. "testing"
  18. "github.com/Azure/azure-sdk-for-go/sdk/azcore"
  19. "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
  20. "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
  21. "github.com/stretchr/testify/assert"
  22. v1 "k8s.io/api/core/v1"
  23. apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
  24. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  25. "k8s.io/client-go/kubernetes"
  26. "sigs.k8s.io/controller-runtime/pkg/client"
  27. clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
  28. )
  29. func TestGenerate(t *testing.T) {
  30. const (
  31. testUsername = "11111111-2222-3333-4444-111111111111"
  32. testURL = "example.azurecr.io"
  33. )
  34. type args struct {
  35. ctx context.Context
  36. jsonSpec *apiextensions.JSON
  37. crClient client.Client
  38. kubeClient kubernetes.Interface
  39. namespace string
  40. accessTokenFetcher accessTokenFetcher
  41. refreshTokenFetcher refreshTokenFetcher
  42. clientSecretCreds clientSecretCredentialFunc
  43. }
  44. tests := []struct {
  45. name string
  46. g *Generator
  47. args args
  48. want map[string][]byte
  49. wantErr bool
  50. }{
  51. {
  52. name: "no spec",
  53. args: args{
  54. jsonSpec: nil,
  55. },
  56. wantErr: true,
  57. },
  58. {
  59. name: "empty spec",
  60. args: args{
  61. jsonSpec: &apiextensions.JSON{},
  62. },
  63. wantErr: true,
  64. },
  65. {
  66. name: "return acr access token if scope is defined",
  67. args: args{
  68. jsonSpec: &apiextensions.JSON{
  69. Raw: []byte(fmt.Sprintf(`apiVersion: generators.external-secrets.io/v1alpha1
  70. kind: ACRAccessToken
  71. spec:
  72. tenantId: %s
  73. registry: %s
  74. scope: "repository:foo:pull,push"
  75. environmentType: "PublicCloud"
  76. auth:
  77. servicePrincipal:
  78. secretRef:
  79. clientSecret:
  80. name: az-secret
  81. key: clientsecret
  82. clientId:
  83. name: az-secret
  84. key: clientid`, testUsername, testURL)),
  85. },
  86. crClient: clientfake.NewClientBuilder().WithObjects(&v1.Secret{
  87. ObjectMeta: metav1.ObjectMeta{
  88. Name: "az-secret",
  89. Namespace: "foobar",
  90. },
  91. Data: map[string][]byte{
  92. "clientsecret": []byte("foo"),
  93. "clientid": []byte("bar"),
  94. },
  95. }).Build(),
  96. namespace: "foobar",
  97. ctx: context.Background(),
  98. accessTokenFetcher: func(acrRefreshToken, tenantID, registryURL, scope string) (string, error) {
  99. assert.Equal(t, "acrrefreshtoken", acrRefreshToken)
  100. assert.Equal(t, tenantID, testUsername)
  101. assert.Equal(t, registryURL, testURL)
  102. assert.Equal(t, scope, "repository:foo:pull,push")
  103. return "acraccesstoken", nil
  104. },
  105. refreshTokenFetcher: func(aadAccessToken, tenantID, registryURL string) (string, error) {
  106. assert.Equal(t, "1234", aadAccessToken)
  107. assert.Equal(t, tenantID, testUsername)
  108. assert.Equal(t, registryURL, testURL)
  109. return "acrrefreshtoken", nil
  110. },
  111. clientSecretCreds: func(tenantID, clientID, clientSecret string, options *azidentity.ClientSecretCredentialOptions) (TokenGetter, error) {
  112. return &FakeTokenGetter{
  113. token: azcore.AccessToken{
  114. Token: "1234",
  115. },
  116. }, nil
  117. },
  118. },
  119. want: map[string][]byte{
  120. "username": []byte(defaultLoginUsername),
  121. "password": []byte("acraccesstoken"),
  122. },
  123. },
  124. {
  125. name: "return acr refresh token if scope is not defined",
  126. args: args{
  127. jsonSpec: &apiextensions.JSON{
  128. Raw: []byte(fmt.Sprintf(`apiVersion: generators.external-secrets.io/v1alpha1
  129. kind: ACRAccessToken
  130. spec:
  131. tenantId: %s
  132. registry: %s
  133. environmentType: "PublicCloud"
  134. auth:
  135. servicePrincipal:
  136. secretRef:
  137. clientSecret:
  138. name: az-secret
  139. key: clientsecret
  140. clientId:
  141. name: az-secret
  142. key: clientid`, testUsername, testURL)),
  143. },
  144. crClient: clientfake.NewClientBuilder().WithObjects(&v1.Secret{
  145. ObjectMeta: metav1.ObjectMeta{
  146. Name: "az-secret",
  147. Namespace: "foobar",
  148. },
  149. Data: map[string][]byte{
  150. "clientsecret": []byte("foo"),
  151. "clientid": []byte("bar"),
  152. },
  153. }).Build(),
  154. namespace: "foobar",
  155. ctx: context.Background(),
  156. accessTokenFetcher: func(acrRefreshToken, tenantID, registryURL, scope string) (string, error) {
  157. t.Fail()
  158. return "", nil
  159. },
  160. refreshTokenFetcher: func(aadAccessToken, tenantID, registryURL string) (string, error) {
  161. assert.Equal(t, "1234", aadAccessToken)
  162. assert.Equal(t, tenantID, testUsername)
  163. assert.Equal(t, registryURL, testURL)
  164. return "acrrefreshtoken", nil
  165. },
  166. clientSecretCreds: func(tenantID, clientID, clientSecret string, options *azidentity.ClientSecretCredentialOptions) (TokenGetter, error) {
  167. return &FakeTokenGetter{
  168. token: azcore.AccessToken{
  169. Token: "1234",
  170. },
  171. }, nil
  172. },
  173. },
  174. want: map[string][]byte{
  175. "username": []byte(defaultLoginUsername),
  176. "password": []byte("acrrefreshtoken"),
  177. },
  178. },
  179. }
  180. for _, tt := range tests {
  181. t.Run(tt.name, func(t *testing.T) {
  182. g := &Generator{
  183. clientSecretCreds: tt.args.clientSecretCreds,
  184. }
  185. got, err := g.generate(
  186. tt.args.ctx,
  187. tt.args.jsonSpec,
  188. tt.args.crClient,
  189. tt.args.namespace,
  190. tt.args.kubeClient,
  191. tt.args.accessTokenFetcher,
  192. tt.args.refreshTokenFetcher,
  193. )
  194. if (err != nil) != tt.wantErr {
  195. t.Errorf("Generator.Generate() error = %v, wantErr %v", err, tt.wantErr)
  196. return
  197. }
  198. if !reflect.DeepEqual(got, tt.want) {
  199. t.Errorf("Generator.Generate() = %v, want %v", got, tt.want)
  200. }
  201. })
  202. }
  203. }
  204. type FakeTokenGetter struct {
  205. token azcore.AccessToken
  206. err error
  207. }
  208. func (f *FakeTokenGetter) GetToken(_ context.Context, _ policy.TokenRequestOptions) (azcore.AccessToken, error) {
  209. return f.token, f.err
  210. }