fix: retain conversation ownership across blank paragraphs

This commit is contained in:
2026-10-10 01:51:14 +08:00
parent 8f3026e459
commit b093f4d026
2 changed files with 29 additions and 7 deletions
+2 -5
View File
@@ -130,11 +130,8 @@ func redactConversationLines(body string) string {
lines := strings.SplitAfter(body, "\n")
hiding := false
for i, line := range lines {
trimmed := strings.TrimSpace(line)
if hiding && trimmed == "" {
hiding = false
continue
}
// Whitespace separates paragraphs inside a conversation, not records.
// Ownership ends only at the explicit non-conversation field below.
field := textFieldLine.FindStringSubmatch(line)
if hiding {
// Continuation lines and conversation speaker labels are not business
+27 -2
View File
@@ -29,6 +29,31 @@ func TestAssociatedSensitiveControlsHideContentWithoutSwallowingBusiness(t *test
}
}
func TestConversationOwnershipPersistsAcrossBlankLines(t *testing.T) {
for _, gap := range []string{"\n", "\n\n", "\n \n\t\n", "\r\n\r\n"} {
for _, label := range []string{"messages", "prompt", "transcript", "content"} {
value := "upstream failed\n" + label + ":" + gap + "user: private-user-turn" + gap + "assistant: private-assistant-turn" + gap + "status=retry_pending\nattempts=2"
for _, debug := range []bool{false, true} {
out := installTestLogger(t, debug)
slog.Error("operation failed", "error", errors.New(value), "detail", value)
slog.Info(value, "stage", "failure_observed")
TextBody(t.Context(), "HTTP text observed", []byte(value), "transport", "http")
text := out.String()
for _, secret := range []string{"private-user-turn", "private-assistant-turn"} {
if strings.Contains(text, secret) {
t.Fatalf("label %s gap %q debug %v leak: %s", label, gap, debug, text)
}
}
for _, keep := range []string{"upstream failed", "retry_pending", "attempts=2"} {
if !strings.Contains(text, keep) {
t.Fatal("business diagnostics lost", text)
}
}
}
}
}
}
func TestFreeTextConversationIsHiddenInBothModesAndAllScalarPaths(t *testing.T) {
value := "upstream failed\nmessages:\nuser: private-user-turn\nassistant: private-assistant-turn\n\nstatus=retry_pending\nattempts=2"
for _, debug := range []bool{false, true} {
@@ -103,7 +128,7 @@ func TestReadableMarkupFormAndMultilineConversationAreSanitized(t *testing.T) {
}
func TestReadablePlainHTTPBodiesAreObservedSafelyWithoutChangingBytes(t *testing.T) {
body := "status=ready\ntask_id=4\nremaining=27\nAuthorization: Basic dXNlcjpwYXNzd29yZA==\napi_key=private-key\n-----BEGIN PRIVATE KEY-----\nprivate-pem-material\n-----END PRIVATE KEY-----\nretry_after=60\n" + strings.Repeat("business-data ", 12000)
body := "status=ready\ntask_id=4\nremaining=27\nmessages:\n\nuser: private-http-user-turn\n\nassistant: private-http-assistant-turn\n\nstatus=ready\nAuthorization: Basic dXNlcjpwYXNzd29yZA==\napi_key=private-key\n-----BEGIN PRIVATE KEY-----\nprivate-pem-material\n-----END PRIVATE KEY-----\nretry_after=60\n" + strings.Repeat("business-data ", 12000)
for _, debug := range []bool{false, true} {
out := installTestLogger(t, debug)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -127,7 +152,7 @@ func TestReadablePlainHTTPBodiesAreObservedSafelyWithoutChangingBytes(t *testing
t.Fatal("response changed", err)
}
text := out.String()
for _, secret := range []string{"dXNlcjpwYXNzd29yZA==", "private-key", "private-pem-material"} {
for _, secret := range []string{"dXNlcjpwYXNzd29yZA==", "private-key", "private-pem-material", "private-http-user-turn", "private-http-assistant-turn"} {
if strings.Contains(text, secret) {
t.Fatalf("leak %s", secret)
}