[Unit] Description=VesperOS Profile Daemon (profiles + Zero-Touch Enrollment) Documentation=https://vesperos.oxmc.me/docs/vesperprofiled # Must run before cloud-init so preinstalled profiles (WiFi, MDM drop-ins, # first-boot config) are on disk when cloud-init starts. Before=cloud-init-local.service cloud-init.service After=local-fs.target dbus.service systemd-udev-settle.service # Start after NetworkManager so ZTE can immediately check current # connectivity state rather than waiting for a StateChanged signal. After=NetworkManager.service # But don't hard-require NM — ZTE degrades gracefully if NM isn't present. Wants=NetworkManager.service [Service] Type=notify NotifyAccess=main ExecStart=/usr/sbin/vesperprofiled ExecReload=/bin/kill -HUP $MAINPID User=root Group=root # Restart the whole daemon (profile service + ZTE watcher) on crash. Restart=on-failure RestartSec=5s TimeoutStartSec=60 RuntimeDirectory=vesperprofiled RuntimeDirectoryMode=0750 StateDirectory=vesperprofiled StateDirectoryMode=0700 # Writable paths — profile daemon writes config drops, ZTE writes state ReadWritePaths=/etc /var/lib/vesperprofiled /run/vesperprofiled \ /var/lib/gnome-initial-setup SystemCallFilter=@system-service @file-system @network-io @process SystemCallErrorNumber=EPERM NoNewPrivileges=false PrivateTmp=true ProtectKernelLogs=true ProtectKernelModules=true ProtectControlGroups=true StandardOutput=journal StandardError=journal SyslogIdentifier=vesperprofiled [Install] WantedBy=multi-user.target WantedBy=cloud-init.target