set('app.exception_mail', null); }); test('reported exceptions reach glitchtip with the user id only', function () { $glitchTip = FakeGlitchTip::install(); $user = User::forceCreate(['email' => 'kunde@example.com', 'password' => bcrypt('secret'), 'lang' => 'de']); $this->actingAs($user); report(new RuntimeException('Import für kunde@example.com fehlgeschlagen')); expect($glitchTip->events)->toHaveCount(1); $event = $glitchTip->events[0]; expect($event->getUser()?->getId())->toBe($user->id) ->and($event->getUser()?->getEmail())->toBeNull() ->and($event->getExceptions()[0]->getValue())->toBe('Import für [email] fehlgeschlagen'); }); test('exceptions laravel does not report stay out of glitchtip', function () { $glitchTip = FakeGlitchTip::install(); $this->get('/diese/seite/gibt-es/nicht')->assertNotFound(); expect($glitchTip->events)->toBe([]); }); test('a mistyped artisan command is not reported', function () { $glitchTip = FakeGlitchTip::install(); report(new CommandNotFoundException('Command "config:cachels" is not defined.')); expect($glitchTip->events)->toBe([]); }); test('request data loses tokens, signatures and bodies', function () { $scrubbed = ErrorReportScrubber::scrubRequest([ 'url' => 'https://my.mivita.care/einladung/5?signature=abc123&expires=1700000000&page=2', 'query_string' => 'signature=abc123&expires=1700000000&page=2&utm_source=nl', 'data' => ['password' => 'geheim'], 'cookies' => ['mivita_session' => 'x'], 'headers' => ['referer' => ['https://my.mivita.care/password/reset/'.str_repeat('a', 64).'?email=kunde@example.com']], ]); expect($scrubbed['url'])->toBe('https://my.mivita.care/einladung/5?signature=%5BFiltered%5D&expires=%5BFiltered%5D&page=2') ->and($scrubbed['query_string'])->toBe('signature=%5BFiltered%5D&expires=%5BFiltered%5D&page=2&utm_source=nl') ->and($scrubbed)->not->toHaveKeys(['data', 'cookies']) ->and($scrubbed['headers']['referer'][0])->toBe('https://my.mivita.care/password/reset/[Filtered]?email=%5BFiltered%5D'); }); test('route parameters named like secrets are removed from the url', function () { Route::middleware('web')->get('/_test/monitoring/magic/{token}', function () { $event = Event::createEvent(); $event->setRequest(['url' => request()->fullUrl()]); return ErrorReportScrubber::beforeSend($event)?->getRequest()['url']; }); $this->get('/_test/monitoring/magic/kurz123') ->assertSuccessful() ->assertSee('/_test/monitoring/magic/[Filtered]', false) ->assertDontSee('kurz123'); }); test('messages and exception values lose e-mail addresses', function () { $event = Event::createEvent(); $event->setMessage('Bounce von info@firma.de', [], 'Bounce von info@firma.de'); $event->setExceptions([new ExceptionDataBag(new RuntimeException('Duplicate entry \'a.b@c.org\''))]); $scrubbed = ErrorReportScrubber::beforeSend($event); expect($scrubbed?->getMessage())->toBe('Bounce von [email]') ->and($scrubbed?->getMessageFormatted())->toBe('Bounce von [email]') ->and($scrubbed?->getExceptions()[0]->getValue())->toBe('Duplicate entry \'[email]\'') ->and($scrubbed?->getUser())->toBeNull(); }); test('the test suite never reports to the real glitchtip or ntfy', function () { // Ohne diese Absicherung landeten absichtlich provozierte Fehler // („Queue weg“, „Datenbank nicht erreichbar“) in GlitchTip bzw. als Push. expect(config('sentry.dsn'))->toBeEmpty() ->and(config('monitoring.browser.dsn'))->toBeEmpty() ->and(config('monitoring.alerts.ntfy.url'))->toBeEmpty() ->and(SentrySdk::getCurrentHub()->getClient()?->getOptions()->getDsn())->toBeNull(); });