CluPilotCloud/tests/Feature/Admin
Claude 457eeeeaef
tests / pest (push) Successful in 10m12s Details
tests / assets (push) Successful in 21s Details
tests / release (push) Successful in 5s Details
Serve the console inside the tunnel, without publishing the internal network
The owner's phone shows a blank page on the VPN. That page is the reverse proxy
refusing the request, and it refuses because the phone is not on the tunnel: the
client config routes only the management subnet, so a request to the console's
public hostname leaves over the mobile network and arrives from a carrier
address. It is also why the peer reads "last contact: never" — WireGuard only
handshakes when it has traffic to send, and nothing is ever routed in.

The obvious fixes are both wrong. Adding the server's public address to
AllowedIPs routes the WireGuard endpoint into the tunnel it is trying to
establish. A public DNS record pointing at 10.66.0.1 publishes the internal
subnet to anyone enumerating the domain — the owner raised that himself, and he
was right.

So the console is served INSIDE the tunnel instead. A small resolver and a small
gateway share the hub container's network namespace, which is where wg0 lives,
and answer on 10.66.0.1 directly. A client therefore needs no route beyond the
subnet it already has, the host's docker bridge is never exposed, and the
request reaches the application with its real 10.66.0.x source — which is what
the console's own allowlist checks. The gateway reuses the certificate the
public Caddy already renews: a certificate is bound to the name, not to the
address serving it, so nothing new is issued and nothing internal reaches a
public zone.

Most of this commit is the arithmetic of not lying about it. Review found
fourteen ways the arrangement could report itself working while it was not:
enabling the compose profile after the services were started rather than before;
starting a gateway with empty certificate paths, which can only crash; treating
"container created" as "container running"; carrying a stale readiness marker
through a failed restart; reusing the previous hostname's certificate after a
rename; leaving the profile enabled when the hostname was cleared, in a script
that exits early precisely when nothing else would fix it; reading the renewal
timestamp as a user who cannot traverse Caddy's storage; and a `find | head`
that aborts the whole installer under pipefail the moment two issuers hold a
certificate for the same name.

One of them was mine and worth naming: to let the container read the
certificate, I had made the TLS private key world-readable. On a multi-user host
that hands the console's identity to every local account.

The client is told about the resolver only when both services are confirmed
running, because a config naming a resolver that does not exist takes the
device's entire name resolution with it for as long as the tunnel is up.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 10:14:33 +02:00
..
AdminConsoleTest.php feat(admin): dark Tactical-Terminal operator console 2026-07-25 08:35:03 +02:00
AdminHostRestrictionTest.php fix(security): match ADMIN_HOSTS case-insensitively; share test helpers 2026-07-25 20:56:26 +02:00
AdminSettingsTest.php fix(admin): shown-once temp password for invited staff; suppress announcements for cancelled windows at send time 2026-07-25 16:23:21 +02:00
ConsoleHostSeparationTest.php Let the console keep its recovery hostnames without breaking route caching 2026-07-27 06:20:44 +02:00
ConsoleNetworkTest.php Let people change their own password, and a location be switched off while editing it 2026-07-27 07:49:07 +02:00
ConsoleReportsRealDataTest.php Report the estate from the database, and print the traffic that is sold 2026-07-27 04:48:51 +02:00
CustomerRevenueTest.php feat(billing): the plan catalogue becomes three tables, and config stops selling 2026-07-26 12:05:56 +02:00
DatacenterTest.php Let people change their own password, and a location be switched off while editing it 2026-07-27 07:49:07 +02:00
HostManagementTest.php fix(security): match ADMIN_HOSTS case-insensitively; share test helpers 2026-07-25 20:56:26 +02:00
InstanceAdminAccessTest.php fix(admin): the admin password is shown once, and means it 2026-07-26 05:34:57 +02:00
MaintenanceTest.php fix(maintenance): make the window form usable 2026-07-25 23:05:33 +02:00
PlanAdminTest.php Make the console's access list reach the proxy, price in euros, and answer errors 2026-07-27 06:51:05 +02:00
ProvisioningActionsTest.php fix(ui): modal above sidebar (z-index); datacenter edit buttons stay right; toast slides from bottom; provisioning retry action 2026-07-25 15:29:37 +02:00
RbacTest.php fix(security): console and account checks now survive a Livewire action 2026-07-26 20:04:34 +02:00
SecretVaultTest.php Manage the Stripe key from the console, behind a password and a test 2026-07-27 09:01:16 +02:00
SecretsPageTest.php Manage the Stripe key from the console, behind a password and a test 2026-07-27 09:01:16 +02:00
UpdateButtonTest.php Let people change their own password, and a location be switched off while editing it 2026-07-27 07:49:07 +02:00
VpnTest.php Serve the console inside the tunnel, without publishing the internal network 2026-07-27 10:14:33 +02:00