Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/selfhost/sentry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,18 @@ const SUMMARY_SKIP_KEYS = new Set([
function summarizeLogFields(obj: Record<string, unknown>): string {
return Object.entries(obj)
.filter(([k, v]) => !SUMMARY_SKIP_KEYS.has(k) && v !== null)
.map(([k, v]) => `${k}=${typeof v === "object" ? JSON.stringify(v) : String(v)}`)
.map(([k, v]) => `${k}=${summarizeLogFieldValue(k, v)}`)
.filter((part) => part.length <= 90) // a long blob (id/body) belongs in the context, not the title
.slice(0, 5) // a few salient fields, not a dump
.join(", ");
}

function summarizeLogFieldValue(key: string, value: unknown): string {
if (SECRET_KEY.test(key)) return "[redacted]";
if (typeof value !== "object") return String(value);
return JSON.stringify(scrubEvent({ extra: structuredClone(value) }).extra);
}

/** Forward a structured console line to Sentry when it is an ERROR-level log. The engine logs operational
* failures (orb_broker_unavailable, gate-check errors, relay drops, …) as JSON strings, often via console.error.
* No-op when Sentry is off, the line isn't a JSON object string, or its level isn't error/fatal — routine logs
Expand Down
19 changes: 19 additions & 0 deletions test/unit/selfhost-sentry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,25 @@ describe("forwardStructuredLogToSentry — central console.log → Sentry error
"project=JSONbored/gittensory, closePrecision=0.6, floor=0.8",
);
});

it("redacts secret-keyed values in field-only error summaries (regression)", async () => {
await initSentry({ SENTRY_DSN: "d" } as unknown as NodeJS.ProcessEnv);
forwardStructuredLogToSentry(
JSON.stringify({
level: "error",
event: "field_only_secret",
apiKey: "sensitive-value",
password: "sensitive-value",
project: "demo",
details: { authToken: "nested-sensitive", count: 2 },
}),
);

expect(lastCapturedError().name).toBe("field_only_secret");
expect(lastCapturedError().message).toBe(
'apiKey=[redacted], password=[redacted], project=demo, details={"authToken":"[redacted]","count":2}',
);
});
});

describe("installStructuredLogForwarding — central console sink instrumentation (#1468)", () => {
Expand Down
Loading