Files
XC_VM/tests/Unit/LicenseGateTest.php
T
Divarion_D 5ef12b1cde feat(license): fanout licence gate seam (soft, fail-open)
Adds LicenseGate::fanoutUsable() — the single "should this request use the
fanout daemon?" check (control socket present AND licence permits it). The two
fanout choke points now consult it instead of bare file_exists(FANOUT_CTL_SOCK):
StreamProcess::supervisionEnabled() and the three delivery tests in
Public/stream/live.php. When it returns false, live streams fall back to the
legacy delivery path automatically (soft enforcement) — nothing is hard-blocked.

The licence verdict itself (HWID-bound key tied to install_id, hidden
method-selector bytes, weekly re-validation, 7-day offline grace) lives in the
compiled xcvm_core extension; PHP only reads it via \XC_VM::license_valid()
when present. Fail-open where the extension or method is absent (dev/CI and
installs without xcvm_core), so this is behaviour-preserving until the C side
ships the verdict — and never bricks a working panel.

Helper kept in the new LicenseGate (not FanoutClient) to avoid touching that
debt-heavy file. supervisionEnabled() simplifies (cc 4->2). README disclosure
for activation will land when the verdict goes live.

Tests: fail-open without extension, unusable without control socket. Full
suite (816) + gates + CRAP + phpcs green.
2026-09-18 15:32:50 +03:00

30 lines
1.1 KiB
PHP

<?php
use PHPUnit\Framework\TestCase;
use XcVm\Core\License\LicenseGate;
/**
* Covers the soft, fail-open licence gate for the fanout daemon: without the
* xcvm_core extension the gate must never block fanout, and fanoutUsable() must
* report the daemon unusable when its control socket is absent.
*/
final class LicenseGateTest extends TestCase {
/** No xcvm_core in dev/CI → the gate must fail open (fanout stays available). */
public function testFanoutAllowedFailsOpenWithoutExtension(): void {
if (class_exists('XC_VM') && method_exists('XC_VM', 'license_valid')) {
$this->markTestSkipped('xcvm_core present — cannot assert the fail-open path.');
}
$this->assertTrue(LicenseGate::fanoutAllowed());
}
/** Fanout is unusable when the control socket is absent, regardless of licence. */
public function testFanoutUnavailableWithoutControlSocket(): void {
if (defined('FANOUT_CTL_SOCK') && file_exists(FANOUT_CTL_SOCK)) {
$this->markTestSkipped('FANOUT_CTL_SOCK exists in this environment.');
}
$this->assertFalse(LicenseGate::fanoutUsable());
}
}