CluPilotCloud/app/Provisioning/Jobs
nexxo 1fd5d5f8d2 Was der Auftrag ausfuehrt, ist die Absicht von jetzt, nicht die von vorhin
Drei Befunde aus dem Gesamt-Review, alle dieselbe Klasse: die Zeile im Portal
behauptet etwas, das in der Cloud des Kunden nicht gilt.

K1 — Entziehen, waehrend die Einladung noch in der Warteschlange steht. Der
Arbeiter teilt sich die Warteschlange mit der bezahlten Bereitstellung; das
Fenster ist Minuten lang. queueSync() stieg bei nc_synced_at === null aus und
kannte damit den dritten Waechter-Fall nicht: bei `pending` entsteht dort
gerade etwas, das gesperrt werden muss. Und der invite-Auftrag liest den Status
jetzt am Ende frisch aus der Datenbank nach und schiebt bei revoked/suspended
ein disable hinterher — dieselbe Begruendung wie beim schon gebauten "ein
angelegtes Konto sofort vermerken". Vorher endete der Ablauf mit
status=revoked, nc_state=synced und einem aktiven Konto in der Nextcloud, ohne
jeden Knopf, es nachzuholen.

K2 — retry() konnte ein gescheitertes Entsperren nie wiederholen: die Ableitung
kannte disable, invite und role, aber kein enable, und waehlte deshalb role.
Der Auftrag fuhr Gruppen und Quota, gelang, die Zeile sprang auf "Aktiv" — und
user:enable war nie geschickt. Woran das zu erkennen waere, steht nirgends am
Sitz; ein Feld dafuer waere die naechste Behauptung ueber die Cloud, die
irgendwann nicht mehr stimmt. Deshalb raet retry() nicht, sondern schickt an
einer offenen Zeile beides: der neue Auftrag `restore` sperrt auf UND setzt die
Rolle. suspend() bleibt bei enable, denn dort ist bekannt, was fehlt.

W2 — der Inhaber konnte sich selbst aussperren. setRole() nahm jede Rolle aus
Seat::ROLES an, also auch owner; das Auswahlfeld bietet sie nicht an, die
Livewire-Methode ist trotzdem oeffentlich erreichbar. Mit zwei Inhaber-Sitzen
griff die Zaehlung in revoke() nicht mehr, und der echte Inhaber bekam
user:disable admin samt user:auth-tokens:delete admin in seine eigene Cloud.
revoke() und setRole() weisen owner jetzt genauso ab wie suspend(), und owner
ist keine zulaessige Zielrolle mehr. Damit faellt die Zaehlung selbst weg —
eine Sperre, die man sich erst erarbeiten muss, ist keine — und mit ihr die
Meldung users.last_owner.

Sechs Pruefungen, jede einzeln gegen den zurueckgedrehten Fix rot gesehen.
Umlaute in den beruehrten Dateien nachgezogen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 23:56:48 +02:00
..
AdvanceRunJob.php fix(engine): durable queueing for long provisioning steps 2026-07-25 10:36:49 +02:00
ApplyHostVpnPeer.php Release v1.3.81 — Host anlegen scheiterte am WireGuard-Peer 2026-08-01 00:43:10 +02:00
ApplyVpnPeer.php fix(vpn): a late revocation must not disconnect whoever holds the key now 2026-07-26 01:24:55 +02:00
CollectHostLoad.php Release v1.3.94 — die Kurven zeigen wieder, wie ausgelastet der Host ist 2026-08-01 11:56:10 +02:00
CollectInstanceTraffic.php Deliver the storage a customer actually buys 2026-07-29 19:13:10 +02:00
IssueInstanceAdminAccess.php Fix nine defects in the provisioning pipelines 2026-07-30 01:34:55 +02:00
PingHosts.php Let an incident be deleted, and start measuring whether the hosts answer 2026-07-29 15:16:48 +02:00
PurgeHost.php Hostnamen vergibt CluPilot: ein Name statt zweier, und der Zaehler ueberlebt das Loeschen 2026-08-01 13:45:43 +02:00
RecordProvisioningHeartbeat.php Notice when nobody is picking up the queue 2026-07-30 14:32:09 +02:00
RemoveWireguardPeer.php fix(vpn): lock every hub mutation; resolve duplicate keys inside the lock 2026-07-25 21:55:57 +02:00
ScanForIntrusions.php fix(security): Aufheben einer Sperre sagt die Wahrheit und wird nachgeholt 2026-08-03 17:28:28 +02:00
SyncMonitoringStatus.php Measure availability, and let a customer move down again 2026-07-27 16:41:15 +02:00
SyncSeatToNextcloud.php Was der Auftrag ausfuehrt, ist die Absicht von jetzt, nicht die von vorhin 2026-08-03 23:56:48 +02:00
SyncVpnPeers.php fix(vpn): a replaced key must not stall the reconciliation 2026-07-26 01:23:15 +02:00