mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-04 04:28:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			273 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			273 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package command
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"reflect"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/hashicorp/vault/api"
 | 
						|
)
 | 
						|
 | 
						|
// TestAddPrefixToKVPath tests the addPrefixToKVPath helper function
 | 
						|
func TestAddPrefixToKVPath(t *testing.T) {
 | 
						|
	cases := map[string]struct {
 | 
						|
		path         string
 | 
						|
		mountPath    string
 | 
						|
		apiPrefix    string
 | 
						|
		skipIfExists bool
 | 
						|
		expected     string
 | 
						|
	}{
 | 
						|
		"simple": {
 | 
						|
			path:         "kv-v2/foo",
 | 
						|
			mountPath:    "kv-v2/",
 | 
						|
			apiPrefix:    "data",
 | 
						|
			skipIfExists: false,
 | 
						|
			expected:     "kv-v2/data/foo",
 | 
						|
		},
 | 
						|
 | 
						|
		"multi-part": {
 | 
						|
			path:         "my/kv-v2/mount/path/foo/bar/baz",
 | 
						|
			mountPath:    "my/kv-v2/mount/path",
 | 
						|
			apiPrefix:    "metadata",
 | 
						|
			skipIfExists: false,
 | 
						|
			expected:     "my/kv-v2/mount/path/metadata/foo/bar/baz",
 | 
						|
		},
 | 
						|
 | 
						|
		"with-namespace": {
 | 
						|
			path:         "my/kv-v2/mount/path/foo/bar/baz",
 | 
						|
			mountPath:    "my/ns1/my/kv-v2/mount/path",
 | 
						|
			apiPrefix:    "metadata",
 | 
						|
			skipIfExists: false,
 | 
						|
			expected:     "my/kv-v2/mount/path/metadata/foo/bar/baz",
 | 
						|
		},
 | 
						|
 | 
						|
		"skip-if-exists-true": {
 | 
						|
			path:         "kv-v2/data/foo",
 | 
						|
			mountPath:    "kv-v2/",
 | 
						|
			apiPrefix:    "data",
 | 
						|
			skipIfExists: true,
 | 
						|
			expected:     "kv-v2/data/foo",
 | 
						|
		},
 | 
						|
 | 
						|
		"skip-if-exists-false": {
 | 
						|
			path:         "kv-v2/data/foo",
 | 
						|
			mountPath:    "kv-v2",
 | 
						|
			apiPrefix:    "data",
 | 
						|
			skipIfExists: false,
 | 
						|
			expected:     "kv-v2/data/data/foo",
 | 
						|
		},
 | 
						|
 | 
						|
		"skip-if-exists-with-namespace": {
 | 
						|
			path:         "my/kv-v2/mount/path/metadata/foo/bar/baz",
 | 
						|
			mountPath:    "my/ns1/my/kv-v2/mount/path",
 | 
						|
			apiPrefix:    "metadata",
 | 
						|
			skipIfExists: true,
 | 
						|
			expected:     "my/kv-v2/mount/path/metadata/foo/bar/baz",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for name, tc := range cases {
 | 
						|
		name, tc := name, tc
 | 
						|
		t.Run(name, func(t *testing.T) {
 | 
						|
			t.Parallel()
 | 
						|
 | 
						|
			actual := addPrefixToKVPath(
 | 
						|
				tc.path,
 | 
						|
				tc.mountPath,
 | 
						|
				tc.apiPrefix,
 | 
						|
				tc.skipIfExists,
 | 
						|
			)
 | 
						|
 | 
						|
			if tc.expected != actual {
 | 
						|
				t.Fatalf("unexpected output; want: %v, got: %v", tc.expected, actual)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// TestWalkSecretsTree tests the walkSecretsTree helper function
 | 
						|
func TestWalkSecretsTree(t *testing.T) {
 | 
						|
	// test setup
 | 
						|
	client, closer := testVaultServer(t)
 | 
						|
	defer closer()
 | 
						|
 | 
						|
	// enable kv-v1 backend
 | 
						|
	if err := client.Sys().Mount("kv-v1/", &api.MountInput{
 | 
						|
		Type: "kv-v1",
 | 
						|
	}); err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
	time.Sleep(time.Second)
 | 
						|
 | 
						|
	// enable kv-v2 backend
 | 
						|
	if err := client.Sys().Mount("kv-v2/", &api.MountInput{
 | 
						|
		Type: "kv-v2",
 | 
						|
	}); err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
	time.Sleep(time.Second)
 | 
						|
 | 
						|
	ctx, cancelContextFunc := context.WithTimeout(context.Background(), 5*time.Second)
 | 
						|
	defer cancelContextFunc()
 | 
						|
 | 
						|
	// populate secrets
 | 
						|
	for _, path := range []string{
 | 
						|
		"foo",
 | 
						|
		"app-1/foo",
 | 
						|
		"app-1/bar",
 | 
						|
		"app-1/nested/x/y/z",
 | 
						|
		"app-1/nested/x/y",
 | 
						|
		"app-1/nested/bar",
 | 
						|
	} {
 | 
						|
		if err := client.KVv1("kv-v1").Put(ctx, path, map[string]interface{}{
 | 
						|
			"password": "Hashi123",
 | 
						|
		}); err != nil {
 | 
						|
			t.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		if _, err := client.KVv2("kv-v2").Put(ctx, path, map[string]interface{}{
 | 
						|
			"password": "Hashi123",
 | 
						|
		}); err != nil {
 | 
						|
			t.Fatal(err)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	type treePath struct {
 | 
						|
		path      string
 | 
						|
		directory bool
 | 
						|
	}
 | 
						|
 | 
						|
	cases := map[string]struct {
 | 
						|
		path          string
 | 
						|
		expected      []treePath
 | 
						|
		expectedError bool
 | 
						|
	}{
 | 
						|
		"kv-v1-simple": {
 | 
						|
			path: "kv-v1/app-1/nested/x/y",
 | 
						|
			expected: []treePath{
 | 
						|
				{path: "kv-v1/app-1/nested/x/y/z", directory: false},
 | 
						|
			},
 | 
						|
			expectedError: false,
 | 
						|
		},
 | 
						|
 | 
						|
		"kv-v2-simple": {
 | 
						|
			path: "kv-v2/metadata/app-1/nested/x/y",
 | 
						|
			expected: []treePath{
 | 
						|
				{path: "kv-v2/metadata/app-1/nested/x/y/z", directory: false},
 | 
						|
			},
 | 
						|
			expectedError: false,
 | 
						|
		},
 | 
						|
 | 
						|
		"kv-v1-nested": {
 | 
						|
			path: "kv-v1/app-1/nested/",
 | 
						|
			expected: []treePath{
 | 
						|
				{path: "kv-v1/app-1/nested/bar", directory: false},
 | 
						|
				{path: "kv-v1/app-1/nested/x", directory: true},
 | 
						|
				{path: "kv-v1/app-1/nested/x/y", directory: false},
 | 
						|
				{path: "kv-v1/app-1/nested/x/y", directory: true},
 | 
						|
				{path: "kv-v1/app-1/nested/x/y/z", directory: false},
 | 
						|
			},
 | 
						|
			expectedError: false,
 | 
						|
		},
 | 
						|
 | 
						|
		"kv-v2-nested": {
 | 
						|
			path: "kv-v2/metadata/app-1/nested/",
 | 
						|
			expected: []treePath{
 | 
						|
				{path: "kv-v2/metadata/app-1/nested/bar", directory: false},
 | 
						|
				{path: "kv-v2/metadata/app-1/nested/x", directory: true},
 | 
						|
				{path: "kv-v2/metadata/app-1/nested/x/y", directory: false},
 | 
						|
				{path: "kv-v2/metadata/app-1/nested/x/y", directory: true},
 | 
						|
				{path: "kv-v2/metadata/app-1/nested/x/y/z", directory: false},
 | 
						|
			},
 | 
						|
			expectedError: false,
 | 
						|
		},
 | 
						|
 | 
						|
		"kv-v1-all": {
 | 
						|
			path: "kv-v1",
 | 
						|
			expected: []treePath{
 | 
						|
				{path: "kv-v1/app-1", directory: true},
 | 
						|
				{path: "kv-v1/app-1/bar", directory: false},
 | 
						|
				{path: "kv-v1/app-1/foo", directory: false},
 | 
						|
				{path: "kv-v1/app-1/nested", directory: true},
 | 
						|
				{path: "kv-v1/app-1/nested/bar", directory: false},
 | 
						|
				{path: "kv-v1/app-1/nested/x", directory: true},
 | 
						|
				{path: "kv-v1/app-1/nested/x/y", directory: false},
 | 
						|
				{path: "kv-v1/app-1/nested/x/y", directory: true},
 | 
						|
				{path: "kv-v1/app-1/nested/x/y/z", directory: false},
 | 
						|
				{path: "kv-v1/foo", directory: false},
 | 
						|
			},
 | 
						|
			expectedError: false,
 | 
						|
		},
 | 
						|
 | 
						|
		"kv-v2-all": {
 | 
						|
			path: "kv-v2/metadata",
 | 
						|
			expected: []treePath{
 | 
						|
				{path: "kv-v2/metadata/app-1", directory: true},
 | 
						|
				{path: "kv-v2/metadata/app-1/bar", directory: false},
 | 
						|
				{path: "kv-v2/metadata/app-1/foo", directory: false},
 | 
						|
				{path: "kv-v2/metadata/app-1/nested", directory: true},
 | 
						|
				{path: "kv-v2/metadata/app-1/nested/bar", directory: false},
 | 
						|
				{path: "kv-v2/metadata/app-1/nested/x", directory: true},
 | 
						|
				{path: "kv-v2/metadata/app-1/nested/x/y", directory: false},
 | 
						|
				{path: "kv-v2/metadata/app-1/nested/x/y", directory: true},
 | 
						|
				{path: "kv-v2/metadata/app-1/nested/x/y/z", directory: false},
 | 
						|
				{path: "kv-v2/metadata/foo", directory: false},
 | 
						|
			},
 | 
						|
			expectedError: false,
 | 
						|
		},
 | 
						|
 | 
						|
		"kv-v1-not-found": {
 | 
						|
			path:          "kv-v1/does/not/exist",
 | 
						|
			expected:      nil,
 | 
						|
			expectedError: true,
 | 
						|
		},
 | 
						|
 | 
						|
		"kv-v2-not-found": {
 | 
						|
			path:          "kv-v2/metadata/does/not/exist",
 | 
						|
			expected:      nil,
 | 
						|
			expectedError: true,
 | 
						|
		},
 | 
						|
 | 
						|
		"kv-v1-not-listable-leaf-node": {
 | 
						|
			path:          "kv-v1/foo",
 | 
						|
			expected:      nil,
 | 
						|
			expectedError: true,
 | 
						|
		},
 | 
						|
 | 
						|
		"kv-v2-not-listable-leaf-node": {
 | 
						|
			path:          "kv-v2/metadata/foo",
 | 
						|
			expected:      nil,
 | 
						|
			expectedError: true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for name, tc := range cases {
 | 
						|
		t.Run(name, func(t *testing.T) {
 | 
						|
			var descendants []treePath
 | 
						|
 | 
						|
			err := walkSecretsTree(ctx, client, tc.path, func(path string, directory bool) error {
 | 
						|
				descendants = append(descendants, treePath{
 | 
						|
					path:      path,
 | 
						|
					directory: directory,
 | 
						|
				})
 | 
						|
				return nil
 | 
						|
			})
 | 
						|
 | 
						|
			if tc.expectedError {
 | 
						|
				if err == nil {
 | 
						|
					t.Fatal("an error was expected but the test succeeded")
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				if err != nil {
 | 
						|
					t.Fatal(err)
 | 
						|
				}
 | 
						|
 | 
						|
				if !reflect.DeepEqual(tc.expected, descendants) {
 | 
						|
					t.Fatalf("unexpected list output; want: %v, got: %v", tc.expected, descendants)
 | 
						|
				}
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 |