diff --git a/scripts/validation/scadabridge-sdk-compatibility/README.md b/scripts/validation/scadabridge-sdk-compatibility/README.md index 62a012776..5206ff21d 100644 --- a/scripts/validation/scadabridge-sdk-compatibility/README.md +++ b/scripts/validation/scadabridge-sdk-compatibility/README.md @@ -45,7 +45,11 @@ roundtrips, durable hierarchical browse including the native alarm, data quality and timestamps on raw and UNS subscriptions, alarm filter/ConditionRefresh, disconnect/reconnect, and (ScadaBridge#125) a Server-object alarm subscription on the reconnected session whose ConditionRefresh must replay the active native -condition (11 cases per trusted leg). History +condition (11 cases per trusted leg). The API key has the production +`ApiKeySecret.Generate` shape and length, 65 characters (lmxopcua#880): the +55-character `otua_matrix_` key used before stayed under SDK 2's 64-byte +`RsaEncryptedSecret` threshold, so it could not show whether an SDK 2 consumer +still sends the password in a format an SDK 1.5 server decrypts. History and Part 9 acknowledgment are not exposed by the inspected consumer interfaces; the parent Shared/CLI matrix covers those application services instead. @@ -97,3 +101,16 @@ legs (11/11 cases each). Loss-to-backup timings are the same on both versions: waits out a connect timeout against the silent primary. `rig-failover.sh` passed 9/9 against the docker-dev pair (image SDK 2.0.1), central-1 killed, about 20 s to central-2. + +Run 2026-11-12 (ScadaBridge#125) with the consumer itself on SDK **2.0.1** +(ScadaBridge `731d1ed7`, on main as `a2e9d718`; the DCL sends UserName passwords in the +legacy RSA format), 65-character key, against the SDK 1.5.378 baseline +(`83ed880e`) and master `412da27c` (SDK 2.0.1): matrix 11/11 in None, Sign and +SignAndEncrypt on both with the ACL off and on, all 8 trust controls failed +closed (0x80130000 / 0x801A0000), failover 8/8 legs. `kill` reaches the backup +in about 20 s as before; `freeze` is now detected in about 15 s (SDK 2 +keep-alive; about 20 s on the SDK 1.5 client) and reaches the backup in 81–125 s. +A mutation run with the consumer's UserName identity reverted to the SDK 2 +default handler fails every trusted leg against the baseline with +`BadIdentityTokenInvalid` (0x80200000) and passes against master, which is +lmxopcua#880 reproduced from the consumer side. diff --git a/scripts/validation/scadabridge-sdk-compatibility/run.py b/scripts/validation/scadabridge-sdk-compatibility/run.py index 1de2e7e45..535ae8961 100644 --- a/scripts/validation/scadabridge-sdk-compatibility/run.py +++ b/scripts/validation/scadabridge-sdk-compatibility/run.py @@ -16,7 +16,11 @@ SECURITY = {"None": "none", "Sign": "sign", "SignAndEncrypt": None} def leg_env(mode): env = os.environ.copy() - env["OPCUA_MATRIX_PASSWORD"] = "otua_matrix_" + secrets.token_urlsafe(32) + # The production ApiKeySecret.Generate shape and length, 65 characters (lmxopcua#880, ScadaBridge#125): the + # 55-character key used before stayed under SDK 2's 64-byte RsaEncryptedSecret threshold, so it could not show + # whether an SDK 2 consumer still sends the password in a format an SDK 1.5 server decrypts. + env["OPCUA_MATRIX_PASSWORD"] = "otua_" + secrets.token_hex(8) + "_" + secrets.token_urlsafe(32) + assert len(env["OPCUA_MATRIX_PASSWORD"]) == 65 for name in ("SCADABRIDGE_PROBE_PKI", "SCADABRIDGE_PROBE_SERVER_CERTS", "OPCUA_MATRIX_SERVER_SECURITY"): env.pop(name, None) if SECURITY[mode]: