Repository: snowflakedb/gosnowflake
Pull request #1116 (2024-04-24 06:35:18)

SNOW-1260011: mask password in the logs
### Description

issue: https://github.com/snowflakedb/snowflake-sdks-drivers-issues-teamwork/issues/936
SNOW-1260011: Driver exposes password in the logs

The logger will now masked all secrets in the logs.

### Checklist
- [x] Created tests which fail without the change (if possible)
- [ ] Extended the README / documentation, if necessary


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/snowflakedb/gosnowflake/pull/1116?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=snowflakedb) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 75.38%. Comparing base [(`bd156e9`)](https://app.codecov.io/gh/snowflakedb/gosnowflake/commit/bd156e93e91986e567846667158e95a7951b5e14?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=snowflakedb) to head [(`aedc911`)](https://app.codecov.io/gh/snowflakedb/gosnowflake/pull/1116?dropdown=coverage&src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=snowflakedb).
> Report is 1 commits behind head on master.


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


```diff
@@           Coverage Diff           @@
##           master    #1116   +/-   ##
=======================================
  Coverage   75.38%   75.38%           
=======================================
  Files          53       53           
  Lines       11243    11243           
=======================================
  Hits         8476     8476           
  Misses       2767     2767           
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/snowflakedb/gosnowflake/pull/1116?dropdown=coverage&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/log.go b/log.go
index cf1774c..983319e 100644
--- a/log.go
+++ b/log.go
@@ -5,13 +5,14 @@ package gosnowflake
 import (
 	"context"
 	"fmt"
-	rlog "github.com/sirupsen/logrus"
 	"io"
 	"os"
 	"path"
 	"runtime"
 	"strings"
 	"time"
+
+	rlog "github.com/sirupsen/logrus"
 )
 
 // SFSessionIDKey is context key of session id
@@ -61,6 +62,16 @@ type defaultLogger struct {
 	file    *os.File
 }
 
+type sfTextFormatter struct {
+	rlog.TextFormatter
+}
+
+func (f *sfTextFormatter) Format(entry *rlog.Entry) ([]byte, error) {
+	// mask all secrets before calling the default Format method
+	entry.Message = maskSecrets(entry.Message)
+	return f.TextFormatter.Format(entry)
+}
+
 // SetLogLevel set logging level for calling defaultLogger
 func (log *defaultLogger) SetLogLevel(level string) error {
 	newEnabled := strings.ToUpper(level) != "OFF"
@@ -116,9 +127,10 @@ func (log *defaultLogger) WithContext(ctx context.Context) *rlog.Entry {
 // CreateDefaultLogger return a new instance of SFLogger with default config
 func CreateDefaultLogger() SFLogger {
 	var rLogger = rlog.New()
-	var formatter = rlog.TextFormatter{CallerPrettyfier: SFCallerPrettyfier}
+	var formatter = new(sfTextFormatter)
+	formatter.CallerPrettyfier = SFCallerPrettyfier
+	rLogger.SetFormatter(formatter)
 	rLogger.SetReportCaller(true)
-	rLogger.SetFormatter(&formatter)
 	var ret = defaultLogger{inner: rLogger, enabled: true}
 	return &ret //(&ret).(*SFLogger)
 }


Test patch:
diff --git a/log_test.go b/log_test.go
index 727bb49..9c1544f 100644
--- a/log_test.go
+++ b/log_test.go
@@ -323,3 +323,20 @@ func TestLogKeysWithRegisterContextVariableToLog(t *testing.T) {
 		t.Fatalf("expected that REQUEST_ID would be in logs if logger.WithContext and RegisterContextVariableToLog was used, but got: %v", strbuf)
 	}
 }
+
+func TestLogMaskSecrets(t *testing.T) {
+	logger := CreateDefaultLogger()
+	buf := &bytes.Buffer{}
+	logger.SetOutput(buf)
+
+	ctx := context.Background()
+	query := "create user testuser password='testpassword'"
+	logger.WithContext(ctx).Infof("Query: %#v", query)
+
+	// verify output
+	expected := "create user testuser password='****"
+	var strbuf = buf.String()
+	if !strings.Contains(strbuf, expected) {
+		t.Fatalf("expected that password would be masked. WithContext was used, but got: %v", strbuf)
+	}
+}