WS-7 Observability — closure #8

Merged
bert.hausmans merged 30 commits from feat/ws-7-observability into main 2026-05-07 22:49:31 +02:00
3 changed files with 18 additions and 14 deletions
Showing only changes of commit 5980c36ae4 - Show all commits

View File

@@ -44,7 +44,7 @@ final class SentryEventScrubber
private const MAX_DEPTH = 10;
public function scrub(Event $event, ?EventHint $hint = null): ?Event
public static function scrub(Event $event, ?EventHint $hint = null): ?Event
{
if ($hint?->exception instanceof HttpException && $hint->exception->getStatusCode() < 500) {
return null;
@@ -54,9 +54,9 @@ final class SentryEventScrubber
if ($request !== []) {
$event->setRequest(array_merge($request, [
'data' => $this->scrubBody($request['data'] ?? []),
'headers' => $this->scrubHeaders($request['headers'] ?? []),
'query_string' => $this->scrubQueryString($request['query_string'] ?? ''),
'data' => self::scrubBody($request['data'] ?? []),
'headers' => self::scrubHeaders($request['headers'] ?? []),
'query_string' => self::scrubQueryString($request['query_string'] ?? ''),
'cookies' => self::SCRUBBED,
]));
}
@@ -68,7 +68,7 @@ final class SentryEventScrubber
* @param mixed $data
* @return mixed
*/
private function scrubBody($data, int $depth = 0)
private static function scrubBody($data, int $depth = 0)
{
if (! is_array($data)) {
return $data;
@@ -92,7 +92,7 @@ final class SentryEventScrubber
}
if (is_array($value)) {
$data[$key] = $this->scrubBody($value, $depth + 1);
$data[$key] = self::scrubBody($value, $depth + 1);
}
}
@@ -103,7 +103,7 @@ final class SentryEventScrubber
* @param array<string, mixed>|string $headers
* @return array<string, mixed>|string
*/
private function scrubHeaders($headers)
private static function scrubHeaders($headers)
{
if (! is_array($headers)) {
return $headers;
@@ -118,7 +118,7 @@ final class SentryEventScrubber
return $headers;
}
private function scrubQueryString(string $queryString): string
private static function scrubQueryString(string $queryString): string
{
if ($queryString === '') {
return '';

View File

@@ -25,8 +25,12 @@ return [
// When left empty or `null` the Laravel environment will be used (usually discovered from `APP_ENV` in your `.env`)
'environment' => env('SENTRY_ENVIRONMENT', env('APP_ENV')),
// Crewli observability scrubber (RFC-WS-7 §3.7).
'before_send' => static fn (\Sentry\Event $event, ?\Sentry\EventHint $hint = null): ?\Sentry\Event => app(\App\Services\Observability\SentryEventScrubber::class)->scrub($event, $hint),
// RFC-WS-7 §3.7 — stateless static method + array notation.
// Configuration is declarative (a reference, not executable logic);
// container-resolution per event would be overhead without value for
// stateless scrubbing, and stack traces show the class name instead of
// an anonymous closure frame.
'before_send' => [\App\Services\Observability\SentryEventScrubber::class, 'scrub'],
// Errors-only — RFC §2 amendment B explicitly excludes performance tracing.
// Force traces/profiles off regardless of env.

View File

@@ -25,7 +25,7 @@ final class PiiScrubbingTest extends TestCase
$event = Event::createEvent();
$event->setRequest($request);
return (new SentryEventScrubber)->scrub($event, $hint);
return SentryEventScrubber::scrub($event, $hint);
}
public function test_password_in_request_body_is_scrubbed(): void
@@ -171,7 +171,7 @@ final class PiiScrubbingTest extends TestCase
$event = Event::createEvent();
$hint = EventHint::fromArray(['exception' => new NotFoundHttpException]);
$this->assertNull((new SentryEventScrubber)->scrub($event, $hint));
$this->assertNull(SentryEventScrubber::scrub($event, $hint));
}
public function test_http_exception_500_is_captured(): void
@@ -179,7 +179,7 @@ final class PiiScrubbingTest extends TestCase
$event = Event::createEvent();
$hint = EventHint::fromArray(['exception' => new HttpException(500, 'boom')]);
$this->assertNotNull((new SentryEventScrubber)->scrub($event, $hint));
$this->assertNotNull(SentryEventScrubber::scrub($event, $hint));
}
public function test_throwable_from_controller_is_captured(): void
@@ -187,7 +187,7 @@ final class PiiScrubbingTest extends TestCase
$event = Event::createEvent();
$hint = EventHint::fromArray(['exception' => new RuntimeException('programmer error')]);
$this->assertNotNull((new SentryEventScrubber)->scrub($event, $hint));
$this->assertNotNull(SentryEventScrubber::scrub($event, $hint));
}
public function test_form_values_replacement_blocks_attempts_to_smuggle_pii(): void