using ZB.MOM.WW.ScadaBridge.ScriptAnalysis; namespace ZB.MOM.WW.ScadaBridge.ScriptAnalysis.Tests; /// /// M3.1: adversarial + legitimate cases for the fused trust validator. Reject /// cases exercise the semantic pass (alias / using static / global::), the /// reflection-gateway hardening pass, and the namespace deny-list union; clean /// cases pin the allowed exceptions (Tasks, CancellationToken, Diagnostics /// other than Process). /// public class ScriptTrustValidatorTests { // ---- Reject (non-empty violations) -------------------------------------- [Fact] public void Rejects_SystemIo_Using() { var code = "using System.IO; var x = File.ReadAllText(\"/etc/passwd\");"; Assert.NotEmpty(ScriptTrustValidator.FindViolations(code)); } [Fact] public void Rejects_SystemIo_GlobalQualified() { var code = "var x = global::System.IO.File.ReadAllText(\"x\");"; Assert.NotEmpty(ScriptTrustValidator.FindViolations(code)); } [Fact] public void Rejects_SystemIo_Aliased() { var code = "using IO = System.IO; var f = IO.File.ReadAllText(\"x\");"; Assert.NotEmpty(ScriptTrustValidator.FindViolations(code)); } [Fact] public void Rejects_SystemIo_UsingStatic() { var code = "using static System.IO.File; var s = ReadAllText(\"x\");"; Assert.NotEmpty(ScriptTrustValidator.FindViolations(code)); } [Fact] public void Rejects_ReflectionGateway_OffPermittedType() { var code = "var t = typeof(string).Assembly.GetType(\"System.IO.File\");"; Assert.NotEmpty(ScriptTrustValidator.FindViolations(code)); } [Fact] public void Rejects_Dynamic_Keyword() { var code = "dynamic d = 5; d.Foo();"; Assert.NotEmpty(ScriptTrustValidator.FindViolations(code)); } [Fact] public void Rejects_Activator_CreateInstance() { var code = "var o = Activator.CreateInstance(typeof(string));"; Assert.NotEmpty(ScriptTrustValidator.FindViolations(code)); } [Fact] public void Rejects_RuntimeInteropServices() { var code = "using System.Runtime.InteropServices; var h = Marshal.SizeOf();"; Assert.NotEmpty(ScriptTrustValidator.FindViolations(code)); } [Fact] public void Rejects_MicrosoftWin32() { var code = "using Microsoft.Win32; var k = Registry.LocalMachine;"; Assert.NotEmpty(ScriptTrustValidator.FindViolations(code)); } [Fact] public void Rejects_Threading_Thread_Sleep() { var code = "System.Threading.Thread.Sleep(10);"; Assert.NotEmpty(ScriptTrustValidator.FindViolations(code)); } [Fact] public void Rejects_All_SystemNet() { var code = "System.Net.WebClient w = null;"; Assert.NotEmpty(ScriptTrustValidator.FindViolations(code)); } [Fact] public void Rejects_ReflectionGateway_OffAllowedTaskType() { // Guards the reflection-first ordering: a gateway member hung off an // allowed System.Threading.Tasks type must still be rejected even though // the chain's namespace prefix is an allowed exception. var code = "var a = System.Threading.Tasks.Task.CompletedTask.GetType().Assembly;"; Assert.NotEmpty(ScriptTrustValidator.FindViolations(code)); } // ---- Clean (empty violations) ------------------------------------------- [Fact] public void Allows_TasksDelay() { var code = "await System.Threading.Tasks.Task.Delay(1);"; Assert.Empty(ScriptTrustValidator.FindViolations(code)); } [Fact] public void Allows_DiagnosticsStopwatch_NotProcess() { var code = "var sw = System.Diagnostics.Stopwatch.StartNew();"; Assert.Empty(ScriptTrustValidator.FindViolations(code)); } [Fact] public void Allows_CancellationTokenSource() { var code = "var c = new System.Threading.CancellationTokenSource();"; Assert.Empty(ScriptTrustValidator.FindViolations(code)); } [Fact] public void Allows_LinqAndMath() { var code = "var n = System.Linq.Enumerable.Range(0,3).Sum(); var m = System.Math.Max(1,2);"; Assert.Empty(ScriptTrustValidator.FindViolations(code)); } }