Files
shopdb-flask/docs/GE-ENFORCE-DISPLAY.md
cproudlock 9d65ef103d geenforce: display-readiness batch (server hardening, PS client wiring, display scope)
Get GE-Enforce closer to running on credential-less Intune/Entra display PCs
that pull manifest + payloads over HTTPS instead of SMB.

Server (plugins/geenforce/api/routes.py):
- Rate-limit + 512MB served-size ceiling on GET /payload/<sha256> (reuses the
  login limiter's cache pattern, config-overridable via GEENFORCE_PAYLOAD_*).
- New tests: payload hardening, manifestblobs model-vs-migration parity, and a
  report-contract test locking the lowercase per-entry report keys.

PS client (plugins/geenforce/client/):
- Fix New-ShopdbReport per-entry key casing to lowercase (name/action/selfhealed/
  exitcode/message) to match what the server reads; the engine emits PascalCase.
- Enforce TLS 1.2 in the network functions.
- Fetch + merge the fleet-wide common scope alongside the pctype scope
  (pctype wins on conflict; -NoCommon opt-out).
- Normalize whatever the engine returns into a well-formed summary.
- Make the empty-cache fail-safe observable: event-log entry + report ping
  instead of a silent exit 0.

Manifest (plugins/geenforce/seed_display_scope.py + docs/GE-ENFORCE-DISPLAY.md):
- Seed a gea-shopfloor-display scope: 4 Edge kiosk drift-heal registry entries
  + 1 data-driven dispatcher (Dashboard/Lobby/3DPrintRoom via display-type.txt).
  Kiosk EXEs stay image-baked; the manifest heals policy/config drift only.
- Documents the common SMB-payload audit (entries needing http/inline before a
  share-less display can inherit common).

Migration registry (shopdb/plugins/alembic_template.py + test):
- Register the pre-existing manifestblobs and the new printersupplyalerts tables
  in PLUGIN_TABLE_OWNERS; update EXPECTED_HEAD_REVISION for geenforce (0002blobs),
  printers (0002supplyalerts), and printedparts (0004txnrev) which had drifted.
2026-07-23 08:16:38 -04:00

6.3 KiB

GE-Enforce: the gea-shopfloor-display scope

Displays are the share-less corner of the fleet. They are Intune/Entra-joined, credential-less kiosk PCs that pull their manifest over HTTPS on port 443 and authenticate with a read-only service PAT scoped geenforce.fetch, sent as X-API-Key. They have no SMB share mount. The kiosk engine and the kiosk browser are baked into the display image, not shipped over HTTPS, so the display manifest heals POLICY / CONFIG drift and inherited common entries, never EXEs.

There are three display subtypes, selected by C:\Enrollment\display-type.txt: Dashboard, Lobby, and 3DPrintRoom.

Authoring the scope

The scope is authored programmatically by plugins/geenforce/seed_display_scope.py, which builds a manifest dict and hands it to service.replace_scope_draft (the same call the import-share CLI uses), then attaches the inline dispatcher payload. From a Flask app context:

from plugins.geenforce.seed_display_scope import seed_display_scope
seed_display_scope(publish=True)   # publish=False leaves it as a draft

replace_scope_draft is an idempotent draft rebuild. publish=True additionally freezes an immutable published snapshot (that step is not idempotent: it always creates a new version).

What the scope contains

  1. Four Registry drift-heal entries that re-assert the Microsoft Edge kiosk relaunch policies set at imaging by 09-Setup-Display.ps1. Each writes the value and detects drift with DetectionMethod = ValueMatches against the same path/name, so a display that loses a policy self-heals on the next enforce cycle with no keyboard or mouse on site:
    • RelaunchNotification = 2 (DWord, Required auto-restart)
    • RelaunchNotificationPeriod = 3600000 (DWord, 1 hour)
    • RelaunchHeadsUpPeriod = 60000 (DWord, 1 minute)
    • RelaunchWindow (String, JSON, 02:00 start, 120 minute duration)
  2. One PS1 dispatcher, delivered inline over HTTPS. It reads C:\Enrollment\display-type.txt and launches the kiosk target for the subtype. The subtype -> route map is a data-driven table (DISPLAY_TYPE_TARGETS) at the top of both the seed module and the generated script, so targets are easy to edit. DetectionMethod = Always so it re-asserts each cycle, but the script is idempotent (it skips relaunch if a kiosk process is already serving the target URL).

display-type -> target map

display-type.txt kiosk route notes
Dashboard /shopfloor core ShopfloorDashboard, standalone full-screen
Lobby /tv slides plugin TV dashboard (surface lobby)
3DPrintRoom /parts-kiosk PLACEHOLDER, TODO-confirm printedparts parts kiosk route; confirm the real 3D-print-room target with the floor team before publishing to production displays

Inheritance: the client merges common

The manifest model has no inheritance column. The display scope is a plain (non-common) runtime scope carrying only display-specific entries. The CLIENT merges the fleet-wide common scope underneath the display scope at fetch time. So common is where the fleet-wide policy/config/self-update entries live, and gea-shopfloor-display adds the kiosk-only entries on top.

Blocker: common carries SMB payloads that break on share-less displays

Before a share-less display can safely inherit common, every common entry that pulls a payload file from the SMB share must first be given an http or inline payload (with a payloadsha256). A display has no share mount, so any inherited entry whose Installer / Source / Script resolves to a share-relative path will fail its fetch.

Registry entries in common carry no payload (they write inline reg values) and are safe to inherit as-is. The entries below reference a share file and must be converted first. This audit is the authoritative to-convert list; the payload bytes themselves are not converted here (that needs the real payload files).

Common entries that reference an SMB/share payload (as of the on-share common/manifest.json, 22 entries, Version 2.0):

# Common entry Type Share payload Field
1 Adobe Acrobat Reader DC CMD scripts/Install-AcroReader.cmd Installer
2 Migrate pc-type.txt to gea-shopfloor-* taxonomy PS1 scripts/Migrate-PCType.ps1 Script
3 WJF Defect Tracker MSI apps/WJF_Defect_Tracker.msi Installer
4 3OF9 barcode font File configs/3OF9.ttf Source
5 Edge IE-Mode site list File configs/enterprise-mode-site-list.xml Source
6 Ensure VNC firewall rule PS1 scripts/ensure-vnc-firewall.ps1 Script
7 FMS hosts pin (WJFMS3.AE.GE.COM) PS1 scripts/Set-FmsHostsEntry.ps1 Script
8 Oracle Client 11.2 CMD scripts/Install-Oracle11r2.cmd Installer
9 PrinterInstallerMap (site-map printer installer) File apps/PrinterInstallerMap.exe Source
10 OpenText HostExplorer ShopFloor CMD scripts/Setup-OpenText.cmd Installer
11 GE-Enforce dispatcher (self-update) File GE-Enforce.ps1 Source
12 Install-FromManifest lib (self-update) File lib/Install-FromManifest.ps1 Source
13 Report asset (host + IP + machine number) to ShopDB PS1 apps/Report-AssetToShopDB.ps1 Script
14 EventSaver screensaver (binary) File apps/EventSaver.scr Source
15 EventSaver screensaver (config) File configs/EventSaver.ini Source
16 EventSaver enable (per-user screensaver) PS1 scripts/Set-EventSaverScreensaver.ps1 Script
17 EventSaver power (keep monitor awake) PS1 scripts/Set-EventSaverPower.ps1 Script
18 EventSaver disable (measuring-tool bays) PS1 scripts/Set-EventSaverDisable.ps1 Script
19 EventSaver disable (specific hostnames) PS1 scripts/Set-EventSaverDisable.ps1 Script

Safe to inherit as-is (Registry entries, no share payload): 3OF9 barcode font registry entry, Edge IE-Mode policy level, Edge IE-Mode policy site list pointer.

Not every entry above is relevant to a display (a display needs no Oracle client, OpenText, or Defect Tracker), so a follow-up decision is which common entries a display should actually run (via PCTypes targeting) versus which must be repackaged as http/inline. But any that survive targeting must have a non-SMB payload before displays inherit common.