clusev/tests/Feature/PostureServiceTest.php

92 lines
3.0 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\Server;
use App\Services\HardeningService;
use App\Services\PostureService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery;
use Tests\TestCase;
class PostureServiceTest extends TestCase
{
use RefreshDatabase;
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
private function server(): Server
{
return Server::create(['name' => 'box', 'ip' => '10.0.0.1', 'ssh_port' => 22, 'status' => 'online']);
}
/** @param array<int,array<string,mixed>> $state */
private function scoreWith(array $state): array
{
$hardening = Mockery::mock(HardeningService::class);
$hardening->shouldReceive('state')->andReturn($state);
return (new PostureService($hardening))->score($this->server());
}
private function item(string $key, bool $secure, bool $supported = true, bool $neutral = false): array
{
return ['key' => $key, 'label' => $key, 'detail' => '', 'featureOn' => false, 'secure' => $secure, 'supported' => $supported, 'reason' => $supported ? null : 'x', 'neutral' => $neutral];
}
public function test_score_is_the_ratio_of_passing_applicable_gates(): void
{
$r = $this->scoreWith([
$this->item('ssh_root', true),
$this->item('ssh_password', true),
$this->item('fail2ban', true),
$this->item('firewall', false), // 3 of 4 secure
]);
$this->assertSame(75, $r['score']);
$this->assertSame(3, $r['passed']);
$this->assertSame(4, $r['applicable']);
$this->assertSame('fair', $r['rating']);
}
public function test_all_secure_is_a_strong_hundred(): void
{
$r = $this->scoreWith([$this->item('a', true), $this->item('b', true)]);
$this->assertSame(100, $r['score']);
$this->assertSame('strong', $r['rating']);
}
public function test_neutral_and_unsupported_items_do_not_count(): void
{
$r = $this->scoreWith([
$this->item('ssh_root', true), // counts, secure
$this->item('unattended', false, neutral: true), // neutral → excluded
$this->item('firewall', false, supported: false), // unsupported → excluded
]);
$this->assertSame(1, $r['applicable']); // only ssh_root counts
$this->assertSame(100, $r['score']); // 1/1 secure
}
public function test_all_failing_is_weak(): void
{
$r = $this->scoreWith([$this->item('a', false), $this->item('b', false)]);
$this->assertSame(0, $r['score']);
$this->assertSame('weak', $r['rating']);
}
public function test_no_applicable_checks_defaults_to_a_full_score(): void
{
$r = $this->scoreWith([$this->item('unattended', false, neutral: true)]);
$this->assertSame(0, $r['applicable']);
$this->assertSame(100, $r['score']); // nothing to fail → not penalised
}
}