using Microsoft.Extensions.Logging.Abstractions; using ScadaLink.SiteRuntime.Scripts; namespace ScadaLink.SiteRuntime.Tests.Scripts; /// /// WP-19: Script Trust Model tests — validates forbidden API detection and compilation. /// public class ScriptCompilationServiceTests { private readonly ScriptCompilationService _service; public ScriptCompilationServiceTests() { _service = new ScriptCompilationService(NullLogger.Instance); } [Fact] public void Compile_ValidScript_Succeeds() { var result = _service.Compile("test", "1 + 1"); Assert.True(result.IsSuccess); Assert.NotNull(result.CompiledScript); Assert.Empty(result.Errors); } [Fact] public void Compile_InvalidSyntax_ReturnsErrors() { var result = _service.Compile("bad", "this is not valid C# {{{"); Assert.False(result.IsSuccess); Assert.NotEmpty(result.Errors); } [Fact] public void ValidateTrustModel_SystemIO_Forbidden() { var violations = _service.ValidateTrustModel("System.IO.File.ReadAllText(\"test\")"); Assert.NotEmpty(violations); Assert.Contains(violations, v => v.Contains("System.IO")); } [Fact] public void ValidateTrustModel_Process_Forbidden() { var violations = _service.ValidateTrustModel( "System.Diagnostics.Process.Start(\"cmd\")"); Assert.NotEmpty(violations); } [Fact] public void ValidateTrustModel_Reflection_Forbidden() { var violations = _service.ValidateTrustModel( "typeof(string).GetType().GetMethods(System.Reflection.BindingFlags.Public)"); Assert.NotEmpty(violations); } [Fact] public void ValidateTrustModel_Sockets_Forbidden() { var violations = _service.ValidateTrustModel( "new System.Net.Sockets.TcpClient()"); Assert.NotEmpty(violations); } [Fact] public void ValidateTrustModel_HttpClient_Forbidden() { var violations = _service.ValidateTrustModel( "new System.Net.Http.HttpClient()"); Assert.NotEmpty(violations); } [Fact] public void ValidateTrustModel_AsyncAwait_Allowed() { // System.Threading.Tasks should be allowed (async/await support) var violations = _service.ValidateTrustModel( "await System.Threading.Tasks.Task.Delay(100)"); Assert.Empty(violations); } [Fact] public void ValidateTrustModel_CancellationToken_Allowed() { var violations = _service.ValidateTrustModel( "System.Threading.CancellationToken.None"); Assert.Empty(violations); } [Fact] public void ValidateTrustModel_CleanCode_NoViolations() { var code = @" var x = 1 + 2; var list = new List { 1, 2, 3 }; var sum = list.Sum(); sum"; var violations = _service.ValidateTrustModel(code); Assert.Empty(violations); } [Fact] public void Compile_ForbiddenApi_FailsValidation() { var result = _service.Compile("evil", "System.IO.File.Delete(\"/tmp/test\")"); Assert.False(result.IsSuccess); Assert.NotEmpty(result.Errors); } }