refactor(inboundapi): M3.4 ForbiddenApiChecker delegates to shared ScriptAnalysis validator
This commit is contained in:
@@ -3,9 +3,18 @@ namespace ZB.MOM.WW.ScadaBridge.InboundAPI.Tests;
|
||||
/// <summary>
|
||||
/// InboundAPI-005 / InboundAPI-015: tests for the script-trust-model checker.
|
||||
///
|
||||
/// InboundAPI-015 hardens the textual walker against reflection reached through
|
||||
/// permitted-type members that never spell a forbidden namespace, e.g.
|
||||
/// <c>typeof(string).Assembly.GetType("System.IO.File")</c>.
|
||||
/// Since M3.4 <see cref="ForbiddenApiChecker"/> delegates to the shared
|
||||
/// <c>ScriptTrustValidator</c> in <c>ZB.MOM.WW.ScadaBridge.ScriptAnalysis</c>.
|
||||
/// The unified policy differs from the old local deny-list in one notable way:
|
||||
/// <c>System.Diagnostics</c> is loosened to <c>System.Diagnostics.Process</c>
|
||||
/// only — <c>Stopwatch</c>, <c>Debug</c>, and other non-Process Diagnostics
|
||||
/// types are now ALLOWED.
|
||||
///
|
||||
/// InboundAPI-015 hardening (reflection-gateway / dynamic / Activator) is
|
||||
/// preserved unchanged via the shared validator.
|
||||
///
|
||||
/// Violation message wording is intentionally not asserted — callers should
|
||||
/// use <c>.Count</c> / <c>.Any()</c> rather than exact strings.
|
||||
/// </summary>
|
||||
public class ForbiddenApiCheckerTests
|
||||
{
|
||||
@@ -26,11 +35,37 @@ public class ForbiddenApiCheckerTests
|
||||
Assert.False(IsRejected(script), script);
|
||||
}
|
||||
|
||||
// --- System.Diagnostics loosening: Process is still forbidden; non-Process types
|
||||
// (Stopwatch, Debug) are now ALLOWED by the unified policy (M3.4). The old
|
||||
// InboundAPI checker blocked the entire System.Diagnostics namespace. ---
|
||||
|
||||
[Fact]
|
||||
public void Diagnostics_Process_StillForbidden()
|
||||
{
|
||||
// System.Diagnostics.Process is an explicit forbidden scope in ScriptTrustPolicy.
|
||||
Assert.True(IsRejected("System.Diagnostics.Process.Start(\"/bin/sh\"); return null;"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Diagnostics_Stopwatch_NowAllowed()
|
||||
{
|
||||
// System.Diagnostics.Stopwatch is NOT under the forbidden scope
|
||||
// "System.Diagnostics.Process" — the unified policy only forbids
|
||||
// System.Diagnostics.Process, not the whole System.Diagnostics namespace.
|
||||
Assert.False(IsRejected("var sw = new System.Diagnostics.Stopwatch(); sw.Start(); return null;"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Diagnostics_Debug_NowAllowed()
|
||||
{
|
||||
// System.Diagnostics.Debug is also not covered by the Process-only scope.
|
||||
Assert.False(IsRejected("System.Diagnostics.Debug.WriteLine(\"hi\"); return null;"));
|
||||
}
|
||||
|
||||
// --- Baseline: forbidden namespaces (textual) must still be rejected ---
|
||||
|
||||
[Theory]
|
||||
[InlineData("System.IO.File.Delete(\"/tmp/x\"); return null;")]
|
||||
[InlineData("System.Diagnostics.Process.Start(\"/bin/sh\"); return null;")]
|
||||
[InlineData("using System.Reflection; return null;")]
|
||||
[InlineData("var s = new System.Net.Sockets.Socket(default, default, default); return null;")]
|
||||
public void ForbiddenNamespace_Rejected(string script)
|
||||
@@ -101,4 +136,17 @@ public class ForbiddenApiCheckerTests
|
||||
// dynamic widens late-bound member access the static walker cannot see through.
|
||||
Assert.True(IsRejected("dynamic d = Parameters; return null;"));
|
||||
}
|
||||
|
||||
// --- FindViolations returns a non-null, non-throwing result for edge inputs ---
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData(" ")]
|
||||
[InlineData(null!)]
|
||||
public void EmptyOrWhitespace_ReturnsEmptyList(string? script)
|
||||
{
|
||||
var result = ForbiddenApiChecker.FindViolations(script!);
|
||||
Assert.NotNull(result);
|
||||
Assert.Empty(result);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user