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

Issue:
Pulumi : Unable to extract structured data
**Describe the bug**
When using the provider pulumi, it's impossible to create a secret with the extract command (extract from structured data, by following the example https://external-secrets.io/latest/guides/all-keys-one-secret/ )


**To Reproduce**
Steps to reproduce the behavior:

Relevant manifests
```yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: test-pulumi-secret

spec:
  refreshInterval: 20s
  secretStoreRef:
    kind: ClusterSecretStore
    name: pulumi-store
  target:
    name: test-pulumi-secret
  dataFrom:
    - extract:
        key: "pulumiConfig"
```

Pulumi environment
```json
{
  "pulumiConfig": {
    "aaa": 42,
    "bbb": "youpi",
    "ccc": "jrjrjrj",
    "ddd": {
      "alpha": true,
      "beta": 4,
      "gamma": "te"
    }
  }
}
```

- Kubernetes version : 1.29.2
- ESO version : 0.9.13

**Expected behavior**
I want my secret to be decoded and extracted.

```
$ kubectl describe secret test-pulumi-secret
...
Data
====
aaa:  2 bytes
bbb:  7 bytes
ccc:  9 bytes
ddd:  36 bytes
```

**Screenshots**

```
  Normal   Updated       3m51s (x11 over 6m22s)  external-secrets  Updated Secret
  Warning  UpdateFailed  3m33s                   external-secrets  unable to get value for key aaa: can not handle secret value with type: json.RawMessage
  Warning  UpdateFailed  3m12s (x2 over 3m33s)   external-secrets  unable to get value for key bbb: can not handle secret value with type: json.RawMessage
  Warning  UpdateFailed  2m51s (x9 over 3m38s)   external-secrets  unable to get value for key ccc: can not handle secret value with type: json.RawMessage
  Warning  UpdateFailed  47s (x3 over 3m36s)     external-secrets  unable to get value for key ddd: can not handle secret value with type: json.RawMessage
```

**Additional context**
`json.RawMessage` is a `[]byte` but is not handled as is. I've made a working fix and submit a PR to fix this.


Pull request description:
Allow Pulimi to extract structured data.
Handle `json.RawMessage` as a `[]byte` in `util.GetByteValue`.
This allow Pulimi to extract structured data.

Close: #3307

## Problem Statement

Pulumi can't extract structured data

## Related Issue

Fixes #3307

## Proposed Changes

Pulumi use `json.RawMessage` who is a `[]byte`, but is not considered as is in the GetByteValue method. The proposed change is tested and fix the problem.

## 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/utils/utils.go b/pkg/utils/utils.go
index 2cefe0786..43dabdeff 100644
--- a/pkg/utils/utils.go
+++ b/pkg/utils/utils.go
@@ -264,6 +264,8 @@ func GetByteValue(v interface{}) ([]byte, error) {
 		return json.Marshal(t)
 	case []string:
 		return []byte(strings.Join(t, "\n")), nil
+	case json.RawMessage:
+		return t, nil
 	case []byte:
 		return t, nil
 	// also covers int and float32 due to json.Marshal


Test patch:
diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go
index 0ca898ee7..f62c089fd 100644
--- a/pkg/utils/utils_test.go
+++ b/pkg/utils/utils_test.go
@@ -15,6 +15,7 @@ limitations under the License.
 package utils
 
 import (
+	"encoding/json"
 	"reflect"
 	"testing"
 	"time"
@@ -624,3 +625,104 @@ func TestFetchValueFromMetadata(t *testing.T) {
 		})
 	}
 }
+
+func TestGetByteValue(t *testing.T) {
+	type args struct {
+		data interface{}
+	}
+	type testCase struct {
+		name    string
+		args    args
+		want    []byte
+		wantErr bool
+	}
+	tests := []testCase{
+		{
+			name: "string",
+			args: args{
+				data: "value",
+			},
+			want:    []byte("value"),
+			wantErr: false,
+		},
+		{
+			name: "map of interface{}",
+			args: args{
+				data: map[string]interface{}{
+					"key": "value",
+				},
+			},
+			want:    []byte(`{"key":"value"}`),
+			wantErr: false,
+		},
+		{
+			name: "slice of string",
+			args: args{
+				data: []string{"value1", "value2"},
+			},
+			want:    []byte("value1\nvalue2"),
+			wantErr: false,
+		},
+		{
+			name: "json.RawMessage",
+			args: args{
+				data: json.RawMessage(`{"key":"value"}`),
+			},
+			want:    []byte(`{"key":"value"}`),
+			wantErr: false,
+		},
+		{
+			name: "float64",
+			args: args{
+				data: 123.45,
+			},
+			want:    []byte("123.45"),
+			wantErr: false,
+		},
+		{
+			name: "json.Number",
+			args: args{
+				data: json.Number("123.45"),
+			},
+			want:    []byte("123.45"),
+			wantErr: false,
+		},
+		{
+			name: "slice of interface{}",
+			args: args{
+				data: []interface{}{"value1", "value2"},
+			},
+			want:    []byte(`["value1","value2"]`),
+			wantErr: false,
+		},
+		{
+			name: "boolean",
+			args: args{
+				data: true,
+			},
+			want:    []byte("true"),
+			wantErr: false,
+		},
+		{
+			name: "nil",
+			args: args{
+				data: nil,
+			},
+			want:    []byte(nil),
+			wantErr: false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := GetByteValue(tt.args.data)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("GetByteValue() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("GetByteValue() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}