package reqid import ( "bytes" "context" "encoding/json" "log/slog" "net/http" "net/http/httptest" "strings" "testing" ) // The id is ours. An id echoed from the caller lets them stamp their own value on our lines and // correlate — or collide with — someone else's. Mutation caught: reading the header from the // request when it is present. func TestRequestIDIsNeverTakenFromTheCaller(t *testing.T) { var seen string h := Middleware(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { seen = FromContext(r.Context()) })) req := httptest.NewRequest(http.MethodGet, "/", nil) req.Header.Set(Header, "attacker-supplied") rec := httptest.NewRecorder() h.ServeHTTP(rec, req) if seen == "" { t.Fatal("no id was stamped") } if seen == "attacker-supplied" || rec.Header().Get(Header) == "attacker-supplied" { t.Fatal("the caller's id was adopted") } if rec.Header().Get(Header) != seen { t.Fatalf("the echoed id %q is not the one in the context %q", rec.Header().Get(Header), seen) } } // Every *Context log call inside a request carries the id without the call site saying so — which // is the point: the error paths that need correlating are the ones nobody remembers to annotate. func TestLogRecordsCarryTheRequestID(t *testing.T) { var buf bytes.Buffer log := slog.New(WithContext(slog.NewJSONHandler(&buf, nil))) h := Middleware(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { log.With("layer", "test").ErrorContext(r.Context(), "something failed") })) h.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest(http.MethodGet, "/", nil)) var rec map[string]any if err := json.Unmarshal(bytes.TrimSpace(buf.Bytes()), &rec); err != nil { t.Fatalf("log line: %v (%s)", err, buf.String()) } if id, _ := rec[Key].(string); id == "" { t.Fatalf("no %s on the record: %s", Key, buf.String()) } if rec["layer"] != "test" { t.Fatalf("the wrapper dropped attributes added with With: %s", buf.String()) } // Outside a request there is nothing to add, and the handler must not invent one. buf.Reset() log.ErrorContext(context.Background(), "background failure") if strings.Contains(buf.String(), Key) { t.Fatalf("an id appeared outside a request: %s", buf.String()) } }