1
0
Files
breadcrumb-the-shire/modules/audit/tests/Module/Audit/Providers/AuditSearchResourceProviderTest.php
fs c6c5d06936 feat(audit): harden API audit log redaction and schema
- Change query_json column from TEXT to JSON, ip/user_agent to CHAR(64)
  for PII redaction compliance
- Update repository, service, and views for hardened schema
- Add architecture contract test for security logging redaction
- Add search resource provider test coverage
- Include DB migration script for existing installs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:20:55 +02:00

172 lines
6.0 KiB
PHP

<?php
namespace MintyPHP\Tests\Module\Audit\Providers;
use MintyPHP\Module\Audit\Providers\AuditSearchResourceProvider;
use PHPUnit\Framework\TestCase;
class AuditSearchResourceProviderTest extends TestCase
{
private AuditSearchResourceProvider $provider;
protected function setUp(): void
{
$this->provider = new AuditSearchResourceProvider();
}
public function testResourcesReturnsBothAuditKeys(): void
{
$resources = $this->provider->resources();
$this->assertArrayHasKey('api-audit', $resources);
$this->assertArrayHasKey('system-audit', $resources);
$this->assertCount(2, $resources);
}
public function testResourcesContainRequiredSqlKeys(): void
{
foreach ($this->provider->resources() as $key => $resource) {
$this->assertArrayHasKey('label', $resource, "Resource '{$key}' missing label");
$this->assertArrayHasKey('permission', $resource, "Resource '{$key}' missing permission");
$this->assertArrayHasKey('count_sql', $resource, "Resource '{$key}' missing count_sql");
$this->assertArrayHasKey('preview_sql', $resource, "Resource '{$key}' missing preview_sql");
$this->assertArrayHasKey('result_sql', $resource, "Resource '{$key}' missing result_sql");
}
}
public function testResourcePermissionKeys(): void
{
$resources = $this->provider->resources();
$this->assertSame('audit.api.view', $resources['api-audit']['permission']);
$this->assertSame('audit.system.view', $resources['system-audit']['permission']);
}
public function testApiAuditSearchSqlIncludesUserAgentHashField(): void
{
$resources = $this->provider->resources();
$apiAudit = $resources['api-audit'];
$this->assertStringContainsString('user_agent like ?', $apiAudit['count_sql']);
$this->assertStringContainsString('user_agent like ?', $apiAudit['preview_sql']);
$this->assertStringContainsString('user_agent like ?', $apiAudit['result_sql']);
}
public function testMapApiAuditItem(): void
{
$row = [
'id' => 42,
'method' => 'POST',
'path' => '/api/v1/users',
'status_code' => 201,
'request_id' => 'req-abc',
'created_at' => '2026-03-15 10:30:00',
];
$result = $this->provider->mapResultItem('api-audit', $row);
$this->assertNotNull($result);
$this->assertSame('POST /api/v1/users', $result['title']);
$this->assertStringContains('201', $result['subtitle']);
$this->assertStringContains('2026-03-15 10:30:00', $result['subtitle']);
$this->assertSame('bi-shield-check', $result['icon']);
$this->assertStringContainsString('admin/api-audit/view/42', $result['url']);
}
public function testMapApiAuditItemFallsBackToRequestId(): void
{
$row = ['id' => 1, 'method' => '', 'path' => '', 'status_code' => 0, 'request_id' => 'req-fallback'];
$result = $this->provider->mapResultItem('api-audit', $row);
$this->assertNotNull($result);
$this->assertSame('req-fallback', $result['title']);
}
public function testMapApiAuditItemReturnsNullWhenEmpty(): void
{
$row = ['id' => 1, 'method' => '', 'path' => '', 'status_code' => 0, 'request_id' => ''];
$result = $this->provider->mapResultItem('api-audit', $row);
$this->assertNull($result);
}
public function testMapSystemAuditItem(): void
{
$row = [
'id' => 99,
'event_type' => 'admin.settings.update',
'outcome' => 'success',
'request_id' => 'req-xyz',
'created_at' => '2026-03-15 11:00:00',
];
$result = $this->provider->mapResultItem('system-audit', $row);
$this->assertNotNull($result);
$this->assertSame('admin.settings.update', $result['title']);
$this->assertStringContains('SUCCESS', $result['subtitle']);
$this->assertStringContains('2026-03-15 11:00:00', $result['subtitle']);
$this->assertSame('bi-journal-lock', $result['icon']);
$this->assertStringContainsString('admin/system-audit/view/99', $result['url']);
}
public function testMapSystemAuditItemFallsBackToRequestId(): void
{
$row = ['id' => 1, 'event_type' => '', 'outcome' => '', 'request_id' => 'req-fallback'];
$result = $this->provider->mapResultItem('system-audit', $row);
$this->assertNotNull($result);
$this->assertSame('req-fallback', $result['title']);
}
public function testMapSystemAuditItemReturnsNullWhenEmpty(): void
{
$row = ['id' => 1, 'event_type' => '', 'outcome' => '', 'request_id' => ''];
$result = $this->provider->mapResultItem('system-audit', $row);
$this->assertNull($result);
}
public function testMapResultItemReturnsNullForUnknownKey(): void
{
$result = $this->provider->mapResultItem('unknown', ['id' => 1]);
$this->assertNull($result);
}
public function testListUrlForApiAudit(): void
{
$url = $this->provider->listUrl('api-audit', 'test%20query');
$this->assertStringContainsString('admin/api-audit', $url);
$this->assertStringContainsString('search=test%20query', $url);
}
public function testListUrlForSystemAudit(): void
{
$url = $this->provider->listUrl('system-audit', 'test');
$this->assertStringContainsString('admin/system-audit', $url);
$this->assertStringContainsString('search=test', $url);
}
public function testListUrlReturnsEmptyForUnknownKey(): void
{
$url = $this->provider->listUrl('unknown', 'test');
$this->assertSame('', $url);
}
/**
* Helper to check string containment (mirrors assertStringContainsString for readability).
*/
private static function assertStringContains(string $needle, string $haystack): void
{
self::assertStringContainsString($needle, $haystack);
}
}