mirror of
https://github.com/warmbly/warmbly.git
synced 2026-10-12 16:02:44 +00:00
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
121 lines
4.5 KiB
Go
121 lines
4.5 KiB
Go
package middleware
|
|
|
|
import (
|
|
"bytes"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func TestRequestLoggerKeepsCredentialsOutOfTheLog(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
var buf bytes.Buffer
|
|
prev := gin.DefaultWriter
|
|
gin.DefaultWriter = &buf
|
|
t.Cleanup(func() { gin.DefaultWriter = prev })
|
|
|
|
r := gin.New()
|
|
r.Use(RequestLogger())
|
|
ok := func(c *gin.Context) { c.Status(http.StatusNoContent) }
|
|
r.POST("/api/v1/integrations/inbound/calendly/:secret", ok)
|
|
r.POST("/unsubscribe/:token/resubscribe", ok)
|
|
r.GET("/mailboxes/:remoteId/warmup-tokens/:token", ok)
|
|
r.GET("/invitations/lookup", ok)
|
|
r.POST("/cli-auth/codes/:code/approve", ok)
|
|
|
|
cases := []struct{ method, target, want, leak string }{
|
|
{"POST", "/api/v1/integrations/inbound/calendly/whsec-abc", "/api/v1/integrations/inbound/calendly/:secret", "whsec-abc"},
|
|
{"POST", "/unsubscribe/unsub-tok/resubscribe", "/unsubscribe/:token/resubscribe", "unsub-tok"},
|
|
{"GET", "/mailboxes/remote-7/warmup-tokens/warm-tok", "/mailboxes/remote-7/warmup-tokens/:token", "warm-tok"},
|
|
{"GET", "/invitations/lookup?token=invite-tok", "/invitations/lookup", "invite-tok"},
|
|
{"POST", "/cli-auth/codes/PAIR1234/approve", "/cli-auth/codes/:code/approve", "PAIR1234"},
|
|
}
|
|
for _, tc := range cases {
|
|
buf.Reset()
|
|
r.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest(tc.method, tc.target, nil))
|
|
line := buf.String()
|
|
if strings.Contains(line, tc.leak) {
|
|
t.Errorf("%s logged the credential: %q", tc.target, line)
|
|
}
|
|
if !strings.Contains(line, `"`+tc.want+`"`) {
|
|
t.Errorf("%s logged %q, want path %q", tc.target, line, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRequestLoggerReleaseRetainsFailuresAndMutations(t *testing.T) {
|
|
previousMode := gin.Mode()
|
|
gin.SetMode(gin.ReleaseMode)
|
|
t.Cleanup(func() { gin.SetMode(previousMode) })
|
|
var buf bytes.Buffer
|
|
previousWriter := gin.DefaultWriter
|
|
gin.DefaultWriter = &buf
|
|
t.Cleanup(func() { gin.DefaultWriter = previousWriter })
|
|
|
|
cases := []struct {
|
|
name, method, path string
|
|
status int
|
|
log bool
|
|
handlerError bool
|
|
}{
|
|
{"healthy probe", "GET", "/health", 200, false, false},
|
|
{"failed probe", "GET", "/health", 503, true, false},
|
|
{"successful internal lookup", "GET", "/api/v1/internal/sync/folder-messages", 200, false, false},
|
|
{"expected missing mapping", "GET", "/api/v1/internal/email-message-map", 404, false, false},
|
|
{"failed mapping lookup", "GET", "/api/v1/internal/email-message-map", 500, true, false},
|
|
{"bad lookup input", "GET", "/api/v1/internal/email-message-map", 400, true, false},
|
|
{"unauthorized lookup", "GET", "/api/v1/internal/email-message-map", 401, true, false},
|
|
{"forbidden lookup", "GET", "/api/v1/internal/email-message-map", 403, true, false},
|
|
{"other missing internal resource", "GET", "/api/v1/internal/sync/folder-messages", 404, true, false},
|
|
{"internal mutation", "PUT", "/api/v1/internal/email-message-map", 204, true, false},
|
|
{"ordinary successful request", "GET", "/v1/emails", 200, true, false},
|
|
{"ordinary missing resource", "GET", "/v1/emails", 404, true, false},
|
|
{"internal handler error with successful status", "GET", "/api/v1/internal/sync/folder-messages", 200, true, true},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
buf.Reset()
|
|
r := gin.New()
|
|
r.Use(RequestLogger())
|
|
r.Handle(tc.method, tc.path, func(c *gin.Context) {
|
|
if tc.handlerError {
|
|
_ = c.Error(http.ErrHandlerTimeout)
|
|
}
|
|
c.Status(tc.status)
|
|
})
|
|
r.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest(tc.method, tc.path, nil))
|
|
if logged := buf.Len() > 0; logged != tc.log {
|
|
t.Fatalf("logged = %v, want %v", logged, tc.log)
|
|
}
|
|
})
|
|
}
|
|
buf.Reset()
|
|
r := gin.New()
|
|
r.Use(RequestLogger())
|
|
r.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/api/v1/internal/unknown", nil))
|
|
if buf.Len() == 0 {
|
|
t.Fatal("unmatched internal route was not logged")
|
|
}
|
|
}
|
|
|
|
func TestRequestLoggerDebugKeepsRoutineLookups(t *testing.T) {
|
|
previousMode := gin.Mode()
|
|
gin.SetMode(gin.DebugMode)
|
|
t.Cleanup(func() { gin.SetMode(previousMode) })
|
|
var buf bytes.Buffer
|
|
previousWriter := gin.DefaultWriter
|
|
gin.DefaultWriter = &buf
|
|
t.Cleanup(func() { gin.DefaultWriter = previousWriter })
|
|
r := gin.New()
|
|
r.Use(RequestLogger())
|
|
r.GET("/api/v1/internal/email-message-map", func(c *gin.Context) { c.Status(404) })
|
|
buf.Reset()
|
|
r.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/api/v1/internal/email-message-map", nil))
|
|
if buf.Len() == 0 {
|
|
t.Fatal("debug mode did not log routine lookup")
|
|
}
|
|
}
|