fix: error-only Sentry telemetry, storm-proof capture, and crash fixes (#476)

Removes Sentry tracing entirely (BullMQ idle polling burned 4.8M transactions in 2 days at the baked 0.1 rate), decouples PostHog sampling, and replaces the type-only error scrub with a vetted-field sanitizer plus SafeError/ToolInputError contracts. One classified capture path with per-signature throttles and a per-process ceiling makes storms impossible (NODE-1E was 4,541 events from one 30s loop). Browser errors move to a dedicated web Sentry project with their own source maps. Adds the SNAPOTTER_TELEMETRY runtime kill switch and silences test fleets.

Crash fixes: remote 204/304 SSRF process kill (NODE-20), conversion-preset boot crash loop (NODE-21), Redis version preflight + unhandled subscribe rejection (NODE-1T), Sign PDF on plain-http origins (NODE-1K/1M), wavesurfer/pdf.js teardown rejections (NODE-1P/1N), bundle-import ZlibError to 400 (NODE-1Z), chart-maker input errors declassified (NODE-1H/1J), asset requests skip the session DB lookup (NODE-1D).
This commit is contained in:
SnapOtter
2026-07-10 21:41:49 +08:00
committed by GitHub
parent 3d1744aec8
commit ae6a4c8b7c
75 changed files with 2198 additions and 260 deletions
+64 -4
View File
@@ -47,7 +47,8 @@ const enabledConfig = {
posthogApiKey: "phc_test",
posthogHost: "https://ph.test",
sentryDsn: "https://sentry.test/123",
sampleRate: 1,
sentryDsnWeb: "https://sentry.test/web/456",
posthogSampleRate: 1,
instanceId: "inst-1",
};
@@ -56,7 +57,8 @@ const disabledConfig = {
posthogApiKey: "",
posthogHost: "",
sentryDsn: "",
sampleRate: 0,
sentryDsnWeb: "",
posthogSampleRate: 0,
instanceId: "",
};
@@ -68,6 +70,7 @@ describe("Analytics No-Leak Invariant (baked model)", () => {
mockPosthogInit.mockClear();
mockCapture.mockClear();
mockSentryInit.mockClear();
mockBrowserTracingIntegration.mockClear();
vi.resetModules();
mod = await import("../../../apps/web/src/lib/analytics");
});
@@ -103,18 +106,75 @@ describe("Analytics No-Leak Invariant (baked model)", () => {
expect(mockCapture).toHaveBeenCalledWith("tool_opened", { tool_id: "resize" });
});
it("initAnalytics initializes Sentry when sentryDsn provided", async () => {
it("initAnalytics initializes Sentry with the web DSN when sentryDsnWeb provided", async () => {
await mod.initAnalytics(enabledConfig);
expect(mockSentryInit).toHaveBeenCalledOnce();
expect(mockSentryInit).toHaveBeenCalledWith(
expect.objectContaining({
dsn: "https://sentry.test/123",
dsn: "https://sentry.test/web/456",
sendDefaultPii: false,
}),
);
});
});
describe("errors-only web Sentry init", () => {
async function getSentryOptions() {
await mod.initAnalytics(enabledConfig);
return mockSentryInit.mock.calls[0]?.[0];
}
it("passes no tracesSampleRate and never constructs a tracing integration", async () => {
const options = await getSentryOptions();
expect(options).toBeDefined();
expect("tracesSampleRate" in options).toBe(false);
expect("tracesSampler" in options).toBe(false);
expect(mockBrowserTracingIntegration).not.toHaveBeenCalled();
});
it("disables SDK client reports", async () => {
const options = await getSentryOptions();
expect(options.sendClientReports).toBe(false);
});
it("filters the release-health session integration out of the defaults", async () => {
const options = await getSentryOptions();
const filtered = options.integrations([{ name: "BrowserSession" }, { name: "Dedupe" }]);
expect(filtered).toEqual([{ name: "Dedupe" }]);
});
it("does not init Sentry when sentryDsnWeb is empty even if sentryDsn is set", async () => {
await mod.initAnalytics({ ...enabledConfig, sentryDsnWeb: "" });
expect(mockSentryInit).not.toHaveBeenCalled();
});
});
describe("web-DSN-only init (no PostHog key)", () => {
const sentryOnlyConfig = { ...enabledConfig, posthogApiKey: "", posthogHost: "" };
it("skips posthog.init entirely but still initializes Sentry", async () => {
await mod.initAnalytics(sentryOnlyConfig);
expect(mockPosthogInit).not.toHaveBeenCalled();
expect(mockSentryInit).toHaveBeenCalledOnce();
expect(mockSentryInit).toHaveBeenCalledWith(
expect.objectContaining({ dsn: "https://sentry.test/web/456" }),
);
});
it("keeps beforeSend active: error events still pass the enabled gate", async () => {
await mod.initAnalytics(sentryOnlyConfig);
const beforeSend = mockSentryInit.mock.calls[0]?.[0]?.beforeSend;
expect(beforeSend).toBeDefined();
const result = beforeSend({
exception: { values: [{ type: "TypeError", value: "boom" }] },
});
// A null here would mean the enabled gate never opened for a web-DSN-only
// bake; the event must survive (scrubbed to type-only).
expect(result).not.toBeNull();
expect(result.exception.values[0].value).toBe("TypeError");
});
});
describe("PII never leaks even when analytics enabled", () => {
it("Sentry strips the entire user object from events", async () => {
await mod.initAnalytics(enabledConfig);