vault/command/base_predict_test.go
Nick Cabatoff 34ba7acdb8
Start using entAddExtPlugins instead of the init hook addExternalPlugins (#23665)
This causes the registry to now contain ent plugins on ent; previously it did not, though that appears to have been the intention. I believe this is because of the order in which inits were run.

Having changed this, various tests broke that were relying on the incorrect behaviour. Several tests were changed to rely less on opaque counts of expected plugins, instead they're now using explicit comparison by name.
2023-10-17 09:46:54 -04:00

755 lines
14 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package command
import (
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/vault/api"
"github.com/posener/complete"
)
func TestPredictVaultPaths(t *testing.T) {
t.Parallel()
client, closer := testVaultServer(t)
defer closer()
data := map[string]interface{}{"a": "b"}
if _, err := client.Logical().Write("secret/bar", data); err != nil {
t.Fatal(err)
}
if _, err := client.Logical().Write("secret/foo", data); err != nil {
t.Fatal(err)
}
if _, err := client.Logical().Write("secret/zip/zap", data); err != nil {
t.Fatal(err)
}
if _, err := client.Logical().Write("secret/zip/zonk", data); err != nil {
t.Fatal(err)
}
if _, err := client.Logical().Write("secret/zip/twoot", data); err != nil {
t.Fatal(err)
}
if err := client.Sys().Mount("level1a/level2a/level3a", &api.MountInput{Type: "kv"}); err != nil {
t.Fatal(err)
}
if err := client.Sys().Mount("level1a/level2a/level3b", &api.MountInput{Type: "kv"}); err != nil {
t.Fatal(err)
}
cases := []struct {
name string
args complete.Args
includeFiles bool
exp []string
}{
{
"has_args",
complete.Args{
All: []string{"read", "secret/foo", "a=b"},
Last: "a=b",
},
true,
nil,
},
{
"has_args_no_files",
complete.Args{
All: []string{"read", "secret/foo", "a=b"},
Last: "a=b",
},
false,
nil,
},
{
"part_mount",
complete.Args{
All: []string{"read", "s"},
Last: "s",
},
true,
[]string{"secret/", "sys/"},
},
{
"part_mount_no_files",
complete.Args{
All: []string{"read", "s"},
Last: "s",
},
false,
[]string{"secret/", "sys/"},
},
{
"only_mount",
complete.Args{
All: []string{"read", "sec"},
Last: "sec",
},
true,
[]string{"secret/bar", "secret/foo", "secret/zip/"},
},
{
"only_mount_no_files",
complete.Args{
All: []string{"read", "sec"},
Last: "sec",
},
false,
[]string{"secret/zip/"},
},
{
"full_mount",
complete.Args{
All: []string{"read", "secret"},
Last: "secret",
},
true,
[]string{"secret/bar", "secret/foo", "secret/zip/"},
},
{
"full_mount_no_files",
complete.Args{
All: []string{"read", "secret"},
Last: "secret",
},
false,
[]string{"secret/zip/"},
},
{
"full_mount_slash",
complete.Args{
All: []string{"read", "secret/"},
Last: "secret/",
},
true,
[]string{"secret/bar", "secret/foo", "secret/zip/"},
},
{
"full_mount_slash_no_files",
complete.Args{
All: []string{"read", "secret/"},
Last: "secret/",
},
false,
[]string{"secret/zip/"},
},
{
"path_partial",
complete.Args{
All: []string{"read", "secret/z"},
Last: "secret/z",
},
true,
[]string{"secret/zip/twoot", "secret/zip/zap", "secret/zip/zonk"},
},
{
"path_partial_no_files",
complete.Args{
All: []string{"read", "secret/z"},
Last: "secret/z",
},
false,
[]string{"secret/zip/"},
},
{
"subpath_partial_z",
complete.Args{
All: []string{"read", "secret/zip/z"},
Last: "secret/zip/z",
},
true,
[]string{"secret/zip/zap", "secret/zip/zonk"},
},
{
"subpath_partial_z_no_files",
complete.Args{
All: []string{"read", "secret/zip/z"},
Last: "secret/zip/z",
},
false,
[]string{"secret/zip/z"},
},
{
"subpath_partial_t",
complete.Args{
All: []string{"read", "secret/zip/t"},
Last: "secret/zip/t",
},
true,
[]string{"secret/zip/twoot"},
},
{
"subpath_partial_t_no_files",
complete.Args{
All: []string{"read", "secret/zip/t"},
Last: "secret/zip/t",
},
false,
[]string{"secret/zip/t"},
},
{
"multi_nested",
complete.Args{
All: []string{"read", "level1a/level2a"},
Last: "level1a/level2a",
},
false,
[]string{
"level1a/level2a/level3a/",
"level1a/level2a/level3b/",
},
},
}
t.Run("group", func(t *testing.T) {
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
p := NewPredict()
p.client = client
f := p.vaultPaths(tc.includeFiles)
act := f(tc.args)
if !reflect.DeepEqual(act, tc.exp) {
t.Errorf("expected %q to be %q", act, tc.exp)
}
})
}
})
}
func TestPredict_Audits(t *testing.T) {
t.Parallel()
client, closer := testVaultServer(t)
defer closer()
badClient, badCloser := testVaultServerBad(t)
defer badCloser()
if err := client.Sys().EnableAuditWithOptions("file", &api.EnableAuditOptions{
Type: "file",
Options: map[string]string{
"file_path": "discard",
},
}); err != nil {
t.Fatal(err)
}
cases := []struct {
name string
client *api.Client
exp []string
}{
{
"not_connected_client",
badClient,
nil,
},
{
"good_path",
client,
[]string{"file/"},
},
}
t.Run("group", func(t *testing.T) {
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
p := NewPredict()
p.client = tc.client
act := p.audits()
if !reflect.DeepEqual(act, tc.exp) {
t.Errorf("expected %q to be %q", act, tc.exp)
}
})
}
})
}
func TestPredict_Mounts(t *testing.T) {
t.Parallel()
client, closer := testVaultServer(t)
defer closer()
badClient, badCloser := testVaultServerBad(t)
defer badCloser()
cases := []struct {
name string
client *api.Client
exp []string
}{
{
"not_connected_client",
badClient,
defaultPredictVaultMounts,
},
{
"good_path",
client,
[]string{"cubbyhole/", "identity/", "secret/", "sys/"},
},
}
t.Run("group", func(t *testing.T) {
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
p := NewPredict()
p.client = tc.client
act := p.mounts()
if !reflect.DeepEqual(act, tc.exp) {
t.Errorf("expected %q to be %q", act, tc.exp)
}
})
}
})
}
func TestPredict_Plugins(t *testing.T) {
t.Parallel()
client, closer := testVaultServer(t)
defer closer()
badClient, badCloser := testVaultServerBad(t)
defer badCloser()
cases := []struct {
name string
client *api.Client
exp []string
}{
{
"not_connected_client",
badClient,
nil,
},
{
"good_path",
client,
[]string{
"ad",
"alicloud",
"approle",
"aws",
"azure",
"cassandra-database-plugin",
"centrify",
"cert",
"cf",
"consul",
"couchbase-database-plugin",
"elasticsearch-database-plugin",
"gcp",
"gcpkms",
"github",
"hana-database-plugin",
"influxdb-database-plugin",
"jwt",
"kerberos",
"keymgmt",
"kmip",
"kubernetes",
"kv",
"ldap",
"mongodb-database-plugin",
"mongodbatlas",
"mongodbatlas-database-plugin",
"mssql-database-plugin",
"mysql-aurora-database-plugin",
"mysql-database-plugin",
"mysql-legacy-database-plugin",
"mysql-rds-database-plugin",
"nomad",
"oci",
"oidc",
"okta",
"openldap",
"pcf", // Deprecated.
"pki",
"postgresql-database-plugin",
"rabbitmq",
"radius",
"redis-database-plugin",
"redis-elasticache-database-plugin",
"redshift-database-plugin",
"saml",
"snowflake-database-plugin",
"ssh",
"terraform",
"totp",
"transform",
"transit",
"userpass",
},
},
}
t.Run("group", func(t *testing.T) {
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
p := NewPredict()
p.client = tc.client
act := p.plugins()
if !strutil.StrListContains(act, "keymgmt") {
for i, v := range tc.exp {
if v == "keymgmt" {
tc.exp = append(tc.exp[:i], tc.exp[i+1:]...)
break
}
}
}
if !strutil.StrListContains(act, "kmip") {
for i, v := range tc.exp {
if v == "kmip" {
tc.exp = append(tc.exp[:i], tc.exp[i+1:]...)
break
}
}
}
if !strutil.StrListContains(act, "transform") {
for i, v := range tc.exp {
if v == "transform" {
tc.exp = append(tc.exp[:i], tc.exp[i+1:]...)
break
}
}
}
if !strutil.StrListContains(act, "saml") {
for i, v := range tc.exp {
if v == "saml" {
tc.exp = append(tc.exp[:i], tc.exp[i+1:]...)
break
}
}
}
if d := cmp.Diff(act, tc.exp); len(d) > 0 {
t.Errorf("expected: %q, got: %q, diff: %v", tc.exp, act, d)
}
})
}
})
}
func TestPredict_Policies(t *testing.T) {
t.Parallel()
client, closer := testVaultServer(t)
defer closer()
badClient, badCloser := testVaultServerBad(t)
defer badCloser()
cases := []struct {
name string
client *api.Client
exp []string
}{
{
"not_connected_client",
badClient,
nil,
},
{
"good_path",
client,
[]string{"default", "root"},
},
}
t.Run("group", func(t *testing.T) {
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
p := NewPredict()
p.client = tc.client
act := p.policies()
if !reflect.DeepEqual(act, tc.exp) {
t.Errorf("expected %q to be %q", act, tc.exp)
}
})
}
})
}
func TestPredict_Paths(t *testing.T) {
t.Parallel()
client, closer := testVaultServer(t)
defer closer()
data := map[string]interface{}{"a": "b"}
if _, err := client.Logical().Write("secret/bar", data); err != nil {
t.Fatal(err)
}
if _, err := client.Logical().Write("secret/foo", data); err != nil {
t.Fatal(err)
}
if _, err := client.Logical().Write("secret/zip/zap", data); err != nil {
t.Fatal(err)
}
cases := []struct {
name string
path string
includeFiles bool
exp []string
}{
{
"bad_path",
"nope/not/a/real/path/ever",
true,
[]string{"nope/not/a/real/path/ever"},
},
{
"good_path",
"secret/",
true,
[]string{"secret/bar", "secret/foo", "secret/zip/"},
},
{
"good_path_no_files",
"secret/",
false,
[]string{"secret/zip/"},
},
{
"partial_match",
"secret/z",
true,
[]string{"secret/zip/"},
},
{
"partial_match_no_files",
"secret/z",
false,
[]string{"secret/zip/"},
},
}
t.Run("group", func(t *testing.T) {
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
p := NewPredict()
p.client = client
act := p.paths("kv", "1", tc.path, tc.includeFiles)
if !reflect.DeepEqual(act, tc.exp) {
t.Errorf("expected %q to be %q", act, tc.exp)
}
})
}
})
}
func TestPredict_PathsKVv2(t *testing.T) {
t.Parallel()
client, closer := testVaultServerWithKVVersion(t, "2")
defer closer()
data := map[string]interface{}{"data": map[string]interface{}{"a": "b"}}
if _, err := client.Logical().Write("secret/data/bar", data); err != nil {
t.Fatal(err)
}
if _, err := client.Logical().Write("secret/data/foo", data); err != nil {
t.Fatal(err)
}
if _, err := client.Logical().Write("secret/data/zip/zap", data); err != nil {
t.Fatal(err)
}
cases := []struct {
name string
path string
includeFiles bool
exp []string
}{
{
"bad_path",
"nope/not/a/real/path/ever",
true,
[]string{"nope/not/a/real/path/ever"},
},
{
"good_path",
"secret/",
true,
[]string{"secret/bar", "secret/foo", "secret/zip/"},
},
{
"good_path_no_files",
"secret/",
false,
[]string{"secret/zip/"},
},
{
"partial_match",
"secret/z",
true,
[]string{"secret/zip/"},
},
{
"partial_match_no_files",
"secret/z",
false,
[]string{"secret/zip/"},
},
}
t.Run("group", func(t *testing.T) {
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
p := NewPredict()
p.client = client
act := p.paths("kv", "2", tc.path, tc.includeFiles)
if !reflect.DeepEqual(act, tc.exp) {
t.Errorf("expected %q to be %q", act, tc.exp)
}
})
}
})
}
func TestPredict_ListPaths(t *testing.T) {
t.Parallel()
client, closer := testVaultServer(t)
defer closer()
badClient, badCloser := testVaultServerBad(t)
defer badCloser()
data := map[string]interface{}{"a": "b"}
if _, err := client.Logical().Write("secret/bar", data); err != nil {
t.Fatal(err)
}
if _, err := client.Logical().Write("secret/foo", data); err != nil {
t.Fatal(err)
}
cases := []struct {
name string
client *api.Client
path string
exp []string
}{
{
"bad_path",
client,
"nope/not/a/real/path/ever",
nil,
},
{
"good_path",
client,
"secret/",
[]string{"bar", "foo"},
},
{
"not_connected_client",
badClient,
"secret/",
nil,
},
}
t.Run("group", func(t *testing.T) {
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
p := NewPredict()
p.client = tc.client
act := p.listPaths(tc.path)
if !reflect.DeepEqual(act, tc.exp) {
t.Errorf("expected %q to be %q", act, tc.exp)
}
})
}
})
}
func TestPredict_HasPathArg(t *testing.T) {
t.Parallel()
cases := []struct {
name string
args []string
exp bool
}{
{
"nil",
nil,
false,
},
{
"empty",
[]string{},
false,
},
{
"empty_string",
[]string{""},
false,
},
{
"single",
[]string{"foo"},
false,
},
{
"multiple",
[]string{"foo", "bar", "baz"},
true,
},
}
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
p := NewPredict()
if act := p.hasPathArg(tc.args); act != tc.exp {
t.Errorf("expected %t to be %t", act, tc.exp)
}
})
}
}