From ff8f1be0a15998f2eed40cacdb0431f553029bfd Mon Sep 17 00:00:00 2001 From: Michael Li Date: Tue, 20 Dec 2022 13:53:59 -0500 Subject: [PATCH] test(e2e): Add test for when an incorrect tag is used in a dynamic host catalog (#2731) * refact(e2e): Move Dynamic Host Catalog env to its own file This keeps each scenario consistent (an env_test.go file in each directory) * refact(e2e): Update to use type casting * refact(e2e): Rename existing dynamic host catalog test * test(e2e): Add test for an empty dynamic host catalog This test verifies that you fail to connect to a target with an empty host set (in a dynamic host catalog) * fix(e2e): Update return statement since we know err is nil * fix(e2e): Add ok checks in type assertions --- testing/internal/e2e/boundary/boundary.go | 2 +- .../dynamichostcatalog_host_set_empty_test.go | 116 ++++++++++++++++++ ...go => dynamichostcatalog_host_set_test.go} | 27 +--- testing/internal/e2e/tests/aws/env_test.go | 25 ++++ .../e2e/tests/database/migration_test.go | 3 +- .../tests/static/connect_authz_token_test.go | 7 +- .../e2e/tests/static/connect_ssh_test.go | 8 +- .../e2e/tests/static/credential_store_test.go | 12 +- .../connect_authz_token_test.go | 6 +- .../static_with_vault/connect_ssh_test.go | 7 +- .../tests/static_with_vault/connect_test.go | 6 +- .../credential_store_test.go | 19 +-- testing/internal/e2e/vault/vault.go | 2 +- 13 files changed, 189 insertions(+), 51 deletions(-) create mode 100644 testing/internal/e2e/tests/aws/dynamichostcatalog_host_set_empty_test.go rename testing/internal/e2e/tests/aws/{dynamichostcatalog_test.go => dynamichostcatalog_host_set_test.go} (87%) create mode 100644 testing/internal/e2e/tests/aws/env_test.go diff --git a/testing/internal/e2e/boundary/boundary.go b/testing/internal/e2e/boundary/boundary.go index 48029abb7e..b697669be3 100644 --- a/testing/internal/e2e/boundary/boundary.go +++ b/testing/internal/e2e/boundary/boundary.go @@ -51,7 +51,7 @@ func loadConfig() (*config, error) { return nil, err } - return &c, err + return &c, nil } // NewApiClient creates a new Api client for the specified Boundary instance and diff --git a/testing/internal/e2e/tests/aws/dynamichostcatalog_host_set_empty_test.go b/testing/internal/e2e/tests/aws/dynamichostcatalog_host_set_empty_test.go new file mode 100644 index 0000000000..0709fc1ece --- /dev/null +++ b/testing/internal/e2e/tests/aws/dynamichostcatalog_host_set_empty_test.go @@ -0,0 +1,116 @@ +package aws_test + +import ( + "context" + "encoding/json" + "fmt" + "testing" + "time" + + "github.com/hashicorp/boundary/api/hostcatalogs" + "github.com/hashicorp/boundary/api/hostsets" + "github.com/hashicorp/boundary/testing/internal/e2e" + "github.com/hashicorp/boundary/testing/internal/e2e/boundary" + "github.com/stretchr/testify/require" +) + +// TestCliCreateAwsDynamicHostCatalogWithEmptyHostSet uses the boundary cli to create a host catalog with the AWS +// plugin. The test sets up an AWS dynamic host catalog, creates some host sets, sets up a target to +// one of the host sets, and attempts to connect to the target. +func TestCliCreateAwsDynamicHostCatalogWithEmptyHostSet(t *testing.T) { + e2e.MaybeSkipTest(t) + c, err := loadConfig() + require.NoError(t, err) + + ctx := context.Background() + boundary.AuthenticateAdminCli(t, ctx) + newOrgId := boundary.CreateNewOrgCli(t, ctx) + t.Cleanup(func() { + ctx := context.Background() + boundary.AuthenticateAdminCli(t, ctx) + output := e2e.RunCommand(ctx, "boundary", e2e.WithArgs("scopes", "delete", "-id", newOrgId)) + require.NoError(t, output.Err, string(output.Stderr)) + }) + newProjectId := boundary.CreateNewProjectCli(t, ctx, newOrgId) + newHostCatalogId := boundary.CreateNewAwsHostCatalogCli(t, ctx, newProjectId, c.AwsAccessKeyId, c.AwsSecretAccessKey) + + // Set up a host set + newHostSetId := boundary.CreateNewAwsHostSetCli(t, ctx, newHostCatalogId, "tag:empty_test=true") + + // Check that there are no hosts in the host set + t.Logf("Looking for items in the host set...") + var actualHostSetCount int + for i := 1; i <= 3; i++ { + if i != 1 { + time.Sleep(3 * time.Second) + } + + output := e2e.RunCommand(ctx, "boundary", + e2e.WithArgs( + "host-sets", "read", + "-id", newHostSetId, + "-format", "json", + ), + ) + require.NoError(t, output.Err, string(output.Stderr)) + var hostSetsReadResult hostsets.HostSetReadResult + err := json.Unmarshal(output.Stdout, &hostSetsReadResult) + require.NoError(t, err) + + actualHostSetCount = len(hostSetsReadResult.Item.HostIds) + require.Equal(t, actualHostSetCount, 0, + fmt.Sprintf("Detected incorrect number of hosts. Expected: 0, Actual: %d", actualHostSetCount), + ) + } + t.Log("Successfully detected zero hosts in the host set") + + // Check that there are no hosts in the host catalog + t.Logf("Looking for items in the host catalog...") + var actualHostCatalogCount int + for i := 1; i <= 3; i++ { + if i != 1 { + time.Sleep(3 * time.Second) + } + + output := e2e.RunCommand(ctx, "boundary", + e2e.WithArgs("hosts", "list", "-host-catalog-id", newHostCatalogId, "-format", "json"), + ) + require.NoError(t, output.Err, string(output.Stderr)) + var hostCatalogListResult hostcatalogs.HostCatalogListResult + err := json.Unmarshal(output.Stdout, &hostCatalogListResult) + require.NoError(t, err) + + actualHostCatalogCount = len(hostCatalogListResult.Items) + require.Equal(t, actualHostCatalogCount, 0, + fmt.Sprintf("Detected incorrect number of hosts. Expected: 0, Actual: %d", actualHostCatalogCount), + ) + } + t.Log("Successfully detected zero hosts in the host catalog") + + // Create target + newTargetId := boundary.CreateNewTargetCli(t, ctx, newProjectId, c.TargetPort) + boundary.AddHostSourceToTargetCli(t, ctx, newTargetId, newHostSetId) + + // Attempt to connect to target + output := e2e.RunCommand(ctx, "boundary", + e2e.WithArgs( + "connect", + "-target-id", newTargetId, + "-format", "json", + "-exec", "/usr/bin/ssh", "--", + "-l", c.TargetSshUser, + "-i", c.TargetSshKeyPath, + "-o", "UserKnownHostsFile=/dev/null", + "-o", "StrictHostKeyChecking=no", + "-o", "IdentitiesOnly=yes", // forces the use of the provided key + "-p", "{{boundary.port}}", // this is provided by boundary + "{{boundary.ip}}", + "hostname", "-i", + ), + ) + var response boundary.CliError + err = json.Unmarshal(output.Stderr, &response) + require.NoError(t, err) + require.Equal(t, response.Status, 404, "Expected to error when connecting to a target with zero hosts") + t.Log("Successfully failed to connect to target") +} diff --git a/testing/internal/e2e/tests/aws/dynamichostcatalog_test.go b/testing/internal/e2e/tests/aws/dynamichostcatalog_host_set_test.go similarity index 87% rename from testing/internal/e2e/tests/aws/dynamichostcatalog_test.go rename to testing/internal/e2e/tests/aws/dynamichostcatalog_host_set_test.go index 9ee2d91655..7f16c46e18 100644 --- a/testing/internal/e2e/tests/aws/dynamichostcatalog_test.go +++ b/testing/internal/e2e/tests/aws/dynamichostcatalog_host_set_test.go @@ -16,37 +16,14 @@ import ( "github.com/hashicorp/boundary/api/scopes" "github.com/hashicorp/boundary/testing/internal/e2e" "github.com/hashicorp/boundary/testing/internal/e2e/boundary" - "github.com/kelseyhightower/envconfig" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -type config struct { - AwsAccessKeyId string `envconfig:"E2E_AWS_ACCESS_KEY_ID" required:"true"` - AwsSecretAccessKey string `envconfig:"E2E_AWS_SECRET_ACCESS_KEY" required:"true"` - AwsHostSetFilter1 string `envconfig:"E2E_AWS_HOST_SET_FILTER" required:"true"` // e.g. "tag:testtag=true" - AwsHostSetIps1 string `envconfig:"E2E_AWS_HOST_SET_IPS" required:"true"` // e.g. "[\"1.2.3.4\", \"2.3.4.5\"]" - AwsHostSetFilter2 string `envconfig:"E2E_AWS_HOST_SET_FILTER2" required:"true"` // e.g. "tag:testtagtwo=test" - AwsHostSetIps2 string `envconfig:"E2E_AWS_HOST_SET_IPS2" required:"true"` // e.g. "[\"1.2.3.4\"]" - TargetSshKeyPath string `envconfig:"E2E_SSH_KEY_PATH" required:"true"` // e.g. "/Users/username/key.pem" - TargetSshUser string `envconfig:"E2E_SSH_USER" required:"true"` // e.g. "ubuntu" - TargetPort string `envconfig:"E2E_SSH_PORT" default:"22"` -} - -func loadConfig() (*config, error) { - var c config - err := envconfig.Process("", &c) - if err != nil { - return nil, err - } - - return &c, err -} - -// TestCliCreateAwsDynamicHostCatalog uses the boundary cli to create a host catalog with the AWS +// TestCliCreateAwsDynamicHostCatalogWithHostSet uses the boundary cli to create a host catalog with the AWS // plugin. The test sets up an AWS dynamic host catalog, creates some host sets, sets up a target to // one of the host sets, and attempts to connect to the target. -func TestCliCreateAwsDynamicHostCatalog(t *testing.T) { +func TestCliCreateAwsDynamicHostCatalogWithHostSet(t *testing.T) { e2e.MaybeSkipTest(t) c, err := loadConfig() require.NoError(t, err) diff --git a/testing/internal/e2e/tests/aws/env_test.go b/testing/internal/e2e/tests/aws/env_test.go new file mode 100644 index 0000000000..9f1e0987e5 --- /dev/null +++ b/testing/internal/e2e/tests/aws/env_test.go @@ -0,0 +1,25 @@ +package aws_test + +import "github.com/kelseyhightower/envconfig" + +type config struct { + AwsAccessKeyId string `envconfig:"E2E_AWS_ACCESS_KEY_ID" required:"true"` + AwsSecretAccessKey string `envconfig:"E2E_AWS_SECRET_ACCESS_KEY" required:"true"` + AwsHostSetFilter1 string `envconfig:"E2E_AWS_HOST_SET_FILTER" required:"true"` // e.g. "tag:testtag=true" + AwsHostSetIps1 string `envconfig:"E2E_AWS_HOST_SET_IPS" required:"true"` // e.g. "[\"1.2.3.4\", \"2.3.4.5\"]" + AwsHostSetFilter2 string `envconfig:"E2E_AWS_HOST_SET_FILTER2" required:"true"` // e.g. "tag:testtagtwo=test" + AwsHostSetIps2 string `envconfig:"E2E_AWS_HOST_SET_IPS2" required:"true"` // e.g. "[\"1.2.3.4\"]" + TargetSshKeyPath string `envconfig:"E2E_SSH_KEY_PATH" required:"true"` // e.g. "/Users/username/key.pem" + TargetSshUser string `envconfig:"E2E_SSH_USER" required:"true"` // e.g. "ubuntu" + TargetPort string `envconfig:"E2E_SSH_PORT" default:"22"` +} + +func loadConfig() (*config, error) { + var c config + err := envconfig.Process("", &c) + if err != nil { + return nil, err + } + + return &c, nil +} diff --git a/testing/internal/e2e/tests/database/migration_test.go b/testing/internal/e2e/tests/database/migration_test.go index 1d0c56e133..d9b9c42561 100644 --- a/testing/internal/e2e/tests/database/migration_test.go +++ b/testing/internal/e2e/tests/database/migration_test.go @@ -273,7 +273,8 @@ func populateBoundaryDatabase(t testing.TB, ctx context.Context, c *config, te T var authenticationResult boundary.AuthenticateCliOutput err = json.Unmarshal(buf.Bytes(), &authenticationResult) require.NoError(t, err) - auth_token := authenticationResult.Item.Attributes["token"].(string) + auth_token, ok := authenticationResult.Item.Attributes["token"].(string) + require.True(t, ok) connectTarget := infra.ConnectToTarget(t, te.Pool, te.Network, te.Boundary.UriNetwork, auth_token, newTargetId) t.Cleanup(func() { diff --git a/testing/internal/e2e/tests/static/connect_authz_token_test.go b/testing/internal/e2e/tests/static/connect_authz_token_test.go index 571d3f65a3..780e33e100 100644 --- a/testing/internal/e2e/tests/static/connect_authz_token_test.go +++ b/testing/internal/e2e/tests/static/connect_authz_token_test.go @@ -52,8 +52,11 @@ func TestCliConnectTargetWithAuthzToken(t *testing.T) { require.NoError(t, err) newSessionAuthorization := newSessionAuthorizationResult.Item - retrievedUser := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["username"]) - retrievedKey := fmt.Sprintf("%s\n", newSessionAuthorization.Credentials[0].Credential["private_key"]) + retrievedUser, ok := newSessionAuthorization.Credentials[0].Credential["username"].(string) + require.True(t, ok) + retrievedKey, ok := newSessionAuthorization.Credentials[0].Credential["private_key"].(string) + require.True(t, ok) + retrievedKey += "\n" assert.Equal(t, c.TargetSshUser, retrievedUser) k, err := os.ReadFile(c.TargetSshKeyPath) diff --git a/testing/internal/e2e/tests/static/connect_ssh_test.go b/testing/internal/e2e/tests/static/connect_ssh_test.go index ee35d5ce50..7fc56240d2 100644 --- a/testing/internal/e2e/tests/static/connect_ssh_test.go +++ b/testing/internal/e2e/tests/static/connect_ssh_test.go @@ -3,7 +3,6 @@ package static_test import ( "context" "encoding/json" - "fmt" "os" "testing" @@ -52,8 +51,11 @@ func TestCliConnectTargetWithSsh(t *testing.T) { require.NoError(t, err) newSessionAuthorization := newSessionAuthorizationResult.Item - retrievedUser := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["username"]) - retrievedKey := fmt.Sprintf("%s\n", newSessionAuthorization.Credentials[0].Credential["private_key"]) + retrievedUser, ok := newSessionAuthorization.Credentials[0].Credential["username"].(string) + require.True(t, ok) + retrievedKey, ok := newSessionAuthorization.Credentials[0].Credential["private_key"].(string) + require.True(t, ok) + retrievedKey += "\n" assert.Equal(t, c.TargetSshUser, retrievedUser) k, err := os.ReadFile(c.TargetSshKeyPath) diff --git a/testing/internal/e2e/tests/static/credential_store_test.go b/testing/internal/e2e/tests/static/credential_store_test.go index 0bb5d015d9..11a39e32d2 100644 --- a/testing/internal/e2e/tests/static/credential_store_test.go +++ b/testing/internal/e2e/tests/static/credential_store_test.go @@ -65,8 +65,10 @@ func TestCliStaticCredentialStore(t *testing.T) { require.NoError(t, err) newSessionAuthorization := newSessionAuthorizationResult.Item - retrievedUser := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["username"]) - retrievedPassword := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["password"]) + retrievedUser, ok := newSessionAuthorization.Credentials[0].Credential["username"].(string) + require.True(t, ok) + retrievedPassword, ok := newSessionAuthorization.Credentials[0].Credential["password"].(string) + require.True(t, ok) assert.Equal(t, c.TargetSshUser, retrievedUser) assert.Equal(t, "password", retrievedPassword) @@ -156,8 +158,10 @@ func TestApiStaticCredentialStore(t *testing.T) { newSessionAuthorizationResult, err := tClient.AuthorizeSession(ctx, newTargetId) require.NoError(t, err) newSessionAuthorization := newSessionAuthorizationResult.Item - retrievedUser := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["username"]) - retrievedKey := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["private_key"]) + retrievedUser, ok := newSessionAuthorization.Credentials[0].Credential["username"].(string) + require.True(t, ok) + retrievedKey, ok := newSessionAuthorization.Credentials[0].Credential["private_key"].(string) + require.True(t, ok) assert.Equal(t, c.TargetSshUser, retrievedUser) require.Equal(t, string(k), retrievedKey) t.Log("Successfully retrieved credentials for target") diff --git a/testing/internal/e2e/tests/static_with_vault/connect_authz_token_test.go b/testing/internal/e2e/tests/static_with_vault/connect_authz_token_test.go index a9f2bcde43..78edc3712e 100644 --- a/testing/internal/e2e/tests/static_with_vault/connect_authz_token_test.go +++ b/testing/internal/e2e/tests/static_with_vault/connect_authz_token_test.go @@ -126,8 +126,10 @@ func TestCliVaultConnectTargetWithAuthzToken(t *testing.T) { require.NoError(t, err) newSessionAuthorization := newSessionAuthorizationResult.Item - retrievedUser := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["username"]) - retrievedKey := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["private_key"]) + retrievedUser, ok := newSessionAuthorization.Credentials[0].Credential["username"].(string) + require.True(t, ok) + retrievedKey, ok := newSessionAuthorization.Credentials[0].Credential["private_key"].(string) + require.True(t, ok) assert.Equal(t, c.TargetSshUser, retrievedUser) k, err := os.ReadFile(c.TargetSshKeyPath) diff --git a/testing/internal/e2e/tests/static_with_vault/connect_ssh_test.go b/testing/internal/e2e/tests/static_with_vault/connect_ssh_test.go index 3d629b2d3b..266e5a4118 100644 --- a/testing/internal/e2e/tests/static_with_vault/connect_ssh_test.go +++ b/testing/internal/e2e/tests/static_with_vault/connect_ssh_test.go @@ -3,7 +3,6 @@ package static_with_vault_test import ( "context" "encoding/json" - "fmt" "os" "testing" @@ -127,8 +126,10 @@ func TestCliVaultConnectTargetWithSsh(t *testing.T) { require.NoError(t, err) newSessionAuthorization := newSessionAuthorizationResult.Item - retrievedUser := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["username"]) - retrievedKey := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["private_key"]) + retrievedUser, ok := newSessionAuthorization.Credentials[0].Credential["username"].(string) + require.True(t, ok) + retrievedKey, ok := newSessionAuthorization.Credentials[0].Credential["private_key"].(string) + require.True(t, ok) assert.Equal(t, c.TargetSshUser, retrievedUser) k, err := os.ReadFile(c.TargetSshKeyPath) diff --git a/testing/internal/e2e/tests/static_with_vault/connect_test.go b/testing/internal/e2e/tests/static_with_vault/connect_test.go index 1c55047317..060ad0fd40 100644 --- a/testing/internal/e2e/tests/static_with_vault/connect_test.go +++ b/testing/internal/e2e/tests/static_with_vault/connect_test.go @@ -128,8 +128,10 @@ func TestCliVaultConnectTarget(t *testing.T) { require.NoError(t, err) newSessionAuthorization := newSessionAuthorizationResult.Item - retrievedUser := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["username"]) - retrievedKey := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["private_key"]) + retrievedUser, ok := newSessionAuthorization.Credentials[0].Credential["username"].(string) + require.True(t, ok) + retrievedKey, ok := newSessionAuthorization.Credentials[0].Credential["private_key"].(string) + require.True(t, ok) assert.Equal(t, c.TargetSshUser, retrievedUser) k, err := os.ReadFile(c.TargetSshKeyPath) diff --git a/testing/internal/e2e/tests/static_with_vault/credential_store_test.go b/testing/internal/e2e/tests/static_with_vault/credential_store_test.go index 0f1b3d3e9c..339c7eb688 100644 --- a/testing/internal/e2e/tests/static_with_vault/credential_store_test.go +++ b/testing/internal/e2e/tests/static_with_vault/credential_store_test.go @@ -3,7 +3,6 @@ package static_with_vault_test import ( "context" "encoding/json" - "fmt" "os" "testing" @@ -159,8 +158,10 @@ func TestCliVaultCredentialStore(t *testing.T) { for _, v := range newSessionAuthorization.Credentials { if v.CredentialSource.CredentialType == "ssh_private_key" { - retrievedUser := v.Credential["username"].(string) - retrievedKey := v.Credential["private_key"].(string) + retrievedUser, ok := v.Credential["username"].(string) + require.True(t, ok) + retrievedKey, ok := v.Credential["private_key"].(string) + require.True(t, ok) assert.Equal(t, c.TargetSshUser, retrievedUser) keyData, err := os.ReadFile(c.TargetSshKeyPath) @@ -168,8 +169,10 @@ func TestCliVaultCredentialStore(t *testing.T) { require.Equal(t, string(keyData), retrievedKey) t.Log("Successfully retrieved private key credentials for target") } else if v.CredentialSource.CredentialType == "username_password" { - retrievedUser := v.Credential["username"].(string) - retrievedPassword := v.Credential["password"].(string) + retrievedUser, ok := v.Credential["username"].(string) + require.True(t, ok) + retrievedPassword, ok := v.Credential["password"].(string) + require.True(t, ok) assert.Equal(t, c.TargetSshUser, retrievedUser) assert.Equal(t, password, retrievedPassword) t.Log("Successfully retrieved password credentials for target") @@ -305,8 +308,10 @@ func TestApiVaultCredentialStore(t *testing.T) { require.True(t, keysMatch, "Key retrieved from vault does not match expected value") t.Log("Successfully retrieved credentials for target") } else if v.CredentialSource.CredentialType == "username_password" { - retrievedUser := fmt.Sprintf("%s", v.Credential["username"]) - retrievedPassword := fmt.Sprintf("%s", v.Credential["password"]) + retrievedUser, ok := v.Credential["username"].(string) + require.True(t, ok) + retrievedPassword, ok := v.Credential["password"].(string) + require.True(t, ok) assert.Equal(t, c.TargetSshUser, retrievedUser) assert.Equal(t, password, retrievedPassword) t.Log("Successfully retrieved password credentials for target") diff --git a/testing/internal/e2e/vault/vault.go b/testing/internal/e2e/vault/vault.go index 971cfa9bb4..b9c8db15c7 100644 --- a/testing/internal/e2e/vault/vault.go +++ b/testing/internal/e2e/vault/vault.go @@ -33,7 +33,7 @@ func loadConfig() (*config, error) { return nil, err } - return &c, err + return &c, nil } // Setup verifies if appropriate credentials are set and adds the boundary controller