'box', 'ip' => '10.0.0.1', 'ssh_port' => 22, 'status' => 'online']); } /** @param array> $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 } }