- FileCache: chown the cache dir to xc_vm when constructed under root
(installer, 'console.php status') — a root-owned tmp/cache blocked every
later xc_vm write: FileCache fell back to stale cache and CacheCronJob
spammed 'Permission denied' on every run
- CacheCronJob: route the raw file_put_contents cache writes through
FileCache::set() — identical igbinary bytes for existing readers, but
tmp+rename replaces root-owned files as long as the dir is writable,
and a failure is reported once per process instead of per file
'console.php status' and 'cron:maxmind' refuse to run as non-root, so the
previous sudo -u xc_vm invocations in the installer and service broke the
post-install steps ('Please run as root'). Revert them: startup/status are
root by design (root crontab, system limits, DB migrations) and startup
already delegates 'cron:cache' to xc_vm.
Fix the actual root-owned-cache leak instead:
- StartupCommand::generateCacheIfNeeded() spawned cron:cache_engine as the
current user (root at boot/install) — drop to xc_vm via sudo -u.
- FileCache::set() now chowns the written file to xc_vm when running as
root (same pattern as Logger), covering the remaining root-context
writers such as 'console.php status'.
A failed cache write (bad tmp/ ownership, full or missing tmpfs) left the
panel running on stale settings with no visible symptom. Report the first
failure per process through the error handler so it reaches the panel log.
Apply 'make cs-fix' — 493 files. Mechanical, import-block only:
- sort use statements alphabetically (class/function/const grouped);
- drop imports left unused by the PSR-4 migration (e.g. classes referenced by
leading-backslash FQCN whose redundant 'use' the automated insertion had added);
- one blank line after namespace and after the import block; collapse stray
blank lines around use.
No logic changes. Verified: php -l clean; PHPStan no errors; PHPUnit 295/295; and a
temporary PHPStan pass over src/Public/Controllers confirms no still-referenced
import was removed (0 unresolved classes). 'use' after inline HTML in view
templates is valid and aliases correctly (verified) — those imports are sorted too.