refactor(centralui): M3.5 ScriptAnalysisService uses shared deny-list + delegates trust verdict

This commit is contained in:
Joseph Doherty
2026-06-16 19:40:03 -04:00
parent 64d6ac7288
commit cf935d5744
3 changed files with 167 additions and 40 deletions
@@ -54,11 +54,14 @@ public class ScriptAnalysisServiceTests
}
[Theory]
[InlineData("System.Diagnostics")]
[InlineData("System.Reflection")]
[InlineData("System.Net")]
[InlineData("System.Threading")]
public void ForbiddenUsing_AllBannedNamespaces(string ns)
{
// M3.5: the editor deny-list is sourced from the shared ScriptTrustPolicy.
// System.Threading is now a forbidden root (only Tasks +
// CancellationToken(Source) are excepted).
var resp = _svc.Diagnose(new DiagnoseRequest($"using {ns};"));
Assert.Contains(resp.Markers, m => m.Code == "SCADA001" && m.Message.Contains(ns));
}
@@ -71,6 +74,61 @@ public class ScriptAnalysisServiceTests
Assert.Contains(resp.Markers, m => m.Code == "SCADA002" && m.Message.Contains("File"));
}
[Fact]
public void SystemDiagnosticsNamespace_NoLongerWholesaleForbidden()
{
// M3.5: the unified policy forbids only System.Diagnostics.Process, not the
// whole System.Diagnostics namespace — so a bare `using System.Diagnostics;`
// is no longer flagged (Stopwatch & friends are allowed).
var resp = _svc.Diagnose(new DiagnoseRequest("using System.Diagnostics;"));
Assert.DoesNotContain(resp.Markers, m => m.Code == "SCADA001");
}
[Fact]
public void StopwatchUsage_IsAllowedUnderUnifiedPolicy()
{
// System.Diagnostics.Stopwatch is NOT under the forbidden
// System.Diagnostics.Process scope — it must not be flagged.
var resp = _svc.Diagnose(new DiagnoseRequest(
"using System.Diagnostics; var sw = Stopwatch.StartNew(); return sw.ElapsedMilliseconds;"));
Assert.DoesNotContain(resp.Markers, m => m.Code is "SCADA001" or "SCADA002");
}
[Fact]
public void ProcessUsage_IsForbiddenUnderUnifiedPolicy()
{
// System.Diagnostics.Process IS the forbidden scope — flagged via the
// semantic marker even though the parent namespace is allowed.
var resp = _svc.Diagnose(new DiagnoseRequest(
"using System.Diagnostics; var p = Process.GetCurrentProcess(); return p.Id;"));
Assert.Contains(resp.Markers, m => m.Code == "SCADA002" && m.Message.Contains("Process"));
}
[Theory]
[InlineData("Monitor")]
[InlineData("Interlocked")]
[InlineData("Mutex")]
public void ThreadingPrimitives_NowFlagged_UnderUnifiedPolicy(string typeName)
{
// CentralUI's old deny-list allowed most of System.Threading (only Thread +
// Tasks.Sources were blocked). The unified policy forbids ALL of
// System.Threading except Tasks + CancellationToken(Source), so these
// previously-clean primitives are now flagged by the editor.
var resp = _svc.Diagnose(new DiagnoseRequest(
$"using System.Threading; var x = typeof({typeName}); return 1;"));
Assert.Contains(resp.Markers, m => m.Code is "SCADA001" or "SCADA002");
}
[Fact]
public void CancellationToken_StaysAllowed_UnderUnifiedPolicy()
{
// The AllowedExceptions carve-out keeps CancellationToken(Source) clean even
// though the rest of System.Threading is forbidden.
var resp = _svc.Diagnose(new DiagnoseRequest(
"var cts = new System.Threading.CancellationTokenSource(); return cts.Token.IsCancellationRequested;"));
Assert.DoesNotContain(resp.Markers, m => m.Code is "SCADA001" or "SCADA002");
}
[Fact]
public void UserIdentifierNamedFile_DoesNotFalsePositive()
{