$available detected binaries (apt-get, dnf, ufw, firewall-cmd, systemctl, …) */ public function __construct( public readonly string $family, // debian|rhel|suse|arch|alpine|unknown public readonly string $id, // raw /etc/os-release ID public readonly string $prettyName, // PRETTY_NAME for display public readonly string $packageManager, // apt|dnf|zypper|pacman|apk|none public readonly string $firewallTool, // ufw|firewalld|none public readonly string $serviceManager, // systemd|openrc|none public readonly array $available = [], ) {} public function has(string $binary): bool { return in_array($binary, $this->available, true); } public function isSystemd(): bool { return $this->serviceManager === 'systemd'; } /** True when Clusev can drive package install/update on this host. */ public function managesPackages(): bool { return in_array($this->packageManager, self::SUPPORTED_MANAGERS, true); } /** German family label for the UI. */ public function familyLabel(): string { return match ($this->family) { 'debian' => 'Debian/Ubuntu', 'rhel' => 'RHEL/Fedora', 'suse' => 'openSUSE/SLES', 'arch' => 'Arch Linux', 'alpine' => 'Alpine Linux', default => 'Unbekanntes System', }; } /** German label for the host firewall in the hardening checklist. */ public function firewallLabel(): string { return match ($this->firewallTool) { 'ufw' => 'Firewall (UFW)', 'firewalld' => 'Firewall (firewalld)', default => 'Firewall', }; } /** * Whether a feature is supported on this host. Returns NULL when supported, or * a German reason to show the operator when not — so unsupported combinations * degrade with an explanation instead of failing opaquely. */ public function supports(string $feature): ?string { return match ($feature) { 'ssh' => $this->isSystemd() ? null : 'SSH-Härtung benötigt systemd, das auf '.$this->familyLabel().' nicht erkannt wurde.', 'services' => $this->isSystemd() ? null : 'Dienst-Steuerung benötigt systemd, das hier nicht erkannt wurde.', 'updates' => $this->managesPackages() ? null : 'Paket-Updates über Clusev werden unter '.$this->familyLabel().' noch nicht unterstützt.', 'fail2ban' => ($this->managesPackages() && $this->isSystemd()) ? null : 'fail2ban wird unter '.$this->familyLabel().' über Clusev noch nicht unterstützt.', 'firewall' => ($this->firewallTool !== 'none' && $this->isSystemd() && ($this->firewallTool === 'firewalld' || $this->managesPackages() || $this->has('ufw'))) ? null : 'Eine unterstützte Firewall (UFW oder firewalld) wurde unter '.$this->familyLabel().' nicht gefunden.', // apt -> unattended-upgrades; dnf -> dnf-automatic. A yum-ONLY host (e.g. // CentOS 7) maps to the dnf manager for upgrades but has no dnf-automatic // (it uses yum-cron), so require a real `dnf` binary for this feature. 'auto_updates' => (($this->packageManager === 'apt' || ($this->packageManager === 'dnf' && $this->has('dnf'))) && $this->isSystemd()) ? null : 'Automatische Updates werden unter '.$this->familyLabel().' über Clusev noch nicht unterstützt.', default => null, }; } }