Harden NordVPN reconciliation and WebGUI testing

This commit is contained in:
ms2k 2026-08-07 02:30:26 +09:00
commit b4a30ca190

View file

@ -0,0 +1,126 @@
<?php
use OPNsense\NordVPN\Bootstrapper;
use OPNsense\NordVPN\EndpointStore;
use OPNsense\NordVPN\ManagedConfiguration;
use OPNsense\NordVPN\NordApi;
use OPNsense\NordVPN\ReconciliationLock;
use OPNsense\NordVPN\Settings;
use OPNsense\NordVPN\StatusStore;
use OPNsense\NordVPN\SystemRunner;
use PHPUnit\Framework\TestCase;
class BootstrapperTestApi extends NordApi
{
public string $token = '';
private string $key;
public function __construct(string $key)
{
$this->key = $key;
}
public function recommendations(array $countryCodes = [], int $limit = 5): array
{
return [[
'hostname' => 'nl.example.invalid',
'address' => '198.51.100.10',
'country' => 'NL',
'public_key' => $this->key,
]];
}
public function credentials(string $token): string
{
$this->token = $token;
return $this->key;
}
}
class BootstrapperTestConfiguration extends ManagedConfiguration
{
private Settings $settings;
public array $provisioned = [];
public function __construct()
{
$this->settings = new Settings();
}
public function settings(): Settings
{
return $this->settings;
}
public function provision(string $privateKey, array $candidate): void
{
$this->provisioned = [$privateKey, $candidate];
}
public function repairGatewayInterface(): bool
{
return false;
}
}
class BootstrapperTestRunner extends SystemRunner
{
public array $operations = [];
public function applyWireGuard(): void
{
$this->operations[] = 'wireguard';
}
public function applyRouting(): void
{
$this->operations[] = 'routing';
}
public function applyFirewall(): void
{
$this->operations[] = 'firewall';
}
}
final class BootstrapperTest extends TestCase
{
public function testBootstrapQueuesReconciliationAfterApplyingInitialTunnel(): void
{
$key = base64_encode(str_repeat("\0", 32));
$api = new BootstrapperTestApi($key);
$configuration = new BootstrapperTestConfiguration();
$runner = new BootstrapperTestRunner();
$statusPath = sys_get_temp_dir() . '/nordvpn-bootstrap-' . bin2hex(random_bytes(8)) . '.json';
$lockPath = sys_get_temp_dir() . '/nordvpn-bootstrap-' . bin2hex(random_bytes(8)) . '.lock';
$endpointDirectory = sys_get_temp_dir() . '/nordvpn-bootstrap-' . bin2hex(random_bytes(8));
$endpointPath = $endpointDirectory . '/endpoints.txt';
$configuration->settings()->general->exempt_wireguard = '1';
$queued = 0;
$result = (new Bootstrapper(
$api,
$configuration,
new StatusStore($statusPath),
$runner,
new EndpointStore($endpointPath),
new ReconciliationLock($lockPath),
static function () use (&$queued): void {
$queued++;
}
))->run('synthetic-token');
self::assertSame('ok', $result['status']);
self::assertSame('synthetic-token', $api->token);
self::assertSame($key, $configuration->provisioned[0]);
self::assertSame(['firewall', 'wireguard', 'routing', 'firewall'], $runner->operations);
self::assertSame("198.51.100.10\n", file_get_contents($endpointPath));
self::assertSame('reconciling', $result['tunnel']['state']);
self::assertSame(1, $queued);
unlink($statusPath);
unlink($lockPath);
unlink($endpointPath);
rmdir($endpointDirectory);
}
}