107 lines
4.5 KiB
PHP
107 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace App\Support\Os;
|
|
|
|
/**
|
|
* Immutable description of a fleet host's operating system, resolved once by
|
|
* OsDetector from /etc/os-release + a `command -v` probe. Everything that used to
|
|
* hard-code Debian/apt/ufw/systemd now asks an OsProfile instead.
|
|
*
|
|
* Phase-1 fully-supported package managers: apt, dnf (incl. yum), zypper — all on
|
|
* systemd hosts with ufw or firewalld. Arch (pacman) and Alpine (apk/OpenRC) are
|
|
* DETECTED and surfaced, but features that need an unsupported manager/init are
|
|
* gracefully disabled with a German reason via supports().
|
|
*/
|
|
final class OsProfile
|
|
{
|
|
/** Package managers Clusev can drive for updates/installs in this release. */
|
|
public const SUPPORTED_MANAGERS = ['apt', 'dnf', 'zypper'];
|
|
|
|
/**
|
|
* @param list<string> $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,
|
|
};
|
|
}
|
|
}
|