From 894305e906d9547dcadae32e7d9e2d3bf3b6e005 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Thu, 14 May 2026 19:53:05 -0400 Subject: [PATCH] Monitor: drop AESFMA-connected from Phase 1 done; webapp: LAPS endpoint 1. Phase 1 done gate was requiring 'AESFMA WLAN connected' in addition to the data-side signals (AAD + Intune + EmTask + baseline). If the bay never reached AESFMA (cert never landed, RADIUS unreachable), Phase 1 stayed IN PROGRESS forever even though Intune registration was actually complete. Reverting to the data-side-only definition. 2. New webapp endpoint POST /imaging//laps stores a LAPS password in the session JSON so it survives the 5s dashboard auto-refresh. Empty body clears the field. Daily reset of the server (cron/restart) is the lifetime cap on stored passwords. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Shopfloor/lib/Monitor-IntuneProgress.ps1 | 18 ++------------- webapp/app.py | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/playbook/shopfloor-setup/Shopfloor/lib/Monitor-IntuneProgress.ps1 b/playbook/shopfloor-setup/Shopfloor/lib/Monitor-IntuneProgress.ps1 index 7b6e263..573f30b 100644 --- a/playbook/shopfloor-setup/Shopfloor/lib/Monitor-IntuneProgress.ps1 +++ b/playbook/shopfloor-setup/Shopfloor/lib/Monitor-IntuneProgress.ps1 @@ -860,27 +860,13 @@ function Format-Snapshot { # not just "arriving". Stops the category prompt firing pre-first-reboot # when only ~4 subkeys are present (we tested this empirically; clicking # "assign category" at 4 subkeys = imaging stalls + re-image required). - # AESFMA connected = bay has a live corp WLAN association on the - # machine-auth profile. That's the natural ground-truth that Phase 1 - # is operationally done (not just the data-side flags). Check the - # WLAN state via netsh wlan show interfaces - look for SSID=AESFMA - # with state=connected. - $aesfmaConnected = $false - try { - $wlanOut = netsh wlan show interfaces 2>$null - if ($wlanOut -match '(?ms)SSID\s*:\s*AESFMA.*?State\s*:\s*connected') { - $aesfmaConnected = $true - } - } catch {} $p1Done = ($Snap.Phase1.AzureAdJoined -and $Snap.Phase1.IntuneEnrolled -and - $Snap.Phase1.EmTaskExists -and $Snap.Phase1.PoliciesBaselineReady -and - $aesfmaConnected) + $Snap.Phase1.EmTaskExists -and $Snap.Phase1.PoliciesBaselineReady) $p1Status = Get-PhaseStatus @( @{ Ok = $Snap.Phase1.AzureAdJoined; Failed = $false }, @{ Ok = $Snap.Phase1.IntuneEnrolled; Failed = $false }, @{ Ok = $Snap.Phase1.EmTaskExists; Failed = $false }, - @{ Ok = $Snap.Phase1.PoliciesBaselineReady; Failed = $false }, - @{ Ok = $aesfmaConnected; Failed = $false } + @{ Ok = $Snap.Phase1.PoliciesBaselineReady; Failed = $false } ) # Phase 6 / Lockdown (shared by both flows, rendered last). diff --git a/webapp/app.py b/webapp/app.py index aeb44c7..0bbf747 100644 --- a/webapp/app.py +++ b/webapp/app.py @@ -495,6 +495,29 @@ def imaging_delete_session(serial): return redirect(url_for("imaging_dashboard")) +@app.route("/imaging//laps", methods=["POST"]) +def imaging_set_laps(serial): + """Save (or clear with empty value) the LAPS password for a bay so it + survives the dashboard's 5s auto-refresh. JSON body: {"password": "..."}. + Empty string removes the field. Daily reset wipes natural risk.""" + serial = secure_filename(serial) + body = request.get_json(silent=True) or {} + pw = body.get("password", "") + if not isinstance(pw, str): + return {"ok": False, "error": "password must be string"}, 400 + if pw == "": + # Clear by direct read-modify-write since update_session skips empty values. + state = imaging_status.get_session(serial) or {} + if "laps_password" in state: + state.pop("laps_password", None) + # Re-feed everything (minus laps_password) through update_session. + state["serial"] = serial + imaging_status.update_session(state) + return {"ok": True, "cleared": True} + imaging_status.update_session({"serial": serial, "laps_password": pw}) + return {"ok": True} + + # --------------------------------------------------------------------------- # Routes - Enrollment Packages # ---------------------------------------------------------------------------