# SPDX-License-Identifier: GPL-3.0-or-later """Post-install checks: services, timers, and their functional health. Parity port of validate_firewall, validate_dns_config, validate_avahi, validate_fail2ban, validate_networkmanager, and validate_all_services / validate_service_functions. Mapping of the shell sweep's three outcomes: - validation_fail (hard) -> assert - validation_warn (soft) -> pytest.skip with the reason (visible, never red) - validation_skip (precond)-> pytest.skip gated on a fixture """ import pytest # Required services: (name, must_be_active). ufw can't activate in the VM (no # iptables kernel modules), so it's enabled-only; cronie/atd are enabled-only too. REQUIRED_ENABLED_ACTIVE = ["sshd", "systemd-resolved", "fail2ban", "NetworkManager", "rngd"] REQUIRED_ENABLED_ONLY = ["ufw", "cronie", "atd"] REQUIRED_TIMERS = ["reflector.timer", "paccache.timer"] OPTIONAL_SERVICES = ["avahi-daemon", "bluetooth", "cups", "docker", "tailscaled"] @pytest.mark.attribution("archsetup") @pytest.mark.parametrize("svc", REQUIRED_ENABLED_ACTIVE) def test_required_service_enabled_and_active(host, svc): s = host.service(svc) assert s.is_enabled, "%s should be enabled" % svc assert s.is_running, "%s should be active" % svc @pytest.mark.smoke @pytest.mark.attribution("archsetup") @pytest.mark.parametrize("svc", REQUIRED_ENABLED_ONLY) def test_required_service_enabled(host, svc): assert host.service(svc).is_enabled, "%s should be enabled" % svc @pytest.mark.attribution("archsetup") @pytest.mark.parametrize("timer", REQUIRED_TIMERS) def test_required_timer_enabled(host, timer): assert host.service(timer).is_enabled, "%s should be enabled" % timer @pytest.mark.parametrize("svc", OPTIONAL_SERVICES) def test_optional_service(host, svc): # Optional: warn-if-missing in the shell sweep -> skip here so it never reds. if not host.service(svc).is_enabled: pytest.skip("%s not enabled (optional)" % svc) @pytest.mark.attribution("archsetup") def test_dns_over_tls_dropin_present(host): # archsetup ships /etc/systemd/resolved.conf.d/dns-over-tls.conf. assert host.file("/etc/systemd/resolved.conf.d/dns-over-tls.conf").exists @pytest.mark.attribution("archsetup") def test_fail2ban_responds(host): assert host.run("fail2ban-client status").rc == 0 @pytest.mark.attribution("archsetup") def test_networkmanager_responds(host): assert host.run("nmcli general status").rc == 0 @pytest.mark.attribution("archsetup") def test_log_cleanup_cron_installed(host, target_user): out = host.run("sudo -u %s crontab -l" % target_user).stdout assert "log-cleanup" in out, "log-cleanup entry missing from user crontab" @pytest.mark.attribution("archsetup") def test_syncthing_user_lingering_enabled(host, target_user): # syncthing runs as a user service; lingering must be on for autostart. assert host.file("/var/lib/systemd/linger/%s" % target_user).exists def test_dns_resolution(host): # Network-dependent; advisory in the shell sweep. Skip on failure. if host.run("resolvectl query archlinux.org").rc != 0: pytest.skip("DNS resolution query failed (network-dependent)") def test_mdns_resolves(host, on_slirp): # mDNS needs multicast, which QEMU slirp doesn't pass. if on_slirp: pytest.skip("mDNS not possible on slirp networking (no multicast)") if not host.service("avahi-daemon").is_enabled: pytest.skip("avahi-daemon not enabled") hostname = host.run("hostname").stdout.strip() assert host.run("ping -c 1 -W 2 %s.local" % hostname).rc == 0 def test_docker_functional(host): if not host.service("docker").is_enabled: pytest.skip("docker not enabled") if not host.service("docker").is_running: # archsetup enables docker for next boot, not --now; pre-reboot this is correct. pytest.skip("docker enabled but not started (starts on boot by design)") assert host.run("docker info").rc == 0