CluPilotCloud/tests/Feature/Security/SecurityPageTest.php

107 lines
4.9 KiB
PHP

<?php // tests/Feature/Security/SecurityPageTest.php
use App\Livewire\Security;
use App\Models\Customer;
use App\Models\Instance;
use App\Models\SecurityBlock;
use Livewire\Livewire;
// Abweichung vom Auftragszettel: Customer::factory()->create() verknuepft
// keinen User (user_id bleibt NULL, siehe CustomerFactory) — jeder bestehende
// Test, der einen Kunden anmeldet, ruft dafuer ensureUser() (Muster:
// tests/Feature/CustomerTwoFactorTest.php::portalUser()). Der RUECKGABEWERT
// wird gebraucht, nicht $customer->user danach: ensureUser() selbst liest
// $this->user als ersten Schritt ("if ($this->user) return $this->user;"),
// bevor user_id gesetzt ist — das cacht die Beziehung als null, und ein
// spaeteres update() raeumt einen bereits geladenen Beziehungs-Cache nicht
// weg. $customer->user bliebe also null, obwohl user_id laengst gesetzt ist.
it('zeigt dem Inhaber die Sperren seiner eigenen Instanz', function () {
$customer = Customer::factory()->create();
$user = $customer->ensureUser();
$instance = Instance::factory()->for($customer)->create();
$block = SecurityBlock::factory()->for($instance)->create(['ip' => '203.0.113.7']);
Livewire::actingAs($user)->test(Security::class)->assertSee('203.0.113.7');
});
it('zeigt einem Inhaber die Sperren eines FREMDEN Kunden nicht', function () {
$meine = Customer::factory()->create();
$user = $meine->ensureUser();
$fremde = Instance::factory()->create();
SecurityBlock::factory()->for($fremde)->create(['ip' => '198.51.100.9']);
Livewire::actingAs($user)->test(Security::class)->assertDontSee('198.51.100.9');
});
it('laesst einen Inhaber eine fremde Sperre nicht aufheben', function () {
$meine = Customer::factory()->create();
$user = $meine->ensureUser();
$fremd = SecurityBlock::factory()->for(Instance::factory()->create())->create();
Livewire::actingAs($user)->test(Security::class)
->call('onReleaseConfirmed', $fremd->uuid)
->assertForbidden();
expect($fremd->fresh()->released_at)->toBeNull();
});
// Der Weg, den ein Mensch nimmt: das Modal mutiert nichts, es schickt nur
// 'block-release-confirmed' (R23). Die bestehenden Pruefungen rufen
// onReleaseConfirmed() direkt auf — damit steht das Ereignis selbst nie auf
// dem Pruefstand, und die Zeile danach auch nicht. Genau das war der Verdacht:
// dass die Zeile nach dem Aufheben weiter auf "Aktiv" steht, bis jemand neu
// laedt. Diese Pruefung nimmt den ganzen Weg.
it('raeumt die Zeile nach dem Aufheben aus der aktiven Liste in den Verlauf', function () {
$customer = Customer::factory()->create();
$user = $customer->ensureUser();
$instance = Instance::factory()->for($customer)->create();
$block = SecurityBlock::factory()->for($instance)->create(['ip' => '203.0.113.7']);
$seite = Livewire::actingAs($user)->test(Security::class)
->assertSee('active-'.$block->uuid, escape: false)
->assertDontSee('history-'.$block->uuid, escape: false);
$seite->dispatch('block-release-confirmed', uuid: $block->uuid)
->assertDontSee('active-'.$block->uuid, escape: false)
->assertSee('history-'.$block->uuid, escape: false)
->assertSee(__('security.status_released'));
});
it('sagt es, wenn die Firewall beim Aufheben nicht mitkam', function () {
// HostFirewall schluckt jeden Fehlschlag und meldet ihn nur ins Log. Ohne
// diesen Unterschied faende der Kunde „Sperre aufgehoben." vor, versuchte
// sich gleich wieder anzumelden — und wuerde wortlos erneut abgewiesen,
// ohne dass ihm irgendjemand sagen kann, warum.
$shell = new \App\Services\Ssh\FakeRemoteShell;
$shell->failConnect = true;
app()->instance(\App\Services\Ssh\RemoteShell::class, $shell);
$customer = Customer::factory()->create();
$user = $customer->ensureUser();
$host = \App\Models\Host::factory()->active()->create(['ssh_host_key' => 'SHA256:abc']);
$instance = Instance::factory()->for($customer)->create(['host_id' => $host->id]);
$block = SecurityBlock::factory()->for($instance)->create();
Livewire::actingAs($user)->test(Security::class)
->call('onReleaseConfirmed', $block->uuid)
->assertDispatched('notify', message: __('security.blocks_released_pending'));
// Der Datensatz steht trotzdem — er IST die Sperre, die Firewall-Menge nur
// ihr Abdruck. ScanForIntrusions traegt das Loeschen nach.
expect($block->fresh()->released_at)->not->toBeNull();
});
it('hebt eine eigene Sperre auf und traegt ein, wer es war', function () {
$customer = Customer::factory()->create();
$user = $customer->ensureUser();
$instance = Instance::factory()->for($customer)->create();
$block = SecurityBlock::factory()->for($instance)->create();
Livewire::actingAs($user)->test(Security::class)
->call('onReleaseConfirmed', $block->uuid);
expect($block->fresh()->released_at)->not->toBeNull()
->and($block->fresh()->released_by_id)->toBe($user->id);
});