| package server |
|
|
| import ( |
| "bytes" |
| "log" |
| "net/http" |
| "net/http/httptest" |
| "strings" |
| "testing" |
| "time" |
|
|
| "github.com/go-chi/chi/v5/middleware" |
| ) |
|
|
| func TestFilteredLogFormatterRedactsSensitiveQueryParams(t *testing.T) { |
| var buf bytes.Buffer |
| formatter := &filteredLogFormatter{ |
| base: &middleware.DefaultLogFormatter{ |
| Logger: log.New(&buf, "", 0), |
| NoColor: true, |
| }, |
| } |
| req := httptest.NewRequest( |
| http.MethodPost, |
| "/v1beta/models/gemini-2.5-pro:generateContent?key=caller-secret&api_key=second-secret&alt=sse", |
| nil, |
| ) |
|
|
| entry := formatter.NewLogEntry(req) |
| entry.Write(http.StatusOK, 0, http.Header{}, time.Millisecond, nil) |
|
|
| got := buf.String() |
| for _, secret := range []string{"caller-secret", "second-secret"} { |
| if strings.Contains(got, secret) { |
| t.Fatalf("log line contains sensitive query value %q: %s", secret, got) |
| } |
| } |
| if !strings.Contains(got, "key=REDACTED") || !strings.Contains(got, "api_key=REDACTED") { |
| t.Fatalf("log line did not include redacted sensitive params: %s", got) |
| } |
| if !strings.Contains(got, "alt=sse") { |
| t.Fatalf("log line did not preserve non-sensitive query param: %s", got) |
| } |
| if req.URL.RawQuery != "key=caller-secret&api_key=second-secret&alt=sse" { |
| t.Fatalf("request was mutated, RawQuery = %q", req.URL.RawQuery) |
| } |
| } |
|
|
| func TestFilteredLogFormatterRedactsSensitiveQueryParamsWhenMalformed(t *testing.T) { |
| tests := []struct { |
| name string |
| target string |
| secrets []string |
| redacted []string |
| preserved []string |
| }{ |
| { |
| name: "semicolon separator", |
| target: "/v1beta/models/gemini-2.5-pro:generateContent?key=caller-secret;alt=sse", |
| secrets: []string{"caller-secret"}, |
| redacted: []string{"key=REDACTED"}, |
| preserved: []string{"alt=sse"}, |
| }, |
| { |
| name: "bad escape in sensitive value", |
| target: "/v1beta/models/gemini-2.5-pro:generateContent?api_key=second-secret%ZZ", |
| secrets: []string{"second-secret"}, |
| redacted: []string{"api_key=REDACTED"}, |
| }, |
| } |
|
|
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| var buf bytes.Buffer |
| formatter := &filteredLogFormatter{ |
| base: &middleware.DefaultLogFormatter{ |
| Logger: log.New(&buf, "", 0), |
| NoColor: true, |
| }, |
| } |
| req := httptest.NewRequest(http.MethodPost, tt.target, nil) |
|
|
| entry := formatter.NewLogEntry(req) |
| entry.Write(http.StatusOK, 0, http.Header{}, time.Millisecond, nil) |
|
|
| got := buf.String() |
| for _, secret := range tt.secrets { |
| if strings.Contains(got, secret) { |
| t.Fatalf("log line contains sensitive query value %q: %s", secret, got) |
| } |
| } |
| for _, want := range tt.redacted { |
| if !strings.Contains(got, want) { |
| t.Fatalf("log line missing redacted query %q: %s", want, got) |
| } |
| } |
| for _, want := range tt.preserved { |
| if !strings.Contains(got, want) { |
| t.Fatalf("log line missing preserved query %q: %s", want, got) |
| } |
| } |
| }) |
| } |
| } |
|
|