'customer@example.com', 'subject' => 'Test', 'content' => 'Test body']; $cases = [ [], array_replace($valid, ['sender_email' => ['customer@example.com']]), array_replace($valid, ['sender_email' => 'Name ']), array_replace($valid, ['subject' => "Header\r\nInjected"]), array_replace($valid, ['subject' => str_repeat('x', 256)]), array_replace($valid, ['subject' => "\xFF"]), array_replace($valid, ['content' => str_repeat('x', 65536)]), array_replace($valid, ['content' => "\xFF"]), array_replace($valid, ['content' => "\0"]), array_replace($valid, ['sender_name' => ['Invalid']]), array_replace($valid, ['sender_name' => "Name\nInjected"]), array_replace($valid, ['sender_name' => str_repeat('x', 256)]), ]; foreach ($cases as $index => $data) { try { $service->import($data); throw new \RuntimeException('Invalid input accepted: ' . $index); } catch (\FOSSBilling\InformationException) { // Must reject before accessing any database services. } } // The production API exposes only the settings page operations. $methods = array_filter((new ReflectionClass(\Box\Mod\Mailgateway\Api\Admin::class))->getMethods(ReflectionMethod::IS_PUBLIC), fn ($method) => $method->getDeclaringClass()->getName() === \Box\Mod\Mailgateway\Api\Admin::class); $names = array_map(fn ($method) => $method->getName(), $methods); sort($names); if ($names !== ['install_dependencies', 'mailbox_delete', 'notifications_setup', 'settings_get', 'settings_save', 'setup', 'test_connection']) { throw new RuntimeException('Unexpected production API endpoints'); } echo 'Passed ', count($cases), " invalid-input checks and production API surface check.\n"; // Exercise the import orchestration with real ticket entities and a simulated // Support autoresponse, without requiring a database or sending email. $client = new class extends \Model_Client { public function __get($property) { return $property === 'id' ? 7 : null; } }; foreach (['on_hold' => 1, 'open' => 0, 'closed' => 0] as $status => $expectedFlushes) { $ticket = new \Box\Mod\Support\Entity\SupportTicket(); $ticket->setStatus($status); $helpdesk = new \Box\Mod\Support\Entity\Helpdesk(); $support = new class($ticket, $helpdesk, $client) { public function __construct(public $ticket, public $helpdesk, public $client) {} public function getHelpdeskRepository() { return $this; } public function findBy($criteria, $order, $limit) { return [$this->helpdesk]; } public function ticketCreateForClient($client, $helpdesk, $data): int { if ($client !== $this->client || $helpdesk !== $this->helpdesk || $data['content'] !== 'Test body') { throw new \RuntimeException('Incorrect customer or message passed to Support'); } return 42; } public function getTicketById(int $id) { return $this->ticket; } public function toApiArray($ticket, $deep, $identity) { if ($identity !== $this->client) { throw new \RuntimeException('Notification uses incorrect customer'); } return ['id' => 42]; } }; $em = new class { public int $flushes = 0; public function flush(): void { ++$this->flushes; } }; $di = new \Pimple\Container(); $di['dbal'] = new class { public function fetchFirstColumn($sql, $params) { return [7]; } }; $di['db'] = new class($client) { public function __construct(public $client) {} public function getExistingModelById($type, $id) { return $this->client; } }; $di['em'] = $em; $di['mailgateway_settings'] = new class { public function get(): array { return ['support_helpdesk_id' => null]; } }; $di['mailgateway_notification_cooldown'] = new class { public function run($sender, $queue): bool { return $queue() !== false; } }; $di['auth'] = new class { public function isClientLoggedIn(): bool { return false; } }; $email = new class { public array $messages = []; public function sendTemplate($data) { $this->messages[] = $data; } }; $di['mod_service'] = $di->protect(fn ($module) => $module === 'email' ? $email : $support); $service->setDi($di); $result = $service->import($valid); $expectedStatus = $status === 'on_hold' ? 'open' : $status; if ($ticket->getStatus() !== $expectedStatus || $em->flushes !== $expectedFlushes || $result['ticket_id'] !== 42 || $result['client_id'] !== 7) { throw new \RuntimeException('Import status regression: ' . $status); } if ($email->messages !== [['to_client' => 7, 'code' => 'mod_support_ticket_open', 'ticket' => ['id' => 42]]]) { throw new \RuntimeException('Customer acknowledgement missing or incorrect'); } } echo "Passed autoresponse status check, existing Open/Closed status checks, and customer identity forwarding.\n"; echo "Passed customer acknowledgement recipient, template, and ticket-number checks.\n"; $guestSupport = new class { public array $received = []; public bool $enabled = true; public function getHelpdeskRepository() { return $this; } public function findBy($criteria, $order, $limit) { $helpdesk = new \Box\Mod\Support\Entity\Helpdesk(); (new \ReflectionProperty($helpdesk, 'id'))->setValue($helpdesk, 3); return [$helpdesk]; } public function ticketCreateForGuest($data): string { if (!$this->enabled) { throw new \FOSSBilling\InformationException('Guest tickets disabled'); } $this->received[] = $data; return 'private-access-hash'; } public function findOneByHash($hash) { if ($hash !== 'private-access-hash') { throw new \RuntimeException('Guest hash lookup incorrect'); } $ticket = new \Box\Mod\Support\Entity\SupportTicket(); (new \ReflectionProperty($ticket, 'id'))->setValue($ticket, 43); return $ticket; } }; $guestDi = new \Pimple\Container(); $lookup = new class { public array $ids = []; public function fetchFirstColumn($sql, $params) { return $this->ids; } }; $guestDi['dbal'] = $lookup; $guestDi['mailgateway_settings'] = new class { public function get(): array { return ['support_helpdesk_id' => null]; } }; $guestDi['mod_service'] = $guestDi->protect(fn ($module) => $guestSupport); $service->setDi($guestDi); foreach ([null, 'Guest Sender'] as $name) { $data = $valid; if ($name !== null) { $data['sender_name'] = $name; } $result = $service->import($data); $received = $guestSupport->received[array_key_last($guestSupport->received)]; if ($result !== ['ticket_id' => 43, 'client_id' => null, 'support_helpdesk_id' => 3] || $received !== ['name' => $name ?? $valid['sender_email'], 'email' => $valid['sender_email'], 'subject' => 'Test', 'content' => 'Test body', 'support_helpdesk_id' => 3]) { throw new \RuntimeException('Guest import or attribution incorrect'); } } $guestSupport->enabled = false; try { $service->import($valid); throw new \RuntimeException('Disabled guest policy bypassed'); } catch (\FOSSBilling\InformationException) { } $lookup->ids = [7, 8]; try { $service->import($valid); throw new \RuntimeException('Ambiguous customer accepted'); } catch (\FOSSBilling\InformationException) { } if (count($guestSupport->received) !== 2) { throw new \RuntimeException('Unexpected guest creation'); } echo "Passed guest routing, sender name fallback, helpdesk mapping, private hash handling, disabled guest policy, and ambiguous customer rejection.\n";