diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Tests/ScriptSandboxTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Tests/ScriptSandboxTests.cs index 0f0a2c0..fbfae16 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Tests/ScriptSandboxTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Tests/ScriptSandboxTests.cs @@ -385,4 +385,65 @@ public sealed class ScriptSandboxTests ex.Diagnostics[0].Location.ShouldNotBeNull(); } } + + // --- Core.Scripting-010: remaining forbidden-namespace vectors not previously tested --- + // System.Threading.Thread, System.Threading.Tasks, System.Runtime.InteropServices, and + // Microsoft.Win32 were all in ForbiddenNamespacePrefixes but had no test asserting their + // rejection. Adding them here closes the coverage gap that allowed Core.Scripting-001 and + // -002 to go undetected. + + [Fact] + public void Rejects_Thread_new_at_compile() + { + // System.Threading.Thread is in ForbiddenNamespacePrefixes — raw thread creation + // in a script would bypass the per-evaluation timeout and tie up a thread-pool thread + // indefinitely. (Core.Scripting-010.) + Should.Throw(() => + ScriptEvaluator.Compile( + """ + var t = new System.Threading.Thread(() => { }); + t.Start(); + return 0; + """)); + } + + [Fact] + public void Rejects_Tasks_TaskRun_at_compile() + { + // System.Threading.Tasks is now in ForbiddenNamespacePrefixes (Core.Scripting-003). + // Scripts are synchronous predicates — background tasks would outlive the evaluation + // timeout. (Core.Scripting-010.) + Should.Throw(() => + ScriptEvaluator.Compile( + """ + var t = System.Threading.Tasks.Task.Run(() => 42); + return 0; + """)); + } + + [Fact] + public void Rejects_InteropServices_at_compile() + { + // System.Runtime.InteropServices gives access to native memory and COM — clearly + // outside the safe predicate surface. (Core.Scripting-010.) + Should.Throw(() => + ScriptEvaluator.Compile( + """ + var p = System.Runtime.InteropServices.Marshal.AllocHGlobal(256); + return 0; + """)); + } + + [Fact] + public void Rejects_Win32_Registry_at_compile() + { + // Microsoft.Win32 provides registry access — not appropriate from a sandboxed + // SCADA predicate. (Core.Scripting-010.) + Should.Throw(() => + ScriptEvaluator.Compile( + """ + var k = Microsoft.Win32.Registry.CurrentUser; + return 0; + """)); + } }