refactor: base event

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-08-08 22:15:24 -04:00
parent c8e6efe203
commit 62b416f13e
20 changed files with 109 additions and 99 deletions
+4 -4
View File
@@ -50,7 +50,7 @@ final class EventDispatcher implements EventDispatcherInterface, DeferredEventPr
try { try {
$this->invoke($event, DeliveryMode::Immediate); $this->invoke($event, DeliveryMode::Immediate);
if ($this->registry->listeners($event->getName(), DeliveryMode::Deferred) !== []) { if ($this->registry->listeners($event->label(), DeliveryMode::Deferred) !== []) {
if ($this->activeExecution === null) { if ($this->activeExecution === null) {
throw new \LogicException('Deferred events require an active execution scope.'); throw new \LogicException('Deferred events require an active execution scope.');
} }
@@ -96,7 +96,7 @@ final class EventDispatcher implements EventDispatcherInterface, DeferredEventPr
} }
$eventListenerCount = count($this->registry->listeners( $eventListenerCount = count($this->registry->listeners(
$event->getName(), $event->label(),
DeliveryMode::Deferred, DeliveryMode::Deferred,
)); ));
if ($listenerInvocations + $eventListenerCount > $this->maxDeferredListenerInvocations) { if ($listenerInvocations + $eventListenerCount > $this->maxDeferredListenerInvocations) {
@@ -134,7 +134,7 @@ final class EventDispatcher implements EventDispatcherInterface, DeferredEventPr
private function invoke(Event $event, DeliveryMode $delivery): int private function invoke(Event $event, DeliveryMode $delivery): int
{ {
$processed = 0; $processed = 0;
foreach ($this->registry->listeners($event->getName(), $delivery) as $listener) { foreach ($this->registry->listeners($event->label(), $delivery) as $listener) {
if ($event->isPropagationStopped()) { if ($event->isPropagationStopped()) {
break; break;
} }
@@ -145,7 +145,7 @@ final class EventDispatcher implements EventDispatcherInterface, DeferredEventPr
$service->{$listener->method}($event); $service->{$listener->method}($event);
} catch (\Throwable $error) { } catch (\Throwable $error) {
$this->logger->error('Event listener failed.', [ $this->logger->error('Event listener failed.', [
'event' => $event->getName(), 'event' => $event->label(),
'module' => $listener->module, 'module' => $listener->module,
'listener' => $listener->service . '::' . $listener->method, 'listener' => $listener->service . '::' . $listener->method,
'exception' => $error, 'exception' => $error,
@@ -6,17 +6,17 @@ namespace KTXC\Security\Event;
interface SecurityEventInterface interface SecurityEventInterface
{ {
public function getName(): string; public function label(): string;
public function get(string $key, mixed $default = null): mixed; public function get(string $key, mixed $default = null): mixed;
public function getData(): array; public function context(): array;
public function getEventId(): string; public function identifier(): string;
public function getTenantId(): ?string; public function tenantIdentifier(): ?string;
public function getIdentityId(): ?string; public function actorIdentity(): ?string;
public function getUserId(): ?string; public function getUserId(): ?string;
+7 -7
View File
@@ -149,7 +149,7 @@ class FirewallService
{ {
$request = $this->requestContext->current(); $request = $this->requestContext->current();
$ipAddress = $request?->getClientIp(); $ipAddress = $request?->getClientIp();
$tenantId = $event->getTenantId() ?? $this->tenantContext->identifier(); $tenantId = $event->tenantIdentifier() ?? $this->tenantContext->identifier();
if (!$ipAddress || !$tenantId) { if (!$ipAddress || !$tenantId) {
return; return;
@@ -262,7 +262,7 @@ class FirewallService
?Request $request = null, ?Request $request = null,
): ?FirewallLogObject ): ?FirewallLogObject
{ {
$tenantId = $event->getTenantId() ?? $this->tenantContext->identifier(); $tenantId = $event->tenantIdentifier() ?? $this->tenantContext->identifier();
$ruleScope = $event->get('ruleScope'); $ruleScope = $event->get('ruleScope');
if (!$tenantId && $ruleScope !== FirewallRuleObject::SCOPE_SYSTEM) { if (!$tenantId && $ruleScope !== FirewallRuleObject::SCOPE_SYSTEM) {
return null; return null;
@@ -271,7 +271,7 @@ class FirewallService
$requestEvent = $event instanceof SecurityRequestEventInterface ? $event : null; $requestEvent = $event instanceof SecurityRequestEventInterface ? $event : null;
$log = new FirewallLogObject(); $log = new FirewallLogObject();
return $log->setEventId($event->getEventId()) return $log->setEventId($event->identifier())
->setTenantId($tenantId) ->setTenantId($tenantId)
->setIpAddress($request?->getClientIp() ?? $requestEvent?->getIpAddress()) ->setIpAddress($request?->getClientIp() ?? $requestEvent?->getIpAddress())
->setDeviceFingerprint( ->setDeviceFingerprint(
@@ -281,13 +281,13 @@ class FirewallService
->setUserAgent($request?->headers->get('User-Agent') ?? $requestEvent?->getUserAgent()) ->setUserAgent($request?->headers->get('User-Agent') ?? $requestEvent?->getUserAgent())
->setRequestPath($request?->getPathInfo() ?? $requestEvent?->getRequestPath()) ->setRequestPath($request?->getPathInfo() ?? $requestEvent?->getRequestPath())
->setRequestMethod($request?->getMethod() ?? $requestEvent?->getRequestMethod()) ->setRequestMethod($request?->getMethod() ?? $requestEvent?->getRequestMethod())
->setEventType($this->mapEventToLogType($event->getName())) ->setEventType($this->mapEventToLogType($event->label()))
->setResult($this->mapEventToResult($event)) ->setResult($this->mapEventToResult($event))
->setRuleId($event->get('ruleId')) ->setRuleId($event->get('ruleId'))
->setRuleScope($ruleScope) ->setRuleScope($ruleScope)
->setIdentityId($event->getUserId() ?? $event->getIdentityId()) ->setIdentityId($event->getUserId() ?? $event->actorIdentity())
->setTimestamp(new \DateTimeImmutable()) ->setTimestamp(new \DateTimeImmutable())
->setMetadata($event->getData()); ->setMetadata($event->context());
} }
/** /**
@@ -317,7 +317,7 @@ class FirewallService
*/ */
private function mapEventToResult(SecurityEventInterface $event): string private function mapEventToResult(SecurityEventInterface $event): string
{ {
return match ($event->getName()) { return match ($event->label()) {
AuthenticationSucceededEvent::class => FirewallLogObject::RESULT_ALLOWED, AuthenticationSucceededEvent::class => FirewallLogObject::RESULT_ALLOWED,
FirewallRuleCreatedEvent::class, FirewallRuleCreatedEvent::class,
FirewallRuleExtendedEvent::class, FirewallRuleExtendedEvent::class,
+5
View File
@@ -61,6 +61,11 @@ abstract class UserEvent extends Event
return $this->userIdentifier; return $this->userIdentifier;
} }
public function tenantIdentifier(): string
{
return $this->tenantIdentifier;
}
public function userIdentity(): string public function userIdentity(): string
{ {
return $this->userIdentity; return $this->userIdentity;
+33 -33
View File
@@ -10,74 +10,74 @@ namespace KTXF\Event;
class Event class Event
{ {
private bool $propagationStopped = false; private bool $propagationStopped = false;
private readonly array $data; private readonly array $context;
private readonly float $timestamp; private readonly float $timestamp;
private readonly string $eventId; private readonly string $identifier;
public function __construct( public function __construct(
private readonly string $name, private readonly string $label,
array $data = [], array $context = [],
private readonly ?string $tenantId = null, private readonly ?string $tenantIdentifier = null,
private readonly ?string $identityId = null, private readonly ?string $actorIdentity = null,
) { ) {
self::validateData($data); self::validateContext($context);
$this->data = $data; $this->context = $context;
$this->timestamp = microtime(true); $this->timestamp = microtime(true);
$this->eventId = bin2hex(random_bytes(16)); $this->identifier = bin2hex(random_bytes(16));
} }
/** /**
* Get the event name * Get the event label
*/ */
public function getName(): string public function label(): string
{ {
return $this->name; return $this->label;
} }
/** /**
* Get a data value by key * Get a context value by key
*/ */
public function get(string $key, mixed $default = null): mixed public function get(string $key, mixed $default = null): mixed
{ {
return $this->data[$key] ?? $default; return $this->context[$key] ?? $default;
} }
/** /**
* Check if a data key exists * Check if a context key exists
*/ */
public function has(string $key): bool public function has(string $key): bool
{ {
return array_key_exists($key, $this->data); return array_key_exists($key, $this->context);
} }
/** /**
* Get all data * Get the event context
*/ */
public function getData(): array public function context(): array
{ {
return $this->data; return $this->context;
} }
/** /**
* Alias for getData() for backward compatibility * Get all event context
*/ */
public function all(): array public function all(): array
{ {
return $this->data; return $this->context;
} }
/** /**
* Get the event timestamp * Get the event timestamp
*/ */
public function getTimestamp(): float public function timestamp(): float
{ {
return $this->timestamp; return $this->timestamp;
} }
public function getEventId(): string public function identifier(): string
{ {
return $this->eventId; return $this->identifier;
} }
/** /**
@@ -99,29 +99,29 @@ class Event
/** /**
* Get tenant ID for multi-tenant context * Get tenant ID for multi-tenant context
*/ */
public function getTenantId(): ?string public function tenantIdentifier(): ?string
{ {
return $this->tenantId; return $this->tenantIdentifier;
} }
/** /**
* Get identity ID (user who triggered the event) * Get the identity of the actor who triggered the event
*/ */
public function getIdentityId(): ?string public function actorIdentity(): ?string
{ {
return $this->identityId; return $this->actorIdentity;
} }
private static function validateData(array $data): void private static function validateContext(array $context): void
{ {
foreach ($data as $value) { foreach ($context as $value) {
if (is_array($value)) { if (is_array($value)) {
self::validateData($value); self::validateContext($value);
continue; continue;
} }
if ($value !== null && !is_scalar($value)) { if ($value !== null && !is_scalar($value)) {
throw new \InvalidArgumentException( throw new \InvalidArgumentException(
'Event data must contain only scalar, null, or array values.', 'Event context must contain only scalar, null, or array values.',
); );
} }
} }
@@ -27,14 +27,14 @@ final class AccessDeniedEventTest extends TestCase
'identity-a', 'identity-a',
); );
self::assertSame(AccessDeniedEvent::class, $event->getName()); self::assertSame(AccessDeniedEvent::class, $event->label());
self::assertSame('203.0.113.10', $event->getIpAddress()); self::assertSame('203.0.113.10', $event->getIpAddress());
self::assertSame('device-a', $event->getDeviceFingerprint()); self::assertSame('device-a', $event->getDeviceFingerprint());
self::assertSame('rule-a', $event->getRuleId()); self::assertSame('rule-a', $event->getRuleId());
self::assertSame(FirewallRuleObject::SCOPE_TENANT, $event->getRuleScope()); self::assertSame(FirewallRuleObject::SCOPE_TENANT, $event->getRuleScope());
self::assertSame('Blocked by policy', $event->getReason()); self::assertSame('Blocked by policy', $event->getReason());
self::assertSame('tenant-a', $event->getTenantId()); self::assertSame('tenant-a', $event->tenantIdentifier());
self::assertSame('identity-a', $event->getIdentityId()); self::assertSame('identity-a', $event->actorIdentity());
self::assertSame(SecurityEventSeverity::WARNING, $event->getSeverity()); self::assertSame(SecurityEventSeverity::WARNING, $event->getSeverity());
} }
@@ -24,11 +24,11 @@ final class AuthenticationFailedEventTest extends TestCase
'identity-a', 'identity-a',
); );
self::assertSame(AuthenticationFailedEvent::class, $event->getName()); self::assertSame(AuthenticationFailedEvent::class, $event->label());
self::assertSame('user-a', $event->getUserId()); self::assertSame('user-a', $event->getUserId());
self::assertSame('Invalid credentials', $event->getReason()); self::assertSame('Invalid credentials', $event->getReason());
self::assertSame('tenant-a', $event->getTenantId()); self::assertSame('tenant-a', $event->tenantIdentifier());
self::assertSame('identity-a', $event->getIdentityId()); self::assertSame('identity-a', $event->actorIdentity());
self::assertSame(SecurityEventSeverity::WARNING, $event->getSeverity()); self::assertSame(SecurityEventSeverity::WARNING, $event->getSeverity());
self::assertNotInstanceOf(SecurityRequestEventInterface::class, $event); self::assertNotInstanceOf(SecurityRequestEventInterface::class, $event);
} }
@@ -22,10 +22,10 @@ final class AuthenticationSucceededEventTest extends TestCase
'tenant-a', 'tenant-a',
); );
self::assertSame(AuthenticationSucceededEvent::class, $event->getName()); self::assertSame(AuthenticationSucceededEvent::class, $event->label());
self::assertSame('user-a', $event->getUserId()); self::assertSame('user-a', $event->getUserId());
self::assertSame('tenant-a', $event->getTenantId()); self::assertSame('tenant-a', $event->tenantIdentifier());
self::assertSame(['userId' => 'user-a'], $event->getData()); self::assertSame(['userId' => 'user-a'], $event->context());
self::assertSame(SecurityEventSeverity::INFO, $event->getSeverity()); self::assertSame(SecurityEventSeverity::INFO, $event->getSeverity());
self::assertNotInstanceOf(SecurityRequestEventInterface::class, $event); self::assertNotInstanceOf(SecurityRequestEventInterface::class, $event);
} }
@@ -23,15 +23,15 @@ final class BruteForceDetectedEventTest extends TestCase
'tenant-a', 'tenant-a',
); );
self::assertSame(BruteForceDetectedEvent::class, $event->getName()); self::assertSame(BruteForceDetectedEvent::class, $event->label());
self::assertSame('203.0.113.10', $event->getIpAddress()); self::assertSame('203.0.113.10', $event->getIpAddress());
self::assertSame(5, $event->getFailureCount()); self::assertSame(5, $event->getFailureCount());
self::assertSame(300, $event->getWindowSeconds()); self::assertSame(300, $event->getWindowSeconds());
self::assertSame('tenant-a', $event->getTenantId()); self::assertSame('tenant-a', $event->tenantIdentifier());
self::assertSame('5 failed attempts in 300 seconds', $event->getReason()); self::assertSame('5 failed attempts in 300 seconds', $event->getReason());
self::assertSame( self::assertSame(
['failureCount' => 5, 'windowSeconds' => 300], ['failureCount' => 5, 'windowSeconds' => 300],
$event->getData(), $event->context(),
); );
self::assertSame(SecurityEventSeverity::CRITICAL, $event->getSeverity()); self::assertSame(SecurityEventSeverity::CRITICAL, $event->getSeverity());
} }
+6 -3
View File
@@ -22,12 +22,15 @@ final class EventTest extends TestCase
'identity-a', 'identity-a',
); );
$copy = $event->getData(); $copy = $event->context();
$copy['nested']['value'] = 'changed'; $copy['nested']['value'] = 'changed';
self::assertSame('original', $event->get('nested')['value']); self::assertSame('original', $event->get('nested')['value']);
self::assertSame('tenant-a', $event->getTenantId()); self::assertSame('test.event', $event->label());
self::assertSame('identity-a', $event->getIdentityId()); self::assertNotSame('', $event->identifier());
self::assertGreaterThan(0, $event->timestamp());
self::assertSame('tenant-a', $event->tenantIdentifier());
self::assertSame('identity-a', $event->actorIdentity());
} }
#[Test] #[Test]
@@ -23,14 +23,14 @@ final class FirewallPolicyEventTest extends TestCase
$allowed = new IpAllowedEvent('203.0.113.11', 'Trusted service', 'tenant-a'); $allowed = new IpAllowedEvent('203.0.113.11', 'Trusted service', 'tenant-a');
$device = new DeviceBlockedEvent('device-a', 'Compromised device', 'tenant-a'); $device = new DeviceBlockedEvent('device-a', 'Compromised device', 'tenant-a');
self::assertSame(IpBlockedEvent::class, $blocked->getName()); self::assertSame(IpBlockedEvent::class, $blocked->label());
self::assertSame('203.0.113.10', $blocked->getIpAddress()); self::assertSame('203.0.113.10', $blocked->getIpAddress());
self::assertSame('Repeated abuse', $blocked->getReason()); self::assertSame('Repeated abuse', $blocked->getReason());
self::assertSame(SecurityEventSeverity::CRITICAL, $blocked->getSeverity()); self::assertSame(SecurityEventSeverity::CRITICAL, $blocked->getSeverity());
self::assertSame(IpAllowedEvent::class, $allowed->getName()); self::assertSame(IpAllowedEvent::class, $allowed->label());
self::assertSame('203.0.113.11', $allowed->getIpAddress()); self::assertSame('203.0.113.11', $allowed->getIpAddress());
self::assertSame(SecurityEventSeverity::INFO, $allowed->getSeverity()); self::assertSame(SecurityEventSeverity::INFO, $allowed->getSeverity());
self::assertSame(DeviceBlockedEvent::class, $device->getName()); self::assertSame(DeviceBlockedEvent::class, $device->label());
self::assertSame('device-a', $device->getDeviceFingerprint()); self::assertSame('device-a', $device->getDeviceFingerprint());
self::assertSame(SecurityEventSeverity::CRITICAL, $device->getSeverity()); self::assertSame(SecurityEventSeverity::CRITICAL, $device->getSeverity());
} }
@@ -47,12 +47,12 @@ final class FirewallPolicyEventTest extends TestCase
'operator-a', 'operator-a',
); );
self::assertSame(FirewallSettingsUpdatedEvent::class, $event->getName()); self::assertSame(FirewallSettingsUpdatedEvent::class, $event->label());
self::assertSame('Tighten controls', $event->getChangeReason()); self::assertSame('Tighten controls', $event->getChangeReason());
self::assertSame(['maxAuthFailures' => 5], $event->getPrevious()); self::assertSame(['maxAuthFailures' => 5], $event->getPrevious());
self::assertSame(['maxAuthFailures' => 3], $event->getCurrent()); self::assertSame(['maxAuthFailures' => 3], $event->getCurrent());
self::assertSame('tenant-a', $event->getTenantId()); self::assertSame('tenant-a', $event->tenantIdentifier());
self::assertSame('operator-a', $event->getIdentityId()); self::assertSame('operator-a', $event->actorIdentity());
self::assertSame('manual', $event->getChangeOrigin()); self::assertSame('manual', $event->getChangeOrigin());
self::assertSame(SecurityEventSeverity::INFO, $event->getSeverity()); self::assertSame(SecurityEventSeverity::INFO, $event->getSeverity());
} }
@@ -41,7 +41,7 @@ final class FirewallRuleEventTest extends TestCase
); );
$rule->setReason('Mutated after publication'); $rule->setReason('Mutated after publication');
self::assertSame(FirewallRuleExtendedEvent::class, $event->getName()); self::assertSame(FirewallRuleExtendedEvent::class, $event->label());
self::assertSame('rule-a', $event->getRuleId()); self::assertSame('rule-a', $event->getRuleId());
self::assertSame(FirewallRuleObject::SCOPE_TENANT, $event->getRuleScope()); self::assertSame(FirewallRuleObject::SCOPE_TENANT, $event->getRuleScope());
self::assertSame(FirewallRuleObject::TYPE_IP, $event->getRuleType()); self::assertSame(FirewallRuleObject::TYPE_IP, $event->getRuleType());
@@ -50,8 +50,8 @@ final class FirewallRuleEventTest extends TestCase
self::assertSame('Repeated abuse', $event->getReason()); self::assertSame('Repeated abuse', $event->getReason());
self::assertSame('automatic', $event->getOrigin()); self::assertSame('automatic', $event->getOrigin());
self::assertSame($expiresAt->format(\DateTimeInterface::ATOM), $event->getExpiresAt()); self::assertSame($expiresAt->format(\DateTimeInterface::ATOM), $event->getExpiresAt());
self::assertSame('tenant-a', $event->getTenantId()); self::assertSame('tenant-a', $event->tenantIdentifier());
self::assertSame('operator-a', $event->getIdentityId()); self::assertSame('operator-a', $event->actorIdentity());
self::assertSame(5, $event->get('failureCount')); self::assertSame(5, $event->get('failureCount'));
self::assertSame('Continue monitoring', $event->get('changeReason')); self::assertSame('Continue monitoring', $event->get('changeReason'));
self::assertSame(SecurityEventSeverity::INFO, $event->getSeverity()); self::assertSame(SecurityEventSeverity::INFO, $event->getSeverity());
@@ -75,7 +75,7 @@ final class FirewallRuleEventTest extends TestCase
FirewallRuleDisabledEvent::class, FirewallRuleDisabledEvent::class,
FirewallRuleRemovedEvent::class, FirewallRuleRemovedEvent::class,
] as $eventClass) { ] as $eventClass) {
self::assertSame($eventClass, $eventClass::fromRule($rule)->getName()); self::assertSame($eventClass, $eventClass::fromRule($rule)->label());
} }
} }
} }
@@ -24,13 +24,13 @@ final class RateLimitExceededEventTest extends TestCase
'tenant-a', 'tenant-a',
); );
self::assertSame(RateLimitExceededEvent::class, $event->getName()); self::assertSame(RateLimitExceededEvent::class, $event->label());
self::assertSame('203.0.113.10', $event->getIpAddress()); self::assertSame('203.0.113.10', $event->getIpAddress());
self::assertSame(101, $event->getRequestCount()); self::assertSame(101, $event->getRequestCount());
self::assertSame(60, $event->getWindowSeconds()); self::assertSame(60, $event->getWindowSeconds());
self::assertSame('/login', $event->getEndpoint()); self::assertSame('/login', $event->getEndpoint());
self::assertSame('/login', $event->getRequestPath()); self::assertSame('/login', $event->getRequestPath());
self::assertSame('tenant-a', $event->getTenantId()); self::assertSame('tenant-a', $event->tenantIdentifier());
self::assertSame('101 requests in 60 seconds', $event->getReason()); self::assertSame('101 requests in 60 seconds', $event->getReason());
self::assertSame(SecurityEventSeverity::ERROR, $event->getSeverity()); self::assertSame(SecurityEventSeverity::ERROR, $event->getSeverity());
} }
@@ -30,13 +30,13 @@ final class SuspiciousActivityEventTest extends TestCase
reason: 'Matched a blocked payload signature', reason: 'Matched a blocked payload signature',
); );
self::assertSame(SuspiciousActivityEvent::class, $event->getName()); self::assertSame(SuspiciousActivityEvent::class, $event->label());
self::assertSame('203.0.113.20', $event->getIpAddress()); self::assertSame('203.0.113.20', $event->getIpAddress());
self::assertSame('payload-signature', $event->getDetector()); self::assertSame('payload-signature', $event->getDetector());
self::assertSame(['score' => 98], $event->getDetectionData()); self::assertSame(['score' => 98], $event->getDetectionData());
self::assertSame(['detector' => 'payload-signature', 'score' => 98], $event->getData()); self::assertSame(['detector' => 'payload-signature', 'score' => 98], $event->context());
self::assertSame('tenant-a', $event->getTenantId()); self::assertSame('tenant-a', $event->tenantIdentifier());
self::assertSame('identity-a', $event->getIdentityId()); self::assertSame('identity-a', $event->actorIdentity());
self::assertSame('device-a', $event->getDeviceFingerprint()); self::assertSame('device-a', $event->getDeviceFingerprint());
self::assertSame('Test Agent', $event->getUserAgent()); self::assertSame('Test Agent', $event->getUserAgent());
self::assertSame('/admin', $event->getRequestPath()); self::assertSame('/admin', $event->getRequestPath());
+8 -6
View File
@@ -6,6 +6,7 @@ namespace KTXT\Unit\Event;
use KTXC\User\Event\UserCreatedEvent; use KTXC\User\Event\UserCreatedEvent;
use KTXC\User\Event\UserDeletingEvent; use KTXC\User\Event\UserDeletingEvent;
use KTXC\User\Event\UserEvent;
use KTXC\User\Event\UserUpdatedEvent; use KTXC\User\Event\UserUpdatedEvent;
use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\TestDox; use PHPUnit\Framework\Attributes\TestDox;
@@ -29,15 +30,16 @@ final class UserEventTest extends TestCase
'actor-a', 'actor-a',
); );
self::assertSame(UserCreatedEvent::class, $event->getName()); self::assertSame(UserCreatedEvent::class, $event->label());
self::assertSame('user-a', $event->userIdentifier()); self::assertSame('user-a', $event->userIdentifier());
self::assertSame('person@example.test', $event->userIdentity()); self::assertSame('person@example.test', $event->userIdentity());
self::assertSame('Person', $event->userLabel()); self::assertSame('Person', $event->userLabel());
self::assertTrue($event->userEnabled()); self::assertTrue($event->userEnabled());
self::assertSame(['member'], $event->userRoles()); self::assertSame(['member'], $event->userRoles());
self::assertSame('tenant-a', $event->getTenantId()); self::assertSame('tenant-a', $event->tenantIdentifier());
self::assertSame('actor-a', $event->actorIdentifier()); self::assertSame('actor-a', $event->actorIdentifier());
self::assertSame('actor-a', $event->getIdentityId()); self::assertSame('actor-a', $event->actorIdentity());
self::assertSame('string', (string) (new \ReflectionMethod(UserEvent::class, 'tenantIdentifier'))->getReturnType());
} }
#[Test] #[Test]
@@ -46,9 +48,9 @@ final class UserEventTest extends TestCase
{ {
$user = ['uid' => 'user-a', 'identity' => 'person@example.test']; $user = ['uid' => 'user-a', 'identity' => 'person@example.test'];
self::assertSame(UserCreatedEvent::class, UserCreatedEvent::fromUser($user, 'tenant-a')->getName()); self::assertSame(UserCreatedEvent::class, UserCreatedEvent::fromUser($user, 'tenant-a')->label());
self::assertSame(UserUpdatedEvent::class, UserUpdatedEvent::fromUser($user, 'tenant-a')->getName()); self::assertSame(UserUpdatedEvent::class, UserUpdatedEvent::fromUser($user, 'tenant-a')->label());
self::assertSame(UserDeletingEvent::class, UserDeletingEvent::fromUser($user, 'tenant-a')->getName()); self::assertSame(UserDeletingEvent::class, UserDeletingEvent::fromUser($user, 'tenant-a')->label());
} }
#[Test] #[Test]
@@ -78,7 +78,7 @@ final class AuthenticationManagerTest extends TestCase
->with(self::callback(static fn($event): bool => ->with(self::callback(static fn($event): bool =>
$event instanceof AuthenticationSucceededEvent $event instanceof AuthenticationSucceededEvent
&& $event->getUserId() === 'user-a' && $event->getUserId() === 'user-a'
&& $event->getTenantId() === 'tenant-a' && $event->tenantIdentifier() === 'tenant-a'
)); ));
$manager = new AuthenticationManager( $manager = new AuthenticationManager(
@@ -198,7 +198,7 @@ final class AuthenticationManagerTest extends TestCase
return $event instanceof AuthenticationFailedEvent return $event instanceof AuthenticationFailedEvent
&& $event->getUserId() === 'user-a' && $event->getUserId() === 'user-a'
&& $event->getReason() === ProviderResult::ERROR_INVALID_FACTOR && $event->getReason() === ProviderResult::ERROR_INVALID_FACTOR
&& $event->getTenantId() === 'tenant-a'; && $event->tenantIdentifier() === 'tenant-a';
})); }));
$manager = new AuthenticationManager( $manager = new AuthenticationManager(
@@ -285,7 +285,7 @@ class FirewallRuleManagerTest extends TestCase
$this->events->expects($this->exactly(2)) $this->events->expects($this->exactly(2))
->method('dispatch') ->method('dispatch')
->willReturnCallback(static function (\KTXF\Event\Event $event) use (&$events): void { ->willReturnCallback(static function (\KTXF\Event\Event $event) use (&$events): void {
$events[$event->getName()] = $event; $events[$event->label()] = $event;
}); });
$this->manager->blockIp( $this->manager->blockIp(
@@ -302,7 +302,7 @@ class FirewallRuleManagerTest extends TestCase
self::assertSame(FirewallRuleObject::TYPE_IP, $audit->get('ruleType')); self::assertSame(FirewallRuleObject::TYPE_IP, $audit->get('ruleType'));
self::assertSame(FirewallRuleObject::ACTION_BLOCK, $audit->get('ruleAction')); self::assertSame(FirewallRuleObject::ACTION_BLOCK, $audit->get('ruleAction'));
self::assertSame(FirewallRuleManager::ORIGIN_MANUAL, $audit->get('origin')); self::assertSame(FirewallRuleManager::ORIGIN_MANUAL, $audit->get('origin'));
self::assertSame('admin-a', $audit->getIdentityId()); self::assertSame('admin-a', $audit->actorIdentity());
self::assertNotNull($audit->get('expiresAt')); self::assertNotNull($audit->get('expiresAt'));
self::assertInstanceOf(IpBlockedEvent::class, $events[IpBlockedEvent::class]); self::assertInstanceOf(IpBlockedEvent::class, $events[IpBlockedEvent::class]);
self::assertSame('203.0.113.10', $events[IpBlockedEvent::class]->getIpAddress()); self::assertSame('203.0.113.10', $events[IpBlockedEvent::class]->getIpAddress());
@@ -385,13 +385,13 @@ class FirewallRuleManagerTest extends TestCase
FirewallRuleEnabledEvent::class, FirewallRuleEnabledEvent::class,
FirewallRuleExtendedEvent::class, FirewallRuleExtendedEvent::class,
FirewallRuleRemovedEvent::class, FirewallRuleRemovedEvent::class,
], array_map(static fn($event): string => $event->getName(), $audits)); ], array_map(static fn($event): string => $event->label(), $audits));
self::assertSame( self::assertSame(
['Investigation', 'Threat confirmed', 'Continue monitoring', 'Case closed'], ['Investigation', 'Threat confirmed', 'Continue monitoring', 'Case closed'],
array_map(static fn($event): string => $event->get('changeReason'), $audits) array_map(static fn($event): string => $event->get('changeReason'), $audits)
); );
self::assertSame(['operator'], array_values(array_unique(array_map( self::assertSame(['operator'], array_values(array_unique(array_map(
static fn($event): ?string => $event->getIdentityId(), static fn($event): ?string => $event->actorIdentity(),
$audits $audits
)))); ))));
} }
@@ -539,7 +539,7 @@ class FirewallServiceTest extends TestCase
&$lifecycleOrigin, &$lifecycleOrigin,
&$bruteForceEvent, &$bruteForceEvent,
): void { ): void {
$publishedTenants[] = $event->getTenantId(); $publishedTenants[] = $event->tenantIdentifier();
if ($event instanceof BruteForceDetectedEvent) { if ($event instanceof BruteForceDetectedEvent) {
$bruteForceEvent = $event; $bruteForceEvent = $event;
} }
@@ -616,12 +616,12 @@ class FirewallServiceTest extends TestCase
->with('tenant-a', '203.0.113.10', 300) ->with('tenant-a', '203.0.113.10', 300)
->willReturn(1); ->willReturn(1);
$event = new AuthenticationFailedEvent(); $event = new AuthenticationFailedEvent();
$eventId = $event->getEventId(); $eventId = $event->identifier();
$this->service->handleAuthFailure($event); $this->service->handleAuthFailure($event);
$this->service->handleAuthFailure($event); $this->service->handleAuthFailure($event);
self::assertSame($eventId, $event->getEventId()); self::assertSame($eventId, $event->identifier());
} }
#[TestDox('Cleanup records successful maintenance counts')] #[TestDox('Cleanup records successful maintenance counts')]
@@ -38,9 +38,9 @@ final class FirewallSettingsServiceTest extends TestCase
$events->expects(self::once()) $events->expects(self::once())
->method('dispatch') ->method('dispatch')
->with(self::callback(static fn(FirewallSettingsUpdatedEvent $event): bool => ->with(self::callback(static fn(FirewallSettingsUpdatedEvent $event): bool =>
$event->getName() === FirewallSettingsUpdatedEvent::class $event->label() === FirewallSettingsUpdatedEvent::class
&& $event->getTenantId() === 'tenant-a' && $event->tenantIdentifier() === 'tenant-a'
&& $event->getIdentityId() === 'admin-a' && $event->actorIdentity() === 'admin-a'
&& $event->get('changeReason') === 'Tighten authentication controls' && $event->get('changeReason') === 'Tighten authentication controls'
&& $event->get('previous')['maxAuthFailures'] === 5 && $event->get('previous')['maxAuthFailures'] === 5
&& $event->get('current')['maxAuthFailures'] === 8 && $event->get('current')['maxAuthFailures'] === 8
@@ -70,7 +70,7 @@ final class UserAccountsServiceTest extends TestCase
self::assertInstanceOf(UserCreatedEvent::class, $emitted[0]); self::assertInstanceOf(UserCreatedEvent::class, $emitted[0]);
self::assertInstanceOf(UserDeletingEvent::class, $emitted[1]); self::assertInstanceOf(UserDeletingEvent::class, $emitted[1]);
self::assertSame('actor-a', $emitted[0]->actorIdentifier()); self::assertSame('actor-a', $emitted[0]->actorIdentifier());
self::assertSame('tenant-a', $emitted[1]->getTenantId()); self::assertSame('tenant-a', $emitted[1]->tenantIdentifier());
self::assertSame(['event', 'delete'], $operations); self::assertSame(['event', 'delete'], $operations);
} }