diff --git a/app.py b/app.py index 5569f33..32388e6 100644 --- a/app.py +++ b/app.py @@ -1761,13 +1761,23 @@ def get_fedora_kickstart(): def agent_bootstrap(payload: AgentBootstrapRequest): agent_secret = secrets.token_urlsafe(32) + # deprovisioned_at wird hier bewusst mitgeprueft: der Agent ruft diesen + # Endpoint auch selbststaendig bei 401 auf checkin auf (siehe agent.py + # Self-Heal). Ohne dieses Gate wuerde ein per Kundenportal + # deprovisioniertes Geraet sich beim naechsten Poll-Zyklus einfach + # selbst ein neues Secret holen und die De-Provisionierung waere + # wirkungslos - das Gate macht reprovision_device() (Loeschen von + # deprovisioned_at) zur tatsaechlichen Voraussetzung fuer den Erfolg + # dieses Aufrufs. + existing = None + with get_database_connection() as conn: with conn.cursor() as cur: cur.execute( """ UPDATE devices SET agent_secret_hash = %s, agent_secret_issued_at = %s - WHERE id = %s + WHERE id = %s AND deprovisioned_at IS NULL RETURNING id """, ( @@ -1778,7 +1788,21 @@ def agent_bootstrap(payload: AgentBootstrapRequest): ) updated = cur.fetchone() + if updated is None: + cur.execute( + "SELECT deprovisioned_at FROM devices WHERE id = %s", + (payload.device_id,), + ) + existing = cur.fetchone() + if updated is None: + if existing is not None and existing[0] is not None: + return { + "success": False, + "error": "device_deprovisioned", + "message": "Das Gerät ist deprovisioniert und muss zuerst über das Kundenportal reprovisioniert werden.", + } + return { "success": False, "error": "device_not_found",