Repository: snowflakedb/gosnowflake
Pull request #1030 (2024-01-11 14:11:37)

SNOW-999076: Easy Logging fixes
### Description
Fix Easy Logging

### Checklist
- [x] Code compiles correctly
- [x] Run ``make fmt`` to fix inconsistent formats
- [x] Run ``make lint`` to get lint errors and fix all of them
- [x] Created tests which fail without the change (if possible)
- [x] All tests passing
- [x] Extended the README / documentation, if necessary


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/snowflakedb/gosnowflake/pull/1030?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=snowflakedb) Report
Attention: `27 lines` in your changes are missing coverage. Please review.
> Comparison is base [(`7328b30`)](https://app.codecov.io/gh/snowflakedb/gosnowflake/commit/7328b302337856a01936511bfdb61aea3dbd370b?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=snowflakedb) 82.79% compared to head [(`88295b2`)](https://app.codecov.io/gh/snowflakedb/gosnowflake/pull/1030?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=snowflakedb) 83.03%.
> Report is 1 commits behind head on master.

| [Files](https://app.codecov.io/gh/snowflakedb/gosnowflake/pull/1030?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=snowflakedb) | Patch % | Lines |
|---|---|---|
| [easy\_logging.go](https://app.codecov.io/gh/snowflakedb/gosnowflake/pull/1030?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=snowflakedb#diff-ZWFzeV9sb2dnaW5nLmdv) | 54.05% | [17 Missing :warning: ](https://app.codecov.io/gh/snowflakedb/gosnowflake/pull/1030?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=snowflakedb) |
| [client\_configuration.go](https://app.codecov.io/gh/snowflakedb/gosnowflake/pull/1030?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=snowflakedb#diff-Y2xpZW50X2NvbmZpZ3VyYXRpb24uZ28=) | 81.13% | [10 Missing :warning: ](https://app.codecov.io/gh/snowflakedb/gosnowflake/pull/1030?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=snowflakedb) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #1030      +/-   ##
==========================================
+ Coverage   82.79%   83.03%   +0.23%     
==========================================
  Files          50       49       -1     
  Lines        9718     9790      +72     
==========================================
+ Hits         8046     8129      +83     
+ Misses       1672     1661      -11     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/snowflakedb/gosnowflake/pull/1030?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=snowflakedb).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=snowflakedb).


Patch:
diff --git a/client_configuration.go b/client_configuration.go
index a727181..bb0c0e8 100644
--- a/client_configuration.go
+++ b/client_configuration.go
@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"os"
 	"path"
+	"runtime"
 	"strings"
 )
 
@@ -26,39 +27,47 @@ const (
 	clientConfEnvName = "SF_CLIENT_CONFIG_FILE"
 )
 
-func getClientConfig(filePathFromConnectionString string) (*ClientConfig, error) {
-	configPredefinedFilePaths := clientConfigPredefinedDirs()
-	filePath := findClientConfigFilePath(filePathFromConnectionString, configPredefinedFilePaths)
+func getClientConfig(filePathFromConnectionString string) (*ClientConfig, string, error) {
+	configPredefinedDirPaths := clientConfigPredefinedDirs()
+	filePath, err := findClientConfigFilePath(filePathFromConnectionString, configPredefinedDirPaths)
+	if err != nil {
+		return nil, "", err
+	}
 	if filePath == "" { // we did not find a config file
-		return nil, nil
+		return nil, "", nil
 	}
-	return parseClientConfiguration(filePath)
+	config, err := parseClientConfiguration(filePath)
+	return config, filePath, err
 }
 
-func findClientConfigFilePath(filePathFromConnectionString string, configPredefinedDirs []string) string {
+func findClientConfigFilePath(filePathFromConnectionString string, configPredefinedDirs []string) (string, error) {
 	if filePathFromConnectionString != "" {
-		return filePathFromConnectionString
+		logger.Infof("Using client configuration path from a connection string: %s", filePathFromConnectionString)
+		return filePathFromConnectionString, nil
 	}
 	envConfigFilePath := os.Getenv(clientConfEnvName)
 	if envConfigFilePath != "" {
-		return envConfigFilePath
+		logger.Infof("Using client configuration path from an environment variable: %s", envConfigFilePath)
+		return envConfigFilePath, nil
 	}
 	return searchForConfigFile(configPredefinedDirs)
 }
 
-func searchForConfigFile(directories []string) string {
+func searchForConfigFile(directories []string) (string, error) {
 	for _, dir := range directories {
 		filePath := path.Join(dir, defaultConfigName)
 		exists, err := existsFile(filePath)
 		if err != nil {
-			logger.Errorf("Error while searching for the client config in %s directory: %s", dir, err)
-			continue
+			return "", fmt.Errorf("error while searching for client config in directory: %s, err: %s", dir, err)
 		}
 		if exists {
-			return filePath
+			logger.Infof("Using client configuration from a default directory: %s", filePath)
+			return filePath, nil
 		}
+		logger.Debugf("No client config found in directory: %s", dir)
 	}
-	return ""
+	logger.Info("No client config file found in default directories")
+	return "", nil
 }
 
 func existsFile(filePath string) (bool, error) {
@@ -75,10 +84,10 @@ func existsFile(filePath string) (bool, error) {
 func clientConfigPredefinedDirs() []string {
 	homeDir, err := os.UserHomeDir()
 	if err != nil {
-		logger.Warnf("Home dir could not be determined: %w", err)
-		return []string{".", os.TempDir()}
+		logger.Warnf("Unable to access Home directory for client configuration search, err: %v", err)
+		return []string{"."}
 	}
-	return []string{".", homeDir, os.TempDir()}
+	return []string{".", homeDir}
 }
 
 // ClientConfig config root
@@ -100,11 +109,21 @@ func parseClientConfiguration(filePath string) (*ClientConfig, error) {
 	if err != nil {
 		return nil, parsingClientConfigError(err)
 	}
+	err = validateCfgPerm(filePath)
+	if err != nil {
+		return nil, parsingClientConfigError(err)
+	}
 	var clientConfig ClientConfig
 	err = json.Unmarshal(fileContents, &clientConfig)
 	if err != nil {
 		return nil, parsingClientConfigError(err)
 	}
+	unknownValues := getUnknownValues(fileContents)
+	if len(unknownValues) > 0 {
+		for val := range unknownValues {
+			logger.Warnf("Unknown configuration entry: %s with value: %s", val, unknownValues[val])
+		}
+	}
 	err = validateClientConfiguration(&clientConfig)
 	if err != nil {
 		return nil, parsingClientConfigError(err)
@@ -112,6 +131,25 @@ func parseClientConfiguration(filePath string) (*ClientConfig, error) {
 	return &clientConfig, nil
 }
 
+func getUnknownValues(fileContents []byte) map[string]interface{} {
+	var values map[string]interface{}
+	err := json.Unmarshal(fileContents, &values)
+	if err != nil {
+		return nil
+	}
+	if values["common"] == nil {
+		return nil
+	}
+	commonValues := values["common"].(map[string]interface{})
+	lowercaseCommonValues := make(map[string]interface{}, len(commonValues))
+	for k, v := range commonValues {
+		lowercaseCommonValues[strings.ToLower(k)] = v
+	}
+	delete(lowercaseCommonValues, "log_level")
+	delete(lowercaseCommonValues, "log_path")
+	return lowercaseCommonValues
+}
+
 func parsingClientConfigError(err error) error {
 	return fmt.Errorf("parsing client config failed: %w", err)
 }
@@ -129,14 +167,30 @@ func validateClientConfiguration(clientConfig *ClientConfig) error {
 func validateLogLevel(clientConfig ClientConfig) error {
 	var logLevel = clientConfig.Common.LogLevel
 	if logLevel != "" {
-		_, error := toLogLevel(logLevel)
-		if error != nil {
-			return error
+		_, err := toLogLevel(logLevel)
+		if err != nil {
+			return err
 		}
 	}
 	return nil
 }
 
+func validateCfgPerm(filePath string) error {
+	if runtime.GOOS == "windows" {
+		return nil
+	}
+	stat, err := os.Stat(filePath)
+	if err != nil {
+		return err
+	}
+	perm := stat.Mode()
+	// Check if group (5th LSB) or others (2nd LSB) have a write permission to the file
+	if perm&(1<<4) != 0 || perm&(1<<1) != 0 {
+		return fmt.Errorf("configuration file: %s can be modified by group or others", filePath)
+	}
+	return nil
+}
+
 func toLogLevel(logLevelString string) (string, error) {
 	var logLevel = strings.ToUpper(logLevelString)
 	switch logLevel {
diff --git a/connection.go b/connection.go
index 7282906..789a57a 100644
--- a/connection.go
+++ b/connection.go
@@ -757,11 +757,10 @@ func buildSnowflakeConn(ctx context.Context, config Config) (*snowflakeConn, err
 		queryContextCache:   (&queryContextCache{}).init(),
 		currentTimeProvider: defaultTimeProvider,
 	}
-	// Easy logging is temporarily disabled
-	//err := initEasyLogging(config.ClientConfigFile)
-	//if err != nil {
-	//	return nil, err
-	//}
+	err := initEasyLogging(config.ClientConfigFile)
+	if err != nil {
+		return nil, err
+	}
 	var st http.RoundTripper = SnowflakeTransport
 	if sc.cfg.Transporter == nil {
 		if sc.cfg.InsecureMode {
diff --git a/easy_logging.go b/easy_logging.go
index a4d782d..6ae16e3 100644
--- a/easy_logging.go
+++ b/easy_logging.go
@@ -2,9 +2,11 @@ package gosnowflake
 
 import (
 	"errors"
+	"fmt"
 	"io"
 	"os"
 	"path"
+	"runtime"
 	"strings"
 )
 
@@ -35,30 +37,39 @@ func (i *initTrials) reset() {
 	i.configureCounter = 0
 }
 
-//lint:ignore U1000 Ignore unused function
 func initEasyLogging(clientConfigFileInput string) error {
 	if !allowedToInitialize(clientConfigFileInput) {
+		logger.Info("Skipping Easy Logging initialization as it is not allowed to initialize")
 		return nil
 	}
-	config, err := getClientConfig(clientConfigFileInput)
+	logger.Infof("Trying to initialize Easy Logging")
+	config, configPath, err := getClientConfig(clientConfigFileInput)
 	if err != nil {
+		logger.Errorf("Failed to initialize Easy Logging, err: %s", err)
 		return easyLoggingInitError(err)
 	}
 	if config == nil {
+		logger.Info("Easy Logging is disabled as no config has been found")
 		easyLoggingInitTrials.setInitTrial(clientConfigFileInput)
 		return nil
 	}
 	var logLevel string
 	logLevel, err = getLogLevel(config.Common.LogLevel)
 	if err != nil {
+		logger.Errorf("Failed to initialize Easy Logging, err: %s", err)
 		return easyLoggingInitError(err)
 	}
 	var logPath string
 	logPath, err = getLogPath(config.Common.LogPath)
 	if err != nil {
+		logger.Errorf("Failed to initialize Easy Logging, err: %s", err)
 		return easyLoggingInitError(err)
 	}
+	logger.Infof("Initializing Easy Logging with logPath=%s and logLevel=%s from file: %s", logPath, logLevel, configPath)
 	err = reconfigureEasyLogging(logLevel, logPath)
+	if err != nil {
+		logger.Errorf("Failed to initialize Easy Logging, err: %s", err)
+	}
 	easyLoggingInitTrials.setInitTrial(clientConfigFileInput)
 	easyLoggingInitTrials.increaseReconfigureCounter()
 	return err
@@ -125,8 +136,12 @@ func getLogLevel(logLevel string) (string, error) {
 func getLogPath(logPath string) (string, error) {
 	logPathOrDefault := logPath
 	if logPath == "" {
-		logPathOrDefault = os.TempDir()
-		logger.Warnf("LogPath in client config not found. Using temporary directory as a default value: %s", logPathOrDefault)
+		homeDir, err := os.UserHomeDir()
+		if err != nil {
+			return "", fmt.Errorf("user home directory is not accessible, err: %w", err)
+		}
+		logPathOrDefault = homeDir
+		logger.Warnf("LogPath in client config not found. Using user home directory as a default value: %s", logPathOrDefault)
 	}
 	pathWithGoSubdir := path.Join(logPathOrDefault, "go")
 	exists, err := dirExists(pathWithGoSubdir)
@@ -134,14 +149,37 @@ func getLogPath(logPath string) (string, error) {
 		return "", err
 	}
 	if !exists {
-		err = os.MkdirAll(pathWithGoSubdir, 0755)
+		err = os.MkdirAll(pathWithGoSubdir, 0700)
 		if err != nil {
 			return "", err
 		}
 	}
+	logDirPermValid, perm, err := isDirAccessCorrect(pathWithGoSubdir)
+	if err != nil {
+		return "", err
+	}
+	if !logDirPermValid {
+		logger.Warnf("Log directory: %s could potentially be accessed by others. Directory chmod: 0%o", pathWithGoSubdir, *perm)
+	}
 	return pathWithGoSubdir, nil
 }
 
+func isDirAccessCorrect(dirPath string) (bool, *os.FileMode, error) {
+	if runtime.GOOS == "windows" {
+		return true, nil, nil
+
+	}
+	dirStat, err := os.Stat(dirPath)
+	if err != nil {
+		return false, nil, err
+	}
+	perm := dirStat.Mode().Perm()
+	if perm != 0700 {
+		return false, &perm, nil
+	}
+	return true, &perm, nil
+}
+
 func dirExists(dirPath string) (bool, error) {
 	stat, err := os.Stat(dirPath)
 	if err == nil {
diff --git a/go.mod b/go.mod
index 62a7551..96285be 100644
--- a/go.mod
+++ b/go.mod
@@ -17,6 +17,7 @@ require (
 	github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
 	github.com/sirupsen/logrus v1.9.0
 	golang.org/x/crypto v0.17.0
+	golang.org/x/sys v0.15.0
 )
 
 require (
@@ -49,7 +50,6 @@ require (
 	golang.org/x/mod v0.13.0 // indirect
 	golang.org/x/net v0.18.0 // indirect
 	golang.org/x/sync v0.4.0 // indirect
-	golang.org/x/sys v0.15.0 // indirect
 	golang.org/x/term v0.15.0 // indirect
 	golang.org/x/text v0.14.0 // indirect
 	golang.org/x/tools v0.14.0 // indirect


Test patch:
diff --git a/client_configuration_test.go b/client_configuration_test.go
index 9e73f72..5a9e7f7 100644
--- a/client_configuration_test.go
+++ b/client_configuration_test.go
@@ -18,8 +18,9 @@ func TestFindConfigFileFromConnectionParameters(t *testing.T) {
 	createFile(t, defaultConfigName, "random content", dirs.predefinedDir1)
 	createFile(t, defaultConfigName, "random content", dirs.predefinedDir2)
 
-	clientConfigFilePath := findClientConfigFilePath(connParameterConfigPath, predefinedTestDirs(dirs))
+	clientConfigFilePath, err := findClientConfigFilePath(connParameterConfigPath, predefinedTestDirs(dirs))
 
+	assertEqualE(t, err, nil)
 	assertEqualE(t, clientConfigFilePath, connParameterConfigPath, "config file path")
 }
 
@@ -30,8 +31,9 @@ func TestFindConfigFileFromEnvVariable(t *testing.T) {
 	createFile(t, defaultConfigName, "random content", dirs.predefinedDir1)
 	createFile(t, defaultConfigName, "random content", dirs.predefinedDir2)
 
-	clientConfigFilePath := findClientConfigFilePath("", predefinedTestDirs(dirs))
+	clientConfigFilePath, err := findClientConfigFilePath("", predefinedTestDirs(dirs))
 
+	assertEqualE(t, err, nil)
 	assertEqualE(t, clientConfigFilePath, envConfigPath, "config file path")
 }
 
@@ -40,8 +42,9 @@ func TestFindConfigFileFromFirstPredefinedDir(t *testing.T) {
 	configPath := createFile(t, defaultConfigName, "random content", dirs.predefinedDir1)
 	createFile(t, defaultConfigName, "random content", dirs.predefinedDir2)
 
-	clientConfigFilePath := findClientConfigFilePath("", predefinedTestDirs(dirs))
+	clientConfigFilePath, err := findClientConfigFilePath("", predefinedTestDirs(dirs))
 
+	assertEqualE(t, err, nil)
 	assertEqualE(t, clientConfigFilePath, configPath, "config file path")
 }
 
@@ -50,8 +53,9 @@ func TestFindConfigFileFromSubsequentDirectoryIfNotFoundInPreviousOne(t *testing
 	createFile(t, "wrong_file_name.json", "random content", dirs.predefinedDir1)
 	configPath := createFile(t, defaultConfigName, "random content", dirs.predefinedDir2)
 
-	clientConfigFilePath := findClientConfigFilePath("", predefinedTestDirs(dirs))
+	clientConfigFilePath, err := findClientConfigFilePath("", predefinedTestDirs(dirs))
 
+	assertEqualE(t, err, nil)
 	assertEqualE(t, clientConfigFilePath, configPath, "config file path")
 }
 
@@ -60,8 +64,9 @@ func TestNotFindConfigFileWhenNotDefined(t *testing.T) {
 	createFile(t, "wrong_file_name.json", "random content", dirs.predefinedDir1)
 	createFile(t, "wrong_file_name.json", "random content", dirs.predefinedDir2)
 
-	clientConfigFilePath := findClientConfigFilePath("", predefinedTestDirs(dirs))
+	clientConfigFilePath, err := findClientConfigFilePath("", predefinedTestDirs(dirs))
 
+	assertEqualE(t, err, nil)
 	assertEqualE(t, clientConfigFilePath, "", "config file path")
 }
 
@@ -71,10 +76,9 @@ func TestCreatePredefinedDirs(t *testing.T) {
 
 	locations := clientConfigPredefinedDirs()
 
-	assertEqualF(t, len(locations), 3, "size")
+	assertEqualF(t, len(locations), 2, "size")
 	assertEqualE(t, locations[0], ".", "driver directory")
 	assertEqualE(t, locations[1], homeDir, "home directory")
-	assertEqualE(t, locations[2], os.TempDir(), "temp directory")
 }
 
 func TestGetClientConfig(t *testing.T) {
@@ -84,7 +88,7 @@ func TestGetClientConfig(t *testing.T) {
 	createFile(t, fileName, configContents, dir)
 	filePath := path.Join(dir, fileName)
 
-	clientConfigFilePath, err := getClientConfig(filePath)
+	clientConfigFilePath, _, err := getClientConfig(filePath)
 
 	assertNilF(t, err)
 	assertNotNilF(t, clientConfigFilePath)
@@ -93,7 +97,7 @@ func TestGetClientConfig(t *testing.T) {
 }
 
 func TestNoResultForGetClientConfigWhenNoFileFound(t *testing.T) {
-	clientConfigFilePath, err := getClientConfig("")
+	clientConfigFilePath, _, err := getClientConfig("")
 
 	assertNilF(t, err)
 	assertNilF(t, clientConfigFilePath)
@@ -223,6 +227,76 @@ func TestParseConfigurationFails(t *testing.T) {
 	}
 }
 
+func TestUnknownValues(t *testing.T) {
+	testCases := []struct {
+		testName       string
+		inputString    string
+		expectedOutput map[string]string
+	}{
+		{
+			testName: "EmptyCommon",
+			inputString: `{
+				"common": {}
+			}`,
+			expectedOutput: map[string]string{},
+		},
+		{
+			testName: "CommonMissing",
+			inputString: `{
+			}`,
+			expectedOutput: map[string]string{},
+		},
+		{
+			testName: "UnknownProperty",
+			inputString: `{
+				"common": {
+					"unknown_key": "unknown_value"
+				}
+			}`,
+			expectedOutput: map[string]string{
+				"unknown_key": "unknown_value",
+			},
+		},
+		{
+			testName: "KnownAndUnknownProperty",
+			inputString: `{
+				"common": {
+					"lOg_level": "level",
+					"log_PATH": "path",
+					"unknown_key": "unknown_value"
+				}
+			}`,
+			expectedOutput: map[string]string{
+				"unknown_key": "unknown_value",
+			},
+		},
+		{
+			testName: "KnownProperties",
+			inputString: `{
+				"common": {
+					"log_level": "level",
+					"log_path": "path"
+				}
+			}`,
+			expectedOutput: map[string]string{},
+		},
+
+		{
+			testName:       "EmptyInput",
+			inputString:    "",
+			expectedOutput: map[string]string{},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.testName, func(t *testing.T) {
+			inputBytes := []byte(tc.inputString)
+			result := getUnknownValues(inputBytes)
+			assertEqualE(t, fmt.Sprint(result), fmt.Sprint(tc.expectedOutput))
+		})
+	}
+}
+
 func createFile(t *testing.T, fileName string, fileContents string, directory string) string {
 	fullFileName := path.Join(directory, fileName)
 	err := os.WriteFile(fullFileName, []byte(fileContents), 0644)
@@ -237,10 +311,10 @@ func createTestDirectories(t *testing.T) struct {
 } {
 	dir := t.TempDir()
 	predefinedDir1 := path.Join(dir, "dir1")
-	err := os.Mkdir(predefinedDir1, 0755)
+	err := os.Mkdir(predefinedDir1, 0700)
 	assertNilF(t, err, "predefined dir1 error")
 	predefinedDir2 := path.Join(dir, "dir2")
-	err = os.Mkdir(predefinedDir2, 0755)
+	err = os.Mkdir(predefinedDir2, 0700)
 	assertNilF(t, err, "predefined dir2 error")
 	return struct {
 		dir            string
diff --git a/easy_logging_test.go b/easy_logging_test.go
index ae82382..a2f9be9 100644
--- a/easy_logging_test.go
+++ b/easy_logging_test.go
@@ -10,12 +10,11 @@ import (
 )
 
 func TestInitializeEasyLoggingOnlyOnceWhenConfigGivenAsAParameter(t *testing.T) {
-	t.Skip("Skip until easy logging enabled")
 	defer cleanUp()
-	dir := t.TempDir()
+	logDir := t.TempDir()
 	logLevel := levelError
-	contents := createClientConfigContent(logLevel, dir)
-	configFilePath := createFile(t, "config.json", contents, dir)
+	contents := createClientConfigContent(logLevel, logDir)
+	configFilePath := createFile(t, "config.json", contents, logDir)
 	easyLoggingInitTrials.reset()
 
 	err := openWithClientConfigFile(t, configFilePath)
@@ -36,16 +35,17 @@ func TestInitializeEasyLoggingOnlyOnceWhenConfigGivenAsAParameter(t *testing.T)
 }
 
 func TestConfigureEasyLoggingOnlyOnceWhenInitializedWithoutConfigFilePath(t *testing.T) {
-	t.Skip("Skip until easy logging enabled")
 	defer cleanUp()
-	dir := t.TempDir()
+	configDir, err := os.UserHomeDir()
+	logDir := t.TempDir()
+	assertNilF(t, err, "user home directory error")
 	logLevel := levelError
-	contents := createClientConfigContent(logLevel, dir)
-	configFilePath := createFile(t, defaultConfigName, contents, os.TempDir())
+	contents := createClientConfigContent(logLevel, logDir)
+	configFilePath := createFile(t, defaultConfigName, contents, configDir)
 	defer os.Remove(configFilePath)
 	easyLoggingInitTrials.reset()
 
-	err := openWithClientConfigFile(t, "")
+	err = openWithClientConfigFile(t, "")
 	assertNilF(t, err, "open config error")
 	err = openWithClientConfigFile(t, "")
 	assertNilF(t, err, "open config error")
@@ -55,23 +55,24 @@ func TestConfigureEasyLoggingOnlyOnceWhenInitializedWithoutConfigFilePath(t *tes
 }
 
 func TestReconfigureEasyLoggingIfConfigPathWasNotGivenForTheFirstTime(t *testing.T) {
-	t.Skip("Skip until easy logging enabled")
 	defer cleanUp()
-	dir := t.TempDir()
-	tmpDirLogLevel := levelError
-	tmpFileContent := createClientConfigContent(tmpDirLogLevel, dir)
-	tmpDirConfigFilePath := createFile(t, defaultConfigName, tmpFileContent, os.TempDir())
-	defer os.Remove(tmpDirConfigFilePath)
+	configDir, err := os.UserHomeDir()
+	logDir := t.TempDir()
+	assertNilF(t, err, "user home directory error")
+	homeConfigLogLevel := levelError
+	homeConfigContent := createClientConfigContent(homeConfigLogLevel, logDir)
+	homeConfigFilePath := createFile(t, defaultConfigName, homeConfigContent, configDir)
+	defer os.Remove(homeConfigFilePath)
 	customLogLevel := levelWarn
-	customFileContent := createClientConfigContent(customLogLevel, dir)
-	customConfigFilePath := createFile(t, "config.json", customFileContent, dir)
+	customFileContent := createClientConfigContent(customLogLevel, logDir)
+	customConfigFilePath := createFile(t, "config.json", customFileContent, configDir)
 	easyLoggingInitTrials.reset()
 
-	err := openWithClientConfigFile(t, "")
+	err = openWithClientConfigFile(t, "")
 	logger.Error("Error message")
 
 	assertNilF(t, err, "open config error")
-	assertEqualE(t, toClientConfigLevel(logger.GetLogLevel()), tmpDirLogLevel, "tmp dir log level check")
+	assertEqualE(t, toClientConfigLevel(logger.GetLogLevel()), homeConfigLogLevel, "tmp dir log level check")
 	assertEqualE(t, easyLoggingInitTrials.configureCounter, 1)
 
 	err = openWithClientConfigFile(t, customConfigFilePath)
@@ -81,14 +82,13 @@ func TestReconfigureEasyLoggingIfConfigPathWasNotGivenForTheFirstTime(t *testing
 	assertEqualE(t, toClientConfigLevel(logger.GetLogLevel()), customLogLevel, "custom dir log level check")
 	assertEqualE(t, easyLoggingInitTrials.configureCounter, 2)
 	var logContents []byte
-	logContents, err = os.ReadFile(path.Join(dir, "go", "snowflake.log"))
+	logContents, err = os.ReadFile(path.Join(logDir, "go", "snowflake.log"))
 	assertNilF(t, err, "read file error")
 	logs := notEmptyLines(string(logContents))
 	assertEqualE(t, len(logs), 2, "number of logs")
 }
 
 func TestEasyLoggingFailOnUnknownLevel(t *testing.T) {
-	t.Skip("Skip until easy logging enabled")
 	defer cleanUp()
 	dir := t.TempDir()
 	easyLoggingInitTrials.reset()
@@ -103,7 +103,6 @@ func TestEasyLoggingFailOnUnknownLevel(t *testing.T) {
 }
 
 func TestEasyLoggingFailOnNotExistingConfigFile(t *testing.T) {
-	t.Skip("Skip until easy logging enabled")
 	defer cleanUp()
 	easyLoggingInitTrials.reset()
 
@@ -115,7 +114,6 @@ func TestEasyLoggingFailOnNotExistingConfigFile(t *testing.T) {
 }
 
 func TestLogToConfiguredFile(t *testing.T) {
-	t.Skip("Skip until easy logging enabled")
 	defer cleanUp()
 	dir := t.TempDir()
 	easyLoggingInitTrials.reset()
@@ -172,7 +170,7 @@ func toClientConfigLevel(logLevel string) string {
 }
 
 func filterStrings(values []string, keep func(string) bool) []string {
-	filteredStrings := []string{}
+	var filteredStrings []string
 	for _, val := range values {
 		if keep(val) {
 			filteredStrings = append(filteredStrings, val)
diff --git a/permissions_test.go b/permissions_test.go
new file mode 100644
index 0000000..95c85c1
--- /dev/null
+++ b/permissions_test.go
@@ -0,0 +1,102 @@
+//go:build !windows
+
+package gosnowflake
+
+import (
+	"fmt"
+	"golang.org/x/sys/unix"
+	"os"
+	"path"
+	"testing"
+)
+
+func TestConfigPermissions(t *testing.T) {
+	testCases := []struct {
+		filePerm int
+		isValid  bool
+	}{
+		{filePerm: 0700, isValid: true},
+		{filePerm: 0600, isValid: true},
+		{filePerm: 0500, isValid: true},
+		{filePerm: 0400, isValid: true},
+		{filePerm: 0300, isValid: true},
+		{filePerm: 0200, isValid: true},
+		{filePerm: 0100, isValid: true},
+		{filePerm: 0707, isValid: false},
+		{filePerm: 0706, isValid: false},
+		{filePerm: 0705, isValid: true},
+		{filePerm: 0704, isValid: true},
+		{filePerm: 0703, isValid: false},
+		{filePerm: 0702, isValid: false},
+		{filePerm: 0701, isValid: true},
+		{filePerm: 0770, isValid: false},
+		{filePerm: 0760, isValid: false},
+		{filePerm: 0750, isValid: true},
+		{filePerm: 0740, isValid: true},
+		{filePerm: 0730, isValid: false},
+		{filePerm: 0720, isValid: false},
+		{filePerm: 0710, isValid: true},
+	}
+
+	oldMask := unix.Umask(0000)
+	defer unix.Umask(oldMask)
+
+	for _, tc := range testCases {
+		t.Run(fmt.Sprintf("0%o", tc.filePerm), func(t *testing.T) {
+			tempFile := path.Join(t.TempDir(), fmt.Sprintf("filePerm_%o", tc.filePerm))
+			err := os.WriteFile(tempFile, nil, os.FileMode(tc.filePerm))
+			assertNilE(t, err)
+			defer os.Remove(tempFile)
+			err = validateCfgPerm(tempFile)
+			if err != nil && tc.isValid {
+				t.Error(err)
+			}
+		})
+	}
+}
+
+func TestLogDirectoryPermissions(t *testing.T) {
+	testCases := []struct {
+		dirPerm       int
+		limitedToUser bool
+	}{
+		{dirPerm: 0700, limitedToUser: true},
+		{dirPerm: 0600, limitedToUser: false},
+		{dirPerm: 0500, limitedToUser: false},
+		{dirPerm: 0400, limitedToUser: false},
+		{dirPerm: 0300, limitedToUser: false},
+		{dirPerm: 0200, limitedToUser: false},
+		{dirPerm: 0100, limitedToUser: false},
+		{dirPerm: 0707, limitedToUser: false},
+		{dirPerm: 0706, limitedToUser: false},
+		{dirPerm: 0705, limitedToUser: false},
+		{dirPerm: 0704, limitedToUser: false},
+		{dirPerm: 0703, limitedToUser: false},
+		{dirPerm: 0702, limitedToUser: false},
+		{dirPerm: 0701, limitedToUser: false},
+		{dirPerm: 0770, limitedToUser: false},
+		{dirPerm: 0760, limitedToUser: false},
+		{dirPerm: 0750, limitedToUser: false},
+		{dirPerm: 0740, limitedToUser: false},
+		{dirPerm: 0730, limitedToUser: false},
+		{dirPerm: 0720, limitedToUser: false},
+		{dirPerm: 0710, limitedToUser: false},
+	}
+
+	oldMask := unix.Umask(0000)
+	defer unix.Umask(oldMask)
+
+	for _, tc := range testCases {
+		t.Run(fmt.Sprintf("0%o", tc.dirPerm), func(t *testing.T) {
+			tempDir := path.Join(t.TempDir(), fmt.Sprintf("filePerm_%o", tc.dirPerm))
+			err := os.Mkdir(tempDir, os.FileMode(tc.dirPerm))
+			assertNilE(t, err)
+			defer os.Remove(tempDir)
+			result, _, err := isDirAccessCorrect(tempDir)
+			if err != nil && tc.limitedToUser {
+				t.Error(err)
+			}
+			assertEqualE(t, result, tc.limitedToUser)
+		})
+	}
+}