Repository: external-secrets/external-secrets (go)

Issue:
Passing '{{' and '}}' through ESO
I have a JSON string in a ConfigMap using an ExternalSecret to template in some secrets. All entirely normal.

```
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: configjson-eso-template
data:
 configjson.json:
    "{\"secret\": \"{{ .clientSecret }}\"}"
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: configjson-config
spec:
  refreshInterval: 1m
  secretStoreRef:
    kind: ClusterSecretStore
    name: secretstore
  target:
    name: configjson-config
    template:
      engineVersion: v2
      templateFrom:
        - target: Data
          configMap:
            name: configjson-eso-template
            items:
              - key: configjson.json
                templateAs: Values
  data:
    - remoteRef:
        key: 'client1-clientSecret'
      secretKey: clientSecret
```

I now need to have another element in the JSON that needs to be the literal string '{{otherValue}}'.
No amount of weird extra quoting or escaping is letting me get that past ESO. I either get some sort of parsing failure, unexpected characters, or an invalid string in the resulting secret.

Using three, instead of two, curly braces results in: `unexpected "{" in command`.
A single backslash on all four curly braces is illegal for kubernetes.
Two backslashes on all four curly braces is legal, and passes ESO, but the resulting string is `\{\{otherValue\}\}` which isn't legal to the container parsing the JSON.
`'{{'otherValue'}}'`, and not trying to escape `otherValue`, just results in ESO trying to go-template it, which obviously fails because ESO can't do that.

How do I make ESO ignore something in mustaches?

Pull request description:
feat: non standard templating delimiters
## Problem Statement

I am tired of issues related to templating conflicts with helm. This addresses that by allowing users to change default templating keys from external-secrets templating engine

## Related Issue

Fixes my sanity
Fixes #4544

## Proposed Changes
* controller level flag for templating delimiters (left and right)
* default values to prevent breaking changes
## Checklist

- [x] I have read the [contribution guidelines](https://external-secrets.io/latest/contributing/process/#submitting-a-pull-request)
- [x] All commits are signed with `git commit --signoff`
- [x] My changes have reasonable test coverage
- [x] All tests pass with `make test`
- [x] I ensured my PR is ready for review with `make reviewable`


Patch:
diff --git a/pkg/template/v2/template.go b/pkg/template/v2/template.go
index 97a99ebd1..c036e5093 100644
--- a/pkg/template/v2/template.go
+++ b/pkg/template/v2/template.go
@@ -20,10 +20,12 @@ import (
 	tpl "text/template"
 
 	"github.com/Masterminds/sprig/v3"
+	"github.com/spf13/pflag"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/util/yaml"
 
 	esapi "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
+	"github.com/external-secrets/external-secrets/pkg/feature"
 )
 
 var tplFuncs = tpl.FuncMap{
@@ -47,6 +49,8 @@ var tplFuncs = tpl.FuncMap{
 	"fromYaml": fromYAML,
 }
 
+var leftDelim, rightDelim string
+
 // So other templating calls can use the same extra functions.
 func FuncMap() tpl.FuncMap {
 	return tplFuncs
@@ -71,6 +75,12 @@ func init() {
 	for k, v := range sprigFuncs {
 		tplFuncs[k] = v
 	}
+	fs := pflag.NewFlagSet("template", pflag.ExitOnError)
+	fs.StringVar(&leftDelim, "template-left-delimiter", "{{", "templating left delimiter")
+	fs.StringVar(&rightDelim, "template-right-delimiter", "}}", "templating right delimiter")
+	feature.Register(feature.Feature{
+		Flags: fs,
+	})
 }
 
 func applyToTarget(k, val string, target esapi.TemplateTarget, secret *corev1.Secret) {
@@ -154,6 +164,7 @@ func execute(k, val string, data map[string][]byte) ([]byte, error) {
 	t, err := tpl.New(k).
 		Option("missingkey=error").
 		Funcs(tplFuncs).
+		Delims("{{", "}}").
 		Parse(val)
 	if err != nil {
 		return nil, fmt.Errorf(errParse, k, err)


Test patch:
diff --git a/pkg/template/v2/template_test.go b/pkg/template/v2/template_test.go
index 1697d900e..6ba1a07ca 100644
--- a/pkg/template/v2/template_test.go
+++ b/pkg/template/v2/template_test.go
@@ -150,6 +150,8 @@ func TestExecute(t *testing.T) {
 		expectedStringData  map[string]string
 		expectedLabels      map[string]string
 		expectedAnnotations map[string]string
+		leftDelimiter       string
+		rightDelimiter      string
 		expErr              string
 		expLblErr           string
 		expAnnoErr          string
@@ -488,6 +490,21 @@ func TestExecute(t *testing.T) {
 				"foo": "1234",
 			},
 		},
+		{
+			name: "NonStandardDelimiters",
+			stringDataTpl: map[string][]byte{
+				"foo": []byte("<< .secret | b64dec >>"),
+			},
+			leftDelimiter:  "<<",
+			rightDelimiter: ">>",
+			data: map[string][]byte{
+				"secret": []byte("MTIzNA=="),
+				"env":    []byte("ZGV2"),
+			},
+			expectedStringData: map[string]string{
+				"foo": "1234",
+			},
+		},
 	}
 
 	for i := range tbl {
@@ -498,6 +515,12 @@ func TestExecute(t *testing.T) {
 				StringData: make(map[string]string),
 				ObjectMeta: v1.ObjectMeta{Labels: make(map[string]string), Annotations: make(map[string]string)},
 			}
+			if row.leftDelimiter != "" {
+				leftDelim = row.leftDelimiter
+			}
+			if row.rightDelimiter != "" {
+				rightDelim = row.rightDelimiter
+			}
 			err := Execute(row.tpl, row.data, esapi.TemplateScopeValues, esapi.TemplateTargetData, sec)
 			if !ErrorContains(err, row.expErr) {
 				t.Errorf("unexpected error: %s, expected: %s", err, row.expErr)