fix(scripting): deny System.AppContext and other process-wide mutators in the script sandbox (lmxopcua#792)
v2-ci / unit-tests (push) Waiting to run
v2-ci / unit-tests (push) Waiting to run
ForbiddenTypeAnalyzer now denies System.AppContext, System.Console, GCSettings, ProfileOptimization,
EncodingProvider/CodePagesEncodingProvider, TypeDescriptor and CryptoConfig as types, and the ambient
CultureInfo.{DefaultThreadCurrentCulture,DefaultThreadCurrentUICulture,CurrentCulture,CurrentUICulture}
and TimeZoneInfo.ClearCachedData members (member deny-list now covers properties and member-access reads).
Shadow-mode tests diverge via culture-sensitive string.Compare (worker is InvariantGlobalization) instead of
AppContext.BaseDirectory, with a premise test. Mutation-proved: 21 new cases fail with the analyzer reverted.
Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
@@ -24,8 +24,13 @@ namespace ZB.MOM.WW.OtOpcUa.ScriptWorker.Tests;
|
||||
[Trait("Category", "ScriptWorker")]
|
||||
public sealed class ShadowModeTests
|
||||
{
|
||||
/// <summary>True only inside the ScriptWorker (its base directory is <c>script-worker/</c>): a test-only divergence.</summary>
|
||||
private const string InWorker = "System.AppContext.BaseDirectory.Contains(\"script-worker\")";
|
||||
/// <summary>
|
||||
/// True only inside the ScriptWorker: a test-only divergence that needs no sandbox-forbidden API. The worker runs
|
||||
/// with <c>InvariantGlobalization</c> (ordinal string comparison) while the test host does linguistic (ICU/NLS)
|
||||
/// comparison, so a culture-sensitive <c>string.Compare("a", "B")</c> is negative in the host and positive in the
|
||||
/// worker. <see cref="Culture_sensitive_comparison_really_diverges_between_host_and_worker"/> pins the premise.
|
||||
/// </summary>
|
||||
private const string InWorker = "(string.Compare(\"a\", \"B\") > 0)";
|
||||
|
||||
private static CancellationToken Ct => TestContext.Current.CancellationToken;
|
||||
|
||||
@@ -60,6 +65,17 @@ public sealed class ShadowModeTests
|
||||
&& System.Collections.StructuralComparisons.StructuralEqualityComparer.Equals(a.Value, b.Value)
|
||||
&& a.Value?.GetType() == b.Value?.GetType();
|
||||
|
||||
[Fact]
|
||||
public async Task Culture_sensitive_comparison_really_diverges_between_host_and_worker()
|
||||
{
|
||||
// Premise of InWorker: the worker is a different process whose globalization mode differs from the host's.
|
||||
string.Compare("a", "B").ShouldBeLessThan(0, "the test host compares linguistically");
|
||||
await using var pool = Scripts.Runner(Scripts.Options());
|
||||
var r = await pool.RunAsync(Scripts.Vt("probe", $"return {InWorker} ? 2 : 1;"), Ct);
|
||||
r.Status.ShouldBe(ScriptRunStatus.Ok, r.Reason);
|
||||
r.Value.ShouldBe(2, "the worker (InvariantGlobalization) compares ordinally");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Ordinary_scripts_match_and_a_divergent_and_an_unsupported_one_are_counted_against_exactly_those_scripts()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user