| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 |
- <?php
- declare(strict_types=1);
- namespace App\Tests\Repositories;
- use App\Repositories\AuditRepository;
- use App\Services\AuditLogger;
- use App\Tests\TestCase;
- use InvalidArgumentException;
- /**
- * R01-N11: AuditRepository::distinctColumn interpolates its argument into
- * SQL. The method is private and both internal callers pass literals, but
- * the runtime whitelist guard makes the contract explicit so a future
- * refactor can't open an injection vector.
- */
- final class AuditRepositoryTest extends TestCase
- {
- public function testDistinctActionsReturnsSortedUniqueValues(): void
- {
- $pdo = $this->makeDb();
- $logger = new AuditLogger($pdo);
- $logger->record('UPDATE', 'worker', 1, ['n' => 1], ['n' => 2]);
- $logger->record('CREATE', 'worker', 2, null, ['n' => 1]);
- $logger->record('UPDATE', 'sprint', 3, ['n' => 1], ['n' => 2]);
- $repo = new AuditRepository($pdo);
- $this->assertSame(['CREATE', 'UPDATE'], $repo->distinctActions());
- }
- public function testDistinctEntityTypesReturnsSortedUniqueValues(): void
- {
- $pdo = $this->makeDb();
- $logger = new AuditLogger($pdo);
- $logger->record('UPDATE', 'worker', 1, ['n' => 1], ['n' => 2]);
- $logger->record('UPDATE', 'sprint', 2, ['n' => 1], ['n' => 2]);
- $logger->record('UPDATE', 'worker', 3, ['n' => 1], ['n' => 2]);
- $repo = new AuditRepository($pdo);
- $this->assertSame(['sprint', 'worker'], $repo->distinctEntityTypes());
- }
- public function testDistinctColumnRejectsUnknownColumnViaReflection(): void
- {
- $pdo = $this->makeDb();
- $repo = new AuditRepository($pdo);
- $rm = new \ReflectionMethod($repo, 'distinctColumn');
- $rm->setAccessible(true);
- $this->expectException(InvalidArgumentException::class);
- $rm->invoke($repo, 'user_email');
- }
- public function testDistinctColumnRejectsInjectionAttemptViaReflection(): void
- {
- $pdo = $this->makeDb();
- $repo = new AuditRepository($pdo);
- $rm = new \ReflectionMethod($repo, 'distinctColumn');
- $rm->setAccessible(true);
- $this->expectException(InvalidArgumentException::class);
- $rm->invoke($repo, 'action; DROP TABLE audit_log; --');
- }
- }
|