refactor(kernel): unify HTTP and CLI application lifecycle

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-07-27 00:48:11 -04:00
parent 98826143a8
commit 65c1b5fb75
67 changed files with 2737 additions and 1070 deletions
+25 -49
View File
@@ -8,8 +8,8 @@ use KTXC\Http\Request\Request;
use KTXC\Models\Firewall\FirewallRuleObject;
use KTXC\Models\Firewall\FirewallLogObject;
use KTXC\Stores\FirewallStore;
use KTXC\SessionTenant;
use KTXF\Event\EventBus;
use KTXC\Context\TenantContextInterface;
use KTXF\Event\EventDispatcherInterface;
use KTXF\Event\SecurityEvent;
use KTXF\IpUtils;
@@ -41,33 +41,9 @@ class FirewallService
public function __construct(
private readonly FirewallStore $store,
private readonly SessionTenant $tenant,
private readonly EventBus $eventBus
private readonly TenantContextInterface $tenantContext,
private readonly EventDispatcherInterface $events,
) {
// Listen for auth failures to detect brute force
$this->eventBus->subscribe(
SecurityEvent::AUTH_FAILURE,
[$this, 'handleAuthFailure'],
100 // High priority
);
// Log all security events asynchronously
$this->eventBus->subscribeAsync(
SecurityEvent::AUTH_FAILURE,
[$this, 'logSecurityEvent']
);
$this->eventBus->subscribeAsync(
SecurityEvent::AUTH_SUCCESS,
[$this, 'logSecurityEvent']
);
$this->eventBus->subscribeAsync(
SecurityEvent::ACCESS_DENIED,
[$this, 'logSecurityEvent']
);
$this->eventBus->subscribeAsync(
SecurityEvent::BRUTE_FORCE_DETECTED,
[$this, 'logSecurityEvent']
);
}
/**
@@ -100,7 +76,7 @@ class FirewallService
return new FirewallAnalyzeResult(true);
}
$tenantId = $this->tenant->identifier();
$tenantId = $this->tenantContext->identifier();
if (!$tenantId) {
return new FirewallAnalyzeResult(true);
}
@@ -158,7 +134,7 @@ class FirewallService
public function handleAuthFailure(SecurityEvent $event): void
{
$ipAddress = $event->getIpAddress();
$tenantId = $event->getTenantId() ?? $this->tenant->identifier();
$tenantId = $event->getTenantId() ?? $this->tenantContext->identifier();
if (!$ipAddress || !$tenantId) {
return;
@@ -198,8 +174,8 @@ class FirewallService
): void {
// Publish brute force event
$event = SecurityEvent::bruteForceDetected($ipAddress, $failureCount, $windowSeconds);
$event->setTenantId($this->tenant->identifier());
$this->eventBus->publish($event);
$event->setTenantId($this->tenantContext->identifier());
$this->events->dispatch($event);
// Auto-block the IP
$blockDuration = $this->getConfig(
@@ -220,7 +196,7 @@ class FirewallService
*/
public function logSecurityEvent(SecurityEvent $event): void
{
$tenantId = $event->getTenantId() ?? $this->tenant->identifier();
$tenantId = $event->getTenantId() ?? $this->tenantContext->identifier();
if (!$tenantId) {
return;
}
@@ -283,8 +259,8 @@ class FirewallService
$rule->getId(),
$rule->getReason()
);
$event->setTenantId($this->tenant->identifier());
$this->eventBus->publish($event);
$event->setTenantId($this->tenantContext->identifier());
$this->events->dispatch($event);
}
// ========================================
@@ -300,7 +276,7 @@ class FirewallService
?string $createdBy = null,
?int $durationSeconds = null
): FirewallRuleObject {
$tenantId = $this->tenant->identifier();
$tenantId = $this->tenantContext->identifier();
if (!$tenantId) {
throw new \RuntimeException('Cannot create firewall rule: no tenant configured');
}
@@ -340,7 +316,7 @@ class FirewallService
$event->setIpAddress($ipAddress)
->setReason($reason)
->setTenantId($tenantId);
$this->eventBus->publish($event);
$this->events->dispatch($event);
return $rule;
}
@@ -353,7 +329,7 @@ class FirewallService
?string $reason = null,
?string $createdBy = null
): FirewallRuleObject {
$tenantId = $this->tenant->identifier();
$tenantId = $this->tenantContext->identifier();
if (!$tenantId) {
throw new \RuntimeException('Cannot create firewall rule: no tenant configured');
}
@@ -376,7 +352,7 @@ class FirewallService
$event->setIpAddress($ipAddress)
->setReason($reason)
->setTenantId($tenantId);
$this->eventBus->publish($event);
$this->events->dispatch($event);
return $rule;
}
@@ -389,7 +365,7 @@ class FirewallService
?string $reason = null,
?string $createdBy = null
): FirewallRuleObject {
$tenantId = $this->tenant->identifier();
$tenantId = $this->tenantContext->identifier();
if (!$tenantId) {
throw new \RuntimeException('Cannot create firewall rule: no tenant configured');
}
@@ -419,7 +395,7 @@ class FirewallService
?string $createdBy = null,
?int $durationSeconds = null
): FirewallRuleObject {
$tenantId = $this->tenant->identifier();
$tenantId = $this->tenantContext->identifier();
if (!$tenantId) {
throw new \RuntimeException('Cannot create firewall rule: no tenant configured');
}
@@ -448,7 +424,7 @@ class FirewallService
$event->setDeviceFingerprint($fingerprint)
->setReason($reason)
->setTenantId($tenantId);
$this->eventBus->publish($event);
$this->events->dispatch($event);
return $rule;
}
@@ -464,7 +440,7 @@ class FirewallService
}
// Verify tenant ownership
if ($rule->getTenantId() !== $this->tenant->identifier()) {
if ($rule->getTenantId() !== $this->tenantContext->identifier()) {
return false;
}
@@ -485,7 +461,7 @@ class FirewallService
}
// Verify tenant ownership
if ($rule->getTenantId() !== $this->tenant->identifier()) {
if ($rule->getTenantId() !== $this->tenantContext->identifier()) {
return false;
}
@@ -501,7 +477,7 @@ class FirewallService
*/
public function listRules(bool $activeOnly = true): array
{
$tenantId = $this->tenant->identifier();
$tenantId = $this->tenantContext->identifier();
if (!$tenantId) {
return [];
}
@@ -518,7 +494,7 @@ class FirewallService
?string $result = null,
int $limit = 100
): array {
$tenantId = $this->tenant->identifier();
$tenantId = $this->tenantContext->identifier();
if (!$tenantId) {
return [];
}
@@ -531,7 +507,7 @@ class FirewallService
*/
public function getBlockedCount(?\DateTimeImmutable $since = null): int
{
$tenantId = $this->tenant->identifier();
$tenantId = $this->tenantContext->identifier();
if (!$tenantId) {
return 0;
}
@@ -556,7 +532,7 @@ class FirewallService
*/
private function getConfig(string $key, mixed $default = null): mixed
{
$config = $this->tenant->configuration();
$config = $this->tenantContext->configuration();
$parts = explode('.', $key);
foreach ($parts as $part) {
@@ -576,7 +552,7 @@ class FirewallService
private function getActiveRules(): array
{
if ($this->rulesCache === null) {
$tenantId = $this->tenant->identifier();
$tenantId = $this->tenantContext->identifier();
$this->rulesCache = $tenantId
? $this->store->listRules($tenantId, true)
: [];