diff --git a/.env b/.env index f01661783..f3a2d03cf 100644 --- a/.env +++ b/.env @@ -45,7 +45,6 @@ MAIL_RECIPIENTS=info@e-tib.com # ──────────────────────────────────────────────────────────────────────────── LOG_LEVEL=info GATEKEEPER_PASSWORD=klz2026 -SENTRY_DSN= # SENTRY_ENVIRONMENT is set automatically by CI # ──────────────────────────────────────────────────────────────────────────── diff --git a/.env.example b/.env.example index 5af928604..204bfbfb2 100644 --- a/.env.example +++ b/.env.example @@ -45,7 +45,6 @@ MAIL_RECIPIENTS=info@e-tib.com # ──────────────────────────────────────────────────────────────────────────── LOG_LEVEL=info GATEKEEPER_PASSWORD=klz2026 -SENTRY_DSN= # SENTRY_ENVIRONMENT is set automatically by CI # ──────────────────────────────────────────────────────────────────────────── diff --git a/.env.production b/.env.production index 1b34c8d0f..60acfc2da 100644 --- a/.env.production +++ b/.env.production @@ -16,7 +16,7 @@ UMAMI_WEBSITE_ID=d773ea10-a3b3-4ccf-9024-987e14c4d669 UMAMI_API_ENDPOINT=https://analytics.infra.mintel.me # Error Tracking (GlitchTip/Sentry) -SENTRY_DSN= +SENTRY_DSN=https://dcb81958-dbf2-4a3d-b422-875f4672c14b@glitchtip.infra.mintel.me/5 # Email Configuration (Mailgun) MAIL_HOST=smtp.eu.mailgun.org diff --git a/lib/services/create-services.ts b/lib/services/create-services.ts index ed3c396ba..8800c2a64 100644 --- a/lib/services/create-services.ts +++ b/lib/services/create-services.ts @@ -2,6 +2,7 @@ import { AppServices } from './app-services'; import { NoopAnalyticsService } from './analytics/noop-analytics-service'; import { UmamiAnalyticsService } from './analytics/umami-analytics-service'; import { MemoryCacheService } from './cache/memory-cache-service'; +import { GlitchtipErrorReportingService } from './errors/glitchtip-error-reporting-service'; import { NoopErrorReportingService } from './errors/noop-error-reporting-service'; import { NoopLoggerService } from './logging/noop-logger-service'; import { PinoLoggerService } from './logging/pino-logger-service'; @@ -67,7 +68,17 @@ export function getAppServices(): AppServices { logger.info('Notification service initialized (noop)'); // Create error reporting service (GlitchTip/Sentry or no-op) - const errors = new NoopErrorReportingService(); + const errors = sentryEnabled + ? new GlitchtipErrorReportingService( + { + enabled: true, + dsn: config.errors.glitchtip.dsn, + tracesSampleRate: 0.1, // Client-side we usually want lower sample rate + }, + logger, + notifications, + ) + : new NoopErrorReportingService(); if (sentryEnabled) { logger.info( diff --git a/tests/create-services.test.ts b/tests/create-services.test.ts new file mode 100644 index 000000000..99340caba --- /dev/null +++ b/tests/create-services.test.ts @@ -0,0 +1,26 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { getAppServices } from '../lib/services/create-services'; +import { GlitchtipErrorReportingService } from '../lib/services/errors/glitchtip-error-reporting-service'; + +// Mock config to ensure sentry is enabled +vi.mock('../lib/config', () => ({ + config: { + analytics: { umami: { enabled: false } }, + errors: { glitchtip: { enabled: true, dsn: 'https://test@glitchtip.infra.mintel.me/5' } }, + logging: { level: 'info' }, + notifications: { gotify: { enabled: false } }, + }, + getMaskedConfig: () => ({}), +})); + +describe('AppServices (Client)', () => { + beforeEach(() => { + // Reset singleton + globalThis.__appServices = undefined; + }); + + it('should instantiate GlitchtipErrorReportingService when enabled', () => { + const services = getAppServices(); + expect(services.errors).toBeInstanceOf(GlitchtipErrorReportingService); + }); +}); diff --git a/tests/sentry-config.test.ts b/tests/sentry-config.test.ts new file mode 100644 index 000000000..508787505 --- /dev/null +++ b/tests/sentry-config.test.ts @@ -0,0 +1,20 @@ +import { readFileSync } from 'fs'; +import { resolve } from 'path'; +import { describe, it, expect } from 'vitest'; +import * as dotenv from 'dotenv'; + +describe('Sentry Configuration', () => { + it('should have a valid SENTRY_DSN in .env', () => { + // Read the .env file as a string + const envPath = resolve(process.cwd(), '.env'); + const envContent = readFileSync(envPath, 'utf8'); + + // Parse it using dotenv + const envConfig = dotenv.parse(envContent); + + // Assert that SENTRY_DSN is defined and not empty + expect(envConfig.SENTRY_DSN).toBeDefined(); + expect(envConfig.SENTRY_DSN.length).toBeGreaterThan(0); + expect(envConfig.SENTRY_DSN).toMatch(/^https:\/\/.+@glitchtip.infra.mintel.me\/\d+$/); + }); +});