From 7c2b0689b6d105f1d72afd180a564c639b449c90 Mon Sep 17 00:00:00 2001 From: Sourav P Bijoy <71513365+Phloraxx@users.noreply.github.com> Date: Mon, 27 Jul 2026 15:45:49 +0530 Subject: [PATCH 1/5] Restrict libgm production log level --- internal/gmessages/logging.go | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 internal/gmessages/logging.go diff --git a/internal/gmessages/logging.go b/internal/gmessages/logging.go new file mode 100644 index 0000000..f358b21 --- /dev/null +++ b/internal/gmessages/logging.go @@ -0,0 +1,11 @@ +package gmessages + +import "github.com/rs/zerolog" + +// libgmLogger deliberately suppresses libgm Trace/Debug output. Upstream uses +// those levels for encoded HTTP/protobuf response bodies, which can contain +// private Google Messages data and should never be retained in production logs. +// Info and above keep connection lifecycle and actionable failures visible. +func libgmLogger(logger zerolog.Logger, component string) zerolog.Logger { + return logger.Level(zerolog.InfoLevel).With().Str("component", component).Logger() +} From 34d49446d2457e5de433475e98578ead4ea7decf Mon Sep 17 00:00:00 2001 From: Sourav P Bijoy <71513365+Phloraxx@users.noreply.github.com> Date: Mon, 27 Jul 2026 15:46:11 +0530 Subject: [PATCH 2/5] Test libgm log redaction level --- internal/gmessages/logging_test.go | 32 ++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 internal/gmessages/logging_test.go diff --git a/internal/gmessages/logging_test.go b/internal/gmessages/logging_test.go new file mode 100644 index 0000000..250207d --- /dev/null +++ b/internal/gmessages/logging_test.go @@ -0,0 +1,32 @@ +package gmessages + +import ( + "bytes" + "strings" + "testing" + + "github.com/rs/zerolog" +) + +func TestLibGMLoggerSuppressesTraceAndDebug(t *testing.T) { + var output bytes.Buffer + base := zerolog.New(&output).Level(zerolog.TraceLevel) + logger := libgmLogger(base, "libgm") + + logger.Trace().Str("response_body", "sensitive-trace").Msg("trace message") + logger.Debug().Str("response_body", "sensitive-debug").Msg("debug message") + logger.Info().Msg("connection lifecycle") + logger.Warn().Msg("actionable warning") + + got := output.String() + for _, forbidden := range []string{"sensitive-trace", "sensitive-debug", "trace message", "debug message"} { + if strings.Contains(got, forbidden) { + t.Fatalf("libgm logger emitted suppressed content %q: %s", forbidden, got) + } + } + for _, wanted := range []string{"connection lifecycle", "actionable warning", `"component":"libgm"`} { + if !strings.Contains(got, wanted) { + t.Fatalf("libgm logger missing %q: %s", wanted, got) + } + } +} From 62a4b2ec07a656aaed37bb17e294d39eb8f48dfe Mon Sep 17 00:00:00 2001 From: Sourav P Bijoy <71513365+Phloraxx@users.noreply.github.com> Date: Mon, 27 Jul 2026 15:50:46 +0530 Subject: [PATCH 3/5] Expose safe Google Messages production logger --- internal/gmessages/logging.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/gmessages/logging.go b/internal/gmessages/logging.go index f358b21..6ccb54d 100644 --- a/internal/gmessages/logging.go +++ b/internal/gmessages/logging.go @@ -2,10 +2,10 @@ package gmessages import "github.com/rs/zerolog" -// libgmLogger deliberately suppresses libgm Trace/Debug output. Upstream uses -// those levels for encoded HTTP/protobuf response bodies, which can contain -// private Google Messages data and should never be retained in production logs. -// Info and above keep connection lifecycle and actionable failures visible. -func libgmLogger(logger zerolog.Logger, component string) zerolog.Logger { - return logger.Level(zerolog.InfoLevel).With().Str("component", component).Logger() +// ProductionLogger suppresses Trace/Debug output before a logger is handed to +// libgm. Upstream uses those levels for encoded HTTP/protobuf response bodies, +// which can contain private Google Messages data and must not be retained in +// production logs. Info and above keep lifecycle and actionable failures visible. +func ProductionLogger(logger zerolog.Logger) zerolog.Logger { + return logger.Level(zerolog.InfoLevel) } From b96a0e6dc9234cc72d4e2d58933127f2aa13aacd Mon Sep 17 00:00:00 2001 From: Sourav P Bijoy <71513365+Phloraxx@users.noreply.github.com> Date: Mon, 27 Jul 2026 15:52:10 +0530 Subject: [PATCH 4/5] Test production logger suppresses sensitive levels --- internal/gmessages/logging_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/gmessages/logging_test.go b/internal/gmessages/logging_test.go index 250207d..1e67016 100644 --- a/internal/gmessages/logging_test.go +++ b/internal/gmessages/logging_test.go @@ -8,10 +8,10 @@ import ( "github.com/rs/zerolog" ) -func TestLibGMLoggerSuppressesTraceAndDebug(t *testing.T) { +func TestProductionLoggerSuppressesTraceAndDebug(t *testing.T) { var output bytes.Buffer base := zerolog.New(&output).Level(zerolog.TraceLevel) - logger := libgmLogger(base, "libgm") + logger := ProductionLogger(base).With().Str("component", "libgm").Logger() logger.Trace().Str("response_body", "sensitive-trace").Msg("trace message") logger.Debug().Str("response_body", "sensitive-debug").Msg("debug message") @@ -21,12 +21,12 @@ func TestLibGMLoggerSuppressesTraceAndDebug(t *testing.T) { got := output.String() for _, forbidden := range []string{"sensitive-trace", "sensitive-debug", "trace message", "debug message"} { if strings.Contains(got, forbidden) { - t.Fatalf("libgm logger emitted suppressed content %q: %s", forbidden, got) + t.Fatalf("production logger emitted suppressed content %q: %s", forbidden, got) } } for _, wanted := range []string{"connection lifecycle", "actionable warning", `"component":"libgm"`} { if !strings.Contains(got, wanted) { - t.Fatalf("libgm logger missing %q: %s", wanted, got) + t.Fatalf("production logger missing %q: %s", wanted, got) } } } From c71688ef2d93f80de9f858b3af4beb800dbc658d Mon Sep 17 00:00:00 2001 From: Sourav P Bijoy <71513365+Phloraxx@users.noreply.github.com> Date: Mon, 27 Jul 2026 15:54:00 +0530 Subject: [PATCH 5/5] Clamp Google Messages production logging to info --- cmd/payment-api/main.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/payment-api/main.go b/cmd/payment-api/main.go index 4739089..bb23040 100644 --- a/cmd/payment-api/main.go +++ b/cmd/payment-api/main.go @@ -38,18 +38,19 @@ func main() { migratecmd.MustRegister(app, app.RootCmd, migratecmd.Config{Automigrate: false}) zeroLogger := zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: "15:04:05"}).With().Timestamp().Logger() + gmessagesLogger := gmessages.ProductionLogger(zeroLogger) stdLogger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo})) webhookService := webhooks.NewService(app, cfg) webhookService.Logger = stdLogger paymentService := payments.NewService(app, cfg, webhookService) smsService := sms.NewService(app, paymentService) - gmessagesManager := gmessages.NewManager(cfg, zeroLogger, func(input sms.Input) error { + gmessagesManager := gmessages.NewManager(cfg, gmessagesLogger, func(input sms.Input) error { _, err := smsService.Ingest(input) return err }) api.New(cfg, paymentService, smsService, gmessagesManager).Register(app) - registerPairCommand(app, cfg, zeroLogger) + registerPairCommand(app, cfg, gmessagesLogger) registerHealthcheckCommand(app) rootCtx, rootCancel := context.WithCancel(context.Background())