deploy(vd03): b3021e7c — script file access live (AllowedRoots E:\ApiInstall\ScadaBridge\recipes); gate 31/31, rig 8/8

Second vd03 window of the day: no migrations, appsettings.Site.json gains ScriptFileAccess:AllowedRoots
(pushed over SMB before the swap), sample recipes in E:\ApiInstall\ScadaBridge\recipes. The Delmia
test receiver now reads + parses the downloaded file; real HTTP R100 -> 12 values loaded, R900 -> rejected
with line numbers. verify-mes-test-machine.sh: D1's cleared check reads through BTDB, so it only runs
with group C (the rig runs VERIFY_GROUPS=AD).
This commit is contained in:
Joseph Doherty
2026-09-28 10:45:54 -04:00
parent b3021e7c5f
commit 5cc09b08ef
2 changed files with 52 additions and 2 deletions
+1
View File
@@ -159,6 +159,7 @@ def group_D():
print("D. Reset alarm sources")
for inst in ("SBTEST01", "SBTEST02"):
write(inst, "VacuumPressure", 0.5); write(inst, "DoorOpen", "false"); write(inst, "SensorStatus", 0)
if "C" in os.environ["VERIFY_GROUPS"].upper(): # the check reads through BTDB, like group C
r = call("AlarmStatusRequest", {"MachineFilter": {"Code": "SBTEST02"}})
check("D1 cleared", r.get("WasSuccessful") is True and names(r) == [], names(r))
@@ -124,3 +124,52 @@ method 9 (`return new { WasSuccessful = true, Alarms = Array.Empty<Object>() };`
Staging left on the box under `E:\psrem-stage\fe89363b\` (zip, unpacked tree, migration SQL, prep + swap
scripts, `.reg` exports). The `_appsettings-keep-20260928T095846` copy and `*.bak.20260928T095846`
directories can go once the build has soaked.
---
# Second window, same day — `fe89363b` → `b3021e7c` (script file access + recipe-parsing receiver)
**Build:** `main` @ `b3021e7c` (ProductVersion `1.0.0+b3021e7c5ff68ba20abc510f644045c7dbbccd86`; zip
125 585 217 B, SHA-256 `5b7d7c68…2d66df`). **Delta:** the read-only, allow-listed `Files` script global
(design `docs/plans/2026-09-28-script-file-access-design.md`) and the TestMesMachine Delmia simulator now
reading + parsing the downloaded recipe file. **No migrations** (57 before and after — asserted, nothing applied).
**Config (the only change):** `appsettings.Site.json` gained
`ScadaBridge:SiteRuntime:ScriptFileAccess:AllowedRoots = ["E:\\ApiInstall\\ScadaBridge\\recipes"]` (+ a
`_comment_SiteRuntime`), edited on the Mac and pushed over SMB **before** the window so the swap script's
keep/restore carried it through (new SHA-256 `3E7AD9A4…`); original saved as
`E:\psrem-stage\b3021e7c\appsettings.Site.json.pre-b3021e7c`. The three sample recipes
(`docker/recipes/SBTEST-R100.txt`, `SBTEST-R200.txt`, `SBTEST-R900-invalid.txt`) were pushed to
`E:\ApiInstall\ScadaBridge\recipes\`. Central's appsettings unchanged.
**Window:** prep 10:41:47 (COPY_ONLY backup `ScadaBridge_pre-b3021e7c_20260928T104147.bak`, 140 064 768 B,
VERIFYONLY valid); swap 10:42:08 → site ready 10:42:57 (**~50 s**); the swap script asserted the recipes root
(3 files) and logged `site AllowedRoots = E:\ApiInstall\ScadaBridge\recipes`; boot validation accepted it.
Backups: `app.bak.20260928T104207` / `cli.bak.20260928T104207`.
**Re-seed + gate:** `seed-mes-test-machine.sh` added the 14 recipe attributes to `TestDelmiaReceiver` and
updated all nine scripts; `verify-mes-test-machine.sh` (with `RECIPE_ROOT='E:\ApiInstall\ScadaBridge\recipes'`,
`RECIPE_OUTSIDE='E:\ApiInstall\ScadaBridge\app\appsettings.Site.json'`) **PASS 31/31** — group A now proves
accept (12 typed values loaded), re-download, invalid-line rejection with line numbers and nothing loaded,
`NotFound`, and a file **outside** the root refused (`OutsideAllowedRoots`). Real HTTP with a key:
```
DelmiaRecipeDownload R100 -> {"Result":true,"ResultText":"Loaded 12 recipe values from SBTEST-R100.txt for WO-1001"}
DelmiaRecipeDownload R900 -> {"Result":false,"ResultText":"Recipe rejected: line 4: expected RecipeValueName,RecipeValue;
line 5: unknown recipe value 'MysterySetting'; line 6: PotTempSP expects Int32, got '980.5'"}
```
**Recipe file format** (`RecipeValueName,RecipeValue` per line; value = int / double (invariant `.`) / bool /
text; `#` comments and blank lines ignored; everything after the first comma is the value; surrounding double
quotes unwrapped). Loaded all-or-nothing into `TestDelmiaReceiver`'s typed recipe tags (`RecipeName`,
`RecipeRevision`, `CoatingType`, `ReactorTempSP`, `PotTempSP`, `ArgonFlowSP`, `HydrogenFlowSP`,
`ChlorineFlowSP`, `VacuumSP`, `TargetRuntime`, `PurgeEnabled`, `OperatorNote`) plus `RecipeValueCount` /
`RecipeLoadedFile`. To test your own file: drop it in `E:\ApiInstall\ScadaBridge\recipes\` (SMB) and call
`DelmiaRecipeDownload` with that full path.
**Rollback:** stop Site + Central, rename `app` → `app.failed`, `app.bak.20260928T104207` → `app` (same for
`cli`), restore `appsettings.Site.json.pre-b3021e7c` if the key must go (the old build ignores it), start
Central then Site. No DB restore needed (no schema change).
**Rig:** `docker/deploy.sh` from `b3021e7c` (site-a both nodes mount `docker/recipes` read-only at
`/app/recipes`, `AllowedRoots ["/app/recipes"]`); seeded on site-a; `VERIFY_GROUPS=AD` **PASS 8/8**.