CluPilotCloud/tests/Feature/Admin
nexxo 4debc79883 Eine hängende Sperre ist jetzt ein Knopf, kein SSH-Zugang
Am 4. August 2026 hielt ein einziger Aufruf — `timeout 45 docker compose
exec` ohne `--kill-after` — die Sperre stundenlang, und jeder folgende
Lauf wurde übersprungen. Behoben ist die Ursache in v1.6.5; was fehlte,
war der Griff für das nächste Mal. Er lag per SSH auf dem Wirt.

Die Konsole kann ihn nicht selbst führen: sie ist www-data in einem
Behälter, der Sperrenhalter ist ein Prozess auf dem WIRT. Also bittet
sie den Agenten, und der ruft den root-eigenen Helfer — dasselbe Muster
wie `apply-proxy-hosts`, mit eigener sudoers-Zeile.

Die Bitte liegt in einer EIGENEN Datei, und das ist keine
Geschmacksfrage: der Agent nimmt die Sperre in seinen ersten Zeilen,
lange bevor er den Postkasten ansieht. Ein blockierter Lauf steigt
vorher aus — eine Entsperr-Bitte im Postkasten erreichte ihn also genau
dann nie, wenn sie gebraucht wird. Dazu nimmt der Postkasten eine Bitte
zur Zeit an, und die dreißig Minuten, in denen dort eine wartende
Update-Anfrage liegt, sind die, in denen jemand entsperren will.

Der Dienstbenutzer sagt „gib die Sperre frei", nicht „töte 1234": welcher
Prozess das ist, sucht der Helfer selbst. Dürfte der Anrufer die Nummer
liefern, wäre die Freigabe das Recht, jeden beliebigen Prozess als root
zu beenden.

Beendet werden alle, die die Sperrdatei OFFEN halten — nicht nur der,
der das flock genommen hat. Ein flock hängt an der offenen
Dateibeschreibung, und die wird vererbt: stirbt der Agent, sein
hängendes `docker compose exec` aber nicht, bleibt die Sperre gehalten.
Genau das war der Vorfall. Verschont bleiben PID 1 und der Anrufer samt
Vorfahren — im Betrieb hält der blockierte Agent die Datei selbst offen
und ist zugleich der, der anruft.

Erst SIGTERM, fünf Sekunden, dann SIGKILL. Eine Frist ohne Nachdruck ist
keine Frist.

Bestätigt wird im Modal (R23), das VORHER nennt, was es beendet — PID,
Laufzeit und Kommandozeile aus dem Lebenszeichen. Eigene Berechtigung
`deployment.unblock`, nicht `site.manage`: wer aktualisieren darf, darf
damit nicht automatisch in einen laufenden Vorgang hineingreifen.

Der Helfer-Vertrag steigt auf 3, und update.sh verlangt ihn. Ohne das
wäre der Knopf auf einem Wirt, der install-agent.sh seither nicht mehr
gefahren hat, ein Knopf, der still nichts tut — und die Konsole sagt es
jetzt, statt den Betreiber dorthin zurückzuschicken, wo er ohne sie
schon war.

Geprüft wird ausgeführt, nicht begutachtet: der Helfer läuft im Test
gegen eine echte Sperrdatei mit echten Prozessen daran. Das hat gleich
einen Fehler gefunden — der Helfer erbt den Deskriptor und hielt seine
eigenen Kommandosubstitutionen für Halter, sodass die Runde nie zum Ende
gekommen wäre.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 10:07:24 +02:00
..
AdminConsoleTest.php Send a guest bounced off the console to the console's own sign-in 2026-07-28 13:32:05 +02:00
AdminHostRestrictionTest.php Move the console's identity out of the customer table 2026-07-28 10:31:43 +02:00
AdminSettingsTest.php Ein Rückweg aus der abgelaufenen Betreiber-Einladung 2026-08-04 02:24:13 +02:00
BroadcastAuthTest.php Authorize the console's live feed on the operator guard, not the default 2026-07-28 13:31:50 +02:00
CapacityQueueTest.php Ein angehefteter Host umging die Reservierung 2026-08-01 18:53:11 +02:00
CatalogueSyncTest.php Hetzner-Cloud-DNS, Bereitschaftsseite aus sich heraus behebbar 2026-07-31 19:50:01 +02:00
CodexFixRoundTest.php Stripe-Client: offene Rechnungen listen und einziehen 2026-07-31 20:04:09 +02:00
ConnectionTestFeedbackTest.php Pruefergebnis als Modal statt am Seitenende 2026-07-31 21:36:43 +02:00
ConsoleAccessListTest.php Ein Waechter, der aufraeumt — und die vier offenen Punkte aus dem Betrieb 2026-08-03 09:43:33 +02:00
ConsoleHostSeparationTest.php Match the logout exemption through AdminArea, not a bare route check 2026-07-28 15:27:06 +02:00
ConsoleNavigationTest.php Die Seitenleiste fragt zuerst, ob etwas auf dich wartet 2026-08-04 02:51:35 +02:00
ConsoleNetworkTest.php Move the console's identity out of the customer table 2026-07-28 10:31:43 +02:00
ConsoleReportsRealDataTest.php Merge main into the operating-mode branch 2026-07-30 17:53:20 +02:00
CustomerDetailTabsTest.php Die neue Leiter: Start 39, Team 79, Business 139 2026-08-01 17:05:58 +02:00
CustomerRevenueTest.php Schalter je Paket, ehrliche Statusanzeige, Reste der alten Leiter 2026-08-01 17:53:06 +02:00
DatacenterTest.php Hostnamen vergibt CluPilot: ein Name statt zweier, und der Zaehler ueberlebt das Loeschen 2026-08-01 13:45:43 +02:00
DunningFeesInEurosTest.php Ein Waechter, der aufraeumt — und die vier offenen Punkte aus dem Betrieb 2026-08-03 09:43:33 +02:00
EditCustomerTest.php Take the address by field, fix the customer type, ask why they leave 2026-07-30 16:41:32 +02:00
EnvFileEditorTest.php Add a raw .env editor to the Integrations page, with a net under it 2026-07-29 01:51:27 +02:00
EnvRestartTest.php Der Tunnel bekommt einen eigenen Container 2026-08-03 07:49:29 +02:00
GrantPlanTest.php Die neue Leiter: Start 39, Team 79, Business 139 2026-08-01 17:05:58 +02:00
HostCapacityTest.php Die neue Leiter: Start 39, Team 79, Business 139 2026-08-01 17:05:58 +02:00
HostManagementTest.php Host anlegen: die Seite beschrieb das Rettungssystem und startete die Pipeline 2026-08-02 01:38:48 +02:00
HostNamingTest.php Hostdetailseite: die Adresse steht neben den IPs und ist ein Klick zur Proxmox-Oberflaeche 2026-08-01 14:12:03 +02:00
HostReservationTest.php Fix-Runde: preferredDatacenter() blind fuer Reservierung, Loeschen hob sie auf 2026-08-01 16:21:46 +02:00
HostTakeoverGuideTest.php Host anlegen: die Seite beschrieb das Rettungssystem und startete die Pipeline 2026-08-02 01:38:48 +02:00
HostTakeoverPageTest.php Host anlegen: die Seite beschrieb das Rettungssystem und startete die Pipeline 2026-08-02 01:38:48 +02:00
HostTerminalTest.php Terminal: das Fenster sagt jetzt selbst, ob die Bruecke laeuft 2026-08-02 22:34:32 +02:00
HostVpnStateTest.php Read VPN host state from the synced peer table, not a live hub call 2026-07-29 00:18:21 +02:00
InboundMailTest.php Read the mailbox password where it actually is, and let the console test it 2026-07-30 13:12:29 +02:00
IncidentConsoleTest.php Rebuild the status page as a status page 2026-07-29 12:45:18 +02:00
IncidentDeleteTest.php Let an incident be deleted, and start measuring whether the hosts answer 2026-07-29 15:16:48 +02:00
InstanceAdminAccessTest.php Move the console's identity out of the customer table 2026-07-28 10:31:43 +02:00
IntegrationsPageTest.php Name the server variable under a credential, not the internal key 2026-07-30 13:20:29 +02:00
MailDeliverySwitchTest.php Hetzner-Cloud-DNS, Bereitschaftsseite aus sich heraus behebbar 2026-07-31 19:50:01 +02:00
MailPacePageTest.php Unter jeder Spur steht, was in ihr faehrt 2026-08-04 00:55:23 +02:00
MailPreviewTest.php Zwei Empfaengerkreise, und eine Wegwahl, die auch das Konto verschiebt 2026-08-03 17:00:20 +02:00
MailRegisterTest.php Der Altbestand des Registers wird geradegezogen 2026-08-03 21:18:26 +02:00
MailRoutingTest.php Zwei Empfaengerkreise, und eine Wegwahl, die auch das Konto verschiebt 2026-08-03 17:00:20 +02:00
MailTemplateTest.php Die neue Leiter: Start 39, Team 79, Business 139 2026-08-01 17:05:58 +02:00
MaintenanceTest.php Move the console's identity out of the customer table 2026-07-28 10:31:43 +02:00
OpenWorkTest.php Offene Punkte: was fehlt und was folgt nebeneinander, statt auf halber Breite zu enden 2026-08-02 16:40:26 +02:00
OperatorLogoutTest.php Stop the console logout from destroying a shared portal session 2026-07-28 13:58:42 +02:00
OperatorModelTest.php Give the people who run CluPilot a table of their own 2026-07-28 09:20:54 +02:00
OperatorTwoFactorEnrollmentTest.php Give the two-factor page a way back, and a shape 2026-07-28 22:25:42 +02:00
OperatorTwoFactorPolicyTest.php Move operator two-factor enrolment off admin.settings onto its own page 2026-07-28 15:11:20 +02:00
PasswordConfirmationGuardTest.php Merge credentials and infrastructure into one Integrations page 2026-07-29 01:49:39 +02:00
PlanAdminTest.php Die Seitenleiste fragt zuerst, ob etwas auf dich wartet 2026-08-04 02:51:35 +02:00
ProvisioningActionsTest.php Ein Waechter, der aufraeumt — und die vier offenen Punkte aus dem Betrieb 2026-08-03 09:43:33 +02:00
ProxyHostsTest.php Keep IP addresses out of a certificate overview 2026-07-31 01:01:47 +02:00
RbacMoveTest.php Eine hängende Sperre ist jetzt ein Knopf, kein SSH-Zugang 2026-08-04 10:07:24 +02:00
RbacTest.php Move the console's identity out of the customer table 2026-07-28 10:31:43 +02:00
RevenueGrantedTest.php Skip the invoice for a full gift, keep it out of revenue, hide its price 2026-07-29 12:41:32 +02:00
RoleManagementTest.php Zwei Attrappen: ein Banner ohne Hintergrund und Rechte, die ihren Schluessel statt ihrer Beschreibung zeigten 2026-08-02 16:47:15 +02:00
SecretCipherTest.php Make isUsable() apply the same 32-byte rule encrypter() does 2026-07-28 05:09:09 +02:00
SecretVaultTest.php Hetzner-Cloud-DNS, Bereitschaftsseite aus sich heraus behebbar 2026-07-31 19:50:01 +02:00
ServiceInvoiceTest.php Write an invoice for work that came off no price list 2026-07-29 20:12:26 +02:00
SettingsTabsTest.php Seitenleiste neu geordnet: Betrieb trug zwoelf Eintraege aus drei Themen 2026-08-02 00:29:14 +02:00
SshKeypairTest.php Hetzner-Cloud-DNS, Bereitschaftsseite aus sich heraus behebbar 2026-07-31 19:50:01 +02:00
StripePublishableKeyTest.php Hetzner-Cloud-DNS, Bereitschaftsseite aus sich heraus behebbar 2026-07-31 19:50:01 +02:00
StripeWebhookSecretInVaultTest.php Hetzner-Cloud-DNS, Bereitschaftsseite aus sich heraus behebbar 2026-07-31 19:50:01 +02:00
UpdateButtonTest.php Ein einzelner übersprungener Lauf ist kein Ausfall 2026-08-04 09:42:07 +02:00
UpdateLockReleaseTest.php Eine hängende Sperre ist jetzt ein Knopf, kein SSH-Zugang 2026-08-04 10:07:24 +02:00
UpdateWindowTest.php Update on a schedule if the owner wants one, and say where incidents go 2026-07-29 15:01:54 +02:00
VpnTest.php Release v1.3.85 — Handshake-Prüfung hing an einem Programm, das es nicht gibt 2026-08-01 03:00:19 +02:00