Просмотр исходного кода

feat(dvls): add name support for entries (#6099)

Co-authored-by: Gergely Bräutigam <gergely.brautigam@sap.com>
Richard Boisvert 1 месяц назад
Родитель
Сommit
cdb74afea4

+ 5 - 0
apis/externalsecrets/v1/secretstore_dvls_types.go

@@ -26,6 +26,11 @@ type DVLSProvider struct {
 	// +kubebuilder:validation:Required
 	ServerURL string `json:"serverUrl"`
 
+	// Vault is the name or UUID of the vault to fetch secrets from.
+	// When omitted, the vault must be specified in the secret key using the legacy format "<vault-id>/<entry-id>".
+	// +optional
+	Vault string `json:"vault,omitempty"`
+
 	// Insecure allows connecting to DVLS over plain HTTP.
 	// This is NOT RECOMMENDED for production use.
 	// Set to true only if you understand the security implications.

+ 5 - 0
config/crds/bases/external-secrets.io_clustersecretstores.yaml

@@ -1900,6 +1900,11 @@ spec:
                       serverUrl:
                         description: ServerURL is the DVLS instance URL (e.g., https://dvls.example.com).
                         type: string
+                      vault:
+                        description: |-
+                          Vault is the name or UUID of the vault to fetch secrets from.
+                          When omitted, the vault must be specified in the secret key using the legacy format "<vault-id>/<entry-id>".
+                        type: string
                     required:
                     - auth
                     - serverUrl

+ 5 - 0
config/crds/bases/external-secrets.io_secretstores.yaml

@@ -1900,6 +1900,11 @@ spec:
                       serverUrl:
                         description: ServerURL is the DVLS instance URL (e.g., https://dvls.example.com).
                         type: string
+                      vault:
+                        description: |-
+                          Vault is the name or UUID of the vault to fetch secrets from.
+                          When omitted, the vault must be specified in the secret key using the legacy format "<vault-id>/<entry-id>".
+                        type: string
                     required:
                     - auth
                     - serverUrl

+ 10 - 0
deploy/crds/bundle.yaml

@@ -4019,6 +4019,11 @@ spec:
                         serverUrl:
                           description: ServerURL is the DVLS instance URL (e.g., https://dvls.example.com).
                           type: string
+                        vault:
+                          description: |-
+                            Vault is the name or UUID of the vault to fetch secrets from.
+                            When omitted, the vault must be specified in the secret key using the legacy format "<vault-id>/<entry-id>".
+                          type: string
                       required:
                         - auth
                         - serverUrl
@@ -16125,6 +16130,11 @@ spec:
                         serverUrl:
                           description: ServerURL is the DVLS instance URL (e.g., https://dvls.example.com).
                           type: string
+                        vault:
+                          description: |-
+                            Vault is the name or UUID of the vault to fetch secrets from.
+                            When omitted, the vault must be specified in the secret key using the legacy format "<vault-id>/<entry-id>".
+                          type: string
                       required:
                         - auth
                         - serverUrl

+ 13 - 0
docs/api/spec.md

@@ -3243,6 +3243,19 @@ string
 </tr>
 <tr>
 <td>
+<code>vault</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>Vault is the name or UUID of the vault to fetch secrets from.
+When omitted, the vault must be specified in the secret key using the legacy format &ldquo;<vault-id>/<entry-id>&rdquo;.</p>
+</td>
+</tr>
+<tr>
+<td>
 <code>insecure</code></br>
 <em>
 bool

+ 40 - 7
docs/provider/devolutions-server.md

@@ -35,6 +35,7 @@ kubectl create secret generic dvls-credentials \
 | Field | Description |
 |-------|-------------|
 | `serverUrl` | The URL of your DVLS instance (e.g., `https://dvls.example.com`) |
+| `vault` | (Optional) The name or UUID of the vault to fetch secrets from. When omitted, the vault must be specified in the secret key using the legacy `<vault-id>/<entry-id>` format. |
 | `insecure` | (Optional) Set to `true` to allow plain HTTP connections. **Not recommended for production.** |
 | `auth.secretRef.appId` | Reference to the secret containing the Application ID |
 | `auth.secretRef.appSecret` | Reference to the secret containing the Application Secret |
@@ -43,12 +44,41 @@ kubectl create secret generic dvls-credentials \
 
 ## Referencing Secrets
 
-Secrets are referenced using the format: `<vault-id>/<entry-id>`
+Entries can be referenced by **UUID** or **name**:
 
-- **vault-id**: The UUID of the vault containing the entry
-- **entry-id**: The UUID of the credential entry
+| Format | Example |
+|--------|---------|
+| Entry UUID | `7c9e6679-7425-40de-944b-e07fc1f90ae7` |
+| Entry name | `db-credentials` |
+| Entry name with folder path | `infrastructure/databases/db-credentials` |
+| Folder path with backslashes | `infrastructure\databases\db-credentials` |
 
-You can find these UUIDs in the DVLS web interface by viewing the entry properties.
+The vault is configured in the SecretStore's `vault` field (name or UUID), so the key only needs to identify the entry.
+
+### Folder paths
+
+If an entry is inside a folder, you can include the folder path before the entry name. Both forward slashes (`/`) and backslashes (`\`) are accepted as path separators:
+
+```text
+folder/subfolder/entry-name
+folder\subfolder\entry-name
+```
+
+**Note:** When using backslashes in YAML, you must escape them with a double backslash (`\\`):
+
+```yaml
+key: "folder\\subfolder\\entry-name"
+```
+
+Forward slashes do not need escaping and are recommended for simplicity.
+
+**Important:** Entry names containing forward slashes (`/`) or backslashes (`\`) are not supported with name-based lookups, as those characters are interpreted as path separators. Use the entry UUID instead.
+
+The folder path is **optional**. Without a path, the provider searches across all folders in the vault. If multiple entries share the same name in different folders, you can either specify the folder path or use the entry UUID to disambiguate.
+
+**Name-based lookups** resolve the name to a UUID at runtime via an API call. If multiple credential entries match, an error is returned. For write-heavy scenarios (frequent `PushSecret` operations), prefer UUID references to avoid the extra lookup per operation.
+
+You can find UUIDs in the DVLS web interface by viewing the entry properties.
 
 ## Supported Credential Types
 
@@ -97,7 +127,6 @@ The DVLS provider supports pushing secrets back to DVLS:
 
 - **GetAllSecrets**: The `find` operation for discovering secrets is not currently supported
 - **Custom CA Certificates**: Custom TLS certificates for self-signed DVLS instances are not yet supported. Use the `SSL_CERT_FILE` environment variable as a workaround
-- **Name-based lookups**: Currently only UUID-based references (`vault-id/entry-id`) are supported. Path/name-based lookups are planned for future releases
 - **Certificate entries**: Certificate entry types (`Document/Certificate`) are not currently supported. Only Credential entries are supported
 
 ## Troubleshooting
@@ -114,7 +143,11 @@ If you receive authentication errors:
 
 If an entry cannot be found:
 
-1. Verify the vault UUID and entry UUID are correct
+1. Verify the vault and entry references are correct (UUID or name)
 2. Ensure the application has at least read access to the vault
 3. Check that the entry exists and is a Credential or Secret type entry
-4. Ensure the application has at least read, view password, and connect (execute) permissions on the entry.
+4. Ensure the application has at least read, view password, and connect (execute) permissions on the entry
+
+### Multiple Entries Found
+
+If you receive a "multiple entries found" error when using name-based references, it means more than one credential entry shares the same name in the vault. Use the entry UUID instead of the name to target the correct entry.

+ 7 - 7
docs/snippets/dvls-external-secret.yaml

@@ -1,5 +1,5 @@
 ---
-# Fetch a single property from a credential entry
+# Fetch a single property from a credential entry by name
 apiVersion: external-secrets.io/v1
 kind: ExternalSecret
 metadata:
@@ -15,14 +15,14 @@ spec:
   data:
     - secretKey: username
       remoteRef:
-        key: 'vault-uuid/entry-uuid'
+        key: 'db-credentials'
         property: username
     - secretKey: password
       remoteRef:
-        key: 'vault-uuid/entry-uuid'
+        key: 'db-credentials'
         property: password
 ---
-# Fetch all fields from a credential entry
+# Fetch all fields from a credential entry with folder path
 apiVersion: external-secrets.io/v1
 kind: ExternalSecret
 metadata:
@@ -37,9 +37,9 @@ spec:
     creationPolicy: Owner
   dataFrom:
     - extract:
-        key: 'vault-uuid/entry-uuid'
+        key: 'infrastructure/apis/my-api-key'
 ---
-# Fetch a Secret entry (Access Code type)
+# Fetch a Secret entry (Access Code type) by UUID
 apiVersion: external-secrets.io/v1
 kind: ExternalSecret
 metadata:
@@ -55,5 +55,5 @@ spec:
   data:
     - secretKey: secret
       remoteRef:
-        key: 'vault-uuid/secret-entry-uuid'
+        key: '<entry-uuid>'
         property: password

+ 3 - 1
docs/snippets/dvls-push-secret.yaml

@@ -14,4 +14,6 @@ spec:
     - match:
         secretKey: password
         remoteRef:
-          remoteKey: 'vault-uuid/entry-uuid'
+          # When vault is set in the SecretStore, remoteKey is the entry name
+          # (or path/name). Without vault, use the legacy 'vault-uuid/entry-uuid' format.
+          remoteKey: 'db-credentials'

+ 1 - 0
docs/snippets/dvls-secret-store.yaml

@@ -7,6 +7,7 @@ spec:
   provider:
     dvls:
       serverUrl: 'https://dvls.example.com'
+      vault: 'my-vault'
       auth:
         secretRef:
           appId:

+ 1 - 1
go.mod

@@ -195,7 +195,7 @@ require (
 	github.com/BurntSushi/toml v1.5.0 // indirect
 	github.com/DelineaXPM/dsv-sdk-go/v2 v2.2.0 // indirect
 	github.com/DelineaXPM/tss-sdk-go/v3 v3.0.2 // indirect
-	github.com/Devolutions/go-dvls v0.15.0 // indirect
+	github.com/Devolutions/go-dvls v0.19.1 // indirect
 	github.com/Microsoft/go-winio v0.6.2 // indirect
 	github.com/Onboardbase/go-cryptojs-aes-decrypt v0.0.0-20230430095000-27c0d3a9016d // indirect
 	github.com/ProtonMail/go-crypto v1.4.0 // indirect

+ 2 - 2
go.sum

@@ -132,8 +132,8 @@ github.com/DelineaXPM/dsv-sdk-go/v2 v2.2.0 h1:62E66sDf+Hs1TChuu3R7d+0U5s7yV84QIO
 github.com/DelineaXPM/dsv-sdk-go/v2 v2.2.0/go.mod h1:58Pflli0BtqeF0VgluDSSVE5QlIfLOJvat0JSvo/d70=
 github.com/DelineaXPM/tss-sdk-go/v3 v3.0.2 h1:8wRzxlo6fujNoDbnp6PnawY3moxqQelxpJGzTHG7Qoo=
 github.com/DelineaXPM/tss-sdk-go/v3 v3.0.2/go.mod h1:VmyoHQ25FhSVHTI3/ptQNOviNEMfCy2ALAf/3E4Eqxg=
-github.com/Devolutions/go-dvls v0.15.0 h1:T/uUK0sKli7i9yxcZb9/Lia/uUwmLi1phryNkYEp5t4=
-github.com/Devolutions/go-dvls v0.15.0/go.mod h1:4O3lb/RK1P1cDwU5auVi7CM4gRER7EuwyLwMVuEZjgg=
+github.com/Devolutions/go-dvls v0.19.1 h1:7EEHGr7qRJ4kYeFmBVf6PP7oSDDtw0EUdMi7UB3awns=
+github.com/Devolutions/go-dvls v0.19.1/go.mod h1:I0YI4GujLbbUojNnKLGVguiWUvnE2J9ltgwxTmtTRyo=
 github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
 github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
 github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=

+ 29 - 7
providers/v1/dvls/auth.go

@@ -28,26 +28,48 @@ import (
 	"github.com/external-secrets/external-secrets/runtime/esutils/resolvers"
 )
 
-// NewDVLSClient creates a new authenticated DVLS client.
-func NewDVLSClient(ctx context.Context, kube kclient.Client, storeKind, namespace string, provider *esv1.DVLSProvider) (credentialClient, error) {
+type realVaultClient struct {
+	vaults *dvls.Vaults
+}
+
+func (r *realVaultClient) GetByName(ctx context.Context, name string) (dvls.Vault, error) {
+	return r.vaults.GetByNameWithContext(ctx, name)
+}
+
+// NewDVLSClient creates a new authenticated DVLS client and resolves the vault.
+func NewDVLSClient(ctx context.Context, kube kclient.Client, storeKind, namespace string, provider *esv1.DVLSProvider) (credentialClient, string, error) {
 	if provider == nil {
-		return nil, fmt.Errorf("missing provider configuration")
+		return nil, "", fmt.Errorf("missing provider configuration")
 	}
 
 	appID, err := resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, &provider.Auth.SecretRef.AppID)
 	if err != nil {
-		return nil, fmt.Errorf("failed to get appId: %w", err)
+		return nil, "", fmt.Errorf("failed to get appId: %w", err)
 	}
 
 	appSecret, err := resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, &provider.Auth.SecretRef.AppSecret)
 	if err != nil {
-		return nil, fmt.Errorf("failed to get appSecret: %w", err)
+		return nil, "", fmt.Errorf("failed to get appSecret: %w", err)
 	}
 
 	client, err := dvls.NewClient(appID, appSecret, provider.ServerURL)
 	if err != nil {
-		return nil, fmt.Errorf("failed to create DVLS client: %w", err)
+		return nil, "", fmt.Errorf("failed to create DVLS client: %w", err)
+	}
+
+	credClient := &realCredentialClient{cred: client.Entries.Credential}
+
+	// When vault is empty, the provider operates in legacy mode where
+	// the vault ID is expected in the secret key (<vault-id>/<entry-id>).
+	if provider.Vault == "" {
+		return credClient, "", nil
+	}
+
+	vaultCl := &realVaultClient{vaults: client.Vaults}
+	vaultID, err := resolveVaultRef(ctx, provider.Vault, vaultCl)
+	if err != nil {
+		return nil, "", fmt.Errorf("failed to resolve vault: %w", err)
 	}
 
-	return &realCredentialClient{cred: client.Entries.Credential}, nil
+	return credClient, vaultID, nil
 }

+ 10 - 7
providers/v1/dvls/auth_test.go

@@ -90,6 +90,7 @@ func TestNewDVLSClient_CrossNamespaceSecurityConstraint(t *testing.T) {
 
 			provider := &esv1.DVLSProvider{
 				ServerURL: testServerURL,
+				Vault:     testVaultUUID,
 				Auth: esv1.DVLSAuth{
 					SecretRef: esv1.DVLSAuthSecretRef{
 						AppID: esmeta.SecretKeySelector{
@@ -106,19 +107,21 @@ func TestNewDVLSClient_CrossNamespaceSecurityConstraint(t *testing.T) {
 				},
 			}
 
-			client, err := NewDVLSClient(context.Background(), kube, tt.storeKind, tt.namespace, provider)
+			credClient, vaultID, err := NewDVLSClient(context.Background(), kube, tt.storeKind, tt.namespace, provider)
 
 			if tt.expectError {
 				require.Error(t, err)
-				require.Nil(t, client)
+				require.Nil(t, credClient)
+				require.Empty(t, vaultID)
 				if tt.errorMsg != "" {
 					assert.Contains(t, err.Error(), tt.errorMsg)
 				}
-			} else if err != nil {
-				// Verify Kubernetes secret access succeeded (DVLS connection will fail due to fake server).
-				assert.NotContains(t, err.Error(), "failed to get appId")
-				assert.NotContains(t, err.Error(), "failed to get appSecret")
-				assert.NotContains(t, err.Error(), "cannot get Kubernetes secret")
+			} else {
+				// DVLS connection will fail due to fake server URL, but we should
+				// have gotten past secret resolution. Verify the error comes from
+				// the DVLS client creation step, not from Kubernetes secret access.
+				require.Error(t, err)
+				assert.Contains(t, err.Error(), "failed to create DVLS client")
 			}
 		})
 	}

+ 195 - 25
providers/v1/dvls/client.go

@@ -20,32 +20,48 @@ import (
 	"context"
 	"errors"
 	"fmt"
-	"net/http"
 	"strings"
+	"sync"
 
 	"github.com/Devolutions/go-dvls"
+	"github.com/google/uuid"
 	corev1 "k8s.io/api/core/v1"
 
 	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
 )
 
-const errFailedToGetEntry = "failed to get entry: %w"
+const (
+	errFailedToGetEntry = "failed to get entry: %w"
+	errVaultNotFound    = "vault %q was not found or has been deleted: %w"
+)
 
 var errNotImplemented = errors.New("not implemented")
 
 var _ esv1.SecretsClient = &Client{}
 
 // Client implements the SecretsClient interface for DVLS.
+// The nameCache maps entry name/path keys to resolved UUIDs, avoiding
+// repeated GetEntries calls during a single reconciliation. The cache is
+// not persisted: each reconciliation creates a new Client via NewClient,
+// so stale entries (e.g. deleted or renamed) are naturally discarded.
 type Client struct {
-	dvls credentialClient
+	cred      credentialClient
+	vaultID   string
+	mu        sync.RWMutex
+	nameCache map[string]string
 }
 
 type credentialClient interface {
 	GetByID(ctx context.Context, vaultID, entryID string) (dvls.Entry, error)
+	GetEntries(ctx context.Context, vaultID string, opts dvls.GetEntriesOptions) ([]dvls.Entry, error)
 	Update(ctx context.Context, entry dvls.Entry) (dvls.Entry, error)
 	DeleteByID(ctx context.Context, vaultID, entryID string) error
 }
 
+type vaultGetter interface {
+	GetByName(ctx context.Context, name string) (dvls.Vault, error)
+}
+
 type realCredentialClient struct {
 	cred *dvls.EntryCredentialService
 }
@@ -54,6 +70,10 @@ func (r *realCredentialClient) GetByID(ctx context.Context, vaultID, entryID str
 	return r.cred.GetByIdWithContext(ctx, vaultID, entryID)
 }
 
+func (r *realCredentialClient) GetEntries(ctx context.Context, vaultID string, opts dvls.GetEntriesOptions) ([]dvls.Entry, error) {
+	return r.cred.GetEntriesWithContext(ctx, vaultID, opts)
+}
+
 func (r *realCredentialClient) Update(ctx context.Context, entry dvls.Entry) (dvls.Entry, error) {
 	return r.cred.UpdateWithContext(ctx, entry)
 }
@@ -63,18 +83,24 @@ func (r *realCredentialClient) DeleteByID(ctx context.Context, vaultID, entryID
 }
 
 // NewClient creates a new DVLS secrets client.
-func NewClient(dvlsClient credentialClient) *Client {
-	return &Client{dvls: dvlsClient}
+func NewClient(cred credentialClient, vaultID string) *Client {
+	return &Client{cred: cred, vaultID: vaultID, nameCache: make(map[string]string)}
 }
 
 // GetSecret retrieves a secret from DVLS.
 func (c *Client) GetSecret(ctx context.Context, ref esv1.ExternalSecretDataRemoteRef) ([]byte, error) {
-	vaultID, entryID, err := c.parseSecretRef(ref.Key)
+	vaultID, entryID, err := c.resolveRef(ctx, ref.Key)
+	if isNotFoundError(err) {
+		return nil, esv1.NoSecretErr
+	}
 	if err != nil {
 		return nil, err
 	}
 
-	entry, err := c.dvls.GetByID(ctx, vaultID, entryID)
+	entry, err := c.cred.GetByID(ctx, vaultID, entryID)
+	if isVaultNotFoundError(err) {
+		return nil, fmt.Errorf(errVaultNotFound, vaultID, err)
+	}
 	if isNotFoundError(err) {
 		return nil, esv1.NoSecretErr
 	}
@@ -82,7 +108,7 @@ func (c *Client) GetSecret(ctx context.Context, ref esv1.ExternalSecretDataRemot
 		return nil, fmt.Errorf(errFailedToGetEntry, err)
 	}
 
-	secretMap, err := c.entryToSecretMap(entry)
+	secretMap, err := entryToSecretMap(entry)
 	if err != nil {
 		return nil, err
 	}
@@ -102,12 +128,18 @@ func (c *Client) GetSecret(ctx context.Context, ref esv1.ExternalSecretDataRemot
 
 // GetSecretMap retrieves all fields from a DVLS entry.
 func (c *Client) GetSecretMap(ctx context.Context, ref esv1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
-	vaultID, entryID, err := c.parseSecretRef(ref.Key)
+	vaultID, entryID, err := c.resolveRef(ctx, ref.Key)
+	if isNotFoundError(err) {
+		return nil, esv1.NoSecretErr
+	}
 	if err != nil {
 		return nil, err
 	}
 
-	entry, err := c.dvls.GetByID(ctx, vaultID, entryID)
+	entry, err := c.cred.GetByID(ctx, vaultID, entryID)
+	if isVaultNotFoundError(err) {
+		return nil, fmt.Errorf(errVaultNotFound, vaultID, err)
+	}
 	if isNotFoundError(err) {
 		return nil, esv1.NoSecretErr
 	}
@@ -115,7 +147,7 @@ func (c *Client) GetSecretMap(ctx context.Context, ref esv1.ExternalSecretDataRe
 		return nil, fmt.Errorf(errFailedToGetEntry, err)
 	}
 
-	return c.entryToSecretMap(entry)
+	return entryToSecretMap(entry)
 }
 
 // GetAllSecrets is not implemented for DVLS.
@@ -128,7 +160,13 @@ func (c *Client) PushSecret(ctx context.Context, secret *corev1.Secret, data esv
 	if secret == nil {
 		return errors.New("secret is required for DVLS push")
 	}
-	vaultID, entryID, err := c.parseSecretRef(data.GetRemoteKey())
+	vaultID, entryID, err := c.resolveRef(ctx, data.GetRemoteKey())
+	if isVaultNotFoundError(err) {
+		return fmt.Errorf(errVaultNotFound, c.vaultID, err)
+	}
+	if isNotFoundError(err) {
+		return fmt.Errorf("entry %q not found: entry must exist before pushing secrets", data.GetRemoteKey())
+	}
 	if err != nil {
 		return err
 	}
@@ -138,7 +176,10 @@ func (c *Client) PushSecret(ctx context.Context, secret *corev1.Secret, data esv
 		return err
 	}
 
-	existingEntry, err := c.dvls.GetByID(ctx, vaultID, entryID)
+	existingEntry, err := c.cred.GetByID(ctx, vaultID, entryID)
+	if isVaultNotFoundError(err) {
+		return fmt.Errorf(errVaultNotFound, vaultID, err)
+	}
 	if isNotFoundError(err) {
 		return fmt.Errorf("entry %s not found in vault %s: entry must exist before pushing secrets", entryID, vaultID)
 	}
@@ -151,7 +192,7 @@ func (c *Client) PushSecret(ctx context.Context, secret *corev1.Secret, data esv
 		return err
 	}
 
-	_, err = c.dvls.Update(ctx, existingEntry)
+	_, err = c.cred.Update(ctx, existingEntry)
 	if err != nil {
 		return fmt.Errorf("failed to update entry: %w", err)
 	}
@@ -160,21 +201,33 @@ func (c *Client) PushSecret(ctx context.Context, secret *corev1.Secret, data esv
 
 // DeleteSecret deletes a secret from DVLS.
 func (c *Client) DeleteSecret(ctx context.Context, ref esv1.PushSecretRemoteRef) error {
-	vaultID, entryID, err := c.parseSecretRef(ref.GetRemoteKey())
+	vaultID, entryID, err := c.resolveRef(ctx, ref.GetRemoteKey())
+	if isNotFoundError(err) {
+		return nil
+	}
 	if err != nil {
 		return err
 	}
-	return c.dvls.DeleteByID(ctx, vaultID, entryID)
+	if err := c.cred.DeleteByID(ctx, vaultID, entryID); err != nil {
+		if isNotFoundError(err) {
+			return nil
+		}
+		return fmt.Errorf("failed to delete entry %q from vault %q: %w", entryID, vaultID, err)
+	}
+	return nil
 }
 
 // SecretExists checks if a secret exists in DVLS.
 func (c *Client) SecretExists(ctx context.Context, ref esv1.PushSecretRemoteRef) (bool, error) {
-	vaultID, entryID, err := c.parseSecretRef(ref.GetRemoteKey())
+	vaultID, entryID, err := c.resolveRef(ctx, ref.GetRemoteKey())
+	if isNotFoundError(err) {
+		return false, nil
+	}
 	if err != nil {
 		return false, err
 	}
 
-	_, err = c.dvls.GetByID(ctx, vaultID, entryID)
+	_, err = c.cred.GetByID(ctx, vaultID, entryID)
 	if isNotFoundError(err) {
 		return false, nil
 	}
@@ -186,7 +239,7 @@ func (c *Client) SecretExists(ctx context.Context, ref esv1.PushSecretRemoteRef)
 
 // Validate checks if the client is properly configured.
 func (c *Client) Validate() (esv1.ValidationResult, error) {
-	if c.dvls == nil {
+	if c.cred == nil {
 		return esv1.ValidationResultError, errors.New("DVLS client is not initialized")
 	}
 	return esv1.ValidationResultReady, nil
@@ -197,9 +250,80 @@ func (c *Client) Close(_ context.Context) error {
 	return nil
 }
 
-// parseSecretRef parses the secret reference key.
-// Format: "<vault-id>/<entry-id>".
-func (c *Client) parseSecretRef(key string) (vaultID, entryID string, err error) {
+// resolveRef resolves a key to a vault ID and entry ID.
+// When c.vaultID is set, the key is treated as an entry reference.
+// When c.vaultID is empty, the key is parsed as the legacy "<vault-uuid>/<entry-uuid>" format.
+func (c *Client) resolveRef(ctx context.Context, key string) (vaultID, entryID string, err error) {
+	if c.vaultID == "" {
+		return parseLegacyRef(key)
+	}
+	entryID, err = c.resolveEntryRef(ctx, key)
+	return c.vaultID, entryID, err
+}
+
+// resolveEntryRef resolves an entry reference to a UUID.
+// The key can be:
+//   - A UUID: used directly.
+//   - A name: looked up via GetEntries.
+//   - A path/name: "folder/subfolder/entry-name" — path is used to filter.
+func (c *Client) resolveEntryRef(ctx context.Context, key string) (entryID string, err error) {
+	key = strings.TrimSpace(key)
+	if key == "" {
+		return "", errors.New("entry reference cannot be empty")
+	}
+
+	// UUID passes through directly.
+	if isUUID(key) {
+		return key, nil
+	}
+
+	// Return cached result if available.
+	c.mu.RLock()
+	id, ok := c.nameCache[key]
+	c.mu.RUnlock()
+	if ok {
+		return id, nil
+	}
+
+	// Split into optional path + entry name.
+	entryName, entryPath := parseEntryRef(key)
+	if entryName == "" {
+		return "", errors.New("entry name cannot be empty")
+	}
+
+	opts := dvls.GetEntriesOptions{Name: &entryName}
+	if entryPath != "" {
+		opts.Path = &entryPath
+	}
+
+	entries, err := c.cred.GetEntries(ctx, c.vaultID, opts)
+	if isVaultNotFoundError(err) {
+		return "", fmt.Errorf(errVaultNotFound, c.vaultID, err)
+	}
+	if err != nil {
+		return "", fmt.Errorf("failed to resolve entry %q: %w", key, err)
+	}
+
+	switch len(entries) {
+	case 0:
+		return "", fmt.Errorf("entry %q not found in vault: %w", key, dvls.ErrEntryNotFound)
+	case 1:
+		c.mu.Lock()
+		c.nameCache[key] = entries[0].Id
+		c.mu.Unlock()
+		return entries[0].Id, nil
+	default:
+		details := make([]string, len(entries))
+		for i, e := range entries {
+			details[i] = fmt.Sprintf("  %s (path=%q, type=%s)", e.Id, e.Path, e.Type)
+		}
+		return "", fmt.Errorf("found %d credential entries named %q; use the entry UUID to select one:\n%s", len(entries), entryName, strings.Join(details, "\n"))
+	}
+}
+
+// parseLegacyRef parses the legacy secret reference format "<vault-uuid>/<entry-uuid>".
+// This preserves backward compatibility for users who don't set the vault field.
+func parseLegacyRef(key string) (vaultID, entryID string, err error) {
 	parts := strings.SplitN(key, "/", 2)
 	if len(parts) != 2 {
 		return "", "", fmt.Errorf("invalid key format: expected '<vault-id>/<entry-id>', got %q", key)
@@ -214,12 +338,51 @@ func (c *Client) parseSecretRef(key string) (vaultID, entryID string, err error)
 	if entryID == "" {
 		return "", "", errors.New("entry ID cannot be empty")
 	}
+	if !isUUID(vaultID) {
+		return "", "", fmt.Errorf("invalid vault UUID: %q", vaultID)
+	}
+	if !isUUID(entryID) {
+		return "", "", fmt.Errorf("invalid entry UUID: %q", entryID)
+	}
 
 	return vaultID, entryID, nil
 }
 
+// resolveVaultRef resolves a vault reference (name or UUID) to a vault UUID.
+func resolveVaultRef(ctx context.Context, vaultRef string, vc vaultGetter) (string, error) {
+	if isUUID(vaultRef) {
+		return vaultRef, nil
+	}
+	vault, err := vc.GetByName(ctx, vaultRef)
+	if err != nil {
+		return "", fmt.Errorf("failed to resolve vault %q: %w", vaultRef, err)
+	}
+	return vault.Id, nil
+}
+
+// parseEntryRef splits an entry reference into name and optional path.
+// Both forward slashes and backslashes are accepted as path separators.
+// The last separator splits the path from the entry name.
+// Paths are normalized to backslashes to match the DVLS path format.
+// e.g. "folder/subfolder/my-entry" → name="my-entry", path="folder\subfolder".
+// e.g. "folder\subfolder\my-entry" → name="my-entry", path="folder\subfolder".
+func parseEntryRef(ref string) (name, path string) {
+	// Normalize forward slashes to backslashes.
+	normalized := strings.ReplaceAll(ref, "/", `\`)
+	if idx := strings.LastIndex(normalized, `\`); idx >= 0 {
+		return normalized[idx+1:], normalized[:idx]
+	}
+	return ref, ""
+}
+
+// isUUID returns true if the string is a valid UUID.
+func isUUID(s string) bool {
+	_, err := uuid.Parse(s)
+	return err == nil
+}
+
 // entryToSecretMap converts a DVLS entry to a map of secret values.
-func (c *Client) entryToSecretMap(entry dvls.Entry) (map[string][]byte, error) {
+func entryToSecretMap(entry dvls.Entry) (map[string][]byte, error) {
 	secretMap, err := entry.ToCredentialMap()
 	if err != nil {
 		return nil, err
@@ -263,6 +426,13 @@ func isNotFoundError(err error) bool {
 		return true
 	}
 
-	var reqErr dvls.RequestError
-	return errors.As(err, &reqErr) && reqErr.StatusCode == http.StatusNotFound
+	if errors.Is(err, dvls.ErrEntryNotFound) {
+		return true
+	}
+
+	return false
+}
+
+func isVaultNotFoundError(err error) bool {
+	return err != nil && errors.Is(err, dvls.ErrVaultNotFound)
 }

+ 599 - 191
providers/v1/dvls/client_test.go

@@ -31,13 +31,28 @@ import (
 	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
 )
 
+const (
+	testVaultUUID    = "00000000-0000-0000-0000-000000000001"
+	testEntryUUID    = "00000000-0000-0000-0000-000000000002"
+	testEntryUUID3   = "00000000-0000-0000-0000-000000000003"
+	testEntryUUID4   = "00000000-0000-0000-0000-000000000004"
+	testEntryUUID5   = "00000000-0000-0000-0000-000000000005"
+	testEntryName    = "my-entry"
+	testVaultName    = "my-vault"
+	testSecretName   = "my-secret"
+	testNonExistName = "some-name"
+)
+
+// --- Mock credential client ---
+
 type mockCredentialClient struct {
-	entries     map[string]dvls.Entry
-	getErr      error
-	updateErr   error
-	deleteErr   error
-	lastUpdated dvls.Entry
-	lastDeleted string
+	entries       map[string]dvls.Entry
+	getErr        error
+	getEntriesErr error
+	updateErr     error
+	deleteErr     error
+	lastUpdated   dvls.Entry
+	lastDeleted   string
 }
 
 func newMockCredentialClient(entries map[string]dvls.Entry) *mockCredentialClient {
@@ -59,6 +74,25 @@ func (m *mockCredentialClient) GetByID(_ context.Context, _, entryID string) (dv
 	return dvls.Entry{}, &dvls.RequestError{Err: fmt.Errorf("unexpected status code %d", http.StatusNotFound), Url: entryID, StatusCode: http.StatusNotFound}
 }
 
+func (m *mockCredentialClient) GetEntries(_ context.Context, _ string, opts dvls.GetEntriesOptions) ([]dvls.Entry, error) {
+	if m.getEntriesErr != nil {
+		return nil, m.getEntriesErr
+	}
+	if opts.Name == nil {
+		return nil, nil
+	}
+	var matches []dvls.Entry
+	for _, e := range m.entries {
+		if e.Name == *opts.Name {
+			if opts.Path != nil && e.Path != *opts.Path {
+				continue
+			}
+			matches = append(matches, e)
+		}
+	}
+	return matches, nil
+}
+
 func (m *mockCredentialClient) Update(_ context.Context, entry dvls.Entry) (dvls.Entry, error) {
 	if m.updateErr != nil {
 		return entry, m.updateErr
@@ -78,6 +112,32 @@ func (m *mockCredentialClient) DeleteByID(_ context.Context, _, entryID string)
 	return nil
 }
 
+// --- Mock vault client ---
+
+type mockVaultClient struct {
+	vaults map[string]dvls.Vault
+	getErr error
+}
+
+func newMockVaultClient(vaults map[string]dvls.Vault) *mockVaultClient {
+	if vaults == nil {
+		vaults = make(map[string]dvls.Vault)
+	}
+	return &mockVaultClient{vaults: vaults}
+}
+
+func (m *mockVaultClient) GetByName(_ context.Context, name string) (dvls.Vault, error) {
+	if m.getErr != nil {
+		return dvls.Vault{}, m.getErr
+	}
+	if v, ok := m.vaults[name]; ok {
+		return v, nil
+	}
+	return dvls.Vault{}, dvls.ErrVaultNotFound
+}
+
+// --- Test stubs ---
+
 type pushSecretDataStub struct {
 	remoteKey string
 	secretKey string
@@ -97,52 +157,326 @@ type pushSecretRemoteRefStub struct {
 func (p pushSecretRemoteRefStub) GetRemoteKey() string { return p.remoteKey }
 func (p pushSecretRemoteRefStub) GetProperty() string  { return p.property }
 
-func TestClient_parseSecretRef(t *testing.T) {
-	c := &Client{}
+// --- Helper to create a test client ---
+
+func newTestClient(entries map[string]dvls.Entry) (*Client, *mockCredentialClient) {
+	mockCred := newMockCredentialClient(entries)
+	c := NewClient(mockCred, testVaultUUID)
+	return c, mockCred
+}
+
+// --- Tests: parseEntryRef ---
+
+func TestParseEntryRef(t *testing.T) {
+	t.Run("name only", func(t *testing.T) {
+		name, path := parseEntryRef(testEntryName)
+		assert.Equal(t, testEntryName, name)
+		assert.Equal(t, "", path)
+	})
+
+	t.Run("forward slash path", func(t *testing.T) {
+		name, path := parseEntryRef("folder/my-entry")
+		assert.Equal(t, testEntryName, name)
+		assert.Equal(t, "folder", path)
+	})
+
+	t.Run("backslash path", func(t *testing.T) {
+		name, path := parseEntryRef(`folder\my-entry`)
+		assert.Equal(t, testEntryName, name)
+		assert.Equal(t, "folder", path)
+	})
+
+	t.Run("nested forward slashes", func(t *testing.T) {
+		name, path := parseEntryRef("go-dvls/folders/server/123")
+		assert.Equal(t, "123", name)
+		assert.Equal(t, `go-dvls\folders\server`, path)
+	})
+
+	t.Run("nested backslashes", func(t *testing.T) {
+		name, path := parseEntryRef(`go-dvls\folders\server\123`)
+		assert.Equal(t, "123", name)
+		assert.Equal(t, `go-dvls\folders\server`, path)
+	})
+
+	t.Run("mixed separators", func(t *testing.T) {
+		name, path := parseEntryRef(`go-dvls/folders\server/123`)
+		assert.Equal(t, "123", name)
+		assert.Equal(t, `go-dvls\folders\server`, path)
+	})
+
+	t.Run("trailing separator", func(t *testing.T) {
+		name, path := parseEntryRef("folder/")
+		assert.Equal(t, "", name)
+		assert.Equal(t, "folder", path)
+	})
+}
+
+// --- Tests: isUUID ---
+
+func TestIsUUID(t *testing.T) {
+	t.Run("valid UUID", func(t *testing.T) {
+		assert.True(t, isUUID("00000000-0000-0000-0000-000000000001"))
+	})
+
+	t.Run("valid UUID v4", func(t *testing.T) {
+		assert.True(t, isUUID("550e8400-e29b-41d4-a716-446655440000"))
+	})
+
+	t.Run("name string", func(t *testing.T) {
+		assert.False(t, isUUID("my-vault-name"))
+	})
+
+	t.Run("empty string", func(t *testing.T) {
+		assert.False(t, isUUID(""))
+	})
+
+	t.Run("malformed UUID", func(t *testing.T) {
+		assert.False(t, isUUID("00000000-0000-0000-000000000001"))
+	})
+}
+
+// --- Tests: resolveVaultRef ---
+
+func TestResolveVaultRef(t *testing.T) {
+	t.Run("UUID passthrough", func(t *testing.T) {
+		id, err := resolveVaultRef(context.Background(), testVaultUUID, newMockVaultClient(nil))
+		assert.NoError(t, err)
+		assert.Equal(t, testVaultUUID, id)
+	})
+
+	t.Run("name resolved", func(t *testing.T) {
+		mockVault := newMockVaultClient(map[string]dvls.Vault{
+			testVaultName: {Id: testVaultUUID, Name: testVaultName},
+		})
+		id, err := resolveVaultRef(context.Background(), testVaultName, mockVault)
+		assert.NoError(t, err)
+		assert.Equal(t, testVaultUUID, id)
+	})
+
+	t.Run("name not found", func(t *testing.T) {
+		_, err := resolveVaultRef(context.Background(), "nonexistent", newMockVaultClient(nil))
+		assert.Error(t, err)
+		assert.ErrorIs(t, err, dvls.ErrVaultNotFound)
+	})
+}
+
+// --- Tests: resolveEntryRef ---
+
+func TestResolveEntryRef(t *testing.T) {
+	entry := dvls.Entry{
+		Id:      testEntryUUID,
+		Name:    testEntryName,
+		Type:    dvls.EntryCredentialType,
+		SubType: dvls.EntryCredentialSubTypeDefault,
+	}
+
+	t.Run("UUID passthrough", func(t *testing.T) {
+		c, _ := newTestClient(nil)
+		entryID, err := c.resolveEntryRef(context.Background(), testEntryUUID)
+		assert.NoError(t, err)
+		assert.Equal(t, testEntryUUID, entryID)
+	})
 
-	t.Run("case 1: valid key format", func(t *testing.T) {
-		vaultID, entryID, err := c.parseSecretRef("vault-123/entry-456")
+	t.Run("name resolved", func(t *testing.T) {
+		c, _ := newTestClient(map[string]dvls.Entry{testEntryUUID: entry})
+		entryID, err := c.resolveEntryRef(context.Background(), testEntryName)
 		assert.NoError(t, err)
-		assert.Equal(t, "vault-123", vaultID)
-		assert.Equal(t, "entry-456", entryID)
+		assert.Equal(t, testEntryUUID, entryID)
 	})
 
-	t.Run("case 2: invalid key format - no separator", func(t *testing.T) {
-		_, _, err := c.parseSecretRef("invalid-key")
+	t.Run("name with path resolved", func(t *testing.T) {
+		entryInPath := dvls.Entry{
+			Id:      testEntryUUID,
+			Name:    testEntryName,
+			Path:    `go-dvls\folders`,
+			Type:    dvls.EntryCredentialType,
+			SubType: dvls.EntryCredentialSubTypeDefault,
+		}
+		c, _ := newTestClient(map[string]dvls.Entry{testEntryUUID: entryInPath})
+		entryID, err := c.resolveEntryRef(context.Background(), "go-dvls/folders/my-entry")
+		assert.NoError(t, err)
+		assert.Equal(t, testEntryUUID, entryID)
+	})
+
+	t.Run("path filters out other paths", func(t *testing.T) {
+		entryA := dvls.Entry{Id: testEntryUUID, Name: "db", Path: `prod`, Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault}
+		entryB := dvls.Entry{Id: testEntryUUID5, Name: "db", Path: `staging`, Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault}
+		c, _ := newTestClient(map[string]dvls.Entry{testEntryUUID: entryA, testEntryUUID5: entryB})
+		entryID, err := c.resolveEntryRef(context.Background(), "prod/db")
+		assert.NoError(t, err)
+		assert.Equal(t, testEntryUUID, entryID)
+	})
+
+	t.Run("name not found", func(t *testing.T) {
+		c, _ := newTestClient(nil)
+		_, err := c.resolveEntryRef(context.Background(), "nonexistent")
+		assert.Error(t, err)
+		assert.ErrorIs(t, err, dvls.ErrEntryNotFound)
+	})
+
+	t.Run("multiple entries found", func(t *testing.T) {
+		entry2 := dvls.Entry{Id: testEntryUUID3, Name: "dup", Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault}
+		entry3 := dvls.Entry{Id: testEntryUUID4, Name: "dup", Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeConnectionString}
+		c, _ := newTestClient(map[string]dvls.Entry{
+			testEntryUUID3: entry2,
+			testEntryUUID4: entry3,
+		})
+		_, err := c.resolveEntryRef(context.Background(), "dup")
+		assert.Error(t, err)
+		assert.Contains(t, err.Error(), "found 2 credential entries")
+		assert.Contains(t, err.Error(), testEntryUUID3)
+		assert.Contains(t, err.Error(), testEntryUUID4)
+	})
+
+	t.Run("empty key", func(t *testing.T) {
+		c, _ := newTestClient(nil)
+		_, err := c.resolveEntryRef(context.Background(), "")
+		assert.Error(t, err)
+		assert.Contains(t, err.Error(), "cannot be empty")
+	})
+
+	t.Run("trailing separator produces empty name", func(t *testing.T) {
+		c, _ := newTestClient(nil)
+		_, err := c.resolveEntryRef(context.Background(), "folder/")
+		assert.Error(t, err)
+		assert.Contains(t, err.Error(), "entry name cannot be empty")
+	})
+
+	t.Run("GetEntries API error", func(t *testing.T) {
+		c, mockCred := newTestClient(nil)
+		mockCred.getEntriesErr = errors.New("network error")
+		_, err := c.resolveEntryRef(context.Background(), testNonExistName)
+		assert.Error(t, err)
+		assert.Contains(t, err.Error(), "failed to resolve entry")
+		assert.Contains(t, err.Error(), "network error")
+	})
+
+	t.Run("vault not found during name resolution", func(t *testing.T) {
+		c, mockCred := newTestClient(nil)
+		mockCred.getEntriesErr = dvls.ErrVaultNotFound
+		_, err := c.resolveEntryRef(context.Background(), testNonExistName)
+		assert.Error(t, err)
+		assert.ErrorIs(t, err, dvls.ErrVaultNotFound)
+	})
+
+	t.Run("cache hit avoids second GetEntries call", func(t *testing.T) {
+		entry := dvls.Entry{
+			Id:      testEntryUUID,
+			Name:    testEntryName,
+			Type:    dvls.EntryCredentialType,
+			SubType: dvls.EntryCredentialSubTypeDefault,
+		}
+		c, mockCred := newTestClient(map[string]dvls.Entry{testEntryUUID: entry})
+
+		// First call populates the cache.
+		id1, err := c.resolveEntryRef(context.Background(), testEntryName)
+		assert.NoError(t, err)
+		assert.Equal(t, testEntryUUID, id1)
+
+		// Remove entries from mock so only the cache can satisfy the lookup.
+		mockCred.entries = map[string]dvls.Entry{}
+
+		id2, err := c.resolveEntryRef(context.Background(), testEntryName)
+		assert.NoError(t, err)
+		assert.Equal(t, testEntryUUID, id2)
+	})
+}
+
+// --- Tests: parseLegacyRef ---
+
+func TestParseLegacyRef(t *testing.T) {
+	t.Run("valid format", func(t *testing.T) {
+		vaultID, entryID, err := parseLegacyRef(testVaultUUID + "/" + testEntryUUID)
+		assert.NoError(t, err)
+		assert.Equal(t, testVaultUUID, vaultID)
+		assert.Equal(t, testEntryUUID, entryID)
+	})
+
+	t.Run("no separator", func(t *testing.T) {
+		_, _, err := parseLegacyRef(testEntryUUID)
 		assert.Error(t, err)
 		assert.Contains(t, err.Error(), "invalid key format")
 	})
 
-	t.Run("case 3: invalid key format - empty vault ID", func(t *testing.T) {
-		_, _, err := c.parseSecretRef("/entry-456")
+	t.Run("empty vault", func(t *testing.T) {
+		_, _, err := parseLegacyRef("/" + testEntryUUID)
 		assert.Error(t, err)
 		assert.Contains(t, err.Error(), "vault ID cannot be empty")
 	})
 
-	t.Run("case 4: invalid key format - empty entry ID", func(t *testing.T) {
-		_, _, err := c.parseSecretRef("vault-123/")
+	t.Run("empty entry", func(t *testing.T) {
+		_, _, err := parseLegacyRef(testVaultUUID + "/")
 		assert.Error(t, err)
 		assert.Contains(t, err.Error(), "entry ID cannot be empty")
 	})
 
-	t.Run("case 5: key with spaces", func(t *testing.T) {
-		vaultID, entryID, err := c.parseSecretRef(" vault-123 / entry-456 ")
+	t.Run("invalid vault UUID", func(t *testing.T) {
+		_, _, err := parseLegacyRef("not-a-uuid/" + testEntryUUID)
+		assert.Error(t, err)
+		assert.Contains(t, err.Error(), "invalid vault UUID")
+	})
+
+	t.Run("invalid entry UUID", func(t *testing.T) {
+		_, _, err := parseLegacyRef(testVaultUUID + "/not-a-uuid")
+		assert.Error(t, err)
+		assert.Contains(t, err.Error(), "invalid entry UUID")
+	})
+}
+
+// --- Tests: resolveRef legacy mode ---
+
+func TestResolveRef_LegacyMode(t *testing.T) {
+	entry := dvls.Entry{
+		Id: testEntryUUID, Name: "test",
+		Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault,
+		Data: &dvls.EntryCredentialDefaultData{Password: "pass"},
+	}
+
+	t.Run("legacy format when vaultID is empty", func(t *testing.T) {
+		mockCred := newMockCredentialClient(map[string]dvls.Entry{testEntryUUID: entry})
+		c := NewClient(mockCred, "")
+		vaultID, entryID, err := c.resolveRef(context.Background(), testVaultUUID+"/"+testEntryUUID)
+		assert.NoError(t, err)
+		assert.Equal(t, testVaultUUID, vaultID)
+		assert.Equal(t, testEntryUUID, entryID)
+	})
+
+	t.Run("new format with name when vaultID is set", func(t *testing.T) {
+		c, _ := newTestClient(map[string]dvls.Entry{testEntryUUID: entry})
+		vaultID, entryID, err := c.resolveRef(context.Background(), "test")
 		assert.NoError(t, err)
-		assert.Equal(t, "vault-123", vaultID)
-		assert.Equal(t, "entry-456", entryID)
+		assert.Equal(t, testVaultUUID, vaultID)
+		assert.Equal(t, testEntryUUID, entryID)
+	})
+
+	t.Run("new format when vaultID is set", func(t *testing.T) {
+		c, _ := newTestClient(map[string]dvls.Entry{testEntryUUID: entry})
+		vaultID, entryID, err := c.resolveRef(context.Background(), testEntryUUID)
+		assert.NoError(t, err)
+		assert.Equal(t, testVaultUUID, vaultID)
+		assert.Equal(t, testEntryUUID, entryID)
 	})
 }
 
+// --- Tests: Validate ---
+
 func TestClient_Validate(t *testing.T) {
-	t.Run("case 1: nil client", func(t *testing.T) {
-		c := &Client{dvls: nil}
+	t.Run("nil cred client", func(t *testing.T) {
+		c := &Client{cred: nil, vaultID: testVaultUUID}
 		result, err := c.Validate()
 		assert.Error(t, err)
 		assert.Equal(t, esv1.ValidationResultError, result)
 	})
 
-	t.Run("case 2: initialized client", func(t *testing.T) {
-		c := &Client{dvls: newMockCredentialClient(nil)}
+	t.Run("empty vault ID is valid (legacy mode)", func(t *testing.T) {
+		c := &Client{cred: newMockCredentialClient(nil), vaultID: ""}
+		result, err := c.Validate()
+		assert.NoError(t, err)
+		assert.Equal(t, esv1.ValidationResultReady, result)
+	})
+
+	t.Run("initialized client", func(t *testing.T) {
+		c := NewClient(newMockCredentialClient(nil), testVaultUUID)
 		result, err := c.Validate()
 		assert.NoError(t, err)
 		assert.Equal(t, esv1.ValidationResultReady, result)
@@ -150,32 +484,23 @@ func TestClient_Validate(t *testing.T) {
 }
 
 func TestNewClient(t *testing.T) {
-	// Test that NewClient returns a non-nil client
-	c := NewClient(nil)
+	c := NewClient(nil, "")
 	assert.NotNil(t, c)
-	assert.Nil(t, c.dvls)
+	assert.Nil(t, c.cred)
+	assert.Empty(t, c.vaultID)
 }
 
-func TestClient_entryToSecretMap(t *testing.T) {
-	c := &Client{}
+// --- Tests: entryToSecretMap ---
 
+func TestEntryToSecretMap(t *testing.T) {
 	t.Run("Default credential type", func(t *testing.T) {
 		entry := dvls.Entry{
-			Id:      "entry-id-123",
-			Name:    "test-entry",
-			Type:    dvls.EntryCredentialType,
-			SubType: dvls.EntryCredentialSubTypeDefault,
-			Data: &dvls.EntryCredentialDefaultData{
-				Username: "testuser",
-				Password: "testpass",
-				Domain:   "testdomain",
-			},
+			Id: "entry-id-123", Name: "test-entry",
+			Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault,
+			Data: &dvls.EntryCredentialDefaultData{Username: "testuser", Password: "testpass", Domain: "testdomain"},
 		}
-
-		secretMap, err := c.entryToSecretMap(entry)
+		secretMap, err := entryToSecretMap(entry)
 		assert.NoError(t, err)
-		assert.Equal(t, "entry-id-123", string(secretMap["entry-id"]))
-		assert.Equal(t, "test-entry", string(secretMap["entry-name"]))
 		assert.Equal(t, "testuser", string(secretMap["username"]))
 		assert.Equal(t, "testpass", string(secretMap["password"]))
 		assert.Equal(t, "testdomain", string(secretMap["domain"]))
@@ -183,61 +508,35 @@ func TestClient_entryToSecretMap(t *testing.T) {
 
 	t.Run("AccessCode credential type", func(t *testing.T) {
 		entry := dvls.Entry{
-			Id:      "entry-id-456",
-			Name:    "access-code-entry",
-			Type:    dvls.EntryCredentialType,
-			SubType: dvls.EntryCredentialSubTypeAccessCode,
-			Data: &dvls.EntryCredentialAccessCodeData{
-				Password: "access-code-123",
-			},
+			Id: "entry-id-456", Name: "access-code-entry",
+			Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeAccessCode,
+			Data: &dvls.EntryCredentialAccessCodeData{Password: "access-code-123"},
 		}
-
-		secretMap, err := c.entryToSecretMap(entry)
+		secretMap, err := entryToSecretMap(entry)
 		assert.NoError(t, err)
-		assert.Equal(t, "entry-id-456", string(secretMap["entry-id"]))
-		assert.Equal(t, "access-code-entry", string(secretMap["entry-name"]))
 		assert.Equal(t, "access-code-123", string(secretMap["password"]))
 	})
 
 	t.Run("ApiKey credential type", func(t *testing.T) {
 		entry := dvls.Entry{
-			Id:      "entry-id-789",
-			Name:    "api-key-entry",
-			Type:    dvls.EntryCredentialType,
-			SubType: dvls.EntryCredentialSubTypeApiKey,
-			Data: &dvls.EntryCredentialApiKeyData{
-				ApiId:    "api-id-123",
-				ApiKey:   "api-key-secret",
-				TenantId: "tenant-123",
-			},
+			Id: "entry-id-789", Name: "api-key-entry",
+			Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeApiKey,
+			Data: &dvls.EntryCredentialApiKeyData{ApiId: "api-id-123", ApiKey: "api-key-secret", TenantId: "tenant-123"},
 		}
-
-		secretMap, err := c.entryToSecretMap(entry)
+		secretMap, err := entryToSecretMap(entry)
 		assert.NoError(t, err)
-		assert.Equal(t, "entry-id-789", string(secretMap["entry-id"]))
-		assert.Equal(t, "api-key-entry", string(secretMap["entry-name"]))
 		assert.Equal(t, "api-id-123", string(secretMap["api-id"]))
 		assert.Equal(t, "api-key-secret", string(secretMap["api-key"]))
-		assert.Equal(t, "tenant-123", string(secretMap["tenant-id"]))
 	})
 
 	t.Run("AzureServicePrincipal credential type", func(t *testing.T) {
 		entry := dvls.Entry{
-			Id:      "entry-id-azure",
-			Name:    "azure-sp-entry",
-			Type:    dvls.EntryCredentialType,
-			SubType: dvls.EntryCredentialSubTypeAzureServicePrincipal,
-			Data: &dvls.EntryCredentialAzureServicePrincipalData{
-				ClientId:     "client-id-123",
-				ClientSecret: "client-secret-456",
-				TenantId:     "tenant-id-789",
-			},
+			Id: "entry-id-azure", Name: "azure-sp-entry",
+			Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeAzureServicePrincipal,
+			Data: &dvls.EntryCredentialAzureServicePrincipalData{ClientId: "client-id-123", ClientSecret: "client-secret-456", TenantId: "tenant-id-789"},
 		}
-
-		secretMap, err := c.entryToSecretMap(entry)
+		secretMap, err := entryToSecretMap(entry)
 		assert.NoError(t, err)
-		assert.Equal(t, "entry-id-azure", string(secretMap["entry-id"]))
-		assert.Equal(t, "azure-sp-entry", string(secretMap["entry-name"]))
 		assert.Equal(t, "client-id-123", string(secretMap["client-id"]))
 		assert.Equal(t, "client-secret-456", string(secretMap["client-secret"]))
 		assert.Equal(t, "tenant-id-789", string(secretMap["tenant-id"]))
@@ -245,20 +544,13 @@ func TestClient_entryToSecretMap(t *testing.T) {
 
 	t.Run("ConnectionString credential type", func(t *testing.T) {
 		entry := dvls.Entry{
-			Id:      "entry-id-conn",
-			Name:    "connection-string-entry",
-			Type:    dvls.EntryCredentialType,
-			SubType: dvls.EntryCredentialSubTypeConnectionString,
-			Data: &dvls.EntryCredentialConnectionStringData{
-				ConnectionString: "Server=localhost;Database=mydb;User=admin;Password=secret",
-			},
+			Id: "entry-id-conn", Name: "connection-string-entry",
+			Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeConnectionString,
+			Data: &dvls.EntryCredentialConnectionStringData{ConnectionString: "Server=localhost;Database=mydb"},
 		}
-
-		secretMap, err := c.entryToSecretMap(entry)
+		secretMap, err := entryToSecretMap(entry)
 		assert.NoError(t, err)
-		assert.Equal(t, "entry-id-conn", string(secretMap["entry-id"]))
-		assert.Equal(t, "connection-string-entry", string(secretMap["entry-name"]))
-		assert.Equal(t, "Server=localhost;Database=mydb;User=admin;Password=secret", string(secretMap["connection-string"]))
+		assert.Equal(t, "Server=localhost;Database=mydb", string(secretMap["connection-string"]))
 	})
 
 	t.Run("PrivateKey credential type", func(t *testing.T) {
@@ -270,185 +562,301 @@ func TestClient_entryToSecretMap(t *testing.T) {
 			Data: &dvls.EntryCredentialPrivateKeyData{
 				Username:   "ssh-user",
 				Password:   "key-password",
-				PrivateKey: "-----BEGIN RSA PRIVATE KEY-----\nMIIE...",
-				PublicKey:  "ssh-rsa AAAA...",
+				PrivateKey: "-----BEGIN RSA PRIVATE KEY-----",
+				PublicKey:  "ssh-rsa AAAA",
 				Passphrase: "my-passphrase",
 			},
 		}
-
-		secretMap, err := c.entryToSecretMap(entry)
+		secretMap, err := entryToSecretMap(entry)
 		assert.NoError(t, err)
-		assert.Equal(t, "entry-id-pk", string(secretMap["entry-id"]))
-		assert.Equal(t, "private-key-entry", string(secretMap["entry-name"]))
 		assert.Equal(t, "ssh-user", string(secretMap["username"]))
 		assert.Equal(t, "key-password", string(secretMap["password"]))
-		assert.Equal(t, "-----BEGIN RSA PRIVATE KEY-----\nMIIE...", string(secretMap["private-key"]))
-		assert.Equal(t, "ssh-rsa AAAA...", string(secretMap["public-key"]))
+		assert.Equal(t, "-----BEGIN RSA PRIVATE KEY-----", string(secretMap["private-key"]))
+		assert.Equal(t, "ssh-rsa AAAA", string(secretMap["public-key"]))
 		assert.Equal(t, "my-passphrase", string(secretMap["passphrase"]))
 	})
 
-	t.Run("Unsupported credential type", func(t *testing.T) {
-		entry := dvls.Entry{
-			Id:      "entry-id-unknown",
-			Name:    "unknown-entry",
-			Type:    dvls.EntryCredentialType,
-			SubType: "UnknownType",
-		}
-
-		_, err := c.entryToSecretMap(entry)
-		assert.Error(t, err)
-		assert.Contains(t, err.Error(), "unsupported credential subtype")
-	})
-
 	t.Run("Default credential with partial data", func(t *testing.T) {
 		entry := dvls.Entry{
-			Id:      "entry-id-partial",
-			Name:    "partial-entry",
-			Type:    dvls.EntryCredentialType,
-			SubType: dvls.EntryCredentialSubTypeDefault,
-			Data: &dvls.EntryCredentialDefaultData{
-				Username: "onlyuser",
-				// Password and Domain are empty
-			},
+			Id: "entry-id-partial", Name: "partial-entry",
+			Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault,
+			Data: &dvls.EntryCredentialDefaultData{Username: "onlyuser"},
 		}
-
-		secretMap, err := c.entryToSecretMap(entry)
+		secretMap, err := entryToSecretMap(entry)
 		assert.NoError(t, err)
-		assert.Equal(t, "entry-id-partial", string(secretMap["entry-id"]))
-		assert.Equal(t, "partial-entry", string(secretMap["entry-name"]))
 		assert.Equal(t, "onlyuser", string(secretMap["username"]))
-		// Empty fields should not be included
 		_, hasPassword := secretMap["password"]
 		_, hasDomain := secretMap["domain"]
 		assert.False(t, hasPassword)
 		assert.False(t, hasDomain)
 	})
+
+	t.Run("Unsupported credential type", func(t *testing.T) {
+		entry := dvls.Entry{Id: "x", Name: "x", Type: dvls.EntryCredentialType, SubType: "UnknownType"}
+		_, err := entryToSecretMap(entry)
+		assert.Error(t, err)
+	})
 }
 
-func TestClient_GetSecret_NotFound(t *testing.T) {
-	c := NewClient(newMockCredentialClient(nil))
+// --- Tests: GetSecret ---
 
-	_, err := c.GetSecret(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: "vault/entry"})
+func TestClient_GetSecret_NotFound(t *testing.T) {
+	c, _ := newTestClient(nil)
+	_, err := c.GetSecret(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: testEntryUUID})
 	assert.ErrorIs(t, err, esv1.NoSecretErr)
 }
 
-func TestClient_GetSecretAndMap_Success(t *testing.T) {
+func TestClient_GetSecret_Success(t *testing.T) {
 	entry := dvls.Entry{
-		Id:      "entry-1",
-		Name:    "test-entry",
-		Type:    dvls.EntryCredentialType,
-		SubType: dvls.EntryCredentialSubTypeDefault,
-		Data: &dvls.EntryCredentialDefaultData{
-			Password: "super-secret",
-		},
+		Id: testEntryUUID, Name: "test-entry",
+		Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault,
+		Data: &dvls.EntryCredentialDefaultData{Password: "super-secret"},
 	}
+	c, _ := newTestClient(map[string]dvls.Entry{testEntryUUID: entry})
 
-	mockClient := newMockCredentialClient(map[string]dvls.Entry{"entry-1": entry})
-	c := NewClient(mockClient)
-
-	val, err := c.GetSecret(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: "vault-1/entry-1", Property: "password"})
+	val, err := c.GetSecret(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: testEntryUUID, Property: "password"})
 	assert.NoError(t, err)
 	assert.Equal(t, "super-secret", string(val))
+}
+
+func TestClient_GetSecret_ByName(t *testing.T) {
+	entry := dvls.Entry{
+		Id: testEntryUUID, Name: testSecretName,
+		Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault,
+		Data: &dvls.EntryCredentialDefaultData{Password: "name-resolved"},
+	}
+	c, _ := newTestClient(map[string]dvls.Entry{testEntryUUID: entry})
 
-	secretMap, err := c.GetSecretMap(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: "vault-1/entry-1"})
+	val, err := c.GetSecret(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: testSecretName, Property: "password"})
 	assert.NoError(t, err)
-	assert.Equal(t, "super-secret", string(secretMap["password"]))
-	assert.Equal(t, "test-entry", string(secretMap["entry-name"]))
+	assert.Equal(t, "name-resolved", string(val))
 }
 
+func TestClient_GetSecret_ByNameNotFound(t *testing.T) {
+	c, _ := newTestClient(nil)
+	_, err := c.GetSecret(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: "nonexistent"})
+	assert.ErrorIs(t, err, esv1.NoSecretErr)
+}
+
+func TestClient_GetSecret_WithPath(t *testing.T) {
+	entry := dvls.Entry{
+		Id: testEntryUUID, Name: "db", Path: `prod\databases`,
+		Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault,
+		Data: &dvls.EntryCredentialDefaultData{Password: "prod-pass"},
+	}
+	c, _ := newTestClient(map[string]dvls.Entry{testEntryUUID: entry})
+
+	val, err := c.GetSecret(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: "prod/databases/db", Property: "password"})
+	assert.NoError(t, err)
+	assert.Equal(t, "prod-pass", string(val))
+}
+
+func TestClient_GetSecret_VaultNotFound(t *testing.T) {
+	c, mockCred := newTestClient(nil)
+	mockCred.getErr = dvls.ErrVaultNotFound
+	// UUID key bypasses name resolution, so GetByID is called directly.
+	_, err := c.GetSecret(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: testEntryUUID})
+	assert.Error(t, err)
+	assert.ErrorIs(t, err, dvls.ErrVaultNotFound)
+}
+
+func TestClient_GetSecret_VaultNotFoundDuringNameResolution(t *testing.T) {
+	c, mockCred := newTestClient(nil)
+	mockCred.getEntriesErr = dvls.ErrVaultNotFound
+	_, err := c.GetSecret(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: testNonExistName})
+	assert.Error(t, err)
+	assert.ErrorIs(t, err, dvls.ErrVaultNotFound)
+}
+
+// --- Tests: GetSecretMap ---
+
+func TestClient_GetSecretMap_ByName(t *testing.T) {
+	entry := dvls.Entry{
+		Id: testEntryUUID, Name: testSecretName,
+		Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault,
+		Data: &dvls.EntryCredentialDefaultData{Username: "user", Password: "pass"},
+	}
+	c, _ := newTestClient(map[string]dvls.Entry{testEntryUUID: entry})
+
+	secretMap, err := c.GetSecretMap(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: testSecretName})
+	assert.NoError(t, err)
+	assert.Equal(t, "user", string(secretMap["username"]))
+	assert.Equal(t, "pass", string(secretMap["password"]))
+}
+
+func TestClient_GetSecretMap_NotFoundByUUID(t *testing.T) {
+	c, _ := newTestClient(nil)
+	_, err := c.GetSecretMap(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: testEntryUUID})
+	assert.ErrorIs(t, err, esv1.NoSecretErr)
+}
+
+func TestClient_GetSecretMap_NotFoundByName(t *testing.T) {
+	c, _ := newTestClient(nil)
+	_, err := c.GetSecretMap(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: "nonexistent"})
+	assert.ErrorIs(t, err, esv1.NoSecretErr)
+}
+
+// --- Tests: SecretExists ---
+
 func TestClient_SecretExists(t *testing.T) {
-	mockClient := newMockCredentialClient(nil)
-	c := NewClient(mockClient)
+	c, mockCred := newTestClient(nil)
 
-	exists, err := c.SecretExists(context.Background(), pushSecretRemoteRefStub{remoteKey: "vault/entry"})
+	exists, err := c.SecretExists(context.Background(), pushSecretRemoteRefStub{remoteKey: testEntryUUID})
 	assert.NoError(t, err)
 	assert.False(t, exists)
 
-	mockClient.entries["entry"] = dvls.Entry{Id: "entry", Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault}
+	mockCred.entries[testEntryUUID] = dvls.Entry{Id: testEntryUUID, Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault}
 
-	exists, err = c.SecretExists(context.Background(), pushSecretRemoteRefStub{remoteKey: "vault/entry"})
+	exists, err = c.SecretExists(context.Background(), pushSecretRemoteRefStub{remoteKey: testEntryUUID})
 	assert.NoError(t, err)
 	assert.True(t, exists)
 
-	mockClient.getErr = errors.New("boom")
-	_, err = c.SecretExists(context.Background(), pushSecretRemoteRefStub{remoteKey: "vault/entry"})
+	mockCred.getErr = errors.New("boom")
+	_, err = c.SecretExists(context.Background(), pushSecretRemoteRefStub{remoteKey: testEntryUUID})
 	assert.Error(t, err)
 }
 
+func TestClient_SecretExists_ByName(t *testing.T) {
+	entry := dvls.Entry{Id: testEntryUUID, Name: testEntryName, Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault}
+	c, _ := newTestClient(map[string]dvls.Entry{testEntryUUID: entry})
+
+	exists, err := c.SecretExists(context.Background(), pushSecretRemoteRefStub{remoteKey: testEntryName})
+	assert.NoError(t, err)
+	assert.True(t, exists)
+
+	exists, err = c.SecretExists(context.Background(), pushSecretRemoteRefStub{remoteKey: "nonexistent"})
+	assert.NoError(t, err)
+	assert.False(t, exists)
+}
+
+// --- Tests: DeleteSecret ---
+
 func TestClient_DeleteSecret(t *testing.T) {
-	mockClient := newMockCredentialClient(map[string]dvls.Entry{"entry": {Id: "entry", Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeAccessCode}})
-	c := NewClient(mockClient)
+	c, mockCred := newTestClient(map[string]dvls.Entry{testEntryUUID: {Id: testEntryUUID, Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeAccessCode}})
+
+	err := c.DeleteSecret(context.Background(), pushSecretRemoteRefStub{remoteKey: testEntryUUID})
+	assert.NoError(t, err)
+	assert.Equal(t, testEntryUUID, mockCred.lastDeleted)
+}
+
+func TestClient_DeleteSecret_ByName(t *testing.T) {
+	entry := dvls.Entry{Id: testEntryUUID, Name: testEntryName, Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault}
+	c, mockCred := newTestClient(map[string]dvls.Entry{testEntryUUID: entry})
+
+	err := c.DeleteSecret(context.Background(), pushSecretRemoteRefStub{remoteKey: testEntryName})
+	assert.NoError(t, err)
+	assert.Equal(t, testEntryUUID, mockCred.lastDeleted)
+}
 
-	err := c.DeleteSecret(context.Background(), pushSecretRemoteRefStub{remoteKey: "vault/entry"})
+func TestClient_DeleteSecret_ByNameNotFound(t *testing.T) {
+	c, _ := newTestClient(nil)
+	err := c.DeleteSecret(context.Background(), pushSecretRemoteRefStub{remoteKey: "nonexistent"})
 	assert.NoError(t, err)
-	assert.Equal(t, "entry", mockClient.lastDeleted)
 }
 
+// --- Tests: PushSecret ---
+
 func TestClient_PushSecret_UpdateDefault(t *testing.T) {
-	mockClient := newMockCredentialClient(map[string]dvls.Entry{
-		"entry": {Id: "entry", Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault},
+	c, mockCred := newTestClient(map[string]dvls.Entry{
+		testEntryUUID: {Id: testEntryUUID, Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault},
 	})
-	c := NewClient(mockClient)
+	secret := &corev1.Secret{Data: map[string][]byte{"password": []byte("new-value")}}
+	data := pushSecretDataStub{remoteKey: testEntryUUID, secretKey: "password"}
 
-	secret := &corev1.Secret{
-		Data: map[string][]byte{
-			"password": []byte("new-value"),
-		},
-	}
+	err := c.PushSecret(context.Background(), secret, data)
+	assert.NoError(t, err)
+
+	credData, ok := mockCred.entries[testEntryUUID].Data.(*dvls.EntryCredentialDefaultData)
+	assert.True(t, ok)
+	assert.Equal(t, "new-value", credData.Password)
+}
 
-	data := pushSecretDataStub{remoteKey: "vault/entry", secretKey: "password"}
+func TestClient_PushSecret_ByName(t *testing.T) {
+	entry := dvls.Entry{Id: testEntryUUID, Name: testEntryName, Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeDefault}
+	c, mockCred := newTestClient(map[string]dvls.Entry{testEntryUUID: entry})
+	secret := &corev1.Secret{Data: map[string][]byte{"password": []byte("pushed-via-name")}}
+	data := pushSecretDataStub{remoteKey: testEntryName, secretKey: "password"}
 
 	err := c.PushSecret(context.Background(), secret, data)
 	assert.NoError(t, err)
 
-	updatedEntry := mockClient.entries["entry"]
-	credData, ok := updatedEntry.Data.(*dvls.EntryCredentialDefaultData)
+	credData, ok := mockCred.entries[testEntryUUID].Data.(*dvls.EntryCredentialDefaultData)
 	assert.True(t, ok)
-	assert.Equal(t, "new-value", credData.Password)
+	assert.Equal(t, "pushed-via-name", credData.Password)
 }
 
 func TestClient_PushSecret_UpdateAccessCode(t *testing.T) {
-	mockClient := newMockCredentialClient(map[string]dvls.Entry{
-		"entry": {Id: "entry", Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeAccessCode},
+	c, mockCred := newTestClient(map[string]dvls.Entry{
+		testEntryUUID: {Id: testEntryUUID, Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeAccessCode},
 	})
-	c := NewClient(mockClient)
-
-	secret := &corev1.Secret{
-		Data: map[string][]byte{
-			"code": []byte("code-value"),
-		},
-	}
-
-	data := pushSecretDataStub{remoteKey: "vault/entry", secretKey: "code"}
+	secret := &corev1.Secret{Data: map[string][]byte{"code": []byte("code-value")}}
+	data := pushSecretDataStub{remoteKey: testEntryUUID, secretKey: "code"}
 
 	err := c.PushSecret(context.Background(), secret, data)
 	assert.NoError(t, err)
 
-	updatedEntry := mockClient.entries["entry"]
-	credData, ok := updatedEntry.Data.(*dvls.EntryCredentialAccessCodeData)
+	credData, ok := mockCred.entries[testEntryUUID].Data.(*dvls.EntryCredentialAccessCodeData)
 	assert.True(t, ok)
 	assert.Equal(t, "code-value", credData.Password)
 }
 
+func TestClient_PushSecret_UnsupportedSubtype(t *testing.T) {
+	c, _ := newTestClient(map[string]dvls.Entry{
+		testEntryUUID: {Id: testEntryUUID, Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeApiKey},
+	})
+	secret := &corev1.Secret{Data: map[string][]byte{"password": []byte("pw")}}
+	data := pushSecretDataStub{remoteKey: testEntryUUID, secretKey: "password"}
+
+	err := c.PushSecret(context.Background(), secret, data)
+	assert.Error(t, err)
+	assert.Contains(t, err.Error(), "cannot set secret for credential subtype")
+}
+
 func TestClient_PushSecret_NotFound(t *testing.T) {
-	c := NewClient(newMockCredentialClient(nil))
+	c, _ := newTestClient(nil)
 	secret := &corev1.Secret{Data: map[string][]byte{"password": []byte("pw")}}
-	data := pushSecretDataStub{remoteKey: "vault/missing", secretKey: "password"}
+	data := pushSecretDataStub{remoteKey: "00000000-0000-0000-0000-000000000099", secretKey: "password"}
 
 	err := c.PushSecret(context.Background(), secret, data)
 	assert.Error(t, err)
 	assert.Contains(t, err.Error(), "not found")
 }
 
-func TestClient_PushSecret_UnsupportedSubtype(t *testing.T) {
-	mockClient := newMockCredentialClient(map[string]dvls.Entry{
-		"entry": {Id: "entry", Type: dvls.EntryCredentialType, SubType: dvls.EntryCredentialSubTypeApiKey},
-	})
-	c := NewClient(mockClient)
+func TestClient_PushSecret_VaultNotFoundDuringNameResolution(t *testing.T) {
+	c, mockCred := newTestClient(nil)
+	mockCred.getEntriesErr = dvls.ErrVaultNotFound
 	secret := &corev1.Secret{Data: map[string][]byte{"password": []byte("pw")}}
-	data := pushSecretDataStub{remoteKey: "vault/entry", secretKey: "password"}
+	data := pushSecretDataStub{remoteKey: testNonExistName, secretKey: "password"}
 
 	err := c.PushSecret(context.Background(), secret, data)
 	assert.Error(t, err)
-	assert.Contains(t, err.Error(), "cannot set secret for credential subtype")
+	assert.ErrorIs(t, err, dvls.ErrVaultNotFound)
+}
+
+func TestClient_PushSecret_ByNameNotFound(t *testing.T) {
+	c, _ := newTestClient(nil)
+	secret := &corev1.Secret{Data: map[string][]byte{"password": []byte("pw")}}
+	data := pushSecretDataStub{remoteKey: "nonexistent-entry", secretKey: "password"}
+
+	err := c.PushSecret(context.Background(), secret, data)
+	assert.Error(t, err)
+	assert.Contains(t, err.Error(), "entry must exist before pushing secrets")
+}
+
+// --- Tests: isNotFoundError ---
+
+func TestIsNotFoundError(t *testing.T) {
+	assert.False(t, isNotFoundError(nil))
+	assert.True(t, isNotFoundError(&dvls.RequestError{Err: fmt.Errorf("not found"), StatusCode: http.StatusNotFound}))
+	assert.True(t, isNotFoundError(dvls.ErrEntryNotFound))
+	assert.True(t, isNotFoundError(fmt.Errorf("wrapped: %w", dvls.ErrEntryNotFound)))
+	assert.False(t, isNotFoundError(dvls.ErrMultipleEntriesFound))
+	assert.False(t, isNotFoundError(errors.New("some other error")))
+}
+
+func TestIsVaultNotFoundError(t *testing.T) {
+	assert.False(t, isVaultNotFoundError(nil))
+	assert.True(t, isVaultNotFoundError(dvls.ErrVaultNotFound))
+	assert.True(t, isVaultNotFoundError(fmt.Errorf("wrapped: %w", dvls.ErrVaultNotFound)))
+	assert.False(t, isVaultNotFoundError(errors.New("some other error")))
 }

+ 49 - 44
providers/v1/dvls/go.mod

@@ -3,51 +3,54 @@ module github.com/external-secrets/external-secrets/providers/v1/dvls
 go 1.26.2
 
 require (
-	github.com/Devolutions/go-dvls v0.15.0
+	github.com/Devolutions/go-dvls v0.19.1
 	github.com/external-secrets/external-secrets/apis v0.0.0
 	github.com/external-secrets/external-secrets/runtime v0.0.0
+	github.com/google/uuid v1.6.0
 	github.com/stretchr/testify v1.11.1
-	k8s.io/api v0.35.0
-	k8s.io/apiextensions-apiserver v0.35.0
-	k8s.io/apimachinery v0.35.0
-	sigs.k8s.io/controller-runtime v0.23.1
+	k8s.io/api v0.35.2
+	k8s.io/apiextensions-apiserver v0.35.2
+	k8s.io/apimachinery v0.35.2
+	sigs.k8s.io/controller-runtime v0.23.3
 )
 
 require (
-	dario.cat/mergo v1.0.1 // indirect
+	dario.cat/mergo v1.0.2 // indirect
 	github.com/Masterminds/goutils v1.1.1 // indirect
 	github.com/Masterminds/semver/v3 v3.4.0 // indirect
+	github.com/aws/aws-sdk-go-v2 v1.39.6 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cespare/xxhash/v2 v2.3.0 // indirect
-	github.com/davecgh/go-spew v1.1.1 // indirect
-	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
+	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 // indirect
 	github.com/emicklei/go-restful/v3 v3.13.0 // indirect
 	github.com/evanphx/json-patch/v5 v5.9.11 // indirect
 	github.com/fsnotify/fsnotify v1.9.0 // indirect
 	github.com/fxamacker/cbor/v2 v2.9.0 // indirect
 	github.com/go-logr/logr v1.4.3 // indirect
-	github.com/go-openapi/jsonpointer v0.22.4 // indirect
-	github.com/go-openapi/jsonreference v0.21.4 // indirect
-	github.com/go-openapi/swag v0.25.4 // indirect
-	github.com/go-openapi/swag/cmdutils v0.25.4 // indirect
-	github.com/go-openapi/swag/conv v0.25.4 // indirect
-	github.com/go-openapi/swag/fileutils v0.25.4 // indirect
-	github.com/go-openapi/swag/jsonname v0.25.4 // indirect
-	github.com/go-openapi/swag/jsonutils v0.25.4 // indirect
-	github.com/go-openapi/swag/loading v0.25.4 // indirect
-	github.com/go-openapi/swag/mangling v0.25.4 // indirect
-	github.com/go-openapi/swag/netutils v0.25.4 // indirect
-	github.com/go-openapi/swag/stringutils v0.25.4 // indirect
-	github.com/go-openapi/swag/typeutils v0.25.4 // indirect
-	github.com/go-openapi/swag/yamlutils v0.25.4 // indirect
-	github.com/goccy/go-json v0.10.3 // indirect
+	github.com/go-openapi/jsonpointer v0.22.5 // indirect
+	github.com/go-openapi/jsonreference v0.21.5 // indirect
+	github.com/go-openapi/swag v0.25.5 // indirect
+	github.com/go-openapi/swag/cmdutils v0.25.5 // indirect
+	github.com/go-openapi/swag/conv v0.25.5 // indirect
+	github.com/go-openapi/swag/fileutils v0.25.5 // indirect
+	github.com/go-openapi/swag/jsonname v0.25.5 // indirect
+	github.com/go-openapi/swag/jsonutils v0.25.5 // indirect
+	github.com/go-openapi/swag/loading v0.25.5 // indirect
+	github.com/go-openapi/swag/mangling v0.25.5 // indirect
+	github.com/go-openapi/swag/netutils v0.25.5 // indirect
+	github.com/go-openapi/swag/stringutils v0.25.5 // indirect
+	github.com/go-openapi/swag/typeutils v0.25.5 // indirect
+	github.com/go-openapi/swag/yamlutils v0.25.5 // indirect
+	github.com/goccy/go-json v0.10.5 // indirect
+	github.com/gofrs/flock v0.13.0 // indirect
 	github.com/google/btree v1.1.3 // indirect
 	github.com/google/gnostic-models v0.7.1 // indirect
 	github.com/google/go-cmp v0.7.0 // indirect
-	github.com/google/uuid v1.6.0 // indirect
+	github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect
 	github.com/huandu/xstrings v1.5.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
-	github.com/lestrrat-go/blackmagic v1.0.3 // indirect
+	github.com/lestrrat-go/blackmagic v1.0.4 // indirect
 	github.com/lestrrat-go/httpcc v1.0.1 // indirect
 	github.com/lestrrat-go/httprc v1.0.6 // indirect
 	github.com/lestrrat-go/iter v1.0.2 // indirect
@@ -58,40 +61,42 @@ require (
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
-	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/oracle/oci-go-sdk/v65 v65.103.0 // indirect
+	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
 	github.com/prometheus/client_golang v1.23.2 // indirect
 	github.com/prometheus/client_model v0.6.2 // indirect
 	github.com/prometheus/common v0.67.5 // indirect
-	github.com/prometheus/procfs v0.19.2 // indirect
-	github.com/segmentio/asm v1.2.0 // indirect
+	github.com/prometheus/procfs v0.20.1 // indirect
+	github.com/segmentio/asm v1.2.1 // indirect
 	github.com/shopspring/decimal v1.4.0 // indirect
-	github.com/spf13/cast v1.7.0 // indirect
+	github.com/sony/gobreaker v1.0.0 // indirect
+	github.com/spf13/cast v1.10.0 // indirect
 	github.com/spf13/pflag v1.0.10 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
-	go.yaml.in/yaml/v2 v2.4.3 // indirect
+	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
-	golang.org/x/crypto v0.47.0 // indirect
-	golang.org/x/net v0.49.0 // indirect
-	golang.org/x/oauth2 v0.34.0 // indirect
-	golang.org/x/sync v0.19.0 // indirect
-	golang.org/x/sys v0.40.0 // indirect
-	golang.org/x/term v0.39.0 // indirect
-	golang.org/x/text v0.33.0 // indirect
-	golang.org/x/time v0.14.0 // indirect
+	golang.org/x/crypto v0.49.0 // indirect
+	golang.org/x/net v0.52.0 // indirect
+	golang.org/x/oauth2 v0.36.0 // indirect
+	golang.org/x/sync v0.20.0 // indirect
+	golang.org/x/sys v0.42.0 // indirect
+	golang.org/x/term v0.41.0 // indirect
+	golang.org/x/text v0.35.0 // indirect
+	golang.org/x/time v0.15.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	google.golang.org/protobuf v1.36.11 // indirect
 	gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
-	k8s.io/client-go v0.35.0 // indirect
-	k8s.io/klog/v2 v2.130.1 // indirect
-	k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 // indirect
-	k8s.io/utils v0.0.0-20260108192941-914a6e750570 // indirect
+	k8s.io/client-go v0.35.2 // indirect
+	k8s.io/klog/v2 v2.140.0 // indirect
+	k8s.io/kube-openapi v0.0.0-20260304202019-5b3e3fdb0acf // indirect
+	k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect
 	sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
 	sigs.k8s.io/randfill v1.0.0 // indirect
-	sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 // indirect
+	sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect
 	sigs.k8s.io/yaml v1.6.0 // indirect
-	software.sslmate.com/src/go-pkcs12 v0.6.0 // indirect
+	software.sslmate.com/src/go-pkcs12 v0.7.0 // indirect
 )
 
 replace (

+ 108 - 106
providers/v1/dvls/go.sum

@@ -1,24 +1,25 @@
-dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
-dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
-github.com/Devolutions/go-dvls v0.15.0 h1:T/uUK0sKli7i9yxcZb9/Lia/uUwmLi1phryNkYEp5t4=
-github.com/Devolutions/go-dvls v0.15.0/go.mod h1:4O3lb/RK1P1cDwU5auVi7CM4gRER7EuwyLwMVuEZjgg=
+dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
+dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
+github.com/Devolutions/go-dvls v0.19.1 h1:7EEHGr7qRJ4kYeFmBVf6PP7oSDDtw0EUdMi7UB3awns=
+github.com/Devolutions/go-dvls v0.19.1/go.mod h1:I0YI4GujLbbUojNnKLGVguiWUvnE2J9ltgwxTmtTRyo=
 github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
 github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
 github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
 github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
-github.com/aws/aws-sdk-go-v2 v1.39.3 h1:h7xSsanJ4EQJXG5iuW4UqgP7qBopLpj84mpkNx3wPjM=
-github.com/aws/aws-sdk-go-v2 v1.39.3/go.mod h1:yWSxrnioGUZ4WVv9TgMrNUeLV3PFESn/v+6T/Su8gnM=
-github.com/aws/smithy-go v1.23.1 h1:sLvcH6dfAFwGkHLZ7dGiYF7aK6mg4CgKA/iDKjLDt9M=
-github.com/aws/smithy-go v1.23.1/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
+github.com/aws/aws-sdk-go-v2 v1.39.6 h1:2JrPCVgWJm7bm83BDwY5z8ietmeJUbh3O2ACnn+Xsqk=
+github.com/aws/aws-sdk-go-v2 v1.39.6/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE=
+github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM=
+github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
 github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 h1:5RVFMOWjMyRy8cARdy79nAmgYw3hK/4HUq48LQ6Wwqo=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
 github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
 github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
 github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k=
@@ -35,46 +36,46 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
 github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
 github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
-github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4=
-github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80=
-github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8=
-github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4=
-github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU=
-github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ=
-github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4=
-github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
-github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4=
-github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU=
-github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y=
-github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk=
-github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI=
-github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag=
-github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA=
-github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY=
-github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo=
-github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM=
-github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s=
-github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE=
-github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48=
-github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg=
-github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0=
-github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg=
-github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8=
-github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0=
-github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw=
-github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE=
-github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw=
-github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc=
-github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4=
-github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg=
-github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls=
-github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
+github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA=
+github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0=
+github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE=
+github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw=
+github.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU=
+github.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA=
+github.com/go-openapi/swag/cmdutils v0.25.5 h1:yh5hHrpgsw4NwM9KAEtaDTXILYzdXh/I8Whhx9hKj7c=
+github.com/go-openapi/swag/cmdutils v0.25.5/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
+github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g=
+github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k=
+github.com/go-openapi/swag/fileutils v0.25.5 h1:B6JTdOcs2c0dBIs9HnkyTW+5gC+8NIhVBUwERkFhMWk=
+github.com/go-openapi/swag/fileutils v0.25.5/go.mod h1:V3cT9UdMQIaH4WiTrUc9EPtVA4txS0TOmRURmhGF4kc=
+github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo=
+github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU=
+github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo=
+github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo=
+github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU=
+github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g=
+github.com/go-openapi/swag/mangling v0.25.5 h1:hyrnvbQRS7vKePQPHHDso+k6CGn5ZBs5232UqWZmJZw=
+github.com/go-openapi/swag/mangling v0.25.5/go.mod h1:6hadXM/o312N/h98RwByLg088U61TPGiltQn71Iw0NY=
+github.com/go-openapi/swag/netutils v0.25.5 h1:LZq2Xc2QI8+7838elRAaPCeqJnHODfSyOa7ZGfxDKlU=
+github.com/go-openapi/swag/netutils v0.25.5/go.mod h1:lHbtmj4m57APG/8H7ZcMMSWzNqIQcu0RFiXrPUara14=
+github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M=
+github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII=
+github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E=
+github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc=
+github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ=
+github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ=
+github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 h1:7SgOMTvJkM8yWrQlU8Jm18VeDPuAvB/xWrdxFJkoFag=
+github.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM=
+github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM=
+github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
 github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
 github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
-github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
-github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
-github.com/gofrs/flock v0.10.0 h1:SHMXenfaB03KbroETaCMtbBg3Yn29v4w1r+tgy4ff4k=
-github.com/gofrs/flock v0.10.0/go.mod h1:FirDy1Ing0mI2+kB6wk+vyyAH+e6xiE+EYA0jnzV9jc=
+github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
+github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
+github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw=
+github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0=
 github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
 github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
 github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c=
@@ -84,8 +85,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
 github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
-github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
+github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc=
+github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
@@ -100,8 +101,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
-github.com/lestrrat-go/blackmagic v1.0.3 h1:94HXkVLxkZO9vJI/w2u1T0DAoprShFd13xtnSINtDWs=
-github.com/lestrrat-go/blackmagic v1.0.3/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw=
+github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA=
+github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw=
 github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
 github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
 github.com/lestrrat-go/httprc v1.0.6 h1:qgmgIRhpvBqexMJjA/PmwSvhNk679oqD1RbovdCGW8k=
@@ -128,30 +129,31 @@ github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns
 github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
 github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
 github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
-github.com/oracle/oci-go-sdk/v65 v65.102.1 h1:zLNLz5dVzZxOf5DK/f3WGZUjwrQ9m27fd4abOFwQRCQ=
-github.com/oracle/oci-go-sdk/v65 v65.102.1/go.mod h1:oB8jFGVc/7/zJ+DbleE8MzGHjhs2ioCz5stRTdZdIcY=
+github.com/oracle/oci-go-sdk/v65 v65.103.0 h1:HfyZx+JefCPK3At0Xt45q+wr914jDXuoyzOFX3XCbno=
+github.com/oracle/oci-go-sdk/v65 v65.103.0/go.mod h1:oB8jFGVc/7/zJ+DbleE8MzGHjhs2ioCz5stRTdZdIcY=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
 github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
 github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
 github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
 github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
 github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
-github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
-github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
+github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=
+github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=
 github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
 github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
-github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
-github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
+github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
+github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
 github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
 github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
-github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg=
-github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
-github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
-github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
+github.com/sony/gobreaker v1.0.0 h1:feX5fGGXSl3dYd4aHZItw+FpHLvvoaqkawKjVNiFMNQ=
+github.com/sony/gobreaker v1.0.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
+github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
+github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
 github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
 github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -172,30 +174,30 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
 go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
 go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
 go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
-go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
-go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
+go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
+go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
 go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
-golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
-golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
-golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
-golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
-golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
-golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
-golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
-golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
-golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
-golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
-golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
-golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
-golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
-golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
-golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
-golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
-golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
-golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
-golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
+golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
+golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
+golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
+golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
+golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
+golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
+golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
+golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
+golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
+golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
+golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
+golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
+golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
+golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
+golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
+golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
+golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
+golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
@@ -210,29 +212,29 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-k8s.io/api v0.35.0 h1:iBAU5LTyBI9vw3L5glmat1njFK34srdLmktWwLTprlY=
-k8s.io/api v0.35.0/go.mod h1:AQ0SNTzm4ZAczM03QH42c7l3bih1TbAXYo0DkF8ktnA=
-k8s.io/apiextensions-apiserver v0.35.0 h1:3xHk2rTOdWXXJM+RDQZJvdx0yEOgC0FgQ1PlJatA5T4=
-k8s.io/apiextensions-apiserver v0.35.0/go.mod h1:E1Ahk9SADaLQ4qtzYFkwUqusXTcaV2uw3l14aqpL2LU=
-k8s.io/apimachinery v0.35.0 h1:Z2L3IHvPVv/MJ7xRxHEtk6GoJElaAqDCCU0S6ncYok8=
-k8s.io/apimachinery v0.35.0/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
-k8s.io/client-go v0.35.0 h1:IAW0ifFbfQQwQmga0UdoH0yvdqrbwMdq9vIFEhRpxBE=
-k8s.io/client-go v0.35.0/go.mod h1:q2E5AAyqcbeLGPdoRB+Nxe3KYTfPce1Dnu1myQdqz9o=
-k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
-k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 h1:HhDfevmPS+OalTjQRKbTHppRIz01AWi8s45TMXStgYY=
-k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
-k8s.io/utils v0.0.0-20260108192941-914a6e750570 h1:JT4W8lsdrGENg9W+YwwdLJxklIuKWdRm+BC+xt33FOY=
-k8s.io/utils v0.0.0-20260108192941-914a6e750570/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
-sigs.k8s.io/controller-runtime v0.23.1 h1:TjJSM80Nf43Mg21+RCy3J70aj/W6KyvDtOlpKf+PupE=
-sigs.k8s.io/controller-runtime v0.23.1/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
+k8s.io/api v0.35.2 h1:tW7mWc2RpxW7HS4CoRXhtYHSzme1PN1UjGHJ1bdrtdw=
+k8s.io/api v0.35.2/go.mod h1:7AJfqGoAZcwSFhOjcGM7WV05QxMMgUaChNfLTXDRE60=
+k8s.io/apiextensions-apiserver v0.35.2 h1:iyStXHoJZsUXPh/nFAsjC29rjJWdSgUmG1XpApE29c0=
+k8s.io/apiextensions-apiserver v0.35.2/go.mod h1:OdyGvcO1FtMDWQ+rRh/Ei3b6X3g2+ZDHd0MSRGeS8rU=
+k8s.io/apimachinery v0.35.2 h1:NqsM/mmZA7sHW02JZ9RTtk3wInRgbVxL8MPfzSANAK8=
+k8s.io/apimachinery v0.35.2/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
+k8s.io/client-go v0.35.2 h1:YUfPefdGJA4aljDdayAXkc98DnPkIetMl4PrKX97W9o=
+k8s.io/client-go v0.35.2/go.mod h1:4QqEwh4oQpeK8AaefZ0jwTFJw/9kIjdQi0jpKeYvz7g=
+k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
+k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
+k8s.io/kube-openapi v0.0.0-20260304202019-5b3e3fdb0acf h1:btPscg4cMql0XdYK2jLsJcNEKmACJz8l+U7geC06FiM=
+k8s.io/kube-openapi v0.0.0-20260304202019-5b3e3fdb0acf/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
+k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU=
+k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
+sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80=
+sigs.k8s.io/controller-runtime v0.23.3/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
 sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
 sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
 sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
 sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
-sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 h1:2WOzJpHUBVrrkDjU4KBT8n5LDcj824eX0I5UKcgeRUs=
-sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
+sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8=
+sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
 sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
 sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
-software.sslmate.com/src/go-pkcs12 v0.6.0 h1:f3sQittAeF+pao32Vb+mkli+ZyT+VwKaD014qFGq6oU=
-software.sslmate.com/src/go-pkcs12 v0.6.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=
+software.sslmate.com/src/go-pkcs12 v0.7.0 h1:Db8W44cB54TWD7stUFFSWxdfpdn6fZVcDl0w3R4RVM0=
+software.sslmate.com/src/go-pkcs12 v0.7.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=

+ 8 - 2
providers/v1/dvls/provider.go

@@ -20,6 +20,7 @@ import (
 	"context"
 	"fmt"
 	"net/url"
+	"strings"
 
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
@@ -43,12 +44,12 @@ func (p *Provider) NewClient(ctx context.Context, store esv1.GenericStore, kube
 
 	storeKind := store.GetObjectKind().GroupVersionKind().Kind
 
-	dvlsClient, err := NewDVLSClient(ctx, kube, storeKind, namespace, dvlsProvider)
+	credClient, vaultID, err := NewDVLSClient(ctx, kube, storeKind, namespace, dvlsProvider)
 	if err != nil {
 		return nil, fmt.Errorf("failed to create DVLS client: %w", err)
 	}
 
-	return NewClient(dvlsClient), nil
+	return NewClient(credClient, vaultID), nil
 }
 
 // ValidateStore validates the SecretStore configuration.
@@ -62,6 +63,11 @@ func (p *Provider) ValidateStore(store esv1.GenericStore) (admission.Warnings, e
 		return nil, fmt.Errorf("serverUrl is required")
 	}
 
+	vault := strings.TrimSpace(dvlsProvider.Vault)
+	if vault != dvlsProvider.Vault {
+		return nil, fmt.Errorf("vault must not contain leading or trailing whitespace")
+	}
+
 	parsedURL, err := url.Parse(dvlsProvider.ServerURL)
 	if err != nil {
 		return nil, fmt.Errorf("serverUrl must be a valid URL: %w", err)

+ 106 - 2
providers/v1/dvls/provider_test.go

@@ -50,6 +50,7 @@ func TestProvider_ValidateStore(t *testing.T) {
 				Provider: &esv1.SecretStoreProvider{
 					DVLS: &esv1.DVLSProvider{
 						ServerURL: testServerURL,
+						Vault:     "Default",
 						Auth: esv1.DVLSAuth{
 							SecretRef: esv1.DVLSAuthSecretRef{
 								AppID: esmeta.SecretKeySelector{
@@ -80,6 +81,7 @@ func TestProvider_ValidateStore(t *testing.T) {
 				Provider: &esv1.SecretStoreProvider{
 					DVLS: &esv1.DVLSProvider{
 						ServerURL: testServerURL,
+						Vault:     "Default",
 						Auth: esv1.DVLSAuth{
 							SecretRef: esv1.DVLSAuthSecretRef{
 								AppID: esmeta.SecretKeySelector{
@@ -113,6 +115,7 @@ func TestProvider_ValidateStore(t *testing.T) {
 				Provider: &esv1.SecretStoreProvider{
 					DVLS: &esv1.DVLSProvider{
 						ServerURL: testServerURL,
+						Vault:     "Default",
 						Auth: esv1.DVLSAuth{
 							SecretRef: esv1.DVLSAuthSecretRef{
 								AppID: esmeta.SecretKeySelector{
@@ -159,6 +162,7 @@ func TestProvider_ValidateStore(t *testing.T) {
 				Provider: &esv1.SecretStoreProvider{
 					DVLS: &esv1.DVLSProvider{
 						ServerURL: "http://dvls.example.com",
+						Vault:     "Default",
 						Auth: esv1.DVLSAuth{
 							SecretRef: esv1.DVLSAuthSecretRef{
 								AppID: esmeta.SecretKeySelector{
@@ -190,6 +194,7 @@ func TestProvider_ValidateStore(t *testing.T) {
 				Provider: &esv1.SecretStoreProvider{
 					DVLS: &esv1.DVLSProvider{
 						ServerURL: "http://dvls.example.com",
+						Vault:     "Default",
 						Insecure:  true,
 						Auth: esv1.DVLSAuth{
 							SecretRef: esv1.DVLSAuthSecretRef{
@@ -242,7 +247,7 @@ func TestProvider_ValidateStore(t *testing.T) {
 		assert.Contains(t, err.Error(), "serverUrl is required")
 	})
 
-	t.Run("case 3b: should return error when appId key is missing", func(t *testing.T) {
+	t.Run("case 3a: should accept empty vault (uses default)", func(t *testing.T) {
 		store := &esv1.SecretStore{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      "dvls-store",
@@ -252,6 +257,102 @@ func TestProvider_ValidateStore(t *testing.T) {
 				Provider: &esv1.SecretStoreProvider{
 					DVLS: &esv1.DVLSProvider{
 						ServerURL: testServerURL,
+						Vault:     "",
+						Auth: esv1.DVLSAuth{
+							SecretRef: esv1.DVLSAuthSecretRef{
+								AppID: esmeta.SecretKeySelector{
+									Name: secretName,
+									Key:  appIDKey,
+								},
+								AppSecret: esmeta.SecretKeySelector{
+									Name: secretName,
+									Key:  appSecretKey,
+								},
+							},
+						},
+					},
+				},
+			},
+		}
+		_, err := p.ValidateStore(store)
+		assert.NoError(t, err)
+	})
+
+	t.Run("case 3b: should return error when vault is whitespace-only", func(t *testing.T) {
+		store := &esv1.SecretStore{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "dvls-store",
+				Namespace: testNamespace,
+			},
+			Spec: esv1.SecretStoreSpec{
+				Provider: &esv1.SecretStoreProvider{
+					DVLS: &esv1.DVLSProvider{
+						ServerURL: testServerURL,
+						Vault:     "   ",
+						Auth: esv1.DVLSAuth{
+							SecretRef: esv1.DVLSAuthSecretRef{
+								AppID: esmeta.SecretKeySelector{
+									Name: secretName,
+									Key:  appIDKey,
+								},
+								AppSecret: esmeta.SecretKeySelector{
+									Name: secretName,
+									Key:  appSecretKey,
+								},
+							},
+						},
+					},
+				},
+			},
+		}
+		_, err := p.ValidateStore(store)
+		assert.Error(t, err)
+		assert.Contains(t, err.Error(), "vault must not contain leading or trailing whitespace")
+	})
+
+	t.Run("case 3c: should return error when vault has leading/trailing whitespace", func(t *testing.T) {
+		store := &esv1.SecretStore{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "dvls-store",
+				Namespace: testNamespace,
+			},
+			Spec: esv1.SecretStoreSpec{
+				Provider: &esv1.SecretStoreProvider{
+					DVLS: &esv1.DVLSProvider{
+						ServerURL: testServerURL,
+						Vault:     " my-vault ",
+						Auth: esv1.DVLSAuth{
+							SecretRef: esv1.DVLSAuthSecretRef{
+								AppID: esmeta.SecretKeySelector{
+									Name: secretName,
+									Key:  appIDKey,
+								},
+								AppSecret: esmeta.SecretKeySelector{
+									Name: secretName,
+									Key:  appSecretKey,
+								},
+							},
+						},
+					},
+				},
+			},
+		}
+		_, err := p.ValidateStore(store)
+		assert.Error(t, err)
+		assert.Contains(t, err.Error(), "vault must not contain leading or trailing whitespace")
+	})
+
+	t.Run("case 3d: should return error when appId key is missing", func(t *testing.T) {
+		store := &esv1.SecretStore{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "dvls-store",
+				Namespace: testNamespace,
+			},
+			Spec: esv1.SecretStoreSpec{
+				Provider: &esv1.SecretStoreProvider{
+					DVLS: &esv1.DVLSProvider{
+						ServerURL: testServerURL,
+						Vault:     "Default",
 						Auth: esv1.DVLSAuth{
 							SecretRef: esv1.DVLSAuthSecretRef{
 								AppID: esmeta.SecretKeySelector{
@@ -273,7 +374,7 @@ func TestProvider_ValidateStore(t *testing.T) {
 		assert.Contains(t, err.Error(), "appId secret key is required")
 	})
 
-	t.Run("case 3c: should return error when appSecret name is missing", func(t *testing.T) {
+	t.Run("case 3e: should return error when appSecret name is missing", func(t *testing.T) {
 		store := &esv1.SecretStore{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      "dvls-store",
@@ -283,6 +384,7 @@ func TestProvider_ValidateStore(t *testing.T) {
 				Provider: &esv1.SecretStoreProvider{
 					DVLS: &esv1.DVLSProvider{
 						ServerURL: testServerURL,
+						Vault:     "Default",
 						Auth: esv1.DVLSAuth{
 							SecretRef: esv1.DVLSAuthSecretRef{
 								AppID: esmeta.SecretKeySelector{
@@ -315,6 +417,7 @@ func TestProvider_ValidateStore(t *testing.T) {
 				Provider: &esv1.SecretStoreProvider{
 					DVLS: &esv1.DVLSProvider{
 						ServerURL: testServerURL,
+						Vault:     "Default",
 						Auth: esv1.DVLSAuth{
 							SecretRef: esv1.DVLSAuthSecretRef{
 								AppID: esmeta.SecretKeySelector{
@@ -348,6 +451,7 @@ func TestProvider_ValidateStore(t *testing.T) {
 				Provider: &esv1.SecretStoreProvider{
 					DVLS: &esv1.DVLSProvider{
 						ServerURL: testServerURL,
+						Vault:     "Default",
 						Auth: esv1.DVLSAuth{
 							SecretRef: esv1.DVLSAuthSecretRef{
 								AppID: esmeta.SecretKeySelector{

+ 1 - 0
tests/__snapshot__/clustersecretstore-v1.yaml

@@ -286,6 +286,7 @@ spec:
             namespace: string
       insecure: true
       serverUrl: string
+      vault: string
     fake:
       data:
       - key: string

+ 1 - 0
tests/__snapshot__/secretstore-v1.yaml

@@ -286,6 +286,7 @@ spec:
             namespace: string
       insecure: true
       serverUrl: string
+      vault: string
     fake:
       data:
       - key: string