docs(xmldoc): fill missing XML docs + strip tracking-ID comments across src
v2-ci / build (push) Failing after 41s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
v2-ci / build (push) Failing after 41s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
Adds <summary>/<param>/<returns>/<inheritdoc> where missing and removes project bookkeeping IDs (task/tracking refs) from shipped code comments, so the docs read cleanly and CommentChecker is quiet except for known false positives (PLC/protocol terms, event/IEqualityComparer inheritdoc). Doc/comment-only; no logic changed; solution builds clean.
This commit is contained in:
@@ -32,8 +32,8 @@ namespace ZB.MOM.WW.OtOpcUa.Core.Scripting;
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <b>Lifecycle:</b> compiled scripts hold a collectible
|
||||
/// <see cref="System.Runtime.Loader.AssemblyLoadContext"/> per evaluator
|
||||
/// (Core.Scripting-008 fix). <see cref="Clear"/> disposes every materialised
|
||||
/// <see cref="System.Runtime.Loader.AssemblyLoadContext"/> per evaluator.
|
||||
/// <see cref="Clear"/> disposes every materialised
|
||||
/// evaluator before dropping its dictionary entry so the emitted assemblies are
|
||||
/// eligible for GC immediately after a publish. <see cref="Dispose"/> drops the
|
||||
/// cache itself for graceful server shutdown.
|
||||
@@ -75,7 +75,7 @@ public sealed class CompiledScriptCache<TContext, TResult> : IDisposable
|
||||
// value reference, so if two threads race the same bad source both observe
|
||||
// the same faulted Lazy and both reach this catch, and a concurrent retry
|
||||
// re-added a fresh Lazy under the same key between the two removals, the
|
||||
// second removal does NOT evict the in-flight retry. (Core.Scripting-006.)
|
||||
// second removal does NOT evict the in-flight retry.
|
||||
_cache.TryRemove(new KeyValuePair<string, Lazy<ScriptEvaluator<TContext, TResult>>>(key, lazy));
|
||||
throw;
|
||||
}
|
||||
@@ -88,28 +88,28 @@ public sealed class CompiledScriptCache<TContext, TResult> : IDisposable
|
||||
/// Drop every cached compile. Used on config generation publish + tests.
|
||||
/// Disposes each materialised evaluator before removing it so its collectible
|
||||
/// <see cref="System.Runtime.Loader.AssemblyLoadContext"/> unloads and the
|
||||
/// emitted script assembly becomes eligible for GC (Core.Scripting-008).
|
||||
/// emitted script assembly becomes eligible for GC.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Safe to call after <see cref="Dispose"/> — the operation is idempotent.
|
||||
/// <see cref="Dispose"/> sets <c>_disposed = true</c> before invoking this
|
||||
/// method (so callers see the post-Dispose guard on <see cref="GetOrCompile"/>),
|
||||
/// but this method itself MUST run to completion so the Dispose-triggered
|
||||
/// drain actually unloads every materialised evaluator's ALC. (Core.Scripting-016
|
||||
/// uncovered this — a previous Clear-aborts-when-disposed guard silently
|
||||
/// skipped the entire drain on Dispose, leaving emitted assemblies rooted.)
|
||||
/// drain actually unloads every materialised evaluator's ALC (a previous
|
||||
/// Clear-aborts-when-disposed guard silently skipped the entire drain on
|
||||
/// Dispose, leaving emitted assemblies rooted).
|
||||
/// </remarks>
|
||||
public void Clear()
|
||||
{
|
||||
// Snapshot (key, value) pairs and remove with the value-scoped
|
||||
// TryRemove(KeyValuePair<,>) overload — same shape as the
|
||||
// Core.Scripting-006 fix in GetOrCompile's catch block. A concurrent
|
||||
// fix in GetOrCompile's catch block. A concurrent
|
||||
// GetOrCompile re-add that hashes to the same key between our snapshot
|
||||
// and the TryRemove inserts a *different* Lazy reference; the value-
|
||||
// scoped removal sees the mismatch and leaves the fresh entry intact
|
||||
// (instead of evicting + disposing it while the concurrent caller
|
||||
// still holds it). The fresh evaluator and its ALC stay live for the
|
||||
// concurrent caller. (Core.Scripting-014.)
|
||||
// concurrent caller.
|
||||
foreach (var entry in _cache.ToArray())
|
||||
{
|
||||
if (_cache.TryRemove(entry))
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace ZB.MOM.WW.OtOpcUa.Core.Scripting;
|
||||
/// <summary>
|
||||
/// Parses a script's source text + extracts every <c>ctx.GetTag("literal")</c> and
|
||||
/// <c>ctx.SetVirtualTag("literal", ...)</c> call. Outputs the static dependency set
|
||||
/// the virtual-tag engine uses to build its change-trigger subscription graph (Phase
|
||||
/// 7 plan decision #7 — AST inference, operator doesn't maintain a separate list).
|
||||
/// the virtual-tag engine uses to build its change-trigger subscription graph (AST
|
||||
/// inference, operator doesn't maintain a separate list).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
@@ -29,7 +29,7 @@ namespace ZB.MOM.WW.OtOpcUa.Core.Scripting;
|
||||
/// extractor while still having a working script. Calls with the same method name on
|
||||
/// a different receiver (<c>other.GetTag("X")</c>) are explicitly ignored so that
|
||||
/// scripts defining local helper types with matching names do not produce spurious
|
||||
/// dependencies. (Core.Scripting-004.)
|
||||
/// dependencies.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static class DependencyExtractor
|
||||
@@ -39,6 +39,7 @@ public static class DependencyExtractor
|
||||
/// paths, or a list of rejection messages if non-literal paths were used.
|
||||
/// </summary>
|
||||
/// <param name="scriptSource">The script source code to analyze.</param>
|
||||
/// <returns>The inferred read/write tag dependencies, plus any non-literal-path rejections.</returns>
|
||||
public static DependencyExtractionResult Extract(string scriptSource)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(scriptSource))
|
||||
@@ -81,7 +82,6 @@ public static class DependencyExtractor
|
||||
// field). Calls with the same method name on a different receiver (e.g.
|
||||
// someHelper.GetTag("X")) are ignored — not picking them up avoids spurious
|
||||
// dependencies when scripts define local types with matching method names.
|
||||
// (Core.Scripting-004.)
|
||||
if (node.Expression is MemberAccessExpressionSyntax member
|
||||
&& member.Expression is IdentifierNameSyntax receiver
|
||||
&& receiver.Identifier.ValueText == "ctx")
|
||||
@@ -113,7 +113,7 @@ public static class DependencyExtractor
|
||||
// rather than StringLiteralToken. Checking the expression kind
|
||||
// (StringLiteralExpression) covers all token kinds Roslyn assigns to literal
|
||||
// strings, so a """raw""" path is harvested rather than mis-rejected as a
|
||||
// dynamic path. (Core.Scripting-005.)
|
||||
// dynamic path.
|
||||
if (pathArg is not LiteralExpressionSyntax literal
|
||||
|| !literal.IsKind(SyntaxKind.StringLiteralExpression))
|
||||
{
|
||||
|
||||
@@ -17,13 +17,13 @@ namespace ZB.MOM.WW.OtOpcUa.Core.Scripting;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Deny-list is the authoritative Phase 7 plan decision #6 set:
|
||||
/// Deny-list is the authoritative Phase 7 plan set:
|
||||
/// <c>System.IO</c>, <c>System.Net</c>, <c>System.Diagnostics</c>,
|
||||
/// <c>System.Reflection</c>, <c>System.Threading.Thread</c>,
|
||||
/// <c>System.Threading.Tasks</c> (scripts are synchronous predicates — no
|
||||
/// legitimate need to start background tasks; a <c>Task.Run</c> fan-out outlives
|
||||
/// the evaluation timeout entirely), <c>System.Runtime.InteropServices</c>,
|
||||
/// <c>Microsoft.Win32</c>. (Core.Scripting-003.)
|
||||
/// <c>Microsoft.Win32</c>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Deny-list prefix match. <c>System.Net</c> catches <c>System.Net.Http</c>,
|
||||
@@ -45,7 +45,7 @@ namespace ZB.MOM.WW.OtOpcUa.Core.Scripting;
|
||||
/// <c>Activator.CreateInstance</c> is a reflection-equivalent escape; <c>GC</c>
|
||||
/// and <c>AppDomain</c> expose process-wide control. Legitimate <c>System</c>
|
||||
/// types (<c>Math</c>, <c>String</c>, <c>Convert</c>, <c>DateTime</c>, …) are not
|
||||
/// on the list and stay usable. (Core.Scripting-001.)
|
||||
/// on the list and stay usable.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static class ForbiddenTypeAnalyzer
|
||||
@@ -69,14 +69,13 @@ public static class ForbiddenTypeAnalyzer
|
||||
// ForbiddenFullTypeNames instead so the check actually fires.
|
||||
"System.Threading.Tasks", // Task.Run / Parallel — scripts are synchronous predicates
|
||||
// and have no legitimate need to start background work;
|
||||
// a Task fan-out outlives the evaluation timeout entirely
|
||||
// (Core.Scripting-003).
|
||||
// a Task fan-out outlives the evaluation timeout entirely.
|
||||
"System.Runtime.InteropServices",
|
||||
"System.Runtime.Loader", // AssemblyLoadContext + AssemblyDependencyResolver —
|
||||
// arbitrary DLL load into the host process
|
||||
// (Core.Scripting-012). Namespace-prefix rather than
|
||||
// type-granular so future BCL additions to this
|
||||
// namespace are denied by default.
|
||||
// arbitrary DLL load into the host process.
|
||||
// Namespace-prefix rather than type-granular so
|
||||
// future BCL additions to this namespace are
|
||||
// denied by default.
|
||||
"Microsoft.Win32", // registry
|
||||
];
|
||||
|
||||
@@ -104,15 +103,14 @@ public static class ForbiddenTypeAnalyzer
|
||||
/// per-evaluation timeout; denied type-granularly because its containing
|
||||
/// namespace is <c>System.Threading</c> (shared with allowed types like
|
||||
/// <c>CancellationToken</c>), so a namespace-prefix rule cannot reach it
|
||||
/// without blocking unrelated types. (Core.Scripting-010.)</item>
|
||||
/// without blocking unrelated types.</item>
|
||||
/// <item><c>System.Threading.ThreadPool</c> / <c>System.Threading.Timer</c> —
|
||||
/// background-work vectors that outlive the per-evaluation timeout; same
|
||||
/// threat as <c>Task.Run</c> that Core.Scripting-003 closed. (Core.Scripting-012.)</item>
|
||||
/// threat as <c>Task.Run</c>.</item>
|
||||
/// <item><c>System.Runtime.CompilerServices.Unsafe</c> — exposes raw type-
|
||||
/// reinterpretation (<c>As<TFrom,TTo></c>, <c>As<T>(object)</c>)
|
||||
/// that bypasses the CLR type system without requiring an <c>unsafe</c> context at
|
||||
/// the call site; enables type-confusion and managed heap corruption.
|
||||
/// (Core.Scripting-017.)</item>
|
||||
/// the call site; enables type-confusion and managed heap corruption.</item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
public static readonly IReadOnlyList<string> ForbiddenFullTypeNames =
|
||||
@@ -124,18 +122,15 @@ public static class ForbiddenTypeAnalyzer
|
||||
// System.Threading.Thread lives in the System.Threading namespace (shared with
|
||||
// CancellationToken, SemaphoreSlim, etc.), so a namespace-prefix deny-list cannot
|
||||
// target it without blocking those legitimate types. Denied type-granularly here.
|
||||
// (Core.Scripting-010.)
|
||||
"System.Threading.Thread",
|
||||
// Core.Scripting-012 — broadening the references list to the BCL trusted-platform-
|
||||
// assemblies set (Core.Scripting-008 follow-up) re-exposed two background-work
|
||||
// vectors the original deny-list missed. Both live in System.Threading (shared
|
||||
// with allowed sync primitives like CancellationToken / SemaphoreSlim), so they
|
||||
// must be denied type-granularly:
|
||||
// Broadening the references list to the BCL trusted-platform-assemblies set
|
||||
// re-exposed two background-work vectors the original deny-list missed. Both live
|
||||
// in System.Threading (shared with allowed sync primitives like CancellationToken /
|
||||
// SemaphoreSlim), so they must be denied type-granularly:
|
||||
//
|
||||
// System.Threading.ThreadPool — QueueUserWorkItem / UnsafeQueueUserWorkItem
|
||||
// re-introduce the background-fanout threat
|
||||
// Core.Scripting-003 closed against
|
||||
// System.Threading.Tasks.
|
||||
// closed against System.Threading.Tasks.
|
||||
// System.Threading.Timer — Timer(callback, …) schedules unbounded work
|
||||
// that outlives the per-evaluation timeout.
|
||||
//
|
||||
@@ -144,14 +139,14 @@ public static class ForbiddenTypeAnalyzer
|
||||
// namespace are denied by default.
|
||||
"System.Threading.ThreadPool",
|
||||
"System.Threading.Timer",
|
||||
// Core.Scripting-017 — System.Runtime.CompilerServices.Unsafe exposes raw
|
||||
// type-reinterpretation (Unsafe.As<TFrom, TTo>, Unsafe.As<T>(object)) that
|
||||
// bypasses the CLR type system without requiring an 'unsafe' compilation context
|
||||
// at the call site. In a script, calling Unsafe.As<string>(someObject) can corrupt
|
||||
// managed heap references and cause type-confusion in downstream virtual-tag
|
||||
// consumers. Type-granular (not namespace-prefix) because System.Runtime.CompilerServices
|
||||
// also contains harmless compile-time-only types (CallerMemberNameAttribute,
|
||||
// MethodImplAttribute, MethodImplOptions) that scripts may legitimately reference.
|
||||
// System.Runtime.CompilerServices.Unsafe exposes raw type-reinterpretation
|
||||
// (Unsafe.As<TFrom, TTo>, Unsafe.As<T>(object)) that bypasses the CLR type system
|
||||
// without requiring an 'unsafe' compilation context at the call site. In a script,
|
||||
// calling Unsafe.As<string>(someObject) can corrupt managed heap references and
|
||||
// cause type-confusion in downstream virtual-tag consumers. Type-granular (not
|
||||
// namespace-prefix) because System.Runtime.CompilerServices also contains harmless
|
||||
// compile-time-only types (CallerMemberNameAttribute, MethodImplAttribute,
|
||||
// MethodImplOptions) that scripts may legitimately reference.
|
||||
"System.Runtime.CompilerServices.Unsafe",
|
||||
];
|
||||
|
||||
@@ -176,7 +171,7 @@ public static class ForbiddenTypeAnalyzer
|
||||
/// declares it, even though the receiver type <c>System.Type</c> is allowed).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Pass (2) — the Core.Scripting-002 fix — resolves the <em>type</em> of every
|
||||
/// Pass (2) resolves the <em>type</em> of every
|
||||
/// <c>TypeSyntax</c> node via <c>GetTypeInfo</c>. The old walker only inspected
|
||||
/// the four node kinds above, so a forbidden type named through
|
||||
/// <c>typeof(System.IO.File)</c>, a generic argument
|
||||
@@ -223,7 +218,7 @@ public static class ForbiddenTypeAnalyzer
|
||||
break;
|
||||
}
|
||||
|
||||
// Pass (2) — type-reference surface (Core.Scripting-002). Every TypeSyntax
|
||||
// Pass (2) — type-reference surface. Every TypeSyntax
|
||||
// resolves to the type it names, regardless of the syntactic form that
|
||||
// introduced it (typeof operand, cast type, generic argument, default(T)
|
||||
// operand, array element type, is/as pattern type, declared local type).
|
||||
@@ -275,10 +270,10 @@ public static class ForbiddenTypeAnalyzer
|
||||
|
||||
var typeName = typeSymbol.ToDisplayString();
|
||||
|
||||
// The broadened walk (Core.Scripting-002) resolves both GetSymbolInfo and
|
||||
// GetTypeInfo on every node, so the same forbidden reference can be hit several
|
||||
// times. Dedupe on span + type so the operator sees one rejection per offending
|
||||
// reference, not a noisy pile of identical messages.
|
||||
// The broadened walk resolves both GetSymbolInfo and GetTypeInfo on every node,
|
||||
// so the same forbidden reference can be hit several times. Dedupe on span + type
|
||||
// so the operator sees one rejection per offending reference, not a noisy pile of
|
||||
// identical messages.
|
||||
if (rejections.Any(r => r.Span == span && r.TypeName == typeName))
|
||||
return;
|
||||
|
||||
@@ -298,9 +293,9 @@ public static class ForbiddenTypeAnalyzer
|
||||
}
|
||||
|
||||
// Type-granular deny-list — dangerous types that live in the allow-listed
|
||||
// System namespace and so cannot be caught by ForbiddenNamespacePrefixes
|
||||
// (Core.Scripting-001). Matched on the full type name; OriginalDefinition
|
||||
// unwraps any generic construction before naming.
|
||||
// System namespace and so cannot be caught by ForbiddenNamespacePrefixes.
|
||||
// Matched on the full type name; OriginalDefinition unwraps any generic
|
||||
// construction before naming.
|
||||
var fullTypeName = typeSymbol.OriginalDefinition.ToDisplayString(
|
||||
SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle(
|
||||
SymbolDisplayGlobalNamespaceStyle.Omitted));
|
||||
|
||||
@@ -18,9 +18,9 @@ namespace ZB.MOM.WW.OtOpcUa.Core.Scripting;
|
||||
/// Scripts are wrapped in a synthesized <c>CompiledScript.Run(globals)</c> method
|
||||
/// and compiled via <see cref="CSharpCompilation"/> into a regular .NET assembly
|
||||
/// that is loaded into a <b>collectible</b>
|
||||
/// <see cref="AssemblyLoadContext"/>. The collectible ALC is the fix for
|
||||
/// Core.Scripting-008: per-publish recompile accretion was previously unbounded
|
||||
/// because Roslyn's <c>CSharpScript.CreateDelegate</c> emits into the default ALC
|
||||
/// <see cref="AssemblyLoadContext"/>. The collectible ALC fixes unbounded
|
||||
/// per-publish recompile accretion: previously
|
||||
/// Roslyn's <c>CSharpScript.CreateDelegate</c> emitted into the default ALC
|
||||
/// (non-collectible); now <see cref="Dispose"/> unloads the entire ALC and the
|
||||
/// emitted assembly becomes eligible for GC.
|
||||
/// </para>
|
||||
@@ -38,8 +38,8 @@ namespace ZB.MOM.WW.OtOpcUa.Core.Scripting;
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Runtime exceptions thrown from user code propagate unwrapped. The virtual-tag
|
||||
/// engine catches them per-tag and maps to <c>BadInternalError</c> quality
|
||||
/// per Phase 7 decision #11; this layer doesn't swallow anything so tests can
|
||||
/// engine catches them per-tag and maps to <c>BadInternalError</c> quality;
|
||||
/// this layer doesn't swallow anything so tests can
|
||||
/// assert on the original exception type.
|
||||
/// </para>
|
||||
/// <para>
|
||||
@@ -66,6 +66,7 @@ public sealed class ScriptEvaluator<TContext, TResult> : IDisposable
|
||||
|
||||
/// <summary>Compiles user script source into an evaluator.</summary>
|
||||
/// <param name="scriptSource">The user script source code to compile.</param>
|
||||
/// <returns>A ready-to-run <see cref="ScriptEvaluator{TContext, TResult}"/> wrapping the compiled script.</returns>
|
||||
public static ScriptEvaluator<TContext, TResult> Compile(string scriptSource)
|
||||
{
|
||||
if (scriptSource is null) throw new ArgumentNullException(nameof(scriptSource));
|
||||
@@ -78,7 +79,7 @@ public sealed class ScriptEvaluator<TContext, TResult> : IDisposable
|
||||
var wrapperSource = BuildWrapperSource(scriptSource, sandbox.Imports);
|
||||
var syntaxTree = CSharpSyntaxTree.ParseText(wrapperSource);
|
||||
|
||||
// Step 1a — defend against wrapper-source injection (Core.Scripting-013).
|
||||
// Step 1a — defend against wrapper-source injection.
|
||||
// A script body of `return 0; } public static int Evil() { return 0;` would
|
||||
// close the synthesized `Run` method early, declare a sibling `Evil` method
|
||||
// inside the synthesized `CompiledScript` class, and leave the wrapper's
|
||||
@@ -173,6 +174,7 @@ public sealed class ScriptEvaluator<TContext, TResult> : IDisposable
|
||||
/// <summary>Runs the script against an already-constructed context.</summary>
|
||||
/// <param name="context">The script context.</param>
|
||||
/// <param name="ct">Cancellation token for the operation.</param>
|
||||
/// <returns>A task carrying the script's result.</returns>
|
||||
public Task<TResult> RunAsync(TContext context, CancellationToken ct = default)
|
||||
{
|
||||
if (_disposed) throw new ObjectDisposedException(nameof(ScriptEvaluator<TContext, TResult>));
|
||||
@@ -215,7 +217,7 @@ public sealed class ScriptEvaluator<TContext, TResult> : IDisposable
|
||||
/// exactly one member — the <c>Run</c> method. Anything else (a sibling
|
||||
/// method, nested class, additional class in the namespace, free-floating
|
||||
/// top-level statement) means the user source closed the synthesized braces
|
||||
/// early and injected its own declarations. (Core.Scripting-013.)
|
||||
/// early and injected its own declarations.
|
||||
/// </summary>
|
||||
private static void EnforceSingleRunMember(SyntaxTree syntaxTree)
|
||||
{
|
||||
@@ -344,7 +346,7 @@ public sealed class ScriptEvaluator<TContext, TResult> : IDisposable
|
||||
// emits as `global::Ns.Outer<T>.Inner<U>` — valid C#. The pre-fix code
|
||||
// used `IndexOf('`')` to find the FIRST backtick and truncated the
|
||||
// entire name there, silently dropping the rest of the nested-generic
|
||||
// closed args. (Core.Scripting-015.)
|
||||
// closed args.
|
||||
var rawName = t.GetGenericTypeDefinition().FullName!.Replace('+', '.');
|
||||
var allArgs = t.GetGenericArguments();
|
||||
var segments = rawName.Split('.');
|
||||
@@ -403,7 +405,7 @@ internal sealed class ScriptAssemblyLoadContext : AssemblyLoadContext
|
||||
/// reports compile-time errors against the wrapper source. Mirrors the
|
||||
/// <c>Microsoft.CodeAnalysis.Scripting.CompilationErrorException</c> from the legacy
|
||||
/// <c>CSharpScript</c> path so callers (engines + the Admin test-harness) keep the
|
||||
/// same catch site after the Core.Scripting-008 rewrite.
|
||||
/// same catch site after the rewrite.
|
||||
/// </summary>
|
||||
public sealed class CompilationErrorException : Exception
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace ZB.MOM.WW.OtOpcUa.Core.Scripting;
|
||||
|
||||
/// <summary>
|
||||
/// Factory for the compile-time sandbox every user script is built against.
|
||||
/// Implements Phase 7 plan decision #6 (read-only sandbox) by whitelisting only the
|
||||
/// Enforces a read-only sandbox by whitelisting only the
|
||||
/// assemblies + namespaces the script API needs; no <c>System.IO</c>, no
|
||||
/// <c>System.Net</c>, no <c>System.Diagnostics.Process</c>, no
|
||||
/// <c>System.Reflection</c>. Attempts to reference those types in a script fail at
|
||||
@@ -18,8 +18,8 @@ namespace ZB.MOM.WW.OtOpcUa.Core.Scripting;
|
||||
/// <c>mscorlib</c> / <c>System.Runtime</c> — this class overrides that with an
|
||||
/// explicit minimal allow-list. The list is the same regardless of whether
|
||||
/// <see cref="ScriptEvaluator{TContext, TResult}"/> uses the legacy
|
||||
/// <c>CSharpScript</c> path or the collectible-<c>AssemblyLoadContext</c> path
|
||||
/// (Core.Scripting-008): both go through <see cref="Build"/>.
|
||||
/// <c>CSharpScript</c> path or the collectible-<c>AssemblyLoadContext</c> path:
|
||||
/// both go through <see cref="Build"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Namespaces pre-imported so scripts don't have to write <c>using</c> clauses:
|
||||
@@ -43,6 +43,7 @@ public static class ScriptSandbox
|
||||
/// to resolve <c>ctx.GetTag(...)</c> calls.
|
||||
/// </summary>
|
||||
/// <param name="contextType">The concrete script context type to use for compilation.</param>
|
||||
/// <returns>The sandbox configuration (assembly references + default imports) to compile the script against.</returns>
|
||||
public static SandboxConfig Build(Type contextType)
|
||||
{
|
||||
if (contextType is null) throw new ArgumentNullException(nameof(contextType));
|
||||
@@ -74,8 +75,8 @@ public static class ScriptSandbox
|
||||
// type by FQN — including the ones we forbid (HttpClient, File, Process,
|
||||
// Registry, etc.). Letting those types resolve at compile is intentional: the
|
||||
// hard security gate is ForbiddenTypeAnalyzer in step 3 of the compile pipeline
|
||||
// (Core.Scripting-001 / -002 established the analyzer must be the sole gate
|
||||
// because type forwarding makes any references-list-only restriction porous).
|
||||
// (the analyzer must be the sole gate because type forwarding makes any
|
||||
// references-list-only restriction porous).
|
||||
// The references list now serves only as scoping hygiene — out-of-band BCL
|
||||
// surface (operator-authored hosting helpers, third-party packages, app code)
|
||||
// is not on the list and stays unreachable.
|
||||
@@ -118,7 +119,7 @@ public static class ScriptSandbox
|
||||
string.Equals(name, "mscorlib.dll", StringComparison.Ordinal) ||
|
||||
// Microsoft.Win32.Registry isn't a System.* DLL but the analyzer's
|
||||
// Microsoft.Win32 deny-list relies on the type being resolvable so it
|
||||
// can identify + reject it (Core.Scripting-001 / -002). Add the one
|
||||
// can identify + reject it. Add the one
|
||||
// DLL we need rather than broadening to Microsoft.* (which would also
|
||||
// pull in compilers, build tooling, etc.).
|
||||
string.Equals(name, "Microsoft.Win32.Registry.dll", StringComparison.Ordinal))
|
||||
|
||||
@@ -90,7 +90,7 @@ public sealed class TimedScriptEvaluator<TContext, TResult>
|
||||
// When both fire at nearly the same time, WaitAsync observes them in
|
||||
// non-deterministic order, so a cancel that arrives a few µs after the
|
||||
// timeout still reaches here as TimeoutException. Re-check the token so
|
||||
// the guarantee holds regardless of race ordering. (Core.Scripting-007.)
|
||||
// the guarantee holds regardless of race ordering.
|
||||
if (ct.IsCancellationRequested)
|
||||
throw new OperationCanceledException(ct);
|
||||
throw new ScriptTimeoutException(Timeout);
|
||||
@@ -101,7 +101,7 @@ public sealed class TimedScriptEvaluator<TContext, TResult>
|
||||
/// <summary>
|
||||
/// Thrown when a script evaluation exceeds its configured timeout. The virtual-tag
|
||||
/// engine (Stream B) catches this + maps the owning tag's quality to
|
||||
/// <c>BadInternalError</c> per Phase 7 plan decision #11, logging a structured
|
||||
/// <c>BadInternalError</c> per the Phase 7 plan, logging a structured
|
||||
/// warning with the offending script name so operators can locate + fix it.
|
||||
/// </summary>
|
||||
public sealed class ScriptTimeoutException : Exception
|
||||
|
||||
Reference in New Issue
Block a user