Files
XC_VM/tests/Support/AgentUser.php
T
obscuremind 3e8a295738 fix(cluster): address the mode-2 refusal and connect audit review
Root wrote the audits' files with its own rights in directories xc_vm can
write. cron:root_signals, `startup` and cluster:root count every connect
in mode 1, and the counts, the log, `since` and audit.json's temporary
file followed any link planted there, then were chowned (links followed
too). SettingsAudit::asAgentUser now runs that work as the owner of
config/cluster/: root switches its effective gid, groups and uid to that
user's and back after, so the kernel applies xc_vm's permissions and what
root makes is xc_vm's without a chown. Root writes nothing when
config/cluster/ is missing, a link or root's. The settings misses' merge
and publish use the same path.

A count rewrites its day file in place under an exclusive lock, but the
report read it with no lock and could see a day emptied, reporting SQL 0
for up to a minute. Day files are now read under a shared lock
(SettingsAudit::readDay), the misses' too.

cron:cleanup prunes both audits and rewrites audit.json before its first
query, which mode 2 refuses, so the audit stays bounded there.
`connects_since` now marks where the counts start: mode 0 deletes the
days it counted with it, and the report leaves out a day before its UTC
day.

ArchitectureTest's connect rule matched only `\XC_VM::` with a backslash
and one case: it now matches any case, with or without the backslash,
`new Redis;`, `PDO::connect(`, and forbids mysqli, outside comments and
string literals, with a self-test of the patterns.

Tests: the flush action run through executeAction() with iptables stubbed
and a database that refuses every other statement (a fall-through into
reboot fails); rootCommandsFromMain() with COMMANDS on and no trusted
pin; a new site rewriting a fresh audit.json; RedisCache skipped as
connect machinery; DatabaseFactory::open() keeping its handle; a
connects_since of 0 dropped; a report read while another process counts
never going down; links planted in both directories leaving root-only
files as they were. DbConnectRefusalTest runs on a fixed clock. A suite
run as root hands each test's tree to nobody (Tests\Support\AgentUser).

ADR 0004 and the plan: cron:root_signals in mode 2 runs its iptables sync
and keepalives before the refused signals loop when COMMANDS and the pin
are on; cron:cleanup's stream checks join the known limits; fifteen
direct sites, not sixteen; the seventh increment's refusal notes and
ReplicaBoot's docblock no longer say the refusal is to come. The agent's
contract is unchanged.
2026-09-27 02:27:11 +00:00

29 lines
886 B
PHP

<?php
namespace XcVm\Tests\Support;
/**
* The node's audits (SettingsAudit, ConnectAudit) do their file work as the
* owner of the agent's directory when they run as root, and nothing when
* that owner is root (SettingsAudit::asAgentUser). A suite run as root hands
* a test's throwaway tree to nobody (65534), standing in for xc_vm, as a
* node's tree is xc_vm's. Run as anyone else, it changes nothing.
*/
final class AgentUser {
public const UID = 65534;
public static function root(): bool {
return function_exists('posix_geteuid') && posix_geteuid() === 0;
}
/** Hand each path, and everything below it, to nobody when this is root. */
public static function own(string ...$rPaths): void {
if (!self::root()) {
return;
}
foreach ($rPaths as $rPath) {
exec('chown -R ' . self::UID . ':' . self::UID . ' ' . escapeshellarg(rtrim($rPath, '/')));
}
}
}