Procházet zdrojové kódy

Merge branch 'main' into mj-v2-poc-2

Signed-off-by: Gergely Bräutigam <gergely.brautigam@sap.com>
Gergely Bräutigam před 11 hodinami
rodič
revize
88a969e0df
41 změnil soubory, kde provedl 872 přidání a 328 odebrání
  1. 1 1
      Dockerfile.standalone
  2. 5 0
      apis/externalsecrets/v1/externalsecret_types.go
  3. 10 0
      config/crds/bases/external-secrets.io_clusterexternalsecrets.yaml
  4. 10 0
      config/crds/bases/external-secrets.io_clusterpushsecrets.yaml
  5. 10 0
      config/crds/bases/external-secrets.io_externalsecrets.yaml
  6. 10 0
      config/crds/bases/external-secrets.io_pushsecrets.yaml
  7. 36 0
      deploy/crds/bundle.yaml
  8. 16 1
      docs/api/spec.md
  9. 96 1
      docs/guides/templating.md
  10. 0 4
      go.mod
  11. 3 3
      pkg/controllers/externalsecret/externalsecret_controller_manifest.go
  12. 4 3
      pkg/controllers/externalsecret/externalsecret_controller_secret.go
  13. 4 4
      pkg/controllers/templating/parser.go
  14. 69 0
      pkg/controllers/templating/parser_test.go
  15. 5 5
      providers/v2/adapter/generator/go.mod
  16. 14 14
      providers/v2/adapter/generator/go.sum
  17. 5 5
      providers/v2/adapter/go.mod
  18. 14 14
      providers/v2/adapter/go.sum
  19. 5 5
      providers/v2/adapter/store/go.mod
  20. 14 14
      providers/v2/adapter/store/go.sum
  21. 6 6
      providers/v2/aws/go.mod
  22. 16 16
      providers/v2/aws/go.sum
  23. 5 5
      providers/v2/common/go.mod
  24. 14 14
      providers/v2/common/go.sum
  25. 6 6
      providers/v2/fake/go.mod
  26. 16 16
      providers/v2/fake/go.sum
  27. 6 6
      providers/v2/kubernetes/go.mod
  28. 16 16
      providers/v2/kubernetes/go.sum
  29. 73 0
      runtime/decoding/decoding.go
  30. 211 0
      runtime/decoding/decoding_test.go
  31. 2 49
      runtime/esutils/utils.go
  32. 0 100
      runtime/esutils/utils_test.go
  33. 1 1
      runtime/template/engine.go
  34. 52 0
      runtime/template/engine_test.go
  35. 15 6
      runtime/template/v2/template.go
  36. 97 11
      runtime/template/v2/template_test.go
  37. 1 0
      tests/__snapshot__/clusterexternalsecret-v1.yaml
  38. 1 0
      tests/__snapshot__/externalsecret-v1.yaml
  39. 1 0
      tests/__snapshot__/pushsecret-v1alpha1.yaml
  40. 1 1
      tilt.debug.dockerfile
  41. 1 1
      tilt.dockerfile

+ 1 - 1
Dockerfile.standalone

@@ -1,6 +1,6 @@
 # This version of Dockerfile is for building without external dependencies.
 # This version of Dockerfile is for building without external dependencies.
 # Build a multi-platform image e.g. `docker buildx build --push --platform linux/arm64,linux/amd64 --tag external-secrets:dev --file Dockerfile.standalone .`
 # Build a multi-platform image e.g. `docker buildx build --push --platform linux/arm64,linux/amd64 --tag external-secrets:dev --file Dockerfile.standalone .`
-FROM golang:1.26.4-alpine@sha256:7a3e50096189ad57c9f9f865e7e4aa8585ed1585248513dc5cda498e2f41812c AS builder
+FROM golang:1.26.4-alpine@sha256:3ad57304ad93bbec8548a0437ad9e06a455660655d9af011d58b993f6f615648 AS builder
 # Add metadata
 # Add metadata
 LABEL maintainer="cncf-externalsecretsop-maintainers@lists.cncf.io" \
 LABEL maintainer="cncf-externalsecretsop-maintainers@lists.cncf.io" \
       description="External Secrets Operator is a Kubernetes operator that integrates external secret management systems"
       description="External Secrets Operator is a Kubernetes operator that integrates external secret management systems"

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

@@ -163,6 +163,11 @@ type TemplateFrom struct {
 
 
 	// +optional
 	// +optional
 	Literal *string `json:"literal,omitempty"`
 	Literal *string `json:"literal,omitempty"`
+
+	// Used to define a decoding Strategy for the rendered template values.
+	// +optional
+	// +kubebuilder:default="None"
+	ValuesDecodingStrategy ExternalSecretDecodingStrategy `json:"valuesDecodingStrategy,omitempty"`
 }
 }
 
 
 // TemplateScope specifies how the template keys should be interpreted.
 // TemplateScope specifies how the template keys should be interpreted.

+ 10 - 0
config/crds/bases/external-secrets.io_clusterexternalsecrets.yaml

@@ -724,6 +724,16 @@ spec:
                                     For custom resources (when spec.target.manifest is set), this supports
                                     For custom resources (when spec.target.manifest is set), this supports
                                     nested paths like "spec.database.config" or "data".
                                     nested paths like "spec.database.config" or "data".
                                   type: string
                                   type: string
+                                valuesDecodingStrategy:
+                                  default: None
+                                  description: Used to define a decoding Strategy
+                                    for the rendered template values.
+                                  enum:
+                                  - Auto
+                                  - Base64
+                                  - Base64URL
+                                  - None
+                                  type: string
                               type: object
                               type: object
                             type: array
                             type: array
                           type:
                           type:

+ 10 - 0
config/crds/bases/external-secrets.io_clusterpushsecrets.yaml

@@ -660,6 +660,16 @@ spec:
                                 For custom resources (when spec.target.manifest is set), this supports
                                 For custom resources (when spec.target.manifest is set), this supports
                                 nested paths like "spec.database.config" or "data".
                                 nested paths like "spec.database.config" or "data".
                               type: string
                               type: string
+                            valuesDecodingStrategy:
+                              default: None
+                              description: Used to define a decoding Strategy for
+                                the rendered template values.
+                              enum:
+                              - Auto
+                              - Base64
+                              - Base64URL
+                              - None
+                              type: string
                           type: object
                           type: object
                         type: array
                         type: array
                       type:
                       type:

+ 10 - 0
config/crds/bases/external-secrets.io_externalsecrets.yaml

@@ -703,6 +703,16 @@ spec:
                                 For custom resources (when spec.target.manifest is set), this supports
                                 For custom resources (when spec.target.manifest is set), this supports
                                 nested paths like "spec.database.config" or "data".
                                 nested paths like "spec.database.config" or "data".
                               type: string
                               type: string
+                            valuesDecodingStrategy:
+                              default: None
+                              description: Used to define a decoding Strategy for
+                                the rendered template values.
+                              enum:
+                              - Auto
+                              - Base64
+                              - Base64URL
+                              - None
+                              type: string
                           type: object
                           type: object
                         type: array
                         type: array
                       type:
                       type:

+ 10 - 0
config/crds/bases/external-secrets.io_pushsecrets.yaml

@@ -582,6 +582,16 @@ spec:
                             For custom resources (when spec.target.manifest is set), this supports
                             For custom resources (when spec.target.manifest is set), this supports
                             nested paths like "spec.database.config" or "data".
                             nested paths like "spec.database.config" or "data".
                           type: string
                           type: string
+                        valuesDecodingStrategy:
+                          default: None
+                          description: Used to define a decoding Strategy for the
+                            rendered template values.
+                          enum:
+                          - Auto
+                          - Base64
+                          - Base64URL
+                          - None
+                          type: string
                       type: object
                       type: object
                     type: array
                     type: array
                   type:
                   type:

+ 36 - 0
deploy/crds/bundle.yaml

@@ -675,6 +675,15 @@ spec:
                                       For custom resources (when spec.target.manifest is set), this supports
                                       For custom resources (when spec.target.manifest is set), this supports
                                       nested paths like "spec.database.config" or "data".
                                       nested paths like "spec.database.config" or "data".
                                     type: string
                                     type: string
+                                  valuesDecodingStrategy:
+                                    default: None
+                                    description: Used to define a decoding Strategy for the rendered template values.
+                                    enum:
+                                      - Auto
+                                      - Base64
+                                      - Base64URL
+                                      - None
+                                    type: string
                                 type: object
                                 type: object
                               type: array
                               type: array
                             type:
                             type:
@@ -2313,6 +2322,15 @@ spec:
                                   For custom resources (when spec.target.manifest is set), this supports
                                   For custom resources (when spec.target.manifest is set), this supports
                                   nested paths like "spec.database.config" or "data".
                                   nested paths like "spec.database.config" or "data".
                                 type: string
                                 type: string
+                              valuesDecodingStrategy:
+                                default: None
+                                description: Used to define a decoding Strategy for the rendered template values.
+                                enum:
+                                  - Auto
+                                  - Base64
+                                  - Base64URL
+                                  - None
+                                type: string
                             type: object
                             type: object
                           type: array
                           type: array
                         type:
                         type:
@@ -13720,6 +13738,15 @@ spec:
                                   For custom resources (when spec.target.manifest is set), this supports
                                   For custom resources (when spec.target.manifest is set), this supports
                                   nested paths like "spec.database.config" or "data".
                                   nested paths like "spec.database.config" or "data".
                                 type: string
                                 type: string
+                              valuesDecodingStrategy:
+                                default: None
+                                description: Used to define a decoding Strategy for the rendered template values.
+                                enum:
+                                  - Auto
+                                  - Base64
+                                  - Base64URL
+                                  - None
+                                type: string
                             type: object
                             type: object
                           type: array
                           type: array
                         type:
                         type:
@@ -15071,6 +15098,15 @@ spec:
                               For custom resources (when spec.target.manifest is set), this supports
                               For custom resources (when spec.target.manifest is set), this supports
                               nested paths like "spec.database.config" or "data".
                               nested paths like "spec.database.config" or "data".
                             type: string
                             type: string
+                          valuesDecodingStrategy:
+                            default: None
+                            description: Used to define a decoding Strategy for the rendered template values.
+                            enum:
+                              - Auto
+                              - Base64
+                              - Base64URL
+                              - None
+                            type: string
                         type: object
                         type: object
                       type: array
                       type: array
                     type:
                     type:

+ 16 - 1
docs/api/spec.md

@@ -4423,7 +4423,8 @@ ExternalSecretNullBytePolicy
 <p>
 <p>
 (<em>Appears on:</em>
 (<em>Appears on:</em>
 <a href="#external-secrets.io/v1.ExternalSecretDataRemoteRef">ExternalSecretDataRemoteRef</a>, 
 <a href="#external-secrets.io/v1.ExternalSecretDataRemoteRef">ExternalSecretDataRemoteRef</a>, 
-<a href="#external-secrets.io/v1.ExternalSecretFind">ExternalSecretFind</a>)
+<a href="#external-secrets.io/v1.ExternalSecretFind">ExternalSecretFind</a>, 
+<a href="#external-secrets.io/v1.TemplateFrom">TemplateFrom</a>)
 </p>
 </p>
 <p>
 <p>
 <p>ExternalSecretDecodingStrategy defines strategies for decoding secret values.</p>
 <p>ExternalSecretDecodingStrategy defines strategies for decoding secret values.</p>
@@ -11662,6 +11663,20 @@ string
 <em>(Optional)</em>
 <em>(Optional)</em>
 </td>
 </td>
 </tr>
 </tr>
+<tr>
+<td>
+<code>valuesDecodingStrategy</code></br>
+<em>
+<a href="#external-secrets.io/v1.ExternalSecretDecodingStrategy">
+ExternalSecretDecodingStrategy
+</a>
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>Used to define a decoding Strategy for the rendered template values.</p>
+</td>
+</tr>
 </tbody>
 </tbody>
 </table>
 </table>
 <h3 id="external-secrets.io/v1.TemplateMergePolicy">TemplateMergePolicy
 <h3 id="external-secrets.io/v1.TemplateMergePolicy">TemplateMergePolicy

+ 96 - 1
docs/guides/templating.md

@@ -57,7 +57,102 @@ You do not have to define your templates inline in an ExternalSecret but you can
 
 
 Lastly, `TemplateFrom` also supports adding `Literal` blocks for quick templating. These `Literal` blocks differ from `Template.Data` as they are rendered as a a `key:value` pair (while the `Template.Data`, you can only template the value).
 Lastly, `TemplateFrom` also supports adding `Literal` blocks for quick templating. These `Literal` blocks differ from `Template.Data` as they are rendered as a a `key:value` pair (while the `Template.Data`, you can only template the value).
 
 
-See an example, how to produce a `htpasswd` file that can be used by an ingress-controller (for example: https://kubernetes.github.io/ingress-nginx/examples/auth/basic/) where the contents of the `htpasswd` file needs to be presented via the `auth` key. We use the `htpasswd` function to create a `bcrytped` hash of the password.
+#### ValuesDecodingStrategy example
+
+`TemplateFrom` entries can also decode rendered values with `ValuesDecodingStrategy`. This is useful when the template selects Base64-encoded values from structured provider data and the final Kubernetes Secret must contain the decoded bytes.
+
+For example, imagine several remote secrets matched by `dataFrom.find` contain JSON values like this:
+
+```json
+{
+  "cert": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCg==",
+  "description": "certificate encoded as base64"
+}
+```
+
+And let's imagine an ExternalSecret definition as this one:
+
+```yaml
+{% raw %}
+apiVersion: external-secrets.io/v1
+kind: ExternalSecret
+metadata:
+  name: nginx-certs
+spec:
+  refreshInterval: 1h
+  secretStoreRef:
+    kind: ClusterSecretStore
+    name: aws-secretsmanager
+  dataFrom:
+  - find:
+      name:
+        regexp: ^productA/nginx/.*
+    rewrite:
+    - regexp:
+        source: ^productA/nginx/(.*)
+        target: $1
+  target:
+    name: nginx-certs
+    template:
+      engineVersion: v2
+      templateFrom:
+      - literal: |-
+          {{- range $key, $val := . }}
+          {{- $json := $val | fromJson }}
+          {{ $key }}: {{ $json.cert }}
+          {{- end }}
+{% endraw %}
+```
+Without `templateFrom[0].ValuesDecodingStrategy`, the template will select the `cert` property, and get the base64 text. The resulting Kubernetes Secret value will be stored as Base64 text.
+
+Alternatively, you can use the `templateFrom[0].valuesDecodingStrategy: Base64` as following:
+
+```yaml
+{% raw %}
+apiVersion: external-secrets.io/v1
+kind: ExternalSecret
+metadata:
+  name: nginx-certs
+spec:
+  refreshInterval: 1h
+  secretStoreRef:
+    kind: ClusterSecretStore
+    name: aws-secretsmanager
+  dataFrom:
+  - find:
+      name:
+        regexp: ^productA/nginx/.*
+    rewrite:
+    - regexp:
+        source: ^productA/nginx/(.*)
+        target: $1
+  target:
+    name: nginx-certs
+    template:
+      engineVersion: v2
+      templateFrom:
+      - valuesDecodingStrategy: Base64
+        literal: |-
+          {{- range $key, $val := . }}
+          {{- $json := $val | fromJson }}
+          {{ $key }}: {{ $json.cert }}
+          {{- end }}
+{% endraw %}
+```
+
+This way, the template still renders safe Base64 text internally.
+ESO then decodes the value and writes the decoded bytes in the Kubernetes Secret's data.
+Only rendered values are decoded; rendered keys are left unchanged.
+
+In other words, use `valuesDecodingStrategy` to `None` when values are not encoded, and our usual strategies like `Base64`, `Base64URL` (or even `Auto`) when values may be either Base64/Base64URL encoded.
+
+!!! note
+
+    This is safer for binary data than decoding inside the template with `{% raw %}{{ $json.cert | b64dec }}{% endraw %}`, because `b64dec` injects raw bytes into the intermediate rendered YAML.
+
+#### htpasswd example
+
+See an example, how to produce a `htpasswd` file that can be used by an ingress-controller (for example: https://kubernetes.github.io/ingress-nginx/examples/auth/basic/) where the contents of the `htpasswd` file needs to be presented via the `auth` key. We use the `htpasswd` function to create a `bcrypted` hash of the password.
 
 
 Suppose you have multiple key-value pairs within your provider secret like
 Suppose you have multiple key-value pairs within your provider secret like
 
 

+ 0 - 4
go.mod

@@ -312,7 +312,6 @@ require (
 	github.com/hashicorp/vault/api/auth/gcp v0.11.0 // indirect
 	github.com/hashicorp/vault/api/auth/gcp v0.11.0 // indirect
 	github.com/ianlancetaylor/demangle v0.0.0-20250628045327-2d64ad6b7ec5 // indirect
 	github.com/ianlancetaylor/demangle v0.0.0-20250628045327-2d64ad6b7ec5 // indirect
 	github.com/infisical/go-sdk v0.8.0 // indirect
 	github.com/infisical/go-sdk v0.8.0 // indirect
-	github.com/keeper-security/secrets-manager-go/core v1.6.4 // indirect
 	github.com/kylelemons/godebug v1.1.0 // indirect
 	github.com/kylelemons/godebug v1.1.0 // indirect
 	github.com/lestrrat-go/httprc v1.0.6 // indirect
 	github.com/lestrrat-go/httprc v1.0.6 // indirect
 	github.com/nebius/gosdk v0.0.0-20260204094009-511fd4d4f7a1 // indirect
 	github.com/nebius/gosdk v0.0.0-20260204094009-511fd4d4f7a1 // indirect
@@ -321,9 +320,6 @@ require (
 	github.com/openbao/openbao/api/auth/userpass/v2 v2.5.1 // indirect
 	github.com/openbao/openbao/api/auth/userpass/v2 v2.5.1 // indirect
 	github.com/openbao/openbao/api/v2 v2.5.1-0.20260603121413-a08669ff09ec // indirect
 	github.com/openbao/openbao/api/v2 v2.5.1-0.20260603121413-a08669ff09ec // indirect
 	github.com/ovh/okms-sdk-go v0.5.1 // indirect
 	github.com/ovh/okms-sdk-go v0.5.1 // indirect
-	github.com/passbolt/go-passbolt v0.8.0 // indirect
-	github.com/previder/vault-cli v0.1.3 // indirect
-	github.com/pulumi/esc-sdk/sdk v0.14.0 // indirect
 	github.com/rs/zerolog v1.33.0 // indirect
 	github.com/rs/zerolog v1.33.0 // indirect
 	github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
 	github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
 	github.com/segmentio/asm v1.2.1 // indirect
 	github.com/segmentio/asm v1.2.1 // indirect

+ 3 - 3
pkg/controllers/externalsecret/externalsecret_controller_manifest.go

@@ -288,7 +288,7 @@ func (r *Reconciler) renderTemplatedManifest(ctx context.Context, es *esv1.Exter
 			// Execute template directly against the unstructured object
 			// Execute template directly against the unstructured object
 			out := make(map[string][]byte)
 			out := make(map[string][]byte)
 			out[*tplFrom.Literal] = []byte(*tplFrom.Literal)
 			out[*tplFrom.Literal] = []byte(*tplFrom.Literal)
-			if err := execute(out, dataMap, esv1.TemplateScopeKeysAndValues, targetPath, obj); err != nil {
+			if err := execute(out, dataMap, esv1.TemplateScopeKeysAndValues, targetPath, obj, tplFrom.ValuesDecodingStrategy); err != nil {
 				return nil, fmt.Errorf("failed to execute literal template: %w", err)
 				return nil, fmt.Errorf("failed to execute literal template: %w", err)
 			}
 			}
 		}
 		}
@@ -316,7 +316,7 @@ func (r *Reconciler) renderTemplatedManifest(ctx context.Context, es *esv1.Exter
 			}
 			}
 
 
 			// apply collected data to the target object
 			// apply collected data to the target object
-			if err := execute(tempSecret.Data, dataMap, esv1.TemplateScopeValues, targetPath, obj); err != nil {
+			if err := execute(tempSecret.Data, dataMap, esv1.TemplateScopeValues, targetPath, obj, esv1.ExternalSecretDecodeNone); err != nil {
 				return nil, fmt.Errorf("failed to apply merged templates to path %s: %w", targetPath, err)
 				return nil, fmt.Errorf("failed to apply merged templates to path %s: %w", targetPath, err)
 			}
 			}
 		}
 		}
@@ -329,7 +329,7 @@ func (r *Reconciler) renderTemplatedManifest(ctx context.Context, es *esv1.Exter
 			tplMap[k] = []byte(v)
 			tplMap[k] = []byte(v)
 		}
 		}
 
 
-		if err := execute(tplMap, dataMap, esv1.TemplateScopeValues, esv1.TemplateTargetData, obj); err != nil {
+		if err := execute(tplMap, dataMap, esv1.TemplateScopeValues, esv1.TemplateTargetData, obj, esv1.ExternalSecretDecodeNone); err != nil {
 			return nil, fmt.Errorf("failed to execute template.data: %w", err)
 			return nil, fmt.Errorf("failed to execute template.data: %w", err)
 		}
 		}
 	}
 	}

+ 4 - 3
pkg/controllers/externalsecret/externalsecret_controller_secret.go

@@ -31,6 +31,7 @@ import (
 	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
 	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
 	genv1alpha1 "github.com/external-secrets/external-secrets/apis/generators/v1alpha1"
 	genv1alpha1 "github.com/external-secrets/external-secrets/apis/generators/v1alpha1"
 	"github.com/external-secrets/external-secrets/runtime/clientmanager"
 	"github.com/external-secrets/external-secrets/runtime/clientmanager"
+	"github.com/external-secrets/external-secrets/runtime/decoding"
 	"github.com/external-secrets/external-secrets/runtime/esutils"
 	"github.com/external-secrets/external-secrets/runtime/esutils"
 	"github.com/external-secrets/external-secrets/runtime/esutils/resolvers"
 	"github.com/external-secrets/external-secrets/runtime/esutils/resolvers"
 	"github.com/external-secrets/external-secrets/runtime/statemanager"
 	"github.com/external-secrets/external-secrets/runtime/statemanager"
@@ -134,7 +135,7 @@ func (r *Reconciler) handleSecretData(ctx context.Context, externalSecret *esv1.
 	}
 	}
 
 
 	// decode the secret if needed
 	// decode the secret if needed
-	secretData, err = esutils.Decode(secretRef.RemoteRef.DecodingStrategy, secretData)
+	secretData, err = decoding.Decode(secretRef.RemoteRef.DecodingStrategy, secretData)
 	if err != nil {
 	if err != nil {
 		return fmt.Errorf(errDecode, secretRef.RemoteRef.DecodingStrategy, err)
 		return fmt.Errorf(errDecode, secretRef.RemoteRef.DecodingStrategy, err)
 	}
 	}
@@ -247,7 +248,7 @@ func (r *Reconciler) handleExtractSecrets(
 	}
 	}
 
 
 	// decode the secrets if needed
 	// decode the secrets if needed
-	secretMap, err = esutils.DecodeMap(remoteRef.Extract.DecodingStrategy, secretMap)
+	secretMap, err = decoding.DecodeMap(remoteRef.Extract.DecodingStrategy, secretMap)
 	if err != nil {
 	if err != nil {
 		return nil, fmt.Errorf(errDecode, remoteRef.Extract.DecodingStrategy, err)
 		return nil, fmt.Errorf(errDecode, remoteRef.Extract.DecodingStrategy, err)
 	}
 	}
@@ -298,7 +299,7 @@ func (r *Reconciler) handleFindAllSecrets(
 	}
 	}
 
 
 	// decode the secrets if needed
 	// decode the secrets if needed
-	secretMap, err = esutils.DecodeMap(remoteRef.Find.DecodingStrategy, secretMap)
+	secretMap, err = decoding.DecodeMap(remoteRef.Find.DecodingStrategy, secretMap)
 	if err != nil {
 	if err != nil {
 		return nil, fmt.Errorf(errDecode, remoteRef.Find.DecodingStrategy, err)
 		return nil, fmt.Errorf(errDecode, remoteRef.Find.DecodingStrategy, err)
 	}
 	}

+ 4 - 4
pkg/controllers/templating/parser.go

@@ -83,7 +83,7 @@ func (p *Parser) MergeConfigMap(ctx context.Context, namespace string, tpl esv1.
 		case esv1.TemplateScopeKeysAndValues:
 		case esv1.TemplateScopeKeysAndValues:
 			out[val] = []byte(val)
 			out[val] = []byte(val)
 		}
 		}
-		err := p.Exec(out, p.DataMap, k.TemplateAs, tpl.Target, p.TargetSecret)
+		err := p.Exec(out, p.DataMap, k.TemplateAs, tpl.Target, p.TargetSecret, tpl.ValuesDecodingStrategy)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
@@ -122,7 +122,7 @@ func (p *Parser) MergeSecret(ctx context.Context, namespace string, tpl esv1.Tem
 		case esv1.TemplateScopeKeysAndValues:
 		case esv1.TemplateScopeKeysAndValues:
 			out[string(val)] = val
 			out[string(val)] = val
 		}
 		}
-		err := p.Exec(out, p.DataMap, k.TemplateAs, tpl.Target, p.TargetSecret)
+		err := p.Exec(out, p.DataMap, k.TemplateAs, tpl.Target, p.TargetSecret, tpl.ValuesDecodingStrategy)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
@@ -137,7 +137,7 @@ func (p *Parser) MergeLiteral(_ context.Context, tpl esv1.TemplateFrom) error {
 	}
 	}
 	out := make(map[string][]byte)
 	out := make(map[string][]byte)
 	out[*tpl.Literal] = []byte(*tpl.Literal)
 	out[*tpl.Literal] = []byte(*tpl.Literal)
-	return p.Exec(out, p.DataMap, esv1.TemplateScopeKeysAndValues, tpl.Target, p.TargetSecret)
+	return p.Exec(out, p.DataMap, esv1.TemplateScopeKeysAndValues, tpl.Target, p.TargetSecret, tpl.ValuesDecodingStrategy)
 }
 }
 
 
 // MergeTemplateFrom merges all templates specified in the ExternalSecretTemplate's TemplateFrom field.
 // MergeTemplateFrom merges all templates specified in the ExternalSecretTemplate's TemplateFrom field.
@@ -169,7 +169,7 @@ func (p *Parser) MergeMap(tplMap map[string]string, target string) error {
 	for k, v := range tplMap {
 	for k, v := range tplMap {
 		byteMap[k] = []byte(v)
 		byteMap[k] = []byte(v)
 	}
 	}
-	err := p.Exec(byteMap, p.DataMap, esv1.TemplateScopeValues, target, p.TargetSecret)
+	err := p.Exec(byteMap, p.DataMap, esv1.TemplateScopeValues, target, p.TargetSecret, esv1.ExternalSecretDecodeNone)
 	if err != nil {
 	if err != nil {
 		return fmt.Errorf(errExecTpl, err)
 		return fmt.Errorf(errExecTpl, err)
 	}
 	}

+ 69 - 0
pkg/controllers/templating/parser_test.go

@@ -0,0 +1,69 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package templating
+
+import (
+	"context"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	corev1 "k8s.io/api/core/v1"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+
+	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+)
+
+func TestParserMergeLiteralPassesTemplateFromValuesDecodingStrategy(t *testing.T) {
+	literal := "decoded: SGVsbG8="
+	var got esv1.ExternalSecretDecodingStrategy
+
+	p := &Parser{
+		Exec: func(_ map[string][]byte, _ map[string][]byte, _ esv1.TemplateScope, _ string, _ client.Object, decodingStrategy esv1.ExternalSecretDecodingStrategy) error {
+			got = decodingStrategy
+			return nil
+		},
+		DataMap:      map[string][]byte{},
+		TargetSecret: &corev1.Secret{},
+	}
+
+	err := p.MergeLiteral(context.Background(), esv1.TemplateFrom{
+		Literal:                &literal,
+		ValuesDecodingStrategy: esv1.ExternalSecretDecodeBase64,
+	})
+
+	require.NoError(t, err)
+	assert.Equal(t, esv1.ExternalSecretDecodeBase64, got)
+}
+
+func TestParserMergeMapKeepsTemplateDataUndecoded(t *testing.T) {
+	var got esv1.ExternalSecretDecodingStrategy
+
+	p := &Parser{
+		Exec: func(_ map[string][]byte, _ map[string][]byte, _ esv1.TemplateScope, _ string, _ client.Object, decodingStrategy esv1.ExternalSecretDecodingStrategy) error {
+			got = decodingStrategy
+			return nil
+		},
+		DataMap:      map[string][]byte{},
+		TargetSecret: &corev1.Secret{},
+	}
+
+	err := p.MergeMap(map[string]string{"encoded": "SGVsbG8="}, esv1.TemplateTargetData)
+
+	require.NoError(t, err)
+	assert.Equal(t, esv1.ExternalSecretDecodeNone, got)
+}

+ 5 - 5
providers/v2/adapter/generator/go.mod

@@ -62,12 +62,12 @@ require (
 	go.opentelemetry.io/otel/trace v1.43.0 // indirect
 	go.opentelemetry.io/otel/trace v1.43.0 // indirect
 	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
-	golang.org/x/net v0.54.0 // indirect
+	golang.org/x/net v0.56.0 // indirect
 	golang.org/x/oauth2 v0.36.0 // indirect
 	golang.org/x/oauth2 v0.36.0 // indirect
-	golang.org/x/sync v0.20.0 // indirect
-	golang.org/x/sys v0.44.0 // indirect
-	golang.org/x/term v0.43.0 // indirect
-	golang.org/x/text v0.37.0 // indirect
+	golang.org/x/sync v0.21.0 // indirect
+	golang.org/x/sys v0.46.0 // indirect
+	golang.org/x/term v0.44.0 // indirect
+	golang.org/x/text v0.38.0 // indirect
 	golang.org/x/time v0.15.0 // indirect
 	golang.org/x/time v0.15.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect

+ 14 - 14
providers/v2/adapter/generator/go.sum

@@ -145,24 +145,24 @@ 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/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 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
-golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
-golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
-golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
-golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ=
+golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
+golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
+golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
+golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
 golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
 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/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.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
-golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
-golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
-golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
-golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
-golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
+golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
+golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
+golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
+golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
+golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
+golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
 golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
 golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
-golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
-golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
+golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
+golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=

+ 5 - 5
providers/v2/adapter/go.mod

@@ -62,12 +62,12 @@ require (
 	github.com/x448/float16 v0.8.4 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
 	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
-	golang.org/x/net v0.54.0 // indirect
+	golang.org/x/net v0.56.0 // indirect
 	golang.org/x/oauth2 v0.36.0 // indirect
 	golang.org/x/oauth2 v0.36.0 // indirect
-	golang.org/x/sync v0.20.0 // indirect
-	golang.org/x/sys v0.44.0 // indirect
-	golang.org/x/term v0.43.0 // indirect
-	golang.org/x/text v0.37.0 // indirect
+	golang.org/x/sync v0.21.0 // indirect
+	golang.org/x/sys v0.46.0 // indirect
+	golang.org/x/term v0.44.0 // indirect
+	golang.org/x/text v0.38.0 // indirect
 	golang.org/x/time v0.15.0 // indirect
 	golang.org/x/time v0.15.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect

+ 14 - 14
providers/v2/adapter/go.sum

@@ -144,24 +144,24 @@ 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/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 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
-golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
-golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
-golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
-golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ=
+golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
+golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
+golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
+golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
 golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
 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/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.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
-golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
-golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
-golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
-golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
-golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
+golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
+golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
+golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
+golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
+golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
+golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
 golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
 golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
-golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
-golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
+golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
+golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=

+ 5 - 5
providers/v2/adapter/store/go.mod

@@ -60,12 +60,12 @@ require (
 	github.com/x448/float16 v0.8.4 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
 	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
-	golang.org/x/net v0.54.0 // indirect
+	golang.org/x/net v0.56.0 // indirect
 	golang.org/x/oauth2 v0.36.0 // indirect
 	golang.org/x/oauth2 v0.36.0 // indirect
-	golang.org/x/sync v0.20.0 // indirect
-	golang.org/x/sys v0.44.0 // indirect
-	golang.org/x/term v0.43.0 // indirect
-	golang.org/x/text v0.37.0 // indirect
+	golang.org/x/sync v0.21.0 // indirect
+	golang.org/x/sys v0.46.0 // indirect
+	golang.org/x/term v0.44.0 // indirect
+	golang.org/x/text v0.38.0 // indirect
 	golang.org/x/time v0.15.0 // indirect
 	golang.org/x/time v0.15.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect

+ 14 - 14
providers/v2/adapter/store/go.sum

@@ -144,24 +144,24 @@ 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/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 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
-golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
-golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
-golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
-golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ=
+golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
+golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
+golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
+golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
 golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
 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/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.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
-golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
-golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
-golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
-golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
-golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
+golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
+golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
+golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
+golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
+golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
+golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
 golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
 golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
-golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
-golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
+golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
+golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=

+ 6 - 6
providers/v2/aws/go.mod

@@ -99,13 +99,13 @@ require (
 	github.com/x448/float16 v0.8.4 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
 	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
-	golang.org/x/crypto v0.51.0 // indirect
-	golang.org/x/net v0.54.0 // indirect
+	golang.org/x/crypto v0.53.0 // indirect
+	golang.org/x/net v0.56.0 // indirect
 	golang.org/x/oauth2 v0.36.0 // indirect
 	golang.org/x/oauth2 v0.36.0 // indirect
-	golang.org/x/sync v0.20.0 // indirect
-	golang.org/x/sys v0.44.0 // indirect
-	golang.org/x/term v0.43.0 // indirect
-	golang.org/x/text v0.37.0 // indirect
+	golang.org/x/sync v0.21.0 // indirect
+	golang.org/x/sys v0.46.0 // indirect
+	golang.org/x/term v0.44.0 // indirect
+	golang.org/x/text v0.38.0 // indirect
 	golang.org/x/time v0.15.0 // indirect
 	golang.org/x/time v0.15.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect

+ 16 - 16
providers/v2/aws/go.sum

@@ -233,26 +233,26 @@ 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/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 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
-golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
-golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
-golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
-golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
-golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
-golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ=
+golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
+golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
+golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
+golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
+golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
+golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
 golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
 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/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.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
-golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
-golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
-golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
-golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
-golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
+golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
+golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
+golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
+golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
+golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
+golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
 golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
 golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
-golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
-golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
+golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
+golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=

+ 5 - 5
providers/v2/common/go.mod

@@ -59,12 +59,12 @@ require (
 	go.opentelemetry.io/otel/trace v1.43.0 // indirect
 	go.opentelemetry.io/otel/trace v1.43.0 // indirect
 	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
-	golang.org/x/net v0.54.0 // indirect
+	golang.org/x/net v0.56.0 // indirect
 	golang.org/x/oauth2 v0.36.0 // indirect
 	golang.org/x/oauth2 v0.36.0 // indirect
-	golang.org/x/sync v0.20.0 // indirect
-	golang.org/x/sys v0.44.0 // indirect
-	golang.org/x/term v0.43.0 // indirect
-	golang.org/x/text v0.37.0 // indirect
+	golang.org/x/sync v0.21.0 // indirect
+	golang.org/x/sys v0.46.0 // indirect
+	golang.org/x/term v0.44.0 // indirect
+	golang.org/x/text v0.38.0 // indirect
 	golang.org/x/time v0.15.0 // indirect
 	golang.org/x/time v0.15.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect

+ 14 - 14
providers/v2/common/go.sum

@@ -145,24 +145,24 @@ 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/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 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
-golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
-golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
-golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
-golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ=
+golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
+golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
+golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
+golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
 golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
 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/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.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
-golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
-golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
-golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
-golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
-golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
+golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
+golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
+golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
+golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
+golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
+golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
 golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
 golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
-golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
-golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
+golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
+golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=

+ 6 - 6
providers/v2/fake/go.mod

@@ -91,13 +91,13 @@ require (
 	github.com/x448/float16 v0.8.4 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
 	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
-	golang.org/x/crypto v0.51.0 // indirect
-	golang.org/x/net v0.54.0 // indirect
+	golang.org/x/crypto v0.53.0 // indirect
+	golang.org/x/net v0.56.0 // indirect
 	golang.org/x/oauth2 v0.36.0 // indirect
 	golang.org/x/oauth2 v0.36.0 // indirect
-	golang.org/x/sync v0.20.0 // indirect
-	golang.org/x/sys v0.44.0 // indirect
-	golang.org/x/term v0.43.0 // indirect
-	golang.org/x/text v0.37.0 // indirect
+	golang.org/x/sync v0.21.0 // indirect
+	golang.org/x/sys v0.46.0 // indirect
+	golang.org/x/term v0.44.0 // indirect
+	golang.org/x/text v0.38.0 // indirect
 	golang.org/x/time v0.15.0 // indirect
 	golang.org/x/time v0.15.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect

+ 16 - 16
providers/v2/fake/go.sum

@@ -200,26 +200,26 @@ 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/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 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
-golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
-golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
-golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
-golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
-golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
-golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ=
+golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
+golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
+golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
+golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
+golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
+golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
 golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
 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/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.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
-golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
-golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
-golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
-golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
-golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
+golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
+golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
+golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
+golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
+golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
+golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
 golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
 golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
-golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
-golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
+golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
+golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=

+ 6 - 6
providers/v2/kubernetes/go.mod

@@ -88,13 +88,13 @@ require (
 	github.com/x448/float16 v0.8.4 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
 	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
-	golang.org/x/crypto v0.51.0 // indirect
-	golang.org/x/net v0.54.0 // indirect
+	golang.org/x/crypto v0.53.0 // indirect
+	golang.org/x/net v0.56.0 // indirect
 	golang.org/x/oauth2 v0.36.0 // indirect
 	golang.org/x/oauth2 v0.36.0 // indirect
-	golang.org/x/sync v0.20.0 // indirect
-	golang.org/x/sys v0.44.0 // indirect
-	golang.org/x/term v0.43.0 // indirect
-	golang.org/x/text v0.37.0 // indirect
+	golang.org/x/sync v0.21.0 // indirect
+	golang.org/x/sys v0.46.0 // indirect
+	golang.org/x/term v0.44.0 // indirect
+	golang.org/x/text v0.38.0 // indirect
 	golang.org/x/time v0.15.0 // indirect
 	golang.org/x/time v0.15.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect

+ 16 - 16
providers/v2/kubernetes/go.sum

@@ -200,26 +200,26 @@ 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/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 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
-golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
-golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
-golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
-golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
-golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
-golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ=
+golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
+golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
+golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
+golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
+golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
+golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
 golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
 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/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.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
-golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
-golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
-golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
-golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
-golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
+golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
+golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
+golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
+golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
+golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
+golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
 golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
 golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
-golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
-golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
+golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
+golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=

+ 73 - 0
runtime/decoding/decoding.go

@@ -0,0 +1,73 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package decoding provides helpers for decoding ExternalSecret values.
+package decoding
+
+import (
+	"encoding/base64"
+	"fmt"
+
+	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+)
+
+// DecodeMap decodes values from a secretMap.
+func DecodeMap(strategy esv1.ExternalSecretDecodingStrategy, in map[string][]byte) (map[string][]byte, error) {
+	out := make(map[string][]byte, len(in))
+	for k, v := range in {
+		val, err := Decode(strategy, v)
+		if err != nil {
+			return nil, fmt.Errorf("failure decoding key %v: %w", k, err)
+		}
+		out[k] = val
+	}
+	return out, nil
+}
+
+// Decode decodes the input byte slice according to the provided decoding strategy.
+func Decode(strategy esv1.ExternalSecretDecodingStrategy, in []byte) ([]byte, error) {
+	switch strategy {
+	case esv1.ExternalSecretDecodeBase64:
+		out, err := base64.StdEncoding.DecodeString(string(in))
+		if err != nil {
+			return nil, err
+		}
+		return out, nil
+	case esv1.ExternalSecretDecodeBase64URL:
+		out, err := base64.URLEncoding.DecodeString(string(in))
+		if err != nil {
+			return nil, err
+		}
+		return out, nil
+	case esv1.ExternalSecretDecodeNone:
+		return in, nil
+	// default when stored version is v1alpha1
+	case "":
+		return in, nil
+	case esv1.ExternalSecretDecodeAuto:
+		out, err := Decode(esv1.ExternalSecretDecodeBase64, in)
+		if err != nil {
+			out, err := Decode(esv1.ExternalSecretDecodeBase64URL, in)
+			if err != nil {
+				return Decode(esv1.ExternalSecretDecodeNone, in)
+			}
+			return out, nil
+		}
+		return out, nil
+	default:
+		return nil, fmt.Errorf("decoding strategy %v is not supported", strategy)
+	}
+}

+ 211 - 0
runtime/decoding/decoding_test.go

@@ -0,0 +1,211 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package decoding
+
+import (
+	"reflect"
+	"testing"
+
+	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+)
+
+const (
+	base64DecodedValue    string = "foo%_?bar"
+	base64EncodedValue    string = "Zm9vJV8/YmFy"
+	base64URLEncodedValue string = "Zm9vJV8_YmFy"
+)
+
+func TestDecode(t *testing.T) {
+	tests := []struct {
+		name     string
+		strategy esv1.ExternalSecretDecodingStrategy
+		in       []byte
+		want     []byte
+		wantErr  bool
+	}{
+		{
+			name:     "base64 decoded",
+			strategy: esv1.ExternalSecretDecodeBase64,
+			in:       []byte("YmFy"),
+			want:     []byte("bar"),
+		},
+		{
+			name:     "invalid base64",
+			strategy: esv1.ExternalSecretDecodeBase64,
+			in:       []byte("foo"),
+			wantErr:  true,
+		},
+		{
+			name:     "base64url decoded",
+			strategy: esv1.ExternalSecretDecodeBase64URL,
+			in:       []byte(base64URLEncodedValue),
+			want:     []byte(base64DecodedValue),
+		},
+		{
+			name:     "invalid base64url",
+			strategy: esv1.ExternalSecretDecodeBase64URL,
+			in:       []byte("foo"),
+			wantErr:  true,
+		},
+		{
+			name:     "none",
+			strategy: esv1.ExternalSecretDecodeNone,
+			in:       []byte(base64URLEncodedValue),
+			want:     []byte(base64URLEncodedValue),
+		},
+		{
+			name:     "empty strategy defaults to none",
+			strategy: "",
+			in:       []byte(base64URLEncodedValue),
+			want:     []byte(base64URLEncodedValue),
+		},
+		{
+			name:     "auto base64",
+			strategy: esv1.ExternalSecretDecodeAuto,
+			in:       []byte(base64EncodedValue),
+			want:     []byte(base64DecodedValue),
+		},
+		{
+			name:     "auto base64url",
+			strategy: esv1.ExternalSecretDecodeAuto,
+			in:       []byte(base64URLEncodedValue),
+			want:     []byte(base64DecodedValue),
+		},
+		{
+			name:     "auto invalid base64 returns input",
+			strategy: esv1.ExternalSecretDecodeAuto,
+			in:       []byte("foo"),
+			want:     []byte("foo"),
+		},
+		{
+			name:     "unsupported strategy",
+			strategy: esv1.ExternalSecretDecodingStrategy("unsupported"),
+			in:       []byte("foo"),
+			wantErr:  true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := Decode(tt.strategy, tt.in)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Decode() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("Decode() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestDecodeMap(t *testing.T) {
+	type args struct {
+		strategy esv1.ExternalSecretDecodingStrategy
+		in       map[string][]byte
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    map[string][]byte
+		wantErr bool
+	}{
+		{
+			name: "base64 decoded",
+			args: args{
+				strategy: esv1.ExternalSecretDecodeBase64,
+				in: map[string][]byte{
+					"foo": []byte("YmFy"),
+				},
+			},
+			want: map[string][]byte{
+				"foo": []byte("bar"),
+			},
+		},
+		{
+			name: "invalid base64",
+			args: args{
+				strategy: esv1.ExternalSecretDecodeBase64,
+				in: map[string][]byte{
+					"foo": []byte("foo"),
+				},
+			},
+			wantErr: true,
+		},
+		{
+			name: "base64url decoded",
+			args: args{
+				strategy: esv1.ExternalSecretDecodeBase64URL,
+				in: map[string][]byte{
+					"foo": []byte(base64URLEncodedValue),
+				},
+			},
+			want: map[string][]byte{
+				"foo": []byte(base64DecodedValue),
+			},
+		},
+		{
+			name: "invalid base64url",
+			args: args{
+				strategy: esv1.ExternalSecretDecodeBase64URL,
+				in: map[string][]byte{
+					"foo": []byte("foo"),
+				},
+			},
+			wantErr: true,
+		},
+		{
+			name: "none",
+			args: args{
+				strategy: esv1.ExternalSecretDecodeNone,
+				in: map[string][]byte{
+					"foo": []byte(base64URLEncodedValue),
+				},
+			},
+			want: map[string][]byte{
+				"foo": []byte(base64URLEncodedValue),
+			},
+		},
+		{
+			name: "auto",
+			args: args{
+				strategy: esv1.ExternalSecretDecodeAuto,
+				in: map[string][]byte{
+					"b64":        []byte(base64EncodedValue),
+					"invalidb64": []byte("foo"),
+					"b64url":     []byte(base64URLEncodedValue),
+				},
+			},
+			want: map[string][]byte{
+				"b64":        []byte(base64DecodedValue),
+				"invalidb64": []byte("foo"),
+				"b64url":     []byte(base64DecodedValue),
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := DecodeMap(tt.args.strategy, tt.args.in)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("DecodeMap() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("DecodeMap() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}

+ 2 - 49
runtime/esutils/utils.go

@@ -55,6 +55,7 @@ import (
 	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
 	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
+	"github.com/external-secrets/external-secrets/runtime/decoding"
 	"github.com/external-secrets/external-secrets/runtime/esutils/resolvers"
 	"github.com/external-secrets/external-secrets/runtime/esutils/resolvers"
 	estemplate "github.com/external-secrets/external-secrets/runtime/template/v2"
 	estemplate "github.com/external-secrets/external-secrets/runtime/template/v2"
 )
 )
@@ -228,54 +229,6 @@ func RewriteTransform(operation esv1.ExternalSecretRewriteTransform, in map[stri
 	return out, nil
 	return out, nil
 }
 }
 
 
-// DecodeMap decodes values from a secretMap.
-func DecodeMap(strategy esv1.ExternalSecretDecodingStrategy, in map[string][]byte) (map[string][]byte, error) {
-	out := make(map[string][]byte, len(in))
-	for k, v := range in {
-		val, err := Decode(strategy, v)
-		if err != nil {
-			return nil, fmt.Errorf("failure decoding key %v: %w", k, err)
-		}
-		out[k] = val
-	}
-	return out, nil
-}
-
-// Decode decodes the input byte slice according to the provided decoding strategy.
-func Decode(strategy esv1.ExternalSecretDecodingStrategy, in []byte) ([]byte, error) {
-	switch strategy {
-	case esv1.ExternalSecretDecodeBase64:
-		out, err := base64.StdEncoding.DecodeString(string(in))
-		if err != nil {
-			return nil, err
-		}
-		return out, nil
-	case esv1.ExternalSecretDecodeBase64URL:
-		out, err := base64.URLEncoding.DecodeString(string(in))
-		if err != nil {
-			return nil, err
-		}
-		return out, nil
-	case esv1.ExternalSecretDecodeNone:
-		return in, nil
-	// default when stored version is v1alpha1
-	case "":
-		return in, nil
-	case esv1.ExternalSecretDecodeAuto:
-		out, err := Decode(esv1.ExternalSecretDecodeBase64, in)
-		if err != nil {
-			out, err := Decode(esv1.ExternalSecretDecodeBase64URL, in)
-			if err != nil {
-				return Decode(esv1.ExternalSecretDecodeNone, in)
-			}
-			return out, nil
-		}
-		return out, nil
-	default:
-		return nil, fmt.Errorf("decoding strategy %v is not supported", strategy)
-	}
-}
-
 // ValidateKeys checks if the keys in the secret map are valid keys for a Kubernetes secret.
 // ValidateKeys checks if the keys in the secret map are valid keys for a Kubernetes secret.
 func ValidateKeys(log logr.Logger, in map[string][]byte) error {
 func ValidateKeys(log logr.Logger, in map[string][]byte) error {
 	for key := range in {
 	for key := range in {
@@ -778,7 +731,7 @@ func base64decode(cert []byte) ([]byte, error) {
 	}
 	}
 
 
 	// try decoding and test for validity again...
 	// try decoding and test for validity again...
-	certificate, err := Decode(esv1.ExternalSecretDecodeAuto, cert)
+	certificate, err := decoding.Decode(esv1.ExternalSecretDecodeAuto, cert)
 	if err != nil {
 	if err != nil {
 		return nil, fmt.Errorf("failed to decode base64: %w", err)
 		return nil, fmt.Errorf("failed to decode base64: %w", err)
 	}
 	}

+ 0 - 100
runtime/esutils/utils_test.go

@@ -38,9 +38,6 @@ import (
 )
 )
 
 
 const (
 const (
-	base64DecodedValue         string = "foo%_?bar"
-	base64EncodedValue         string = "Zm9vJV8/YmFy"
-	base64URLEncodedValue      string = "Zm9vJV8_YmFy"
 	keyWithEmojis              string = "😀foo😁bar😂baz😈bing"
 	keyWithEmojis              string = "😀foo😁bar😂baz😈bing"
 	keyWithInvalidChars        string = "some-array[0].entity"
 	keyWithInvalidChars        string = "some-array[0].entity"
 	keyWithEncodedInvalidChars string = "some-array_U005b_0_U005d_.entity"
 	keyWithEncodedInvalidChars string = "some-array_U005b_0_U005d_.entity"
@@ -318,103 +315,6 @@ func TestReverseKeys(t *testing.T) {
 	}
 	}
 }
 }
 
 
-func TestDecode(t *testing.T) {
-	type args struct {
-		strategy esv1.ExternalSecretDecodingStrategy
-		in       map[string][]byte
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    map[string][]byte
-		wantErr bool
-	}{
-		{
-			name: "base64 decoded",
-			args: args{
-				strategy: esv1.ExternalSecretDecodeBase64,
-				in: map[string][]byte{
-					"foo": []byte("YmFy"),
-				},
-			},
-			want: map[string][]byte{
-				"foo": []byte("bar"),
-			},
-		},
-		{
-			name: "invalid base64",
-			args: args{
-				strategy: esv1.ExternalSecretDecodeBase64,
-				in: map[string][]byte{
-					"foo": []byte("foo"),
-				},
-			},
-			wantErr: true,
-		},
-		{
-			name: "base64url decoded",
-			args: args{
-				strategy: esv1.ExternalSecretDecodeBase64URL,
-				in: map[string][]byte{
-					"foo": []byte(base64URLEncodedValue),
-				},
-			},
-			want: map[string][]byte{
-				"foo": []byte(base64DecodedValue),
-			},
-		},
-		{
-			name: "invalid base64url",
-			args: args{
-				strategy: esv1.ExternalSecretDecodeBase64URL,
-				in: map[string][]byte{
-					"foo": []byte("foo"),
-				},
-			},
-			wantErr: true,
-		},
-		{
-			name: "none",
-			args: args{
-				strategy: esv1.ExternalSecretDecodeNone,
-				in: map[string][]byte{
-					"foo": []byte(base64URLEncodedValue),
-				},
-			},
-			want: map[string][]byte{
-				"foo": []byte(base64URLEncodedValue),
-			},
-		},
-		{
-			name: "auto",
-			args: args{
-				strategy: esv1.ExternalSecretDecodeAuto,
-				in: map[string][]byte{
-					"b64":        []byte(base64EncodedValue),
-					"invalidb64": []byte("foo"),
-					"b64url":     []byte(base64URLEncodedValue),
-				},
-			},
-			want: map[string][]byte{
-				"b64":        []byte(base64DecodedValue),
-				"invalidb64": []byte("foo"),
-				"b64url":     []byte(base64DecodedValue),
-			},
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			got, err := DecodeMap(tt.args.strategy, tt.args.in)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("DecodeMap() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
-			if !reflect.DeepEqual(got, tt.want) {
-				t.Errorf("DecodeMap() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
 func TestValidate(t *testing.T) {
 func TestValidate(t *testing.T) {
 	err := NetworkValidate("http://google.com", 10*time.Second)
 	err := NetworkValidate("http://google.com", 10*time.Second)
 	if err != nil {
 	if err != nil {

+ 1 - 1
runtime/template/engine.go

@@ -27,7 +27,7 @@ import (
 )
 )
 
 
 // ExecFunc is the function signature type for executing a template engine.
 // ExecFunc is the function signature type for executing a template engine.
-type ExecFunc func(tpl, data map[string][]byte, scope esapi.TemplateScope, target string, secret client.Object) error
+type ExecFunc func(tpl, data map[string][]byte, scope esapi.TemplateScope, target string, secret client.Object, valueDecodingStrategy esapi.ExternalSecretDecodingStrategy) error
 
 
 // EngineForVersion returns the appropriate template engine for the given version.
 // EngineForVersion returns the appropriate template engine for the given version.
 func EngineForVersion(version esapi.TemplateEngineVersion) (ExecFunc, error) {
 func EngineForVersion(version esapi.TemplateEngineVersion) (ExecFunc, error) {

+ 52 - 0
runtime/template/engine_test.go

@@ -0,0 +1,52 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package template
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	corev1 "k8s.io/api/core/v1"
+
+	esapi "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+)
+
+func TestEngineForVersionSupportsDecodingStrategy(t *testing.T) {
+	exec, err := EngineForVersion(esapi.TemplateEngineV2)
+	require.NoError(t, err)
+
+	secret := &corev1.Secret{}
+	err = exec(
+		map[string][]byte{"tpl": []byte("message: SGVsbG8=\n")},
+		map[string][]byte{},
+		esapi.TemplateScopeKeysAndValues,
+		esapi.TemplateTargetData,
+		secret,
+		esapi.ExternalSecretDecodeBase64,
+	)
+
+	require.NoError(t, err)
+	assert.Equal(t, []byte("Hello"), secret.Data["message"])
+}
+
+func TestEngineForVersionRejectsUnknownVersion(t *testing.T) {
+	exec, err := EngineForVersion(esapi.TemplateEngineVersion("v1"))
+
+	require.Error(t, err)
+	assert.Nil(t, exec)
+}

+ 15 - 6
runtime/template/v2/template.go

@@ -31,6 +31,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 
 	esapi "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
 	esapi "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+	"github.com/external-secrets/external-secrets/runtime/decoding"
 	"github.com/external-secrets/external-secrets/runtime/feature"
 	"github.com/external-secrets/external-secrets/runtime/feature"
 	"github.com/external-secrets/external-secrets/runtime/template/v2/sprig"
 	"github.com/external-secrets/external-secrets/runtime/template/v2/sprig"
 )
 )
@@ -145,12 +146,16 @@ func applyToTarget(k string, val []byte, target string, obj client.Object) error
 	return nil
 	return nil
 }
 }
 
 
-func valueScopeApply(tplMap, data map[string][]byte, target string, secret client.Object) error {
+func valueScopeApply(tplMap, data map[string][]byte, target string, secret client.Object, decodingStrategy esapi.ExternalSecretDecodingStrategy) error {
 	for k, v := range tplMap {
 	for k, v := range tplMap {
 		val, err := execute(k, string(v), data)
 		val, err := execute(k, string(v), data)
 		if err != nil {
 		if err != nil {
 			return fmt.Errorf(errExecute, k, err)
 			return fmt.Errorf(errExecute, k, err)
 		}
 		}
+		val, err = decoding.Decode(decodingStrategy, val)
+		if err != nil {
+			return fmt.Errorf("failed to decode rendered template value for key %s: %w", k, err)
+		}
 		if err := applyToTarget(k, val, target, secret); err != nil {
 		if err := applyToTarget(k, val, target, secret); err != nil {
 			return fmt.Errorf("failed to apply to target: %w", err)
 			return fmt.Errorf("failed to apply to target: %w", err)
 		}
 		}
@@ -158,7 +163,7 @@ func valueScopeApply(tplMap, data map[string][]byte, target string, secret clien
 	return nil
 	return nil
 }
 }
 
 
-func mapScopeApply(tpl string, data map[string][]byte, target string, secret client.Object) error {
+func mapScopeApply(tpl string, data map[string][]byte, target string, secret client.Object, decodingStrategy esapi.ExternalSecretDecodingStrategy) error {
 	val, err := execute(tpl, tpl, data)
 	val, err := execute(tpl, tpl, data)
 	if err != nil {
 	if err != nil {
 		return fmt.Errorf(errExecute, tpl, err)
 		return fmt.Errorf(errExecute, tpl, err)
@@ -175,7 +180,11 @@ func mapScopeApply(tpl string, data map[string][]byte, target string, secret cli
 			return fmt.Errorf("could not unmarshal template to 'map[string][]byte': %w", err)
 			return fmt.Errorf("could not unmarshal template to 'map[string][]byte': %w", err)
 		}
 		}
 		for k, val := range src {
 		for k, val := range src {
-			if err := applyToTarget(k, []byte(val), target, secret); err != nil {
+			decodedVal, err := decoding.Decode(decodingStrategy, []byte(val))
+			if err != nil {
+				return fmt.Errorf("failed to decode rendered template value for key %s: %w", k, err)
+			}
+			if err := applyToTarget(k, decodedVal, target, secret); err != nil {
 				return fmt.Errorf("failed to apply to target: %w", err)
 				return fmt.Errorf("failed to apply to target: %w", err)
 			}
 			}
 		}
 		}
@@ -196,20 +205,20 @@ func mapScopeApply(tpl string, data map[string][]byte, target string, secret cli
 }
 }
 
 
 // Execute renders the secret data as template. If an error occurs processing is stopped immediately.
 // Execute renders the secret data as template. If an error occurs processing is stopped immediately.
-func Execute(tpl, data map[string][]byte, scope esapi.TemplateScope, target string, secret client.Object) error {
+func Execute(tpl, data map[string][]byte, scope esapi.TemplateScope, target string, secret client.Object, valueDecodingStrategy esapi.ExternalSecretDecodingStrategy) error {
 	if tpl == nil {
 	if tpl == nil {
 		return nil
 		return nil
 	}
 	}
 	switch scope {
 	switch scope {
 	case esapi.TemplateScopeKeysAndValues:
 	case esapi.TemplateScopeKeysAndValues:
 		for _, v := range tpl {
 		for _, v := range tpl {
-			err := mapScopeApply(string(v), data, target, secret)
+			err := mapScopeApply(string(v), data, target, secret, valueDecodingStrategy)
 			if err != nil {
 			if err != nil {
 				return err
 				return err
 			}
 			}
 		}
 		}
 	case esapi.TemplateScopeValues:
 	case esapi.TemplateScopeValues:
-		err := valueScopeApply(tpl, data, target, secret)
+		err := valueScopeApply(tpl, data, target, secret, valueDecodingStrategy)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}

+ 97 - 11
runtime/template/v2/template_test.go

@@ -738,15 +738,15 @@ func TestExecute(t *testing.T) {
 				leftDelim = oldLeftDelim
 				leftDelim = oldLeftDelim
 				rightDelim = oldRightDelim
 				rightDelim = oldRightDelim
 			}()
 			}()
-			err := Execute(tt.tpl, tt.data, esapi.TemplateScopeValues, esapi.TemplateTargetData, sec)
+			err := Execute(tt.tpl, tt.data, esapi.TemplateScopeValues, esapi.TemplateTargetData, sec, esapi.ExternalSecretDecodeNone)
 			if !ErrorContains(err, tt.expErr) {
 			if !ErrorContains(err, tt.expErr) {
 				t.Errorf("unexpected error: %s, expected: %s", err, tt.expErr)
 				t.Errorf("unexpected error: %s, expected: %s", err, tt.expErr)
 			}
 			}
-			err = Execute(tt.labelsTpl, tt.data, esapi.TemplateScopeValues, esapi.TemplateTargetLabels, sec)
+			err = Execute(tt.labelsTpl, tt.data, esapi.TemplateScopeValues, esapi.TemplateTargetLabels, sec, esapi.ExternalSecretDecodeNone)
 			if !ErrorContains(err, tt.expLblErr) {
 			if !ErrorContains(err, tt.expLblErr) {
 				t.Errorf("unexpected error: %s, expected: %s", err, tt.expErr)
 				t.Errorf("unexpected error: %s, expected: %s", err, tt.expErr)
 			}
 			}
-			err = Execute(tt.annotationsTpl, tt.data, esapi.TemplateScopeValues, esapi.TemplateTargetAnnotations, sec)
+			err = Execute(tt.annotationsTpl, tt.data, esapi.TemplateScopeValues, esapi.TemplateTargetAnnotations, sec, esapi.ExternalSecretDecodeNone)
 			if !ErrorContains(err, tt.expAnnoErr) {
 			if !ErrorContains(err, tt.expAnnoErr) {
 				t.Errorf("unexpected error: %s, expected: %s", err, tt.expErr)
 				t.Errorf("unexpected error: %s, expected: %s", err, tt.expErr)
 			}
 			}
@@ -820,7 +820,7 @@ func TestScopeValuesWithSecretFieldsNil(t *testing.T) {
 		row := tbl[i]
 		row := tbl[i]
 		t.Run(row.name, func(t *testing.T) {
 		t.Run(row.name, func(t *testing.T) {
 			sec := &corev1.Secret{}
 			sec := &corev1.Secret{}
-			err := Execute(row.tpl, row.data, esapi.TemplateScopeValues, row.target, sec)
+			err := Execute(row.tpl, row.data, esapi.TemplateScopeValues, row.target, sec, esapi.ExternalSecretDecodeNone)
 			if !ErrorContains(err, row.expErr) {
 			if !ErrorContains(err, row.expErr) {
 				t.Errorf("unexpected error: %s, expected: %s", err, row.expErr)
 				t.Errorf("unexpected error: %s, expected: %s", err, row.expErr)
 			}
 			}
@@ -844,7 +844,7 @@ func TestScopeValuesWithSecretFieldsNil(t *testing.T) {
 
 
 func TestExecuteInvalidTemplateScope(t *testing.T) {
 func TestExecuteInvalidTemplateScope(t *testing.T) {
 	sec := &corev1.Secret{}
 	sec := &corev1.Secret{}
-	err := Execute(map[string][]byte{"foo": []byte("bar")}, nil, "invalid", esapi.TemplateTargetData, sec)
+	err := Execute(map[string][]byte{"foo": []byte("bar")}, nil, "invalid", esapi.TemplateTargetData, sec, esapi.ExternalSecretDecodeNone)
 	require.Error(t, err)
 	require.Error(t, err)
 	assert.ErrorContains(t, err, "expected 'Values' or 'KeysAndValues'")
 	assert.ErrorContains(t, err, "expected 'Values' or 'KeysAndValues'")
 }
 }
@@ -854,7 +854,7 @@ func TestExecuteTargetCaseInsensitive(t *testing.T) {
 	for _, target := range []string{"Annotations", "annotations", "ANNOTATIONS", "AnNoTaTiOnS"} {
 	for _, target := range []string{"Annotations", "annotations", "ANNOTATIONS", "AnNoTaTiOnS"} {
 		t.Run(target, func(t *testing.T) {
 		t.Run(target, func(t *testing.T) {
 			sec := &corev1.Secret{}
 			sec := &corev1.Secret{}
-			require.NoError(t, Execute(map[string][]byte{"foo": []byte("bar")}, nil, esapi.TemplateScopeValues, target, sec))
+			require.NoError(t, Execute(map[string][]byte{"foo": []byte("bar")}, nil, esapi.TemplateScopeValues, target, sec, esapi.ExternalSecretDecodeNone))
 			assert.Equal(t, "bar", sec.Annotations["foo"])
 			assert.Equal(t, "bar", sec.Annotations["foo"])
 			assert.Empty(t, sec.Labels)
 			assert.Empty(t, sec.Labels)
 			assert.Empty(t, sec.Data)
 			assert.Empty(t, sec.Data)
@@ -923,7 +923,7 @@ func TestScopeKeysAndValues(t *testing.T) {
 				StringData: make(map[string]string),
 				StringData: make(map[string]string),
 				ObjectMeta: v1.ObjectMeta{Labels: make(map[string]string), Annotations: make(map[string]string)},
 				ObjectMeta: v1.ObjectMeta{Labels: make(map[string]string), Annotations: make(map[string]string)},
 			}
 			}
-			err := Execute(row.tpl, row.data, esapi.TemplateScopeKeysAndValues, row.target, sec)
+			err := Execute(row.tpl, row.data, esapi.TemplateScopeKeysAndValues, row.target, sec, esapi.ExternalSecretDecodeNone)
 			if !ErrorContains(err, row.expErr) {
 			if !ErrorContains(err, row.expErr) {
 				t.Errorf("unexpected error: %s, expected: %s", err, row.expErr)
 				t.Errorf("unexpected error: %s, expected: %s", err, row.expErr)
 			}
 			}
@@ -1039,7 +1039,7 @@ func TestComplexYAMLFieldsWithSpec(t *testing.T) {
 				Data: make(map[string][]byte),
 				Data: make(map[string][]byte),
 			}
 			}
 
 
-			err := Execute(tt.tpl, tt.data, tt.scope, tt.target, obj)
+			err := Execute(tt.tpl, tt.data, tt.scope, tt.target, obj, esapi.ExternalSecretDecodeNone)
 
 
 			if tt.expErr != "" {
 			if tt.expErr != "" {
 				require.Error(t, err)
 				require.Error(t, err)
@@ -1285,7 +1285,7 @@ func TestConfigMapDataNotBase64Encoded(t *testing.T) {
 		"database": []byte("{{ .database }}"),
 		"database": []byte("{{ .database }}"),
 	}
 	}
 
 
-	err := Execute(tplMap, data, esapi.TemplateScopeValues, "Data", configMap)
+	err := Execute(tplMap, data, esapi.TemplateScopeValues, "Data", configMap, esapi.ExternalSecretDecodeNone)
 	require.NoError(t, err)
 	require.NoError(t, err)
 
 
 	assert.Equal(t, "localhost", configMap.Data["host"], "host should be plain text, not base64")
 	assert.Equal(t, "localhost", configMap.Data["host"], "host should be plain text, not base64")
@@ -1629,7 +1629,7 @@ channel: {{ .new_channel }}
 				}
 				}
 			}
 			}
 
 
-			err := Execute(tt.tpl, tt.data, tt.scope, tt.target, obj)
+			err := Execute(tt.tpl, tt.data, tt.scope, tt.target, obj, esapi.ExternalSecretDecodeNone)
 
 
 			if tt.wantErr {
 			if tt.wantErr {
 				require.Error(t, err)
 				require.Error(t, err)
@@ -1735,7 +1735,7 @@ func TestNestedPathTargetingIsIdempotent(t *testing.T) {
 
 
 			var snapshot map[string]any
 			var snapshot map[string]any
 			for i := range 3 {
 			for i := range 3 {
-				require.NoError(t, Execute(tt.tpl, tt.data, tt.scope, tt.target, obj))
+				require.NoError(t, Execute(tt.tpl, tt.data, tt.scope, tt.target, obj, esapi.ExternalSecretDecodeNone))
 				if i == 0 {
 				if i == 0 {
 					snapshot = obj.DeepCopy().Object
 					snapshot = obj.DeepCopy().Object
 					continue
 					continue
@@ -1749,3 +1749,89 @@ func TestNestedPathTargetingIsIdempotent(t *testing.T) {
 		})
 		})
 	}
 	}
 }
 }
+
+func TestExecuteDecodesRenderedTemplateValues(t *testing.T) {
+	tests := []struct {
+		name             string
+		scope            esapi.TemplateScope
+		tpl              map[string][]byte
+		data             map[string][]byte
+		decodingStrategy esapi.ExternalSecretDecodingStrategy
+		wantData         map[string][]byte
+		wantErr          string
+	}{
+		{
+			name:  "keys and values scope decodes each rendered value",
+			scope: esapi.TemplateScopeKeysAndValues,
+			tpl: map[string][]byte{
+				"tpl": []byte("service-a: SGVsbG8=\nservice-b: V29ybGQ=\n"),
+			},
+			decodingStrategy: esapi.ExternalSecretDecodeBase64,
+			wantData: map[string][]byte{
+				"service-a": []byte("Hello"),
+				"service-b": []byte("World"),
+			},
+		},
+		{
+			name:  "keys are not decoded",
+			scope: esapi.TemplateScopeKeysAndValues,
+			tpl: map[string][]byte{
+				"tpl": []byte("SGVsbG8=: V29ybGQ=\n"),
+			},
+			decodingStrategy: esapi.ExternalSecretDecodeBase64,
+			wantData: map[string][]byte{
+				"SGVsbG8=": []byte("World"),
+			},
+		},
+		{
+			name:  "values scope decodes rendered value",
+			scope: esapi.TemplateScopeValues,
+			tpl: map[string][]byte{
+				"service-a": []byte("{{ .encoded }}"),
+			},
+			data: map[string][]byte{
+				"encoded": []byte("SGVsbG8="),
+			},
+			decodingStrategy: esapi.ExternalSecretDecodeBase64,
+			wantData: map[string][]byte{
+				"service-a": []byte("Hello"),
+			},
+		},
+		{
+			name:  "none keeps rendered value unchanged",
+			scope: esapi.TemplateScopeKeysAndValues,
+			tpl: map[string][]byte{
+				"tpl": []byte("service-a: SGVsbG8=\n"),
+			},
+			decodingStrategy: esapi.ExternalSecretDecodeNone,
+			wantData: map[string][]byte{
+				"service-a": []byte("SGVsbG8="),
+			},
+		},
+		{
+			name:  "base64 fails for non base64 rendered value",
+			scope: esapi.TemplateScopeKeysAndValues,
+			tpl: map[string][]byte{
+				"tpl": []byte("service-a: not-base64!\n"),
+			},
+			decodingStrategy: esapi.ExternalSecretDecodeBase64,
+			wantErr:          "failed to decode rendered template value for key service-a",
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			secret := &corev1.Secret{}
+
+			err := Execute(tt.tpl, tt.data, tt.scope, esapi.TemplateTargetData, secret, tt.decodingStrategy)
+
+			if tt.wantErr != "" {
+				require.Error(t, err)
+				assert.Contains(t, err.Error(), tt.wantErr)
+				return
+			}
+			require.NoError(t, err)
+			assert.Equal(t, tt.wantData, secret.Data)
+		})
+	}
+}

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

@@ -96,6 +96,7 @@ spec:
               templateAs: "Values"
               templateAs: "Values"
             name: string
             name: string
           target: "Data"
           target: "Data"
+          valuesDecodingStrategy: "None"
         type: string
         type: string
   namespaceSelector:
   namespaceSelector:
     matchExpressions:
     matchExpressions:

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

@@ -91,6 +91,7 @@ spec:
             templateAs: "Values"
             templateAs: "Values"
           name: string
           name: string
         target: "Data"
         target: "Data"
+        valuesDecodingStrategy: "None"
       type: string
       type: string
 status:
 status:
   binding:
   binding:

+ 1 - 0
tests/__snapshot__/pushsecret-v1alpha1.yaml

@@ -78,6 +78,7 @@ spec:
           templateAs: "Values"
           templateAs: "Values"
         name: string
         name: string
       target: "Data"
       target: "Data"
+      valuesDecodingStrategy: "None"
     type: string
     type: string
   updatePolicy: "Replace"
   updatePolicy: "Replace"
 status:
 status:

+ 1 - 1
tilt.debug.dockerfile

@@ -1,4 +1,4 @@
-FROM golang:1.26.4@sha256:87a41d2539e5671777734e91f467499ed5eafb1fb1f77221dff2744db7a51775
+FROM golang:1.26.4@sha256:8f4cb3b8d3fd8c3e6eccfde0fcf54e8cea74fbb04cea961a92ee1a913d22cb17
 WORKDIR /
 WORKDIR /
 COPY ./bin/external-secrets /external-secrets
 COPY ./bin/external-secrets /external-secrets
 
 

+ 1 - 1
tilt.dockerfile

@@ -1,4 +1,4 @@
-FROM alpine@sha256:a2d49ea686c2adfe3c992e47dc3b5e7fa6e6b5055609400dc2acaeb241c829f4
+FROM alpine@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b
 WORKDIR /
 WORKDIR /
 COPY ./bin/external-secrets /external-secrets
 COPY ./bin/external-secrets /external-secrets