set('admin_access.hosts', []); $this->actingAs(operator('Owner'), 'operator') ->get('http://app.dev.clupilot.com/admin') ->assertOk(); }); it('404s the console on a hostname that is not allowed', function () { config()->set('admin_access.hosts', ['admin.dev.clupilot.com']); // A PUBLIC hostname must not even hint that a console exists here. $this->actingAs(operator('Owner'), 'operator') ->get('http://app.dev.clupilot.com/admin') ->assertNotFound(); $this->actingAs(operator('Owner'), 'operator') ->get('http://www.dev.clupilot.com/admin/hosts') ->assertNotFound(); }); it('serves the console on an allowed hostname', function () { config()->set('admin_access.hosts', ['admin.dev.clupilot.com', '10.10.90.185']); $this->actingAs(operator('Owner'), 'operator') ->get('http://admin.dev.clupilot.com/admin') ->assertOk(); $this->actingAs(operator('Owner'), 'operator') ->get('http://10.10.90.185/admin') ->assertOk(); }); it('matches configured hostnames case-insensitively', function () { // DNS is case-insensitive and getHost() lowercases, so ADMIN_HOSTS with any // capitals must still match — otherwise a typo silently locks operators out. config()->set('admin_access.hosts', ['Admin.Dev.CluPilot.COM']); $this->actingAs(operator('Owner'), 'operator') ->get('http://admin.dev.clupilot.com/admin') ->assertOk(); // …and the restriction still bites on everything else. $this->actingAs(operator('Owner'), 'operator') ->get('http://www.dev.clupilot.com/admin') ->assertNotFound(); }); it('404s before revealing a login redirect to guests on a public host', function () { config()->set('admin_access.hosts', ['admin.dev.clupilot.com']); // Not a redirect to /login — that would confirm the console's existence. $this->get('http://www.dev.clupilot.com/admin')->assertNotFound(); }); it('blocks admin Livewire actions posted through a public hostname', function () { // Admin actions go to /livewire/update, which a path-based guard would skip. // Livewire must re-apply the host restriction from the component's route. config()->set('admin_access.hosts', ['admin.dev.clupilot.com']); $owner = operator('Owner'); // Render the real page on an ALLOWED host so Livewire records the admin // route's middleware on the snapshot (Livewire::test() skips HTTP routing // and would not, which would make this test pass for the wrong reason). $html = $this->actingAs($owner, 'operator') ->get('http://admin.dev.clupilot.com/admin/datacenters') ->assertOk() ->getContent(); expect($html)->toMatch('/wire:snapshot=/'); preg_match('/wire:snapshot="([^"]+)"/', $html, $m); $snapshot = html_entity_decode($m[1], ENT_QUOTES); $payload = fn () => [ '_token' => csrf_token(), 'components' => [[ 'snapshot' => $snapshot, 'updates' => [], 'calls' => [['path' => '', 'method' => 'save', 'params' => []]], ]], ]; // Replayed against a PUBLIC hostname → must not execute. $this->actingAs($owner, 'operator') ->post('http://www.dev.clupilot.com/livewire/update', $payload()) ->assertNotFound(); // Positive control: the very same payload works on the allowed host, so the // 404 above is the restriction — not a malformed request. $this->actingAs($owner, 'operator') ->post('http://admin.dev.clupilot.com/livewire/update', $payload()) ->assertOk(); }); it('registers the host restriction as Livewire-persistent middleware', function () { // Guards the wiring above: without this, /livewire/update bypasses ADMIN_HOSTS. $persistent = (new ReflectionClass(\Livewire\Mechanisms\PersistentMiddleware\PersistentMiddleware::class)) ->getProperty('persistentMiddleware'); expect($persistent->getValue(app(\Livewire\Mechanisms\PersistentMiddleware\PersistentMiddleware::class))) ->toContain(\App\Http\Middleware\RestrictAdminHost::class); }); it('keeps the customer portal reachable on public hosts', function () { config()->set('admin_access.hosts', ['admin.dev.clupilot.com']); $user = User::factory()->create(); $this->actingAs($user)->get('http://app.dev.clupilot.com/dashboard')->assertOk(); $this->get('http://www.dev.clupilot.com/')->assertOk(); });