Skip to content

Commit

Permalink
feat(azure): Add tests on AzureKeyvault backend argoproj-labs#421
Browse files Browse the repository at this point in the history
  • Loading branch information
YvesZelros committed Sep 1, 2023
1 parent 29bc743 commit 7427e3a
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: 1.17.8
go-version: 1.18.10

- name: Quality checks
run: make quality
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: 1.17.8
go-version: 1.18.10

- name: Install git-chglog
run: go install github.com/git-chglog/git-chglog/cmd/git-chglog@latest
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM index.docker.io/golang:1.17@sha256:55636cf1983628109e569690596b85077f45aca810a77904e8afad48b49aa500
FROM index.docker.io/golang:1.18.10@sha256:312240b2b016c2eecb2e27a8a4265fcafe6612bd9ebd5befb42c21672ed003ee

ADD go.mod go.mod
ADD go.sum go.sum
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/argoproj-labs/argocd-vault-plugin

go 1.17
go 1.18

replace (
github.com/googleapis/gnostic v0.5.7 => github.com/googleapis/gnostic v0.5.5
Expand Down
19 changes: 15 additions & 4 deletions pkg/backends/azurekeyvault.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package backends
import (
"context"
"fmt"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets"
"github.com/argoproj-labs/argocd-vault-plugin/pkg/utils"
Expand All @@ -11,13 +13,22 @@ import (

// AzureKeyVault is a struct for working with an Azure Key Vault backend
type AzureKeyVault struct {
Credential *azidentity.DefaultAzureCredential
Credential *azidentity.DefaultAzureCredential
ClientBuilder func(vaultURL string, credential azcore.TokenCredential, options *azsecrets.ClientOptions) (AzSecretsClient, error)
}

type AzSecretsClient interface {
GetSecret(ctx context.Context, name string, version string, options *azsecrets.GetSecretOptions) (azsecrets.GetSecretResponse, error)
NewListSecretPropertiesPager(options *azsecrets.ListSecretPropertiesOptions) *runtime.Pager[azsecrets.ListSecretPropertiesResponse]
}

// NewAzureKeyVaultBackend initializes a new Azure Key Vault backend
func NewAzureKeyVaultBackend(credential *azidentity.DefaultAzureCredential) *AzureKeyVault {
func NewAzureKeyVaultBackend(credential *azidentity.DefaultAzureCredential, clientBuilder func(vaultURL string, credential azcore.TokenCredential, options *azsecrets.ClientOptions) (*azsecrets.Client, error)) *AzureKeyVault {
return &AzureKeyVault{
Credential: credential,
ClientBuilder: func(vaultURL string, credential azcore.TokenCredential, options *azsecrets.ClientOptions) (AzSecretsClient, error) {
return clientBuilder(vaultURL, credential, options)
},
}
}

Expand All @@ -37,7 +48,7 @@ func (a *AzureKeyVault) GetSecrets(kvpath string, version string, _ map[string]s

VerboseOptionalVersion("Azure Key Vault list all secrets from vault %s", version, kvpath)

client, err := azsecrets.NewClient(kvpath, a.Credential, nil)
client, err := a.ClientBuilder(kvpath, a.Credential, nil)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -90,7 +101,7 @@ func (a *AzureKeyVault) GetIndividualSecret(kvpath, secret, version string, anno
VerboseOptionalVersion("Azure Key Vault getting individual secret %s from vault %s", version, secret, kvpath)

kvpath = fmt.Sprintf("https://%s.vault.azure.net", kvpath)
client, err := azsecrets.NewClient(kvpath, a.Credential, nil)
client, err := a.ClientBuilder(kvpath, a.Credential, nil)
if err != nil {
return nil, err
}
Expand Down
154 changes: 154 additions & 0 deletions pkg/backends/azurekeyvault_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package backends_test

import (
"context"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
"github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets"
"github.com/argoproj-labs/argocd-vault-plugin/pkg/backends"
"reflect"
"testing"
)

type mockClientProxy struct {
}

type MyError struct{}

func (m *MyError) Error() string {
return "boom"
}

func makeSecretProperties(id azsecrets.ID, enable bool) *azsecrets.SecretProperties {
return &azsecrets.SecretProperties{
ID: &id,
Attributes: &azsecrets.SecretAttributes{
Enabled: &enable,
},
}
}

func makeResponse(id azsecrets.ID, value string, err error) (azsecrets.GetSecretResponse, error) {
return azsecrets.GetSecretResponse{
Secret: azsecrets.Secret{
ID: &id,
Value: &value,
},
}, err
}

func (c *mockClientProxy) NewListSecretPropertiesPager(options *azsecrets.ListSecretPropertiesOptions) *runtime.Pager[azsecrets.ListSecretPropertiesResponse] {
var pageCount = 0
pager := runtime.NewPager(runtime.PagingHandler[azsecrets.ListSecretPropertiesResponse]{
More: func(current azsecrets.ListSecretPropertiesResponse) bool {
return pageCount == 0
},
Fetcher: func(ctx context.Context, current *azsecrets.ListSecretPropertiesResponse) (azsecrets.ListSecretPropertiesResponse, error) {
pageCount++
var a []*azsecrets.SecretProperties
a = append(a, makeSecretProperties("https://myvaultname.vault.azure.net/keys/simple/v2", true))
a = append(a, makeSecretProperties("https://myvaultname.vault.azure.net/keys/disabled/v2", false))
return azsecrets.ListSecretPropertiesResponse{
SecretPropertiesListResult: azsecrets.SecretPropertiesListResult{
Value: a,
},
}, nil
},
})
return pager
}

func (c *mockClientProxy) GetSecret(ctx context.Context, name string, version string, options *azsecrets.GetSecretOptions) (azsecrets.GetSecretResponse, error) {
if name == "simple" && (version == "" || version == "v1") {
return makeResponse("simple,v2", "a_value_v1", nil)
} else if name == "simple" && version == "v2" {
return makeResponse("simple,v2", "a_value_v2", nil)
}
return makeResponse("", "", &MyError{})
}

func NewAzureKeyVaultBackendMock() *backends.AzureKeyVault {
return &backends.AzureKeyVault{
Credential: nil,
ClientBuilder: func(vaultURL string, credential azcore.TokenCredential, options *azsecrets.ClientOptions) (backends.AzSecretsClient, error) {
return &mockClientProxy{}, nil
},
}
}

func TestAzGetSecret(t *testing.T) {
var keyVault = NewAzureKeyVaultBackendMock()
var data, err = keyVault.GetIndividualSecret("keyvault", "simple", "", nil)
if err != nil {
t.Fatalf("expected 0 errors but got: %s", err)
}
expected := "a_value_v1"
if !reflect.DeepEqual(expected, data) {
t.Errorf("expected: %s, got: %s.", expected, data)
}
}

func TestAzGetSecretWithVersion(t *testing.T) {
var keyVault = NewAzureKeyVaultBackendMock()
var data, err = keyVault.GetIndividualSecret("keyvault", "simple", "v2", nil)
if err != nil {
t.Fatalf("expected 0 errors but got: %s", err)
}
expected := "a_value_v2"
if !reflect.DeepEqual(expected, data) {
t.Errorf("expected: %s, got: %s.", expected, data)
}
}

func TestAzGetSecretWithError(t *testing.T) {
var keyVault = NewAzureKeyVaultBackendMock()
var _, err = keyVault.GetIndividualSecret("keyvault", "not_existing", "", nil)
if err == nil {
t.Fatalf("expected 1 errors but got nil")
}
}

func TestAzGetSecrets(t *testing.T) {
var keyVault = NewAzureKeyVaultBackendMock()
var res, err = keyVault.GetSecrets("keyvault", "", nil)

if err != nil {
t.Fatalf("expected 0 errors but got: %s", err)
}
expected := map[string]interface{}{
"simple": "a_value_v1",
}
if !reflect.DeepEqual(res, expected) {
t.Errorf("expected: %s, got: %s.", expected, res)
}
}

func TestAzGetSecretsVersionV1(t *testing.T) {
var keyVault = NewAzureKeyVaultBackendMock()
var res, err = keyVault.GetSecrets("keyvault", "v1", nil)

if err != nil {
t.Fatalf("expected 0 errors but got: %s", err)
}
expected := map[string]interface{}{
"simple": "a_value_v1",
}
if !reflect.DeepEqual(res, expected) {
t.Errorf("expected: %s, got: %s.", expected, res)
}
}

func TestAzGetSecretsVersionV2(t *testing.T) {
var keyVault = NewAzureKeyVaultBackendMock()
var res, err = keyVault.GetSecrets("keyvault", "v2", nil)

if err != nil {
t.Fatalf("expected 0 errors but got: %s", err)
}
expected := map[string]interface{}{
"simple": "a_value_v2",
}
if !reflect.DeepEqual(res, expected) {
t.Errorf("expected: %s, got: %s.", expected, res)
}
}
4 changes: 3 additions & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"context"
"fmt"
"github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets"
"os"
"strconv"
"strings"
Expand Down Expand Up @@ -191,7 +192,8 @@ func New(v *viper.Viper, co *Options) (*Config, error) {
if err != nil {
return nil, err
}
backend = backends.NewAzureKeyVaultBackend(cred)

backend = backends.NewAzureKeyVaultBackend(cred, azsecrets.NewClient)
}
case types.Sopsbackend:
{
Expand Down

0 comments on commit 7427e3a

Please sign in to comment.