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

Issue:
Validate `.data[].secretKey` duplicates
**Describe the bug**
I have same `secretKey` `SERVICE_NAME` but point to diferenet parameters in AWS Parameter Store. I see that operator take the last one in YAML and inject into the secret. So in my example into `test` secret I will go `SERVICE_NAME` from ` /dev/project_env_vars` Parameter instead of `/dev/shared_env_vars` Parameter. 

**To Reproduce**
I have such Externalsecret
```yaml
apiVersion: external-secrets.io/v1alpha1
kind: ExternalSecret
metadata:
  name: test
  namespace: default
spec:
  secretStoreRef:
    name: ssm-secret-store-global
    kind: ClusterSecretStore
  refreshInterval: "3m"
  target:
    name: test-env
    creationPolicy: 'Owner'
  data:
    - secretKey: SERVICE_NAME
      remoteRef:
        key: /dev/shared_env_vars
        property: TEST_URL
    - secretKey: KAFKA_BROKER_0
      remoteRef:
        key: /dev/shared_env_vars
        property: KAFKA_BROKER_0
    - secretKey: KAFKA_BROKER_1
      remoteRef:
        key: /dev/shared_env_vars
        property: KAFKA_BROKER_1
    - secretKey: KAFKA_BROKER_2
      remoteRef:
        key: /dev/shared_env_vars
        property: KAFKA_BROKER_2
    - secretKey: SERVICE_NAME
      remoteRef:
        key: /dev/project_env_vars
        property: SERVICE_NAME
```

**Expected behavior**
Error. I want to see some kind of duplication error. This is not transperent behaviour because you can inject wrong parameter.

Operator version: **0.9.3**

Pull request:
Validator
## Problem Statement

Fix duplicates keys .

## Related Issue

Fixes #2921 and related to #2929

## 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/apis/externalsecrets/v1beta1/externalsecret_validator.go b/apis/externalsecrets/v1beta1/externalsecret_validator.go
index 3d8cb7e1f..19fdf699d 100644
--- a/apis/externalsecrets/v1beta1/externalsecret_validator.go
+++ b/apis/externalsecrets/v1beta1/externalsecret_validator.go
@@ -63,5 +63,20 @@ func validateExternalSecret(obj runtime.Object) (admission.Warnings, error) {
 		}
 	}
 
+	errs = validateDuplicateKeys(es, errs)
 	return nil, errs
 }
+
+func validateDuplicateKeys(es *ExternalSecret, errs error) error {
+	if es.Spec.Target.DeletionPolicy == DeletionPolicyRetain {
+		seenKeys := make(map[string]struct{})
+		for _, data := range es.Spec.Data {
+			secretKey := data.SecretKey
+			if _, exists := seenKeys[secretKey]; exists {
+				errs = errors.Join(errs, fmt.Errorf("duplicate secretKey found: %s", secretKey))
+			}
+			seenKeys[secretKey] = struct{}{}
+		}
+	}
+	return errs
+}


Test patch:
diff --git a/apis/externalsecrets/v1beta1/externalsecret_validator_test.go b/apis/externalsecrets/v1beta1/externalsecret_validator_test.go
index c20cef1f8..c6d6d2172 100644
--- a/apis/externalsecrets/v1beta1/externalsecret_validator_test.go
+++ b/apis/externalsecrets/v1beta1/externalsecret_validator_test.go
@@ -122,6 +122,39 @@ either data or dataFrom should be specified`,
 				},
 			},
 		},
+		{
+			name: "duplicate secretKeys",
+			obj: &ExternalSecret{
+				Spec: ExternalSecretSpec{
+					Target: ExternalSecretTarget{
+						DeletionPolicy: DeletionPolicyRetain,
+					},
+					Data: []ExternalSecretData{
+						{SecretKey: "SERVICE_NAME"},
+						{SecretKey: "SERVICE_NAME"},
+						{SecretKey: "SERVICE_NAME-2"},
+						{SecretKey: "SERVICE_NAME-2"},
+						{SecretKey: "NOT_DUPLICATE"},
+					},
+				},
+			},
+			expectedErr: "duplicate secretKey found: SERVICE_NAME\nduplicate secretKey found: SERVICE_NAME-2",
+		},
+		{
+			name: "duplicate secretKey",
+			obj: &ExternalSecret{
+				Spec: ExternalSecretSpec{
+					Target: ExternalSecretTarget{
+						DeletionPolicy: DeletionPolicyRetain,
+					},
+					Data: []ExternalSecretData{
+						{SecretKey: "SERVICE_NAME"},
+						{SecretKey: "SERVICE_NAME"},
+					},
+				},
+			},
+			expectedErr: "duplicate secretKey found: SERVICE_NAME",
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {