From a17de80cdb1f96d968fa421068b6d8504396aa9d Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Fri, 22 May 2026 09:23:29 -0400 Subject: [PATCH] fix(scripting): resolve Medium code-review finding (Core.Scripting-010) Add ScriptSandboxTests cases for all forbidden-namespace deny-list vectors that lacked test coverage: System.Threading.Thread, System.Threading.Tasks.Task.Run (newly denied per Core.Scripting-003), System.Runtime.InteropServices.Marshal, and Microsoft.Win32.Registry. The 001/002 type-granular and node-form vectors were already covered by the -001/-002 resolution commits. All 79 tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ScriptSandboxTests.cs | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) 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; + """)); + } }