From e6a7f8e32176650faf9adfb93e2847ba1cb71ea8 Mon Sep 17 00:00:00 2001 From: Jakub Michalak Date: Thu, 7 Nov 2024 13:41:27 +0100 Subject: [PATCH 1/3] Test more authentication methods --- MIGRATION_GUIDE.md | 2 +- .../testenvs/testing_environment_variables.go | 1 + .../testprofiles/testing_config_profiles.go | 1 + pkg/provider/manual_tests/README.md | 53 +++++++++ pkg/provider/manual_tests/auth_test.go | 102 ++++++++++++++++ pkg/provider/provider.go | 6 +- pkg/provider/provider_acceptance_test.go | 109 +++++++++++++++++- pkg/provider/provider_helpers.go | 42 ------- pkg/resources/view.go | 4 +- pkg/sdk/client.go | 1 + pkg/sdk/config.go | 42 +++++++ pkg/sdk/internal/client/client_test.go | 1 + 12 files changed, 314 insertions(+), 50 deletions(-) create mode 100644 pkg/provider/manual_tests/README.md create mode 100644 pkg/provider/manual_tests/auth_test.go diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 5a79d9cc50..2e6102354d 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -56,7 +56,7 @@ We have added new fields to match the ones in [the driver](https://pkg.go.dev/gi To be more consistent with other configuration options, we have decided to add `driver_tracing` to the configuration schema. This value can also be configured by `SNOWFLAKE_DRIVER_TRACING` environmental variable and by `drivertracing` field in the TOML file. The previous `SF_TF_GOSNOWFLAKE_LOG_LEVEL` environmental variable is not supported now, and was removed from the provider. #### *(behavior change)* deprecated fields -Because of new fields `account_name` and `organization_name`, `account` is now deprecated. It will be removed before v1. Please adjust your configurations from +Because of new fields `account_name` and `organization_name`, `account` is now deprecated. It will be removed with the v1 release. Please adjust your configurations from ```terraform provider "snowflake" { account = "ORGANIZATION-ACCOUNT" diff --git a/pkg/acceptance/testenvs/testing_environment_variables.go b/pkg/acceptance/testenvs/testing_environment_variables.go index 7b6e22a50b..997d8cd8a8 100644 --- a/pkg/acceptance/testenvs/testing_environment_variables.go +++ b/pkg/acceptance/testenvs/testing_environment_variables.go @@ -32,6 +32,7 @@ const ( EnableAcceptance env = resource.EnvTfAcc EnableSweep env = "TEST_SF_TF_ENABLE_SWEEP" + EnableManual env = "TEST_SF_TF_ENABLE_MANUAL_TESTS" ConfigureClientOnce env = "SF_TF_ACC_TEST_CONFIGURE_CLIENT_ONCE" TestObjectsSuffix env = "TEST_SF_TF_TEST_OBJECT_SUFFIX" RequireTestObjectsSuffix env = "TEST_SF_TF_REQUIRE_TEST_OBJECT_SUFFIX" diff --git a/pkg/acceptance/testprofiles/testing_config_profiles.go b/pkg/acceptance/testprofiles/testing_config_profiles.go index 82770d7381..23ff0fb9c2 100644 --- a/pkg/acceptance/testprofiles/testing_config_profiles.go +++ b/pkg/acceptance/testprofiles/testing_config_profiles.go @@ -8,4 +8,5 @@ const ( IncorrectUserAndPassword = "incorrect_test_profile" CompleteFields = "complete_fields" CompleteFieldsInvalid = "complete_fields_invalid" + DefaultWithPasscode = "default_with_passcode" ) diff --git a/pkg/provider/manual_tests/README.md b/pkg/provider/manual_tests/README.md new file mode 100644 index 0000000000..853dd16ba7 --- /dev/null +++ b/pkg/provider/manual_tests/README.md @@ -0,0 +1,53 @@ +# Manual tests + +This directory is dedicated to hold steps for manual provider tests that are not possible to re-recreate in automated tests (or very hard to set up). These tests are disabled by default and require `TEST_SF_TF_ENABLE_MANUAL_TESTS` environmental variable to be set. + +## Okta authenticator test +This test checks `Okta` authenticator option. It requires manual steps because of additional setup on Okta side. It assumes that `default` profile uses a standard values of account name, user, password, etc. +1. Set up a developer Okta account [here](https://developer.okta.com/signup/). +1. Go to admin panel and select Applications -> Create App Integration. +1. Create a new application with SAML 2.0 type and give it a unique name +1. Fill SAML settings - paste the URLs for the testing accounts, like `https://example.snowflakecomputing.com/fed/login` for Single sign on URL, Recipient URL, Destination URL and Audience URI (SP Entity ID) +1. Click Next and Finish +1. After the app gets created, click View SAML setup instructions +1. Save the values provided: IDP SSO URL, IDP Issuer, and X509 certificate +1. Create a new security integration in Snowflake: +``` +CREATE SECURITY INTEGRATION MyIDP +TYPE=SAML2 +ENABLED=true +SAML2_ISSUER='http://www.okta.com/example' +SAML2_SSO_URL='https://dev-123456.oktapreview.com/app/dev-123456_test_1/example/sso/saml' +SAML2_PROVIDER='OKTA' +SAML2_SP_INITIATED_LOGIN_PAGE_LABEL='myidp - okta' +SAML2_ENABLE_SP_INITIATED=false +SAML2_X509_CERT=''; +``` +1. Note that Snowflake and Okta login name must match, otherwise create a temporary user with a login name matching the one in Okta. +1. Prepare a TOML config like: +``` +[okta] +organizationname='ORGANIZATION_NAME' +accountname='ACCOUNT_NAME' +user='LOGIN_NAME' # This is a value used to login in Okta +password='PASSWORD' # This is a password in Okta +oktaurl='https://dev-123456.okta.com' # URL of your Okta environment +``` +1. Run the tests - you should be able to authenticate with Okta. + + +## UsernamePasswordMFA authenticator test +This test checks `UsernamePasswordMFA` authenticator option. It requires manual steps because of additional verification via MFA device. It assumes that `default` profile uses a standard values of account name, user, password, etc. +1. Make sure the user you're testing with has enabled MFA (see [docs](https://docs.snowflake.com/en/user-guide/ui-snowsight-profile#enroll-in-multi-factor-authentication-mfa)) and an MFA bypass is not set (check `mins_to_bypass_mfa` in `SHOW USERS` output for the given user). +1. After running the test, you should get pinged 3 times in MFA app: + - The first two notifiactions are just test setups, also present in other acceptance tests. + - The third notification verifies that MFA is used for the first test step. + - For the second test step we are caching MFA token, so there is not any notification. + +## UsernamePasswordMFA authenticator with passcode test +This test checks `UsernamePasswordMFA` authenticator option with using `passcode`. It requires manual steps because of additional verification via MFA device. It assumes that `default_with_passcode` profile uses a standard values of account name, user, password, etc. with `passcode` set to a value in your MFA app. +1. Make sure the user you're testing with has enabled MFA (see [docs](https://docs.snowflake.com/en/user-guide/ui-snowsight-profile#enroll-in-multi-factor-authentication-mfa)) and an MFA bypass is not set (check `mins_to_bypass_mfa` in `SHOW USERS` output for the given user). +1. After running the test, you should get pinged 2 times in MFA app: + - The first two notifiactions are just test setups, also present in other acceptance tests. + - The first step asks for permition to access your device keychain. + - For the second test step we are caching MFA token, so there is not any notification. diff --git a/pkg/provider/manual_tests/auth_test.go b/pkg/provider/manual_tests/auth_test.go new file mode 100644 index 0000000000..1e8fbef848 --- /dev/null +++ b/pkg/provider/manual_tests/auth_test.go @@ -0,0 +1,102 @@ +package manual + +import ( + "fmt" + "testing" + + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testenvs" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testprofiles" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/snowflakeenvs" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/tfversion" +) + +// This is a manual test for authenticating with Okta. +func TestAcc_Provider_OktaAuth(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableManual) + t.Setenv(string(testenvs.ConfigureClientOnce), "") + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { + acc.TestAccPreCheck(t) + testenvs.AssertEnvNotSet(t, snowflakeenvs.User) + testenvs.AssertEnvNotSet(t, snowflakeenvs.Password) + }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + Steps: []resource.TestStep{ + { + Config: providerConfigWithAuthenticator("okta", sdk.AuthenticationTypeOkta), + }, + }, + }) +} + +// This test requires manual action due to MFA. Make sure the user does not have a positive `mins_to_bypass_mfa` in `SHOW USERS`. +func TestAcc_Provider_UsernamePasswordMfaAuth(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableManual) + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { + acc.TestAccPreCheck(t) + }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + Steps: []resource.TestStep{ + // ensure MFA is checked here - accept login on your MFA device + { + Config: providerConfigWithAuthenticator(testprofiles.Default, sdk.AuthenticationTypeUsernamePasswordMfa), + }, + // check that MFA login is cached - this step should not require manual action + { + Config: providerConfigWithAuthenticator(testprofiles.Default, sdk.AuthenticationTypeUsernamePasswordMfa), + }, + }, + }) +} + +// This test requires manual action due to MFA. Make sure the user does not have a positive `mins_to_bypass_mfa` in `SHOW USERS`. +func TestAcc_Provider_UsernamePasswordMfaAuthWithPasscode(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableManual) + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { + acc.TestAccPreCheck(t) + }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + Steps: []resource.TestStep{ + // ensure MFA is checked here - accept access to keychain on your device + { + Config: providerConfigWithAuthenticator(testprofiles.DefaultWithPasscode, sdk.AuthenticationTypeUsernamePasswordMfa), + }, + // check that MFA login is cached - this step should not require manual action + { + Config: providerConfigWithAuthenticator(testprofiles.DefaultWithPasscode, sdk.AuthenticationTypeUsernamePasswordMfa), + }, + }, + }) +} + +func providerConfigWithAuthenticator(profile string, authenticator sdk.AuthenticationType) string { + return fmt.Sprintf(` +provider "snowflake" { + profile = "%[1]s" + authenticator = "%[2]s" +} +`, profile, authenticator) + datasourceConfig() +} + +func datasourceConfig() string { + return ` +data snowflake_database "t" { + name = "SNOWFLAKE" +}` +} diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index 725879873a..595d9aaeb4 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -330,10 +330,10 @@ func Provider() *schema.Provider { }, "driver_tracing": { Type: schema.TypeString, - Description: envNameFieldDescription(fmt.Sprintf("Specifies the logging level to be used by the driver. Valid options are: %v.", docs.PossibleValuesListed(allDriverLogLevels)), snowflakeenvs.DriverTracing), + Description: envNameFieldDescription(fmt.Sprintf("Specifies the logging level to be used by the driver. Valid options are: %v.", docs.PossibleValuesListed(sdk.AllDriverLogLevels)), snowflakeenvs.DriverTracing), Optional: true, DefaultFunc: schema.EnvDefaultFunc(snowflakeenvs.DriverTracing, nil), - ValidateDiagFunc: validators.NormalizeValidation(toDriverLogLevel), + ValidateDiagFunc: validators.NormalizeValidation(sdk.ToDriverLogLevel), }, "tmp_directory_path": { Type: schema.TypeString, @@ -780,7 +780,7 @@ func getDriverConfigFromTerraform(s *schema.ResourceData) (*gosnowflake.Config, // driver tracing func() error { if v, ok := s.GetOk("driver_tracing"); ok { - driverLogLevel, err := toDriverLogLevel(v.(string)) + driverLogLevel, err := sdk.ToDriverLogLevel(v.(string)) if err != nil { return err } diff --git a/pkg/provider/provider_acceptance_test.go b/pkg/provider/provider_acceptance_test.go index 61650a0b97..97e45b0734 100644 --- a/pkg/provider/provider_acceptance_test.go +++ b/pkg/provider/provider_acceptance_test.go @@ -543,6 +543,84 @@ func TestAcc_Provider_triValueBoolean(t *testing.T) { }) } +func TestAcc_Provider_sessionParameters(t *testing.T) { + t.Setenv(string(testenvs.ConfigureClientOnce), "") + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { + acc.TestAccPreCheck(t) + testenvs.AssertEnvNotSet(t, snowflakeenvs.User) + testenvs.AssertEnvNotSet(t, snowflakeenvs.Password) + }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + Steps: []resource.TestStep{ + { + Config: providerWithParamsConfig(testprofiles.Default, 31337), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("snowflake_unsafe_execute.t", "query_results.#", "1"), + resource.TestCheckResourceAttr("snowflake_unsafe_execute.t", "query_results.0.value", "31337"), + ), + }, + }, + }) +} + +func TestAcc_Provider_JwtAuth(t *testing.T) { + // TODO(SNOW-1752038): unskip + t.Skip("Skip because this test needs a TOML config incompatible with older versions, causing tests with ExternalProvider to fail.") + + t.Setenv(string(testenvs.ConfigureClientOnce), "") + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { + acc.TestAccPreCheck(t) + testenvs.AssertEnvNotSet(t, snowflakeenvs.User) + testenvs.AssertEnvNotSet(t, snowflakeenvs.Password) + }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + Steps: []resource.TestStep{ + // authenticate with unencrypted private key + { + Config: providerConfigWithAuthenticator("jwt_test", sdk.AuthenticationTypeJwt), + }, + // authenticate with unencrypted private key with a legacy authenticator value + // solves https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2983 + { + Config: providerConfigWithAuthenticator("jwt_test", sdk.AuthenticationTypeJwtLegacy), + }, + // authenticate with encrypted private key + { + Config: providerConfigWithAuthenticator("jwt_encrypted_test", sdk.AuthenticationTypeJwt), + }, + }, + }) +} + +func TestAcc_Provider_SnowflakeAuth(t *testing.T) { + t.Setenv(string(testenvs.ConfigureClientOnce), "") + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { + acc.TestAccPreCheck(t) + }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + Steps: []resource.TestStep{ + { + Config: providerConfigWithAuthenticator(testprofiles.Default, sdk.AuthenticationTypeSnowflake), + }, + }, + }) +} + func TestAcc_Provider_invalidConfigurations(t *testing.T) { resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, @@ -591,8 +669,14 @@ func TestAcc_Provider_invalidConfigurations(t *testing.T) { }) } -// TODO(SNOW-1754319): for JWT auth flow, check setting authenticator value as `SNOWFLAKE_JWT`. -// This will ensure https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2983 is solved. +func providerConfigWithAuthenticator(profile string, authenticator sdk.AuthenticationType) string { + return fmt.Sprintf(` +provider "snowflake" { + profile = "%[1]s" + authenticator = "%[2]s" +} +`, profile, authenticator) + datasourceConfig() +} func emptyProviderConfig() string { return ` @@ -812,3 +896,24 @@ provider "snowflake" { } `, profile, orgName, accountName, user, password) + datasourceConfig() } + +// TODO(SNOW-1348325): Use parameter data source with `IN SESSION` filtering. +func providerWithParamsConfig(profile string, statementTimeoutInSeconds int) string { + return fmt.Sprintf(` +provider "snowflake" { + profile = "%[1]s" + params = { + statement_timeout_in_seconds = %[2]d + } +} +`, profile, statementTimeoutInSeconds) + unsafeExecuteShowSessionParameter() +} + +func unsafeExecuteShowSessionParameter() string { + return ` +resource snowflake_unsafe_execute "t" { + execute = "SELECT 1" + query = "SHOW PARAMETERS LIKE 'STATEMENT_TIMEOUT_IN_SECONDS' IN SESSION" + revert = "SELECT 1" +}` +} diff --git a/pkg/provider/provider_helpers.go b/pkg/provider/provider_helpers.go index 1f7d9f2c3d..dd6aa9ab92 100644 --- a/pkg/provider/provider_helpers.go +++ b/pkg/provider/provider_helpers.go @@ -44,48 +44,6 @@ func toProtocol(s string) (protocol, error) { } } -type driverLogLevel string - -const ( - // these values are lower case on purpose to match gosnowflake case - logLevelTrace driverLogLevel = "trace" - logLevelDebug driverLogLevel = "debug" - logLevelInfo driverLogLevel = "info" - logLevelPrint driverLogLevel = "print" - logLevelWarning driverLogLevel = "warning" - logLevelError driverLogLevel = "error" - logLevelFatal driverLogLevel = "fatal" - logLevelPanic driverLogLevel = "panic" -) - -var allDriverLogLevels = []driverLogLevel{ - logLevelTrace, - logLevelDebug, - logLevelInfo, - logLevelPrint, - logLevelWarning, - logLevelError, - logLevelFatal, - logLevelPanic, -} - -func toDriverLogLevel(s string) (driverLogLevel, error) { - lowerCase := strings.ToLower(s) - switch lowerCase { - case string(logLevelTrace), - string(logLevelDebug), - string(logLevelInfo), - string(logLevelPrint), - string(logLevelWarning), - string(logLevelError), - string(logLevelFatal), - string(logLevelPanic): - return driverLogLevel(lowerCase), nil - default: - return "", fmt.Errorf("invalid driver log level: %s", s) - } -} - func getPrivateKey(privateKeyPath, privateKeyString, privateKeyPassphrase string) (*rsa.PrivateKey, error) { if privateKeyPath == "" && privateKeyString == "" { return nil, nil diff --git a/pkg/resources/view.go b/pkg/resources/view.go index 7c5b6d680f..9c782a71bf 100644 --- a/pkg/resources/view.go +++ b/pkg/resources/view.go @@ -124,13 +124,13 @@ var viewSchema = map[string]*schema.Schema{ Optional: true, Description: fmt.Sprintf("Specifies an interval (in minutes) of wait time inserted between runs of the data metric function. Conflicts with `using_cron`. Valid values are: %s. Due to Snowflake limitations, changes in this field are not managed by the provider. Please consider using [taint](https://developer.hashicorp.com/terraform/cli/commands/taint) command, `using_cron` field, or [replace_triggered_by](https://developer.hashicorp.com/terraform/language/meta-arguments/lifecycle#replace_triggered_by) metadata argument.", possibleValuesListed(sdk.AllViewDataMetricScheduleMinutes)), ValidateDiagFunc: IntInSlice(sdk.AllViewDataMetricScheduleMinutes), - ConflictsWith: []string{"data_metric_schedule.using_cron"}, + ConflictsWith: []string{"data_metric_schedule.0.using_cron"}, }, "using_cron": { Type: schema.TypeString, Optional: true, Description: "Specifies a cron expression and time zone for periodically running the data metric function. Supports a subset of standard cron utility syntax. Conflicts with `minutes`.", - ConflictsWith: []string{"data_metric_schedule.minutes"}, + ConflictsWith: []string{"data_metric_schedule.0.minutes"}, }, }, }, diff --git a/pkg/sdk/client.go b/pkg/sdk/client.go index 93e82afb37..a0cb338c17 100644 --- a/pkg/sdk/client.go +++ b/pkg/sdk/client.go @@ -21,6 +21,7 @@ var ( func init() { instrumentedSQL = os.Getenv(snowflakeenvs.NoInstrumentedSql) == "" + gosnowflakeLoggingLevel = os.Getenv(snowflakeenvs.DriverTracing) } type Client struct { diff --git a/pkg/sdk/config.go b/pkg/sdk/config.go index 354779b8ba..c4f5ca99b7 100644 --- a/pkg/sdk/config.go +++ b/pkg/sdk/config.go @@ -447,3 +447,45 @@ func ToAuthenticatorType(s string) (gosnowflake.AuthType, error) { return gosnowflake.AuthType(0), fmt.Errorf("invalid authenticator type: %s", s) } } + +type DriverLogLevel string + +const ( + // these values are lower case on purpose to match gosnowflake case + DriverLogLevelTrace DriverLogLevel = "trace" + DriverLogLevelDebug DriverLogLevel = "debug" + DriverLogLevelInfo DriverLogLevel = "info" + DriverLogLevelPrint DriverLogLevel = "print" + DriverLogLevelWarning DriverLogLevel = "warning" + DriverLogLevelError DriverLogLevel = "error" + DriverLogLevelFatal DriverLogLevel = "fatal" + DriverLogLevelPanic DriverLogLevel = "panic" +) + +var AllDriverLogLevels = []DriverLogLevel{ + DriverLogLevelTrace, + DriverLogLevelDebug, + DriverLogLevelInfo, + DriverLogLevelPrint, + DriverLogLevelWarning, + DriverLogLevelError, + DriverLogLevelFatal, + DriverLogLevelPanic, +} + +func ToDriverLogLevel(s string) (DriverLogLevel, error) { + lowerCase := strings.ToLower(s) + switch lowerCase { + case string(DriverLogLevelTrace), + string(DriverLogLevelDebug), + string(DriverLogLevelInfo), + string(DriverLogLevelPrint), + string(DriverLogLevelWarning), + string(DriverLogLevelError), + string(DriverLogLevelFatal), + string(DriverLogLevelPanic): + return DriverLogLevel(lowerCase), nil + default: + return "", fmt.Errorf("invalid driver log level: %s", s) + } +} diff --git a/pkg/sdk/internal/client/client_test.go b/pkg/sdk/internal/client/client_test.go index a95036ff21..c410012a27 100644 --- a/pkg/sdk/internal/client/client_test.go +++ b/pkg/sdk/internal/client/client_test.go @@ -21,6 +21,7 @@ func TestNewClientWithoutInstrumentedSQL(t *testing.T) { t.Run("registers snowflake-not-instrumented driver", func(t *testing.T) { config := sdk.DefaultConfig() + config.Tracing = string(sdk.DriverLogLevelDebug) _, err := sdk.NewClient(config) require.NoError(t, err) From a19504b830744a4c36663c50391c5d702363b12c Mon Sep 17 00:00:00 2001 From: Jakub Michalak Date: Thu, 7 Nov 2024 13:52:21 +0100 Subject: [PATCH 2/3] pre push --- pkg/provider/provider_helpers_test.go | 42 --------------------------- pkg/resources/custom_diffs_test.go | 3 +- pkg/sdk/config_test.go | 42 +++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 43 deletions(-) diff --git a/pkg/provider/provider_helpers_test.go b/pkg/provider/provider_helpers_test.go index c565894a86..64325e2e3f 100644 --- a/pkg/provider/provider_helpers_test.go +++ b/pkg/provider/provider_helpers_test.go @@ -41,45 +41,3 @@ func Test_Provider_toProtocol(t *testing.T) { }) } } - -func Test_Provider_toDriverLogLevel(t *testing.T) { - type test struct { - input string - want driverLogLevel - } - - valid := []test{ - // Case insensitive. - {input: "WARNING", want: logLevelWarning}, - - // Supported Values. - {input: "trace", want: logLevelTrace}, - {input: "debug", want: logLevelDebug}, - {input: "info", want: logLevelInfo}, - {input: "print", want: logLevelPrint}, - {input: "warning", want: logLevelWarning}, - {input: "error", want: logLevelError}, - {input: "fatal", want: logLevelFatal}, - {input: "panic", want: logLevelPanic}, - } - - invalid := []test{ - {input: ""}, - {input: "foo"}, - } - - for _, tc := range valid { - t.Run(tc.input, func(t *testing.T) { - got, err := toDriverLogLevel(tc.input) - require.NoError(t, err) - require.Equal(t, tc.want, got) - }) - } - - for _, tc := range invalid { - t.Run(tc.input, func(t *testing.T) { - _, err := toDriverLogLevel(tc.input) - require.Error(t, err) - }) - } -} diff --git a/pkg/resources/custom_diffs_test.go b/pkg/resources/custom_diffs_test.go index 50949578ff..fc776ce89b 100644 --- a/pkg/resources/custom_diffs_test.go +++ b/pkg/resources/custom_diffs_test.go @@ -2,10 +2,11 @@ package resources_test import ( "context" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "strings" "testing" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" diff --git a/pkg/sdk/config_test.go b/pkg/sdk/config_test.go index dd5b8bd649..8f67022ba0 100644 --- a/pkg/sdk/config_test.go +++ b/pkg/sdk/config_test.go @@ -310,3 +310,45 @@ func Test_toAuthenticationType(t *testing.T) { }) } } + +func Test_Provider_toDriverLogLevel(t *testing.T) { + type test struct { + input string + want DriverLogLevel + } + + valid := []test{ + // Case insensitive. + {input: "WARNING", want: DriverLogLevelWarning}, + + // Supported Values. + {input: "trace", want: DriverLogLevelTrace}, + {input: "debug", want: DriverLogLevelDebug}, + {input: "info", want: DriverLogLevelInfo}, + {input: "print", want: DriverLogLevelPrint}, + {input: "warning", want: DriverLogLevelWarning}, + {input: "error", want: DriverLogLevelError}, + {input: "fatal", want: DriverLogLevelFatal}, + {input: "panic", want: DriverLogLevelPanic}, + } + + invalid := []test{ + {input: ""}, + {input: "foo"}, + } + + for _, tc := range valid { + t.Run(tc.input, func(t *testing.T) { + got, err := ToDriverLogLevel(tc.input) + require.NoError(t, err) + require.Equal(t, tc.want, got) + }) + } + + for _, tc := range invalid { + t.Run(tc.input, func(t *testing.T) { + _, err := ToDriverLogLevel(tc.input) + require.Error(t, err) + }) + } +} From fa78ceea83814eadba0d5a0d155c39b4b66e7d09 Mon Sep 17 00:00:00 2001 From: Jakub Michalak Date: Fri, 8 Nov 2024 10:42:09 +0100 Subject: [PATCH 3/3] Review --- pkg/manual_tests/README.md | 3 ++- .../authentication_methods}/README.md | 24 +++++++++---------- .../authentication_methods}/auth_test.go | 0 pkg/provider/provider_acceptance_test.go | 13 ++++++---- pkg/sdk/client.go | 6 +---- 5 files changed, 23 insertions(+), 23 deletions(-) rename pkg/{provider/manual_tests => manual_tests/authentication_methods}/README.md (77%) rename pkg/{provider/manual_tests => manual_tests/authentication_methods}/auth_test.go (100%) diff --git a/pkg/manual_tests/README.md b/pkg/manual_tests/README.md index 69fc83e54d..64222ee991 100644 --- a/pkg/manual_tests/README.md +++ b/pkg/manual_tests/README.md @@ -5,4 +5,5 @@ Every test should be placed in the subfolder representing a particular test (mos and should contain a file describing the manual steps to perform the test. Here's the list of cases we currently cannot reproduce and write acceptance tests for: -- `user_default_database_and_role`: Setting up a user with default_namespace and default_role, then logging into that user to see what happens with those values in various scenarios (e.g. insufficient privileges on the role). \ No newline at end of file +- `user_default_database_and_role`: Setting up a user with default_namespace and default_role, then logging into that user to see what happens with those values in various scenarios (e.g. insufficient privileges on the role). +- `authentication_methods`: Some of the authentication methods require manual steps, like confirming MFA or setting more dependencies. diff --git a/pkg/provider/manual_tests/README.md b/pkg/manual_tests/authentication_methods/README.md similarity index 77% rename from pkg/provider/manual_tests/README.md rename to pkg/manual_tests/authentication_methods/README.md index 853dd16ba7..99d9d548b5 100644 --- a/pkg/provider/manual_tests/README.md +++ b/pkg/manual_tests/authentication_methods/README.md @@ -1,17 +1,17 @@ -# Manual tests +# Authentication methods manual tests -This directory is dedicated to hold steps for manual provider tests that are not possible to re-recreate in automated tests (or very hard to set up). These tests are disabled by default and require `TEST_SF_TF_ENABLE_MANUAL_TESTS` environmental variable to be set. +This directory is dedicated to hold steps for manual authentication methods tests in the provider that are not possible to re-recreate in automated tests (or very hard to set up). These tests are disabled by default and require `TEST_SF_TF_ENABLE_MANUAL_TESTS` environmental variable to be set. ## Okta authenticator test This test checks `Okta` authenticator option. It requires manual steps because of additional setup on Okta side. It assumes that `default` profile uses a standard values of account name, user, password, etc. 1. Set up a developer Okta account [here](https://developer.okta.com/signup/). -1. Go to admin panel and select Applications -> Create App Integration. -1. Create a new application with SAML 2.0 type and give it a unique name -1. Fill SAML settings - paste the URLs for the testing accounts, like `https://example.snowflakecomputing.com/fed/login` for Single sign on URL, Recipient URL, Destination URL and Audience URI (SP Entity ID) -1. Click Next and Finish -1. After the app gets created, click View SAML setup instructions -1. Save the values provided: IDP SSO URL, IDP Issuer, and X509 certificate -1. Create a new security integration in Snowflake: +2. Go to admin panel and select Applications -> Create App Integration. +3. Create a new application with SAML 2.0 type and give it a unique name +4. Fill SAML settings - paste the URLs for the testing accounts, like `https://example.snowflakecomputing.com/fed/login` for Single sign on URL, Recipient URL, Destination URL and Audience URI (SP Entity ID) +5. Click Next and Finish +6. After the app gets created, click View SAML setup instructions +7. Save the values provided: IDP SSO URL, IDP Issuer, and X509 certificate +8. Create a new security integration in Snowflake: ``` CREATE SECURITY INTEGRATION MyIDP TYPE=SAML2 @@ -23,8 +23,8 @@ SAML2_SP_INITIATED_LOGIN_PAGE_LABEL='myidp - okta' SAML2_ENABLE_SP_INITIATED=false SAML2_X509_CERT=''; ``` -1. Note that Snowflake and Okta login name must match, otherwise create a temporary user with a login name matching the one in Okta. -1. Prepare a TOML config like: +9. Note that Snowflake and Okta login name must match, otherwise create a temporary user with a login name matching the one in Okta. +10. Prepare a TOML config like: ``` [okta] organizationname='ORGANIZATION_NAME' @@ -33,7 +33,7 @@ user='LOGIN_NAME' # This is a value used to login in Okta password='PASSWORD' # This is a password in Okta oktaurl='https://dev-123456.okta.com' # URL of your Okta environment ``` -1. Run the tests - you should be able to authenticate with Okta. +11. Run the tests - you should be able to authenticate with Okta. ## UsernamePasswordMFA authenticator test diff --git a/pkg/provider/manual_tests/auth_test.go b/pkg/manual_tests/authentication_methods/auth_test.go similarity index 100% rename from pkg/provider/manual_tests/auth_test.go rename to pkg/manual_tests/authentication_methods/auth_test.go diff --git a/pkg/provider/provider_acceptance_test.go b/pkg/provider/provider_acceptance_test.go index 97e45b0734..5369ada5c6 100644 --- a/pkg/provider/provider_acceptance_test.go +++ b/pkg/provider/provider_acceptance_test.go @@ -221,7 +221,7 @@ func TestAcc_Provider_tomlConfig(t *testing.T) { Token: "token", KeepSessionAlive: true, DisableTelemetry: true, - Tracing: "info", + Tracing: string(sdk.DriverLogLevelInfo), TmpDirPath: ".", ClientRequestMfaToken: gosnowflake.ConfigBoolTrue, ClientStoreTemporaryCredential: gosnowflake.ConfigBoolTrue, @@ -229,6 +229,7 @@ func TestAcc_Provider_tomlConfig(t *testing.T) { IncludeRetryReason: gosnowflake.ConfigBoolTrue, DisableConsoleLogin: gosnowflake.ConfigBoolTrue, }, config) + assert.Equal(t, string(sdk.DriverLogLevelInfo), gosnowflake.GetLogger().GetLogLevel()) return nil }, @@ -296,7 +297,7 @@ func TestAcc_Provider_envConfig(t *testing.T) { t.Setenv(snowflakeenvs.DisableQueryContextCache, "false") t.Setenv(snowflakeenvs.IncludeRetryReason, "false") t.Setenv(snowflakeenvs.MaxRetryCount, "2") - t.Setenv(snowflakeenvs.DriverTracing, "debug") + t.Setenv(snowflakeenvs.DriverTracing, string(sdk.DriverLogLevelDebug)) t.Setenv(snowflakeenvs.TmpDirectoryPath, "../") t.Setenv(snowflakeenvs.DisableConsoleLogin, "false") }, @@ -333,7 +334,7 @@ func TestAcc_Provider_envConfig(t *testing.T) { Token: "token", KeepSessionAlive: true, DisableTelemetry: true, - Tracing: "debug", + Tracing: string(sdk.DriverLogLevelDebug), TmpDirPath: "../", ClientRequestMfaToken: gosnowflake.ConfigBoolFalse, ClientStoreTemporaryCredential: gosnowflake.ConfigBoolFalse, @@ -341,6 +342,7 @@ func TestAcc_Provider_envConfig(t *testing.T) { IncludeRetryReason: gosnowflake.ConfigBoolFalse, DisableConsoleLogin: gosnowflake.ConfigBoolFalse, }, config) + assert.Equal(t, string(sdk.DriverLogLevelDebug), gosnowflake.GetLogger().GetLogLevel()) return nil }, @@ -408,7 +410,7 @@ func TestAcc_Provider_tfConfig(t *testing.T) { t.Setenv(snowflakeenvs.DisableQueryContextCache, "false") t.Setenv(snowflakeenvs.IncludeRetryReason, "false") t.Setenv(snowflakeenvs.MaxRetryCount, "2") - t.Setenv(snowflakeenvs.DriverTracing, "debug") + t.Setenv(snowflakeenvs.DriverTracing, string(sdk.DriverLogLevelDebug)) t.Setenv(snowflakeenvs.TmpDirectoryPath, "../") t.Setenv(snowflakeenvs.DisableConsoleLogin, "false") }, @@ -445,7 +447,7 @@ func TestAcc_Provider_tfConfig(t *testing.T) { Token: "token", KeepSessionAlive: true, DisableTelemetry: true, - Tracing: "info", + Tracing: string(sdk.DriverLogLevelInfo), TmpDirPath: "../../", ClientRequestMfaToken: gosnowflake.ConfigBoolTrue, ClientStoreTemporaryCredential: gosnowflake.ConfigBoolTrue, @@ -453,6 +455,7 @@ func TestAcc_Provider_tfConfig(t *testing.T) { IncludeRetryReason: gosnowflake.ConfigBoolTrue, DisableConsoleLogin: gosnowflake.ConfigBoolTrue, }, config) + assert.Equal(t, string(sdk.DriverLogLevelInfo), gosnowflake.GetLogger().GetLogLevel()) return nil }, diff --git a/pkg/sdk/client.go b/pkg/sdk/client.go index a0cb338c17..8f6d66c8a4 100644 --- a/pkg/sdk/client.go +++ b/pkg/sdk/client.go @@ -14,14 +14,10 @@ import ( "github.com/snowflakedb/gosnowflake" ) -var ( - instrumentedSQL bool - gosnowflakeLoggingLevel string -) +var instrumentedSQL bool func init() { instrumentedSQL = os.Getenv(snowflakeenvs.NoInstrumentedSql) == "" - gosnowflakeLoggingLevel = os.Getenv(snowflakeenvs.DriverTracing) } type Client struct {