| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- <?php
- declare(strict_types=1);
- namespace App\Tests\Unit\Logging;
- use App\Logging\SecretScrubbingProcessor;
- use Monolog\Formatter\JsonFormatter;
- use Monolog\Level;
- use Monolog\LogRecord;
- use PHPUnit\Framework\TestCase;
- final class SecretScrubbingProcessorTest extends TestCase
- {
- public function testBearerTokenInContextIsScrubbed(): void
- {
- $processor = new SecretScrubbingProcessor();
- $record = $this->record('outbound api call', [
- 'authorization' => 'Bearer irdb_svc_ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
- ]);
- $out = $processor($record);
- self::assertSame('***', $out->context['authorization']);
- }
- public function testFormattedOutputDoesNotLeakBearerToken(): void
- {
- $processor = new SecretScrubbingProcessor();
- $record = $this->record('outbound', [
- 'headers' => ['Authorization' => 'Bearer irdb_svc_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'],
- ]);
- $out = $processor($record);
- $line = (new JsonFormatter())->format($out);
- self::assertStringNotContainsString('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', $line);
- self::assertStringContainsString('***', $line);
- }
- public function testLocalAdminPasswordHashKeyScrubbed(): void
- {
- $processor = new SecretScrubbingProcessor();
- $record = $this->record('config', [
- 'LOCAL_ADMIN_PASSWORD_HASH' => '$argon2id$v=19$abc$def',
- 'OIDC_CLIENT_SECRET' => 'oidc-secret',
- ]);
- $out = $processor($record);
- self::assertSame('***', $out->context['LOCAL_ADMIN_PASSWORD_HASH']);
- self::assertSame('***', $out->context['OIDC_CLIENT_SECRET']);
- }
- public function testNonSensitiveLeftAlone(): void
- {
- $processor = new SecretScrubbingProcessor();
- $record = $this->record('search ok', ['count' => 42, 'q' => '203.0.113.42']);
- $out = $processor($record);
- self::assertSame(42, $out->context['count']);
- self::assertSame('203.0.113.42', $out->context['q']);
- }
- public function testRawJwtInValueIsScrubbed(): void
- {
- // SEC_REVIEW F65: JWTs anchored on `eyJ` (base64url of `{"`)
- // are scrubbed regardless of the key they're logged under.
- $processor = new SecretScrubbingProcessor();
- $jwt = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI3In0.qj8u_Mt1ZyT5PfksI91X4Aaa';
- $record = $this->record('oidc id_token captured', ['jwt' => $jwt]);
- $out = $processor($record);
- self::assertSame('eyJ***', $out->context['jwt']);
- }
- public function testShortBearerIsScrubbed(): void
- {
- // SEC_REVIEW F65: Bearer floor lowered from {20,} to {8,}.
- $processor = new SecretScrubbingProcessor();
- $record = $this->record('outbound', ['auth' => 'Bearer abcd1234']);
- $out = $processor($record);
- self::assertSame('Bearer ***', $out->context['auth']);
- }
- /**
- * @param array<string, mixed> $context
- */
- private function record(string $message, array $context): LogRecord
- {
- return new LogRecord(
- datetime: new \DateTimeImmutable(),
- channel: 'test',
- level: Level::Info,
- message: $message,
- context: $context,
- );
- }
- }
|