refactor(firewall): separate enforcement from rule management
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KTXT\Unit\Service;
|
||||
|
||||
use KTXC\Models\Firewall\FirewallRuleObject;
|
||||
use KTXC\Service\FirewallRuleCache;
|
||||
use KTXC\Service\FirewallRuleManager;
|
||||
use KTXC\Service\FirewallRuleScope;
|
||||
use KTXC\Stores\FirewallStore;
|
||||
use KTXF\Event\EventDispatcherInterface;
|
||||
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
#[AllowMockObjectsWithoutExpectations]
|
||||
class FirewallRuleManagerTest extends TestCase
|
||||
{
|
||||
private FirewallStore&MockObject $store;
|
||||
private EventDispatcherInterface&MockObject $events;
|
||||
private FirewallRuleManager $manager;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->store = $this->createMock(FirewallStore::class);
|
||||
$this->events = $this->createMock(EventDispatcherInterface::class);
|
||||
$this->manager = new FirewallRuleManager(
|
||||
$this->store,
|
||||
new FirewallRuleCache($this->store),
|
||||
$this->events
|
||||
);
|
||||
}
|
||||
|
||||
#[TestDox('The shared manager creates rules with the supplied scope and owner')]
|
||||
public function testScopeCreation(): void
|
||||
{
|
||||
$this->store->method('findExactIpRule')->willReturn(null);
|
||||
$this->store->expects($this->exactly(2))
|
||||
->method('depositRule')
|
||||
->willReturnArgument(0);
|
||||
|
||||
$tenant = $this->manager->blockIp(
|
||||
FirewallRuleScope::tenant('tenant-a'), '203.0.113.10', null, 'admin-a'
|
||||
);
|
||||
$system = $this->manager->blockIp(
|
||||
FirewallRuleScope::system(), '203.0.113.11', null, 'system-admin'
|
||||
);
|
||||
|
||||
self::assertSame('tenant-a', $tenant->getTenantId());
|
||||
self::assertSame(FirewallRuleObject::SCOPE_TENANT, $tenant->getScope());
|
||||
self::assertNull($system->getTenantId());
|
||||
self::assertSame(FirewallRuleObject::SCOPE_SYSTEM, $system->getScope());
|
||||
}
|
||||
|
||||
#[TestDox('Malformed rule values are rejected before persistence')]
|
||||
public function testValidation(): void
|
||||
{
|
||||
$this->store->expects($this->never())->method('depositRule');
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
||||
$this->manager->blockIpRange(
|
||||
FirewallRuleScope::tenant('tenant-a'), '2001:db8::/129', null, 'admin-a'
|
||||
);
|
||||
}
|
||||
|
||||
#[TestDox('Temporary rules require a positive duration')]
|
||||
public function testDuration(): void
|
||||
{
|
||||
$this->store->expects($this->never())->method('depositRule');
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
||||
$this->manager->blockIp(
|
||||
FirewallRuleScope::system(), '203.0.113.10', null, 'admin', 0
|
||||
);
|
||||
}
|
||||
|
||||
#[TestDox('Rule lifecycle operations cannot cross scope ownership')]
|
||||
public function testOwnership(): void
|
||||
{
|
||||
$tenantRule = (new FirewallRuleObject())
|
||||
->setId('tenant-rule')
|
||||
->setScope(FirewallRuleObject::SCOPE_TENANT)
|
||||
->setTenantId('tenant-a');
|
||||
$this->store->method('fetchRule')->willReturn($tenantRule);
|
||||
$this->store->expects($this->never())->method('destroyRule');
|
||||
|
||||
self::assertFalse($this->manager->remove(FirewallRuleScope::system(), 'tenant-rule'));
|
||||
self::assertFalse($this->manager->remove(FirewallRuleScope::tenant('tenant-b'), 'tenant-rule'));
|
||||
}
|
||||
|
||||
#[TestDox('Rule mutations invalidate the shared enforcement cache')]
|
||||
public function testCacheInvalidation(): void
|
||||
{
|
||||
$this->store->expects($this->exactly(2))
|
||||
->method('listApplicableRules')
|
||||
->with('tenant-a')
|
||||
->willReturnOnConsecutiveCalls([], []);
|
||||
$cache = new FirewallRuleCache($this->store);
|
||||
$manager = new FirewallRuleManager($this->store, $cache, $this->events);
|
||||
$this->store->method('findExactIpRule')->willReturn(null);
|
||||
$this->store->method('depositRule')->willReturnArgument(0);
|
||||
|
||||
self::assertSame([], $cache->applicable('tenant-a'));
|
||||
$manager->blockIp(FirewallRuleScope::tenant('tenant-a'), '203.0.113.10', null, 'admin');
|
||||
self::assertSame([], $cache->applicable('tenant-a'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user