fix(vpn): classify adopted peers as system, not staff; drop duplicate env line
Codex spotted the migration labelling sync-adopted peers as staff with no owner, which breaks the invariant the same migration introduces. The live sync had the identical hole — it never set kind at all, so every adopted peer landed on the 'staff' default. Both now use system for a peer nobody is behind, and promote it to host once the link is known. .env.example carried ADMIN_HOSTS twice; phpdotenv keeps the first, so a fresh checkout would have got the list without localhost and 404'd its own console. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>feat/portal-design
parent
0d9b62eb50
commit
1112b4cdec
|
|
@ -168,7 +168,6 @@ MONITORING_ATTEMPTS=2
|
|||
# Erzeugen: head -c 32 /dev/urandom | base64
|
||||
VPN_CONFIG_KEY=
|
||||
|
||||
ADMIN_HOSTS=admin.dev.clupilot.com,10.10.90.185
|
||||
ADMIN_HOSTS=admin.dev.clupilot.com,10.10.90.185,localhost,127.0.0.1
|
||||
|
||||
# ── Nextcloud blueprint template ─────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -99,6 +99,9 @@ class SyncVpnPeers implements ShouldBeUnique, ShouldQueue
|
|||
// never created through the console.
|
||||
'allowed_ip' => strtok($snapshot->allowedIps, '/') ?: $snapshot->allowedIps,
|
||||
'host_id' => $host?->id,
|
||||
// Never "staff": a staff access has an owner, and nobody is
|
||||
// behind a peer we merely found on the interface.
|
||||
'kind' => $host !== null ? VpnPeer::KIND_HOST : VpnPeer::KIND_SYSTEM,
|
||||
'name' => $host?->name ?? __('vpn.unknown_peer'),
|
||||
'enabled' => true,
|
||||
]);
|
||||
|
|
@ -112,6 +115,9 @@ class SyncVpnPeers implements ShouldBeUnique, ShouldQueue
|
|||
// (created_by is null exactly for sync-adopted rows).
|
||||
if ($peer->host_id === null && $host !== null) {
|
||||
$observed['host_id'] = $host->id;
|
||||
if ($peer->kind === VpnPeer::KIND_SYSTEM) {
|
||||
$observed['kind'] = VpnPeer::KIND_HOST;
|
||||
}
|
||||
if ($peer->created_by === null) {
|
||||
$observed['name'] = $host->name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,13 +32,18 @@ return new class extends Migration
|
|||
$table->unsignedInteger('download_count')->default(0);
|
||||
});
|
||||
|
||||
// Existing rows: pipeline peers are host peers, the rest belong to
|
||||
// whoever created them (created_by is the only ownership hint we have).
|
||||
// Existing rows fall into three groups, and the difference matters:
|
||||
// pipeline peers are host peers; peers someone created in the console
|
||||
// belong to that person; and peers the sync adopted off the interface
|
||||
// have no human behind them at all — calling those "staff" would break
|
||||
// the very invariant this migration introduces (a staff access has an
|
||||
// owner).
|
||||
DB::table('vpn_peers')->whereNotNull('host_id')->update(['kind' => 'host']);
|
||||
DB::table('vpn_peers')->whereNull('host_id')->update([
|
||||
DB::table('vpn_peers')->whereNull('host_id')->whereNotNull('created_by')->update([
|
||||
'kind' => 'staff',
|
||||
'user_id' => DB::raw('created_by'),
|
||||
]);
|
||||
DB::table('vpn_peers')->whereNull('host_id')->whereNull('created_by')->update(['kind' => 'system']);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
|
|
|
|||
|
|
@ -223,6 +223,7 @@ it('adopts host peers from the hub and marks vanished ones absent', function ()
|
|||
|
||||
$adopted = VpnPeer::query()->where('public_key', $key)->firstOrFail();
|
||||
expect($adopted->name)->toBe('pve-fsn1') // named after its host, not "unknown"
|
||||
->and($adopted->kind)->toBe(VpnPeer::KIND_HOST)
|
||||
->and($adopted->host_id)->toBe($host->id)
|
||||
->and($adopted->present)->toBeTrue()
|
||||
->and($adopted->rx_bytes)->toBe(2048)
|
||||
|
|
@ -456,13 +457,16 @@ it('renames a peer it adopted before the host link was known', function () {
|
|||
(new SyncVpnPeers)->handle($hub);
|
||||
$peer = VpnPeer::query()->where('public_key', $key)->firstOrFail();
|
||||
expect($peer->name)->toBe(__('vpn.unknown_peer'))
|
||||
->and($peer->host_id)->toBeNull();
|
||||
->and($peer->host_id)->toBeNull()
|
||||
// Not staff: a staff access has an owner, and this one has nobody.
|
||||
->and($peer->kind)->toBe(VpnPeer::KIND_SYSTEM);
|
||||
|
||||
Host::factory()->active()->create(['name' => 'pve-fsn1', 'wg_pubkey' => $key]);
|
||||
(new SyncVpnPeers)->handle($hub);
|
||||
|
||||
expect($peer->fresh()->name)->toBe('pve-fsn1')
|
||||
->and($peer->fresh()->host_id)->not->toBeNull();
|
||||
->and($peer->fresh()->host_id)->not->toBeNull()
|
||||
->and($peer->fresh()->kind)->toBe(VpnPeer::KIND_HOST);
|
||||
});
|
||||
|
||||
it('does not rename an access an operator named themselves', function () {
|
||||
|
|
|
|||
Loading…
Reference in New Issue