Files
webmail/lib/error-reporting/__tests__/lite.test.ts
T
Linus Rath cba1109444 feat: report browser and server errors to an error tracker the admin sets
Admins had logs and nothing else: client errors only reached the
browser console. An admin can now set a Sentry-protocol address (DSN)
for Bugsink, GlitchTip or Sentry under System > Monitoring, or with
`ERROR_REPORTING_DSN`, `ERROR_REPORTING_DSN_FILE`,
`ERROR_REPORTING_SAMPLE_RATE` and `ERROR_REPORTING_ENVIRONMENT`.
Bulwark Lite reads the same from `errorReporting` in policy.json.
Everything stays off while no address is set.

- browsers report errors from the error boundaries, window.onerror,
  unhandled rejections and failed JMAP requests (method and error type
  only), with route and JMAP method breadcrumbs and the chunks' debug IDs
- the server reports what Next hands to onRequestError and what routes
  log with logger.error
- every report is scrubbed first: quoted text, addresses, URLs, file
  names, tokens and the rest after the first line are removed, and the
  server scrubs what browsers post to /api/errors again
- reports are deduplicated and rate-limited per session and process
- errors are counted per day for "errors today" on the admin page
- startup messages and audit entries go through the logger, so
  `LOG_FORMAT=json` covers them
2026-11-01 02:50:19 +01:00

22 lines
1.0 KiB
TypeScript

// @vitest-environment node
import { describe, expect, it } from 'vitest';
import { liteErrorReporting } from '../lite';
const DSN = 'https://6f0b9c79ed3a4315b76595bc2536ac40@errors.example.org/3';
// Bulwark Lite has no server: policy.json carries the error reporting address.
describe('Lite error reporting from policy.json', () => {
it('is off without a valid DSN', () => {
expect(liteErrorReporting({})).toBeNull();
expect(liteErrorReporting(null)).toBeNull();
expect(liteErrorReporting({ errorReporting: { dsn: 'not a dsn' } })).toBeNull();
});
it('reads the DSN, sample rate and environment, and never asks for server-side counting', () => {
expect(liteErrorReporting({ errorReporting: { dsn: DSN, sampleRate: 0.25, environment: 'lite-prod' } }))
.toEqual({ dsn: DSN, sampleRate: 0.25, environment: 'lite-prod', collect: false });
expect(liteErrorReporting({ errorReporting: { dsn: DSN, sampleRate: 7, environment: 'bad env!' } }))
.toEqual({ dsn: DSN, sampleRate: 1, environment: 'production', collect: false });
});
});