Explorar o código

added first 'final' draft of application code, unit tests and e2e tests

Signed-off-by: Bill Hamilton <bill.hamilton@delinea.com>
Bill Hamilton %!s(int64=2) %!d(string=hai) anos
pai
achega
b3b275f22b

+ 1 - 1
e2e/go.mod

@@ -43,6 +43,7 @@ require (
 	github.com/Azure/go-autorest/autorest v0.11.29
 	github.com/Azure/go-autorest/autorest/azure/auth v0.5.12
 	github.com/DelineaXPM/dsv-sdk-go/v2 v2.1.2
+	github.com/DelineaXPM/tss-sdk-go/v2 v2.0.1
 	github.com/akeylesslabs/akeyless-go-cloud-id v0.3.5
 	github.com/akeylesslabs/akeyless-go/v3 v3.6.2
 	github.com/aliyun/alibaba-cloud-sdk-go v1.62.271
@@ -87,7 +88,6 @@ require (
 	github.com/Azure/go-autorest/logger v0.2.1 // indirect
 	github.com/Azure/go-autorest/tracing v0.6.0 // indirect
 	github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
-	github.com/DelineaXPM/tss-sdk-go/v2 v2.0.1 // indirect
 	github.com/Masterminds/goutils v1.1.1 // indirect
 	github.com/Masterminds/semver/v3 v3.2.1 // indirect
 	github.com/Masterminds/sprig/v3 v3.2.3 // indirect

+ 2 - 23
e2e/suites/provider/cases/secretserver/provider.go

@@ -3,11 +3,9 @@ package secretserver
 import (
 	"encoding/json"
 	"fmt"
-	_"strconv"
 
 	"github.com/DelineaXPM/tss-sdk-go/v2/server"
 	"github.com/external-secrets/external-secrets-e2e/framework"
-	_"github.com/tidwall/gjson"
 	"github.com/onsi/gomega"
 )
 
@@ -19,9 +17,7 @@ type secretStoreProvider struct {
 	secretID map[string]int
 }
 
-
 func (p *secretStoreProvider) init(cfg *config, f *framework.Framework) {
-
 	p.cfg = cfg
 	p.secretID = make(map[string]int)
 	p.framework = f
@@ -37,30 +33,14 @@ func (p *secretStoreProvider) init(cfg *config, f *framework.Framework) {
 	p.api = secretserverClient
 }
 
-/*
-Make sure and look this up
-https://rasteamdev.qa.devsecretservercloud.com/Documents/restapi/TokenAuth/#tag/Secrets/operation/SecretsService_SearchV2
-*/
-
 func (p *secretStoreProvider) CreateSecret(key string, val framework.SecretEntry) {
 	var data map[string]interface{}
 	err := json.Unmarshal([]byte(val.Value), &data)
-	fmt.Printf("\n\n CREATE SECRET VALUE = %+v", string(val.Value))
 	gomega.Expect(err).ToNot(gomega.HaveOccurred())
 
 	fields := make([]server.SecretField, 1)
-/*
-		fields[0].FieldID = 108 // machine
-		fields[0].ItemValue = "Secret Server TEST MACHINE"
-		fields[1].FieldID = 111 // username
-		fields[1].ItemValue = "secretserver_username"
-		fields[2].FieldID = 110 // password
-		fields[2].ItemValue = "secretserver_password"
-*/
-
-		fields[0].FieldID = 439 // Data
-		fields[0].ItemValue = val.Value
-
+	fields[0].FieldID = 439 // Data
+	fields[0].ItemValue = val.Value
 
 	s, err := p.api.CreateSecret(server.Secret{
 		SecretTemplateID: 6098, // custom template
@@ -75,6 +55,5 @@ func (p *secretStoreProvider) CreateSecret(key string, val framework.SecretEntry
 
 func (p *secretStoreProvider) DeleteSecret(key string) {
 	err := p.api.DeleteSecret(p.secretID[key])
-/*	err := p.api.DeleteSecret(1111)*/
 	gomega.Expect(err).ToNot(gomega.HaveOccurred())
 }

+ 0 - 22
e2e/suites/provider/cases/secretserver/secretserver.go

@@ -30,13 +30,6 @@ var _ = ginkgo.Describe("[secretserver]", ginkgo.Label("secretserver"), func() {
 	})
 
 	ginkgo.DescribeTable("sync secrets", framework.TableFuncWithExternalSecret(f, provider),
-
-/*
-JSONDataFromSync
-JSONDataFromRewrite
-DecodingPolicySync
-*/
-
 		ginkgo.Entry(common.JSONDataWithTemplate(f)),
 		ginkgo.Entry(common.JSONDataWithProperty(f)),
 		ginkgo.Entry(common.JSONDataWithoutTargetName(f)),
@@ -96,19 +89,4 @@ func createResources(ctx context.Context, f *framework.Framework, cfg *config) {
 
 	err = f.CRClient.Create(ctx, &secretStoreSpec)
 	gomega.Expect(err).ToNot(gomega.HaveOccurred())
-
-/*
-	externalSecretData := []esv1beta1.ExternalSecretData{
-		{
-			SecretKey: "mysecret",
-			RemoteRef: esv1beta1.ExternalSecretDataRemoteRef{
-				Key: "1111",
-				Property: "Items.1.ItemValue",
-			},
-		},
-	}
-
-	err = f.CRClient.Create(ctx, &externalSecretData)
-	gomega.Expect(err).ToNot(gomega.HaveOccurred())
-*/
 }

+ 22 - 14
pkg/provider/secretserver/client.go

@@ -18,7 +18,6 @@ import (
 	"context"
 	"encoding/json"
 	"errors"
-	"fmt"
 	"strconv"
 
 	"github.com/DelineaXPM/tss-sdk-go/v2/server"
@@ -36,9 +35,14 @@ type client struct {
 var _ esv1beta1.SecretsClient = &client{}
 
 // GetSecret supports two types:
-//  1. get the full secret as json-encoded value
+//  1. Get the secrets using the secret ID in ref.key i.e. key: 53974
+//  2. Get the secret using the secret "name" i.e. key: "secretNameHere"
+//     - Secret names must not contain spaces.
+//     - If using the secret "name" and multiple secrets are found ...
+//     the first secret in the array will be the secret returned.
+//  3. get the full secret as json-encoded value
 //     by leaving the ref.Property empty.
-//  2. get a key from the secret.
+//  4. get a specific value by using a key from the json formatted secret in Items.0.ItemValue.
 //     Nested values are supported by specifying a gjson expression
 func (c *client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
 	secret, err := c.getSecret(ctx, ref)
@@ -53,36 +57,40 @@ func (c *client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretData
 	if err != nil {
 		return nil, err
 	}
-	// return raw json if no property is defined
+	// If no property is defined return the full secret as raw json
 	if ref.Property == "" {
 		return jsonStr, nil
 	}
-	fmt.Printf("\n\n SEARCH SECRETS = %+v\n\n", ref)
-	// extract key from secret using gjson
+	// extract first "field" i.e. Items.0.ItemValue, data from secret using gjson
 	val := gjson.Get(string(jsonStr), "Items.0.ItemValue")
 	if !val.Exists() {
 		return nil, esv1beta1.NoSecretError{}
 	}
+	// extract specific value from data directly above using gjson
 	out := gjson.Get(val.String(), ref.Property)
-	if !val.Exists() {
+	if !out.Exists() {
 		return nil, esv1beta1.NoSecretError{}
 	}
 
 	return []byte(out.String()), nil
 }
 
+// Not supported at this time.
 func (c *client) PushSecret(_ context.Context, _ *corev1.Secret, _ esv1beta1.PushSecretData) error {
 	return errors.New("pushing secrets is not supported by Secret Server at this time")
 }
 
+// Not supported at this time.
 func (c *client) DeleteSecret(_ context.Context, _ esv1beta1.PushSecretRemoteRef) error {
 	return errors.New("deleting secrets is not supported by Secret Server at this time")
 }
 
+// Not supported at this time.
 func (c *client) SecretExists(_ context.Context, _ esv1beta1.PushSecretRemoteRef) (bool, error) {
 	return false, errors.New("not implemented")
 }
 
+// Not supported at this time.
 func (c *client) Validate() (esv1beta1.ValidationResult, error) {
 	return esv1beta1.ValidationResultReady, nil
 }
@@ -101,7 +109,7 @@ func (c *client) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretD
 
 	data := make(map[string][]byte)
 	for k, v := range secretData {
-		data[fmt.Sprint(k)], err = utils.GetByteValue(v)
+		data[k], err = utils.GetByteValue(v)
 		if err != nil {
 			return nil, err
 		}
@@ -109,7 +117,7 @@ func (c *client) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretD
 	return data, nil
 }
 
-// GetAllSecrets is not supported at this time..
+// Not supported at this time.
 func (c *client) GetAllSecrets(_ context.Context, _ esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	return nil, errors.New("getting all secrets is not supported by Delinea Secret Server at this time")
 }
@@ -125,11 +133,11 @@ func (c *client) getSecret(_ context.Context, ref esv1beta1.ExternalSecretDataRe
 	}
 	id, err := strconv.Atoi(ref.Key)
 	if err != nil {
-			s, err := c.api.Secrets(ref.Key, "Name")
-			if err != nil {
-				return nil, fmt.Errorf("unable to retrieve secrets named ", ref.Key)
-			}
-		return s, nil
+		s, err := c.api.Secrets(ref.Key, "Name")
+		if err != nil {
+			return nil, err
+		}
+		return &s[0], nil
 	}
 	return c.api.Secret(id)
 }

+ 64 - 38
pkg/provider/secretserver/client_test.go

@@ -15,13 +15,11 @@ package secretserver
 
 import (
 	"context"
-    "encoding/json"
+	"encoding/json"
 	"errors"
-	"fmt"
 	"io"
-	"io/ioutil"
-	"testing"
 	"os"
+	"testing"
 
 	"github.com/DelineaXPM/tss-sdk-go/v2/server"
 	"github.com/stretchr/testify/assert"
@@ -32,49 +30,62 @@ import (
 var (
 	errNotFound = errors.New("not found")
 )
+
 type fakeAPI struct {
 	secrets []*server.Secret
 }
 
-func printToScreen(w io.Writer, name interface{}) {
-    fmt.Fprintf(w, "the value is %+v\n", name)
+func (f *fakeAPI) Secret(id int) (*server.Secret, error) {
+	for _, s := range f.secrets {
+		if s.ID == id {
+			return s, nil
+		}
+	}
+	return nil, errNotFound
 }
 
-// createSecret assembles a server.Secret from file test_data.json.
-func createSecret(id int, name string) *server.Secret {
-	var s = &server.Secret{}
-	jsonFile, err := os.Open("test_data.json")
-    if err != nil {
-        printToScreen(os.Stdout, fmt.Sprintf("err opening json data file err = %+v \n\n", err.Error()))
-    }
-
-	byteValue, _ := ioutil.ReadAll(jsonFile)
+func (f *fakeAPI) Secrets(searchText, _ string) ([]server.Secret, error) {
+	secret := make([]server.Secret, 1)
+	for _, s := range f.secrets {
+		if s.Name == searchText {
+			secret[0] = *s
+			return secret, nil
+		}
+	}
+	return nil, errNotFound
+}
 
-	json.Unmarshal(byteValue, &s)
+// createSecret assembles a server.Secret from file test_data.json.
+func createSecret(id int, itemValue string) *server.Secret {
+	s, _ := getJSONData()
 	s.ID = id
-	s.Name = name
+	s.Fields[0].ItemValue = itemValue
 	return s
 }
 
-func (f *fakeAPI) Secret(id int) (*server.Secret, error) {
-	for _, s := range f.secrets {
-		if s.ID == id {
-/*
-			printToScreen(os.Stdout, "found a match")
-*/
-			return s, nil
-		}
+func getJSONData() (*server.Secret, error) {
+	var s = &server.Secret{}
+	jsonFile, err := os.Open("test_data.json")
+	if err != nil {
+		return nil, err
 	}
-	return nil, errNotFound
+	defer jsonFile.Close()
+
+	byteValue, _ := io.ReadAll(jsonFile)
+	err = json.Unmarshal(byteValue, &s)
+	if err != nil {
+		return nil, err
+	}
+	return s, nil
 }
 
 func newTestClient() esv1beta1.SecretsClient {
 	return &client{
 		api: &fakeAPI{
 			secrets: []*server.Secret{
-				createSecret(1000, "robertOppenheimer"),
-				createSecret(2000, "helloWorld"),
-				createSecret(3000, "chuckTesta"),
+				createSecret(1000, "{ \"user\": \"robertOppenheimer\", \"password\": \"badPassword\",\"server\":\"192.168.1.50\"}"),
+				createSecret(2000, "{ \"user\": \"helloWorld\", \"password\": \"badPassword\",\"server\":[ \"192.168.1.50\",\"192.168.1.51\"] }"),
+				createSecret(3000, "{ \"user\": \"chuckTesta\", \"password\": \"badPassword\",\"server\":\"192.168.1.50\"}"),
 			},
 		},
 	}
@@ -83,6 +94,8 @@ func newTestClient() esv1beta1.SecretsClient {
 func TestGetSecret(t *testing.T) {
 	ctx := context.Background()
 	c := newTestClient()
+	s, _ := getJSONData()
+	jsonStr, _ := json.Marshal(s)
 
 	testCases := map[string]struct {
 		ref  esv1beta1.ExternalSecretDataRemoteRef
@@ -94,31 +107,44 @@ func TestGetSecret(t *testing.T) {
 				Key: "0",
 			},
 			want: []byte(nil),
-			err: errNotFound,
+			err:  errNotFound,
 		},
-		"key and property returns a single value": {
+		"key = 'secret name' and user property returns a single value": {
 			ref: esv1beta1.ExternalSecretDataRemoteRef{
-				Key:      "1000",
-				Property: "Name",
+				Key:      "ESO-test-secret",
+				Property: "user",
 			},
 			want: []byte(`robertOppenheimer`),
 		},
+		"key and password property returns a single value": {
+			ref: esv1beta1.ExternalSecretDataRemoteRef{
+				Key:      "1000",
+				Property: "password",
+			},
+			want: []byte(`badPassword`),
+		},
 		"key and nested property returns a single value": {
 			ref: esv1beta1.ExternalSecretDataRemoteRef{
 				Key:      "2000",
-				Property: "Items.2.ItemValue",
+				Property: "server.1",
 			},
-			want: []byte(`l*3FFtvZpcXd`),
+			want: []byte(`192.168.1.51`),
 		},
 		"existent key with non-existing propery": {
 			ref: esv1beta1.ExternalSecretDataRemoteRef{
 				Key:      "3000",
-				Property: "foo.bar.x",
+				Property: "foo.bar",
 			},
-			err: esv1beta1.NoSecretErr,
+			err: esv1beta1.NoSecretError{},
+		},
+		"existent 'name' key with no propery": {
+			ref: esv1beta1.ExternalSecretDataRemoteRef{
+				Key: "1000",
+			},
+			want: jsonStr,
 		},
-
 	}
+
 	for name, tc := range testCases {
 		t.Run(name, func(t *testing.T) {
 			got, err := c.GetSecret(ctx, tc.ref)

+ 8 - 9
pkg/provider/secretserver/provider.go

@@ -28,18 +28,17 @@ import (
 )
 
 var (
-	errEmptyUserName             = errors.New("username must not be empty")
-	errEmptyPassword             = errors.New("passWord must be set")
-	errEmptyServerURL            = errors.New("serverURL must be set")
-	errSecretRefAndValueConflict = errors.New("cannot specify both secret reference and value")
-	errSecretRefAndValueMissing  = errors.New("must specify either secret reference or direct value")
-	errMissingStore              = errors.New("missing store specification")
-	errInvalidSpec               = errors.New("invalid specification for secret server provider")
+	errEmptyUserName                 = errors.New("username must not be empty")
+	errEmptyPassword                 = errors.New("password must be set")
+	errEmptyServerURL                = errors.New("serverURL must be set")
+	errSecretRefAndValueConflict     = errors.New("cannot specify both secret reference and value")
+	errSecretRefAndValueMissing      = errors.New("must specify either secret reference or direct value")
+	errMissingStore                  = errors.New("missing store specification")
+	errInvalidSpec                   = errors.New("invalid specification for secret server provider")
 	errClusterStoreRequiresNamespace = errors.New("when using a ClusterSecretStore, namespaces must be explicitly set")
 	errMissingSecretName             = errors.New("must specify a secret name")
 
-	errMissingSecretID = errors.New("must specify a secret id")
-	errMissingSecretKey  = errors.New("must specify a secret key")
+	errMissingSecretKey = errors.New("must specify a secret key")
 )
 
 type Provider struct{}

+ 23 - 24
pkg/provider/secretserver/provider_test.go

@@ -56,7 +56,7 @@ func TestDoesConfigDependOnNamespace(t *testing.T) {
 		},
 		"false when neither Username or Password reference a secret": {
 			cfg: esv1beta1.SecretServerProvider{
-				Username:     &esv1beta1.SecretServerProviderRef{SecretRef: nil},
+				Username: &esv1beta1.SecretServerProviderRef{SecretRef: nil},
 				Password: &esv1beta1.SecretServerProviderRef{SecretRef: nil},
 			},
 			want: false,
@@ -99,8 +99,8 @@ func TestValidateStore(t *testing.T) {
 		},
 		"invalid without serverURL": {
 			cfg: esv1beta1.SecretServerProvider{
-				Username:  validSecretRefUsingValue,
-				Password:  validSecretRefUsingValue,
+				Username: validSecretRefUsingValue,
+				Password: validSecretRefUsingValue,
 				/*ServerURL: testURL,*/
 			},
 			want: errEmptyServerURL,
@@ -171,7 +171,7 @@ func TestNewClient(t *testing.T) {
 	clientSecret := &corev1.Secret{
 		ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
 		Data: map[string][]byte{
-			userNameKey:     []byte(userNameValue),
+			userNameKey: []byte(userNameValue),
 			passwordKey: []byte(passwordValue),
 		},
 	}
@@ -183,7 +183,7 @@ func TestNewClient(t *testing.T) {
 	}
 
 	tests := map[string]struct {
-		store    esv1beta1.GenericStore     // leave nil for namespaced store
+		store    esv1beta1.GenericStore          // leave nil for namespaced store
 		provider *esv1beta1.SecretServerProvider // discarded when store is set
 		kube     kubeClient.Client
 		errCheck func(t *testing.T, err error)
@@ -209,8 +209,8 @@ func TestNewClient(t *testing.T) {
 		},
 		"dangling password ref": {
 			provider: &esv1beta1.SecretServerProvider{
-				Username:      validProvider.Username,
-				Password:     makeSecretRefUsingRef("typo", passwordKey),
+				Username:  validProvider.Username,
+				Password:  makeSecretRefUsingRef("typo", passwordKey),
 				ServerURL: validProvider.ServerURL,
 			},
 			kube: clientfake.NewClientBuilder().WithObjects(clientSecret).Build(),
@@ -220,8 +220,8 @@ func TestNewClient(t *testing.T) {
 		},
 		"dangling username ref": {
 			provider: &esv1beta1.SecretServerProvider{
-				Username:      makeSecretRefUsingRef("typo", userNameKey),
-				Password:     validProvider.Password,
+				Username:  makeSecretRefUsingRef("typo", userNameKey),
+				Password:  validProvider.Password,
 				ServerURL: validProvider.ServerURL,
 			},
 			kube: clientfake.NewClientBuilder().WithObjects(clientSecret).Build(),
@@ -231,8 +231,8 @@ func TestNewClient(t *testing.T) {
 		},
 		"secret ref without name": {
 			provider: &esv1beta1.SecretServerProvider{
-				Username:      makeSecretRefUsingRef("", userNameKey),
-				Password:     validProvider.Password,
+				Username:  makeSecretRefUsingRef("", userNameKey),
+				Password:  validProvider.Password,
 				ServerURL: validProvider.ServerURL,
 			},
 			kube: clientfake.NewClientBuilder().WithObjects(clientSecret).Build(),
@@ -242,8 +242,8 @@ func TestNewClient(t *testing.T) {
 		},
 		"secret ref without key": {
 			provider: &esv1beta1.SecretServerProvider{
-				Username:      validProvider.Password,
-				Password:     makeSecretRefUsingRef(clientSecret.Name, ""),
+				Username:  validProvider.Password,
+				Password:  makeSecretRefUsingRef(clientSecret.Name, ""),
 				ServerURL: validProvider.ServerURL,
 			},
 			kube: clientfake.NewClientBuilder().WithObjects(clientSecret).Build(),
@@ -253,8 +253,8 @@ func TestNewClient(t *testing.T) {
 		},
 		"secret ref with non-existent keys": {
 			provider: &esv1beta1.SecretServerProvider{
-				Username:      makeSecretRefUsingRef(clientSecret.Name, "typo"),
-				Password:     makeSecretRefUsingRef(clientSecret.Name, passwordKey),
+				Username:  makeSecretRefUsingRef(clientSecret.Name, "typo"),
+				Password:  makeSecretRefUsingRef(clientSecret.Name, passwordKey),
 				ServerURL: validProvider.ServerURL,
 			},
 			kube: clientfake.NewClientBuilder().WithObjects(clientSecret).Build(),
@@ -268,9 +268,9 @@ func TestNewClient(t *testing.T) {
 		},
 		"secret values": {
 			provider: &esv1beta1.SecretServerProvider{
-				Username:     makeSecretRefUsingValue(userNameValue),
-				Password:     makeSecretRefUsingValue(passwordValue),
-				ServerURL:    validProvider.ServerURL,
+				Username:  makeSecretRefUsingValue(userNameValue),
+				Password:  makeSecretRefUsingValue(passwordValue),
+				ServerURL: validProvider.ServerURL,
 			},
 			kube: clientfake.NewClientBuilder().WithObjects(clientSecret).Build(),
 		},
@@ -280,9 +280,9 @@ func TestNewClient(t *testing.T) {
 				Spec: esv1beta1.SecretStoreSpec{
 					Provider: &esv1beta1.SecretStoreProvider{
 						SecretServer: &esv1beta1.SecretServerProvider{
-							Username:     makeSecretRefUsingNamespacedRef(clientSecret.Namespace, clientSecret.Name, userNameKey),
-							Password:     makeSecretRefUsingNamespacedRef(clientSecret.Namespace, clientSecret.Name, passwordKey),
-							ServerURL:    validProvider.ServerURL,
+							Username:  makeSecretRefUsingNamespacedRef(clientSecret.Namespace, clientSecret.Name, userNameKey),
+							Password:  makeSecretRefUsingNamespacedRef(clientSecret.Namespace, clientSecret.Name, passwordKey),
+							ServerURL: validProvider.ServerURL,
 						},
 					},
 				},
@@ -312,8 +312,8 @@ func TestNewClient(t *testing.T) {
 				secretServerClient, ok := delineaClient.api.(*server.Server)
 				assert.True(t, ok)
 				assert.Equal(t, server.UserCredential{
-					Username:     userNameValue,
-					Password:     passwordValue,
+					Username: userNameValue,
+					Password: passwordValue,
 				}, secretServerClient.Configuration.Credentials)
 			} else {
 				assert.Nil(t, sc)
@@ -333,7 +333,6 @@ func makeSecretRefUsingValue(val string) *esv1beta1.SecretServerProviderRef {
 	return &esv1beta1.SecretServerProviderRef{Value: val}
 }
 
-
 func makeSecretRefUsingRef(name, key string) *esv1beta1.SecretServerProviderRef {
 	return &esv1beta1.SecretServerProviderRef{
 		SecretRef: &v1.SecretKeySelector{Name: name, Key: key},

+ 1 - 1
pkg/provider/secretserver/secret_api.go

@@ -22,5 +22,5 @@ import (
 // which is supported by tss-sdk-go/v2.
 type secretAPI interface {
 	Secret(id int) (*server.Secret, error)
-	Secrets(searchText, field string) (*server.Secret, error)
+	Secrets(searchText, field string) ([]server.Secret, error)
 }

+ 36 - 114
pkg/provider/secretserver/test_data.json

@@ -1,116 +1,38 @@
 {
-  "Name": "DSV unix template test secret",
-  "FolderID": 67,
-  "ID": 49490,
-  "SiteID": 1,
-  "SecretTemplateID": 6007,
-  "SecretPolicyID": -1,
-  "PasswordTypeWebScriptID": -1,
-  "LauncherConnectAsSecretID": -1,
-  "CheckOutIntervalMinutes": -1,
-  "Active": true,
-  "CheckedOut": false,
-  "CheckOutEnabled": false,
-  "AutoChangeEnabled": false,
-  "CheckOutChangePasswordEnabled": false,
-  "DelayIndexing": false,
-  "EnableInheritPermissions": true,
-  "EnableInheritSecretPolicy": true,
-  "ProxyEnabled": false,
-  "RequiresComment": false,
-  "SessionRecordingEnabled": false,
-  "WebLauncherRequiresIncognitoMode": false,
-  "Items": [
-    {
-      "ItemID": 262098,
-      "FieldID": 108,
-      "FileAttachmentID": 0,
-      "FieldName": "Machine",
-      "Slug": "machine",
-      "FieldDescription": "The Server or Location of the Unix Machine.",
-      "Filename": "",
-      "ItemValue": "192.168.0.2",
-      "IsFile": false,
-      "IsNotes": false,
-      "IsPassword": false
-    },
-    {
-      "ItemID": 262099,
-      "FieldID": 111,
-      "FileAttachmentID": 0,
-      "FieldName": "Username",
-      "Slug": "username",
-      "FieldDescription": "The Unix Machine Username.",
-      "Filename": "",
-      "ItemValue": "chuckTesta",
-      "IsFile": false,
-      "IsNotes": false,
-      "IsPassword": false
-    },
-    {
-      "ItemID": 262100,
-      "FieldID": 110,
-      "FileAttachmentID": 0,
-      "FieldName": "Password",
-      "Slug": "password",
-      "FieldDescription": "The password of the Unix Machine.",
-      "Filename": "",
-      "ItemValue": "l*3FFtvZpcXd",
-      "IsFile": false,
-      "IsNotes": false,
-      "IsPassword": true
-    },
-    {
-      "ItemID": 262101,
-      "FieldID": 109,
-      "FileAttachmentID": 0,
-      "FieldName": "Notes",
-      "Slug": "notes",
-      "FieldDescription": "Any additional notes.",
-      "Filename": "",
-      "ItemValue": "",
-      "IsFile": false,
-      "IsNotes": true,
-      "IsPassword": false
-    },
-    {
-      "ItemID": 262102,
-      "FieldID": 189,
-      "FileAttachmentID": 65,
-      "FieldName": "Private Key",
-      "Slug": "private-key",
-      "FieldDescription": "The SSH private key.",
-      "Filename": "",
-      "ItemValue": "*** Not Valid For Display ***",
-      "IsFile": true,
-      "IsNotes": false,
-      "IsPassword": false
-    },
-    {
-      "ItemID": 262103,
-      "FieldID": 190,
-      "FileAttachmentID": 0,
-      "FieldName": "Private Key Passphrase",
-      "Slug": "private-key-passphrase",
-      "FieldDescription": "The passphrase for decrypting the SSH private key.",
-      "Filename": "",
-      "ItemValue": "",
-      "IsFile": false,
-      "IsNotes": false,
-      "IsPassword": true
-    },
-    {
-      "ItemID": 262104,
-      "FieldID": 374,
-      "FileAttachmentID": 0,
-      "FieldName": "Port",
-      "Slug": "port",
-      "FieldDescription": "Target port",
-      "Filename": "",
-      "ItemValue": "22",
-      "IsFile": false,
-      "IsNotes": false,
-      "IsPassword": false
-    }
-  ]
+"Name": "ESO-test-secret",
+"FolderID": 73,
+"ID": 1000,
+"SiteID": 1,
+"SecretTemplateID": 6098,
+"SecretPolicyID": -1,
+"PasswordTypeWebScriptID": -1,
+"LauncherConnectAsSecretID": -1,
+"CheckOutIntervalMinutes": -1,
+"Active": true,
+"CheckedOut": false,
+"CheckOutEnabled": false,
+"AutoChangeEnabled": false,
+"CheckOutChangePasswordEnabled": false,
+"DelayIndexing": false,
+"EnableInheritPermissions": false,
+"EnableInheritSecretPolicy": false,
+"ProxyEnabled": false,
+"RequiresComment": false,
+"SessionRecordingEnabled": false,
+"WebLauncherRequiresIncognitoMode": false,
+"Items": [
+  {
+	"ItemID": 286259,
+	"FieldID": 439,
+	"FileAttachmentID": 0,
+	"FieldName": "Data",
+	"Slug": "data",
+	"FieldDescription": "json text field",
+	"Filename": "",
+	"ItemValue": "{ \"user\": \"robertOppenheimer\", \"password\": \"badPassword\",\"server\":\"192.168.1.50\"}",
+	"IsFile": false,
+	"IsNotes": false,
+	"IsPassword": false
+  }
+]
 }