Keep the entrypoint UUID out of webhooker's own logs (closes #531)
check / check (push) Canceled after 0s

On the receiver route the access log and the per-entrypoint 429 line
name the route pattern whatever the status. The received line names
the entrypoint and webhook IDs, and the unknown-entrypoint line logs
no path. The pattern is middleware.ReceiverRoute, which routes.go
registers the receiver with.

The README says the proxy's access log holds the UUID and must be
protected like the URL, and its access-log, rate-limit, Sentry and
log-size passages now match the code.

Model: opus-5-5
This commit is contained in:
2026-10-15 08:19:10 +00:00
parent 573f7f986a
commit e2b64c0a66
10 changed files with 265 additions and 161 deletions
+8 -49
View File
@@ -1,19 +1,15 @@
package handlers_test
// The handler-side half of the log-field audit. Two slog calls in
// this package reach a value an UNAUTHENTICATED client picks outright
// and of a length it picks outright:
// The handler-side half of the log-field audit. The slog calls in
// this package that reach a value an UNAUTHENTICATED client picks
// outright, and of a length it picks outright, are the failed-login
// DEBUG lines, whose username is a form field.
//
// - the unknown-entrypoint DEBUG line on /h/{uuid}, whose
// path segment matched no stored entrypoint and so is bounded by
// nothing;
// - the failed-login DEBUG lines, whose username is a form field.
//
// Both are at DEBUG, which is off in production by default. That is
// They are at DEBUG, which is off in production by default. That is
// not a bound: an operator turning DEBUG on to diagnose a flood must
// not thereby hand the flood an unbounded write. Both spend the same
// internal/logfield budget as the access log, and both are held here
// to middleware.MaxAccessLogLineBytes.
// not thereby hand the flood an unbounded write. They spend the same
// internal/logfield budget as the access log, and are held here to
// middleware.MaxAccessLogLineBytes.
//
// The two login lines past the username lookup — "invalid password"
// and "user logged in" — carry the same cap without needing it, since
@@ -260,43 +256,6 @@ func postLoginWithPassword(
return w.Code
}
// TestUnknownEntrypoint_LogLineDoesNotTrackPathSize drives 8 KB of
// client-chosen path at the unauthenticated receiver's
// unknown-entrypoint DEBUG line and holds it to the same ceiling the
// access log states.
func TestUnknownEntrypoint_LogLineDoesNotTrackPathSize(t *testing.T) {
t.Parallel()
for handlerName, newHandler := range logHandlers() {
for fillName, fill := range escapeFills() {
t.Run(handlerName+"/"+fillName, func(t *testing.T) {
t.Parallel()
h, buf := capturingHandlers(t, newHandler)
router := receiverRouter(h)
for i := range floodRequests {
assert.Equal(
t,
http.StatusNotFound,
postReceiver(
t, router,
oversizedFill(fill)+
strings.Repeat("y", i),
),
)
}
lines := logLines(t, buf)
require.Len(t, lines, floodRequests)
assertNoClientText(t, buf)
assertBoundedFlood(t, buf.Len())
})
}
}
}
// TestFailedLogin_LogLineDoesNotTrackUsernameSize drives 8 KB of
// client-chosen username at the unauthenticated login endpoint's
// DEBUG line and holds it to the same ceiling.