test: record actual ScadaBridge consumer and baseline authorization gates

This commit is contained in:
Joseph Doherty
2026-11-10 13:17:13 -05:00
parent 8d75ac8c6c
commit ff44167926
13 changed files with 555 additions and 0 deletions
@@ -0,0 +1,75 @@
#!/usr/bin/env python3
"""Run the real ScadaBridge consumer in separate processes against both application versions."""
import argparse
import hashlib
import json
import os
from pathlib import Path
import secrets
import subprocess
import time
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--baseline-host", type=Path, required=True)
parser.add_argument("--candidate-host", type=Path, required=True)
parser.add_argument("--probe", type=Path, required=True)
parser.add_argument("--results", type=Path, required=True)
args = parser.parse_args()
root = args.results.resolve()
root.mkdir(parents=True, exist_ok=False)
artifacts = {name: path.resolve() for name, path in vars(args).items() if name != "results"}
for path in artifacts.values():
if not path.is_file():
raise FileNotFoundError(path)
receipt = {
"artifacts": {name: {"path": str(path), "sha256": hashlib.sha256(path.read_bytes()).hexdigest()}
for name, path in artifacts.items()},
"legs": [],
}
for version in ("baseline", "candidate"):
for mode in ("None", "SignAndEncrypt"):
leg = root / f"{version}-{mode}"
leg.mkdir()
server_root = leg / "server"
env = os.environ.copy()
env["OPCUA_MATRIX_PASSWORD"] = "otua_matrix_" + secrets.token_urlsafe(32)
if mode == "None":
env["OPCUA_MATRIX_SERVER_SECURITY"] = "none"
else:
env.pop("OPCUA_MATRIX_SERVER_SECURITY", None)
server_command = ["dotnet", str(artifacts[f"{version}_host"]), "server", str(server_root)]
result = {"server": version, "mode": mode, "serverCommand": server_command}
with (leg / "server.log").open("w") as server_log:
server = subprocess.Popen(server_command, env=env, stdout=server_log, stderr=subprocess.STDOUT)
try:
until = time.monotonic() + 40
while not (server_root / "endpoint.txt").is_file():
if server.poll() is not None or time.monotonic() >= until:
raise RuntimeError(f"Server failed to become ready; inspect {leg / 'server.log'}")
time.sleep(0.1)
endpoint = (server_root / "endpoint.txt").read_text().strip()
env["SCADABRIDGE_PROBE_SERVER_CERTS"] = str(server_root / "server-pki" / "own" / "certs")
command = ["dotnet", str(artifacts["probe"]), endpoint, mode, str(leg / "consumer")]
with (leg / "consumer.log").open("w") as log:
probe = subprocess.run(command, env=env, stdout=log, stderr=subprocess.STDOUT, timeout=150)
result.update(command=command, exit=probe.returncode,
result=str(leg / "consumer" / "result.json"))
finally:
server_root.mkdir(exist_ok=True)
(server_root / "stop").touch()
try:
server.wait(timeout=15)
except subprocess.TimeoutExpired:
server.terminate()
server.wait(timeout=10)
result["serverExit"] = server.returncode
receipt["legs"].append(result)
(root / "receipt.json").write_text(json.dumps(receipt, indent=2))
# A pre-existing consumer limitation is evidence to investigate, never converted into a passing leg.
return int(any(leg["exit"] != 0 or leg["serverExit"] != 0 for leg in receipt["legs"]))
if __name__ == "__main__":
raise SystemExit(main())