mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-14 11:03:09 +02:00
3eae0c5f68
* cloud-foundry & sonar from vault * add vault development hint * don't abort on vault errors * cloudfoundry make credentialsId only mandatory when vault is not configured * add vault ref to step ymls * rename vaultAddress to vaultServerUrl * rename PIPER_vaultRole* to PIPER_vaultAppRole* * add resourceRef for detect step * fix error when no namespace is set * added debug logs * added debug logs * fix vault resolving * add vaultCustomBasePath * rename vault_test.go to client_test.go * refactored vault logging * refactored config param lookup for vault * added tüddelchen * rename vaultCustomBasePath to vaultPath * fix tests * change lookup path for group secrets * fix interpolation tests * added vault resource ref to versioning * execute go generate * rename Approle to AppRole * change verbose back to false Co-authored-by: Leander Schulz <leander.schulz01@sap.com> Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>
177 lines
4.8 KiB
Go
177 lines
4.8 KiB
Go
package vault
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/mock"
|
|
|
|
mocks "github.com/SAP/jenkins-library/pkg/vault/mocks"
|
|
|
|
"github.com/hashicorp/vault/api"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
type SecretData = map[string]interface{}
|
|
|
|
const (
|
|
sysLookupPath = "sys/internal/ui/mounts/"
|
|
)
|
|
|
|
func TestGetKV2Secret(t *testing.T) {
|
|
|
|
t.Run("Test missing secret", func(t *testing.T) {
|
|
vaultMock := &mocks.VaultMock{}
|
|
client := Client{vaultMock}
|
|
setupMockKvV2(vaultMock)
|
|
vaultMock.On("Read", "secret/data/notexist").Return(nil, nil)
|
|
secret, err := client.GetKvSecret("secret/notexist")
|
|
assert.NoError(t, err, "Missing secret should not an error")
|
|
assert.Nil(t, secret)
|
|
})
|
|
|
|
t.Run("Test parsing KV2 secrets", func(t *testing.T) {
|
|
t.Parallel()
|
|
const secretAPIPath = "secret/data/test"
|
|
const secretName = "secret/test"
|
|
t.Run("Getting secret from KV engine (v2)", func(t *testing.T) {
|
|
vaultMock := &mocks.VaultMock{}
|
|
setupMockKvV2(vaultMock)
|
|
client := Client{vaultMock}
|
|
vaultMock.On("Read", secretAPIPath).Return(kv2Secret(SecretData{"key1": "value1"}), nil)
|
|
secret, err := client.GetKvSecret(secretName)
|
|
assert.NoError(t, err, "Expect GetKvSecret to succeed")
|
|
assert.Equal(t, "value1", secret["key1"])
|
|
|
|
})
|
|
|
|
t.Run("error is thrown when 'data' field can't be parsed", func(t *testing.T) {
|
|
vaultMock := &mocks.VaultMock{}
|
|
setupMockKvV2(vaultMock)
|
|
client := Client{vaultMock}
|
|
vaultMock.On("Read", secretAPIPath).Return(kv2Secret(SecretData{"key1": "value1", "key2": 5}), nil)
|
|
secret, err := client.GetKvSecret(secretName)
|
|
assert.Error(t, err, "Excpected to fail since value is wrong data type")
|
|
assert.Nil(t, secret)
|
|
|
|
})
|
|
|
|
t.Run("error is thrown when data field is missing", func(t *testing.T) {
|
|
vaultMock := &mocks.VaultMock{}
|
|
setupMockKvV2(vaultMock)
|
|
client := Client{vaultMock}
|
|
vaultMock.On("Read", secretAPIPath).Return(kv1Secret(SecretData{"key1": "value1"}), nil)
|
|
secret, err := client.GetKvSecret(secretName)
|
|
assert.Error(t, err, "Expected to fail since 'data' field is missing")
|
|
assert.Nil(t, secret)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestGetKV1Secret(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const secretName = "secret/test"
|
|
|
|
t.Run("Test missing secret", func(t *testing.T) {
|
|
vaultMock := &mocks.VaultMock{}
|
|
setupMockKvV1(vaultMock)
|
|
client := Client{vaultMock}
|
|
|
|
vaultMock.On("Read", mock.AnythingOfType("string")).Return(nil, nil)
|
|
secret, err := client.GetKvSecret("secret/notexist")
|
|
assert.NoError(t, err, "Missing secret should not an error")
|
|
assert.Nil(t, secret)
|
|
})
|
|
|
|
t.Run("Test parsing KV1 secrets", func(t *testing.T) {
|
|
vaultMock := &mocks.VaultMock{}
|
|
setupMockKvV1(vaultMock)
|
|
client := Client{vaultMock}
|
|
|
|
vaultMock.On("Read", secretName).Return(kv1Secret(SecretData{"key1": "value1"}), nil)
|
|
secret, err := client.GetKvSecret(secretName)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "value1", secret["key1"])
|
|
})
|
|
|
|
t.Run("Test parsing KV1 secrets", func(t *testing.T) {
|
|
vaultMock := &mocks.VaultMock{}
|
|
setupMockKvV1(vaultMock)
|
|
vaultMock.On("Read", secretName).Return(kv1Secret(SecretData{"key1": 5}), nil)
|
|
client := Client{vaultMock}
|
|
|
|
secret, err := client.GetKvSecret(secretName)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, secret)
|
|
|
|
})
|
|
}
|
|
|
|
func TestUnknownKvVersion(t *testing.T) {
|
|
vaultMock := &mocks.VaultMock{}
|
|
client := Client{vaultMock}
|
|
|
|
vaultMock.On("Read", "sys/internal/ui/mounts/secret/secret").Return(&api.Secret{
|
|
Data: map[string]interface{}{
|
|
"path": "secret",
|
|
"options": map[string]interface{}{
|
|
"version": "3",
|
|
},
|
|
}}, nil)
|
|
|
|
secret, err := client.GetKvSecret("/secret/secret")
|
|
assert.EqualError(t, err, "KV Engine in version 3 is currently not supported")
|
|
assert.Nil(t, secret)
|
|
|
|
}
|
|
|
|
func setupMockKvV2(vaultMock *mocks.VaultMock) {
|
|
vaultMock.On("Read", mock.MatchedBy(func(path string) bool {
|
|
return strings.HasPrefix(path, sysLookupPath)
|
|
})).Return(func(path string) *api.Secret {
|
|
pathComponents := strings.Split(strings.TrimPrefix(path, "sys/internal/ui/mounts/"), "/")
|
|
mountpath := "/"
|
|
if len(pathComponents) > 1 {
|
|
mountpath = pathComponents[0]
|
|
}
|
|
return &api.Secret{
|
|
Data: map[string]interface{}{
|
|
"path": mountpath,
|
|
"options": map[string]interface{}{
|
|
"version": "2",
|
|
},
|
|
},
|
|
}
|
|
}, nil)
|
|
}
|
|
|
|
func setupMockKvV1(vaultMock *mocks.VaultMock) {
|
|
vaultMock.On("Read", mock.MatchedBy(func(path string) bool {
|
|
return strings.HasPrefix(path, sysLookupPath)
|
|
})).Return(func(path string) *api.Secret {
|
|
pathComponents := strings.Split(strings.TrimPrefix(path, "sys/internal/ui/mounts/"), "/")
|
|
mountpath := "/"
|
|
if len(pathComponents) > 1 {
|
|
mountpath = pathComponents[0]
|
|
}
|
|
return &api.Secret{
|
|
Data: map[string]interface{}{
|
|
"path": mountpath,
|
|
},
|
|
}
|
|
}, nil)
|
|
}
|
|
|
|
func kv1Secret(data SecretData) *api.Secret {
|
|
return &api.Secret{
|
|
Data: data,
|
|
}
|
|
}
|
|
|
|
func kv2Secret(data SecretData) *api.Secret {
|
|
return &api.Secret{
|
|
Data: SecretData{"data": data},
|
|
}
|
|
}
|