| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- /*
- Copyright © 2025 ESO Maintainer Team
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- https://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package fake
- import (
- "context"
- "errors"
- "fmt"
- "reflect"
- "strings"
- "sync"
- vault "github.com/hashicorp/vault/api"
- "github.com/external-secrets/external-secrets/providers/v1/vault/util"
- )
- // LoginFn is a function type that represents logging in to Vault using a specific authentication method.
- type LoginFn func(ctx context.Context, authMethod vault.AuthMethod) (*vault.Secret, error)
- // Auth is a mock implementation of the Vault authentication interface for testing purposes.
- type Auth struct {
- LoginFn LoginFn
- }
- // Login logs in to Vault using the specified authentication method.
- func (f Auth) Login(ctx context.Context, authMethod vault.AuthMethod) (*vault.Secret, error) {
- return f.LoginFn(ctx, authMethod)
- }
- type ReadWithDataWithContextFn func(ctx context.Context, path string, data map[string][]string) (*vault.Secret, error)
- type ListWithContextFn func(ctx context.Context, path string) (*vault.Secret, error)
- type WriteWithContextFn func(ctx context.Context, path string, data map[string]any) (*vault.Secret, error)
- type DeleteWithContextFn func(ctx context.Context, path string) (*vault.Secret, error)
- type Logical struct {
- ReadWithDataWithContextFn ReadWithDataWithContextFn
- ListWithContextFn ListWithContextFn
- WriteWithContextFn WriteWithContextFn
- DeleteWithContextFn DeleteWithContextFn
- }
- func (f Logical) DeleteWithContext(ctx context.Context, path string) (*vault.Secret, error) {
- return f.DeleteWithContextFn(ctx, path)
- }
- func NewDeleteWithContextFn(secret map[string]any, err error) DeleteWithContextFn {
- return func(ctx context.Context, path string) (*vault.Secret, error) {
- vault := &vault.Secret{
- Data: secret,
- }
- return vault, err
- }
- }
- func buildDataResponse(secret map[string]any, err error) (*vault.Secret, error) {
- if secret == nil {
- return nil, err
- }
- return &vault.Secret{Data: secret}, err
- }
- func buildMetadataResponse(secret map[string]any, err error) (*vault.Secret, error) {
- if secret == nil {
- return nil, err
- }
- // If the secret already has the expected metadata structure, return as-is
- if _, hasCustomMetadata := secret["custom_metadata"]; hasCustomMetadata {
- return &vault.Secret{Data: secret}, err
- }
- // Otherwise, wrap in custom_metadata for backwards compatibility
- metadata := make(map[string]any)
- metadata["custom_metadata"] = secret
- return &vault.Secret{Data: metadata}, err
- }
- func NewReadWithContextFn(secret map[string]any, err error) ReadWithDataWithContextFn {
- return func(ctx context.Context, path string, data map[string][]string) (*vault.Secret, error) {
- return buildDataResponse(secret, err)
- }
- }
- func NewReadMetadataWithContextFn(secret map[string]any, err error) ReadWithDataWithContextFn {
- return func(ctx context.Context, path string, data map[string][]string) (*vault.Secret, error) {
- return buildMetadataResponse(secret, err)
- }
- }
- func NewReadWithDataAndMetadataFn(dataSecret, metadataSecret map[string]any, dataErr, metadataErr error) ReadWithDataWithContextFn {
- return func(ctx context.Context, path string, data map[string][]string) (*vault.Secret, error) {
- // Check if this is a metadata path request
- if strings.Contains(path, "/metadata/") {
- return buildMetadataResponse(metadataSecret, metadataErr)
- }
- // This is a data path request
- return buildDataResponse(dataSecret, dataErr)
- }
- }
- func NewWriteWithContextFn(secret map[string]any, err error) WriteWithContextFn {
- return func(ctx context.Context, path string, data map[string]any) (*vault.Secret, error) {
- return &vault.Secret{Data: secret}, err
- }
- }
- func ExpectWriteWithContextValue(expected map[string]any) WriteWithContextFn {
- return func(ctx context.Context, path string, data map[string]any) (*vault.Secret, error) {
- if strings.Contains(path, "metadata") {
- return &vault.Secret{Data: data}, nil
- }
- if !reflect.DeepEqual(expected, data) {
- return nil, fmt.Errorf("expected: %v, got: %v", expected, data)
- }
- return &vault.Secret{Data: data}, nil
- }
- }
- func ExpectWriteWithContextNoCall() WriteWithContextFn {
- return func(_ context.Context, path string, data map[string]any) (*vault.Secret, error) {
- return nil, errors.New("fail")
- }
- }
- func ExpectDeleteWithContextNoCall() DeleteWithContextFn {
- return func(ctx context.Context, path string) (*vault.Secret, error) {
- return nil, errors.New("fail")
- }
- }
- // ReadWithDataWithContext reads the secret at the specified path in Vault with additional data.
- func (f Logical) ReadWithDataWithContext(ctx context.Context, path string, data map[string][]string) (*vault.Secret, error) {
- return f.ReadWithDataWithContextFn(ctx, path, data)
- }
- // ListWithContext lists the secrets at the specified path in Vault.
- func (f Logical) ListWithContext(ctx context.Context, path string) (*vault.Secret, error) {
- return f.ListWithContextFn(ctx, path)
- }
- // WriteWithContext writes data to the specified path in Vault.
- func (f Logical) WriteWithContext(ctx context.Context, path string, data map[string]any) (*vault.Secret, error) {
- return f.WriteWithContextFn(ctx, path, data)
- }
- // RevokeSelfWithContextFn is a function type that represents revoking the Vault token associated with the current client.
- type RevokeSelfWithContextFn func(ctx context.Context, token string) error
- // LookupSelfWithContextFn is a function type that represents looking up the Vault token associated with the current client.
- type LookupSelfWithContextFn func(ctx context.Context) (*vault.Secret, error)
- // Token is a mock implementation of the Vault token interface for testing purposes.
- type Token struct {
- RevokeSelfWithContextFn RevokeSelfWithContextFn
- LookupSelfWithContextFn LookupSelfWithContextFn
- }
- // RevokeSelfWithContext revokes the token associated with the current client.
- func (f Token) RevokeSelfWithContext(ctx context.Context, token string) error {
- return f.RevokeSelfWithContextFn(ctx, token)
- }
- // LookupSelfWithContext looks up the token associated with the current client.
- func (f Token) LookupSelfWithContext(ctx context.Context) (*vault.Secret, error) {
- return f.LookupSelfWithContextFn(ctx)
- }
- // MockSetTokenFn is a function type that represents setting the Vault token.
- type MockSetTokenFn func(v string)
- // MockTokenFn is a function type that represents getting the Vault token.
- type MockTokenFn func() string
- // MockClearTokenFn is a function type that represents clearing the Vault token.
- type MockClearTokenFn func()
- // MockNamespaceFn is a function type that represents getting the Vault namespace.
- type MockNamespaceFn func() string
- // MockSetNamespaceFn is a function type that represents setting the Vault namespace.
- type MockSetNamespaceFn func(namespace string)
- // MockAddHeaderFn is a function type that represents adding a header to the Vault client requests.
- type MockAddHeaderFn func(key, value string)
- // VaultListResponse is a struct to represent the response from a Vault list operation.
- type VaultListResponse struct {
- Metadata *vault.Response
- Data *vault.Response
- }
- // NewAuthTokenFn returns a MockAuthToken that always returns a nil secret and nil error.
- func NewAuthTokenFn() Token {
- return Token{nil, func(context.Context) (*vault.Secret, error) {
- return &(vault.Secret{}), nil
- }}
- }
- // NewSetTokenFn returns a MockSetTokenFn that calls the provided functions in order.
- func NewSetTokenFn(ofn ...func(v string)) MockSetTokenFn {
- return func(v string) {
- for _, fn := range ofn {
- fn(v)
- }
- }
- }
- // NewTokenFn returns a MockTokenFn that always returns the provided string.
- func NewTokenFn(v string) MockTokenFn {
- return func() string {
- return v
- }
- }
- // VaultClient is a mock implementation of the Vault client interface for testing purposes.
- type VaultClient struct {
- MockLogical Logical
- MockAuth Auth
- MockAuthToken Token
- MockSetToken MockSetTokenFn
- MockToken MockTokenFn
- MockClearToken MockClearTokenFn
- MockNamespace MockNamespaceFn
- MockSetNamespace MockSetNamespaceFn
- MockAddHeader MockAddHeaderFn
- namespace string
- lock sync.RWMutex
- }
- // Logical returns the mock Logical.
- func (c *VaultClient) Logical() Logical {
- return c.MockLogical
- }
- // NewVaultLogical returns a new vault Logical instance.
- func NewVaultLogical() Logical {
- logical := Logical{
- ReadWithDataWithContextFn: func(context.Context, string, map[string][]string) (*vault.Secret, error) {
- return nil, nil
- },
- ListWithContextFn: func(context.Context, string) (*vault.Secret, error) {
- return nil, nil
- },
- WriteWithContextFn: func(context.Context, string, map[string]any) (*vault.Secret, error) {
- return nil, nil
- },
- }
- return logical
- }
- // Auth returns the mock authentication.
- func (c *VaultClient) Auth() Auth {
- return c.MockAuth
- }
- // NewVaultAuth returns a mock authentication Auth.
- func NewVaultAuth() Auth {
- auth := Auth{
- LoginFn: func(context.Context, vault.AuthMethod) (*vault.Secret, error) {
- return nil, nil
- },
- }
- return auth
- }
- // AuthToken returns the mock authentication token interface.
- func (c *VaultClient) AuthToken() Token {
- return c.MockAuthToken
- }
- // SetToken sets the authentication token.
- func (c *VaultClient) SetToken(v string) {
- c.MockSetToken(v)
- }
- // Token returns the current authentication token.
- func (c *VaultClient) Token() string {
- return c.MockToken()
- }
- // ClearToken clears the current authentication token.
- func (c *VaultClient) ClearToken() {
- c.MockClearToken()
- }
- // Namespace returns the current Vault namespace.
- func (c *VaultClient) Namespace() string {
- c.lock.RLock()
- defer c.lock.RUnlock()
- ns := c.namespace
- return ns
- }
- // SetNamespace sets the Vault namespace.
- func (c *VaultClient) SetNamespace(namespace string) {
- c.lock.Lock()
- defer c.lock.Unlock()
- c.namespace = namespace
- }
- // AddHeader adds a header to the Vault client requests.
- func (c *VaultClient) AddHeader(key, value string) {
- c.MockAddHeader(key, value)
- }
- // ClientWithLoginMock returns a client with mocked login functionality.
- func ClientWithLoginMock(config *vault.Config) (vaultutil.Client, error) {
- return clientWithLoginMockOptions(config)
- }
- // ModifiableClientWithLoginMock returns a factory function that creates clients with customizable mock behavior.
- func ModifiableClientWithLoginMock(opts ...func(cl *VaultClient)) func(config *vault.Config) (vaultutil.Client, error) {
- return func(config *vault.Config) (vaultutil.Client, error) {
- return clientWithLoginMockOptions(config, opts...)
- }
- }
- func clientWithLoginMockOptions(_ *vault.Config, opts ...func(cl *VaultClient)) (vaultutil.Client, error) {
- cl := &VaultClient{
- MockAuthToken: NewAuthTokenFn(),
- MockSetToken: NewSetTokenFn(),
- MockToken: NewTokenFn(""),
- MockAuth: NewVaultAuth(),
- MockLogical: NewVaultLogical(),
- }
- for _, opt := range opts {
- opt(cl)
- }
- return &vaultutil.VaultClient{
- SetTokenFunc: cl.SetToken,
- TokenFunc: cl.Token,
- ClearTokenFunc: cl.ClearToken,
- AuthField: cl.Auth(),
- AuthTokenField: cl.AuthToken(),
- LogicalField: cl.Logical(),
- NamespaceFunc: cl.Namespace,
- SetNamespaceFunc: cl.SetNamespace,
- AddHeaderFunc: cl.AddHeader,
- }, nil
- }
|