feat(scriptanalysis): M3.1 shared trust validator + compiler + compile surfaces + tests
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
using System.Data.Common;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Notification;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Types;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.Scripts;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.ScriptAnalysis;
|
||||
|
||||
/// <summary>
|
||||
/// M3.1: a <b>compile-only</b> globals type that mirrors the real SiteRuntime
|
||||
/// <c>ScriptGlobals</c> (+ <c>ScriptRuntimeContext</c> helper surface)
|
||||
/// member-for-member, so a real instance / shared / on-trigger-handler script
|
||||
/// BINDS against it at design time. It is NEVER executed — every member body
|
||||
/// throws <see cref="NotSupportedException"/> or returns <c>default</c>. The
|
||||
/// design-time deploy gate (M3.5) compiles candidate scripts against this type
|
||||
/// via <see cref="RoslynScriptCompiler.Compile(string, Type, System.Collections.Generic.IEnumerable{Microsoft.CodeAnalysis.MetadataReference}, System.Collections.Generic.IEnumerable{string})"/>
|
||||
/// to catch undefined symbols and signature mismatches without touching the
|
||||
/// site runtime.
|
||||
///
|
||||
/// <para>
|
||||
/// Keeping this surface faithful is enforced by the
|
||||
/// <c>RoslynScriptCompilerTests</c> "representative real script" corpus — if a
|
||||
/// member or signature drifts from the runtime <c>ScriptGlobals</c>, that test
|
||||
/// fails.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public sealed class ScriptCompileSurface
|
||||
{
|
||||
private const string CompileOnly = "compile-only surface";
|
||||
|
||||
/// <summary>Mirrors <c>ScriptGlobals.Instance</c>.</summary>
|
||||
public CompileInstance Instance { get; set; } = null!;
|
||||
|
||||
/// <summary>Mirrors <c>ScriptGlobals.Parameters</c>.</summary>
|
||||
public ScriptParameters Parameters { get; set; } = new();
|
||||
|
||||
/// <summary>Mirrors <c>ScriptGlobals.CancellationToken</c>.</summary>
|
||||
public CancellationToken CancellationToken { get; set; }
|
||||
|
||||
/// <summary>Mirrors <c>ScriptGlobals.Alarm</c>.</summary>
|
||||
public AlarmContext? Alarm { get; set; }
|
||||
|
||||
/// <summary>Mirrors <c>ScriptGlobals.Scope</c>.</summary>
|
||||
public ScriptScope Scope { get; set; } = ScriptScope.Root;
|
||||
|
||||
/// <summary>Mirrors <c>ScriptGlobals.ExternalSystem</c> (delegates to Instance).</summary>
|
||||
public CompileExternalSystem ExternalSystem => Instance.ExternalSystem;
|
||||
|
||||
/// <summary>Mirrors <c>ScriptGlobals.Database</c>.</summary>
|
||||
public CompileDatabase Database => Instance.Database;
|
||||
|
||||
/// <summary>Mirrors <c>ScriptGlobals.Notify</c>.</summary>
|
||||
public CompileNotify Notify => Instance.Notify;
|
||||
|
||||
/// <summary>Mirrors <c>ScriptGlobals.Scripts</c>.</summary>
|
||||
public CompileScripts Scripts => Instance.Scripts;
|
||||
|
||||
/// <summary>Mirrors <c>ScriptGlobals.Attributes</c>.</summary>
|
||||
public CompileAttributeAccessor Attributes => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>ScriptGlobals.Children</c>.</summary>
|
||||
public CompileChildrenAccessor Children => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>ScriptGlobals.Parent</c>.</summary>
|
||||
public CompileCompositionAccessor? Parent => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Compile-only mirror of <c>ScriptRuntimeContext</c> (the <c>Instance</c> global).</summary>
|
||||
public sealed class CompileInstance
|
||||
{
|
||||
/// <summary>Mirrors <c>ScriptRuntimeContext.GetAttribute</c>.</summary>
|
||||
public Task<object?> GetAttribute(string attributeName) => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>ScriptRuntimeContext.SetAttribute</c>.</summary>
|
||||
public Task SetAttribute(string attributeName, string value) => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>ScriptRuntimeContext.CallScript</c>.</summary>
|
||||
public Task<object?> CallScript(string scriptName, object? parameters = null) => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>ScriptRuntimeContext.ExternalSystem</c>.</summary>
|
||||
public CompileExternalSystem ExternalSystem => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>ScriptRuntimeContext.Database</c>.</summary>
|
||||
public CompileDatabase Database => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>ScriptRuntimeContext.Notify</c>.</summary>
|
||||
public CompileNotify Notify => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>ScriptRuntimeContext.Scripts</c>.</summary>
|
||||
public CompileScripts Scripts => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>ScriptRuntimeContext.Tracking</c>.</summary>
|
||||
public CompileTracking Tracking => throw new NotSupportedException(CompileOnly);
|
||||
}
|
||||
|
||||
/// <summary>Compile-only mirror of <c>ScriptRuntimeContext.ExternalSystemHelper</c>.</summary>
|
||||
public sealed class CompileExternalSystem
|
||||
{
|
||||
/// <summary>Mirrors <c>ExternalSystemHelper.Call</c>.</summary>
|
||||
public Task<ExternalCallResult> Call(
|
||||
string systemName,
|
||||
string methodName,
|
||||
IReadOnlyDictionary<string, object?>? parameters = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
=> throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>ExternalSystemHelper.CachedCall</c>.</summary>
|
||||
public Task<TrackedOperationId> CachedCall(
|
||||
string systemName,
|
||||
string methodName,
|
||||
IReadOnlyDictionary<string, object?>? parameters = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
=> throw new NotSupportedException(CompileOnly);
|
||||
}
|
||||
|
||||
/// <summary>Compile-only mirror of <c>ScriptRuntimeContext.DatabaseHelper</c>.</summary>
|
||||
public sealed class CompileDatabase
|
||||
{
|
||||
/// <summary>Mirrors <c>DatabaseHelper.Connection</c>.</summary>
|
||||
public Task<DbConnection> Connection(string name, CancellationToken cancellationToken = default)
|
||||
=> throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>DatabaseHelper.CachedWrite</c>.</summary>
|
||||
public Task<TrackedOperationId> CachedWrite(
|
||||
string name,
|
||||
string sql,
|
||||
IReadOnlyDictionary<string, object?>? parameters = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
=> throw new NotSupportedException(CompileOnly);
|
||||
}
|
||||
|
||||
/// <summary>Compile-only mirror of <c>ScriptRuntimeContext.NotifyHelper</c>.</summary>
|
||||
public sealed class CompileNotify
|
||||
{
|
||||
/// <summary>Mirrors <c>NotifyHelper.To</c>.</summary>
|
||||
public CompileNotifyTarget To(string listName) => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>NotifyHelper.Status</c>.</summary>
|
||||
public Task<NotificationDeliveryStatus> Status(string notificationId) => throw new NotSupportedException(CompileOnly);
|
||||
}
|
||||
|
||||
/// <summary>Compile-only mirror of <c>ScriptRuntimeContext.NotifyTarget</c>.</summary>
|
||||
public sealed class CompileNotifyTarget
|
||||
{
|
||||
/// <summary>Mirrors <c>NotifyTarget.Send</c>.</summary>
|
||||
public Task<string> Send(string subject, string message, CancellationToken cancellationToken = default)
|
||||
=> throw new NotSupportedException(CompileOnly);
|
||||
}
|
||||
|
||||
/// <summary>Compile-only mirror of <c>ScriptRuntimeContext.ScriptCallHelper</c>.</summary>
|
||||
public sealed class CompileScripts
|
||||
{
|
||||
/// <summary>Mirrors <c>ScriptCallHelper.CallShared</c>.</summary>
|
||||
public Task<object?> CallShared(
|
||||
string scriptName,
|
||||
object? parameters = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
=> throw new NotSupportedException(CompileOnly);
|
||||
}
|
||||
|
||||
/// <summary>Compile-only mirror of <c>ScriptRuntimeContext.TrackingHelper</c>.</summary>
|
||||
public sealed class CompileTracking
|
||||
{
|
||||
/// <summary>Mirrors <c>TrackingHelper.Status</c>.</summary>
|
||||
public Task<TrackingStatusSnapshot?> Status(
|
||||
TrackedOperationId trackedOperationId,
|
||||
CancellationToken cancellationToken = default)
|
||||
=> throw new NotSupportedException(CompileOnly);
|
||||
}
|
||||
|
||||
/// <summary>Compile-only mirror of <c>AttributeAccessor</c>.</summary>
|
||||
public sealed class CompileAttributeAccessor
|
||||
{
|
||||
/// <summary>Mirrors <c>AttributeAccessor.this[string]</c>.</summary>
|
||||
public object? this[string key]
|
||||
{
|
||||
get => throw new NotSupportedException(CompileOnly);
|
||||
set => throw new NotSupportedException(CompileOnly);
|
||||
}
|
||||
|
||||
/// <summary>Mirrors <c>AttributeAccessor.GetAsync</c>.</summary>
|
||||
public Task<object?> GetAsync(string key) => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>AttributeAccessor.SetAsync</c>.</summary>
|
||||
public Task SetAsync(string key, object? value) => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>AttributeAccessor.Resolve</c>.</summary>
|
||||
public string Resolve(string key) => throw new NotSupportedException(CompileOnly);
|
||||
}
|
||||
|
||||
/// <summary>Compile-only mirror of <c>ChildrenAccessor</c>.</summary>
|
||||
public sealed class CompileChildrenAccessor
|
||||
{
|
||||
/// <summary>Mirrors <c>ChildrenAccessor.this[string]</c>.</summary>
|
||||
public CompileCompositionAccessor this[string compositionName] => throw new NotSupportedException(CompileOnly);
|
||||
}
|
||||
|
||||
/// <summary>Compile-only mirror of <c>CompositionAccessor</c>.</summary>
|
||||
public sealed class CompileCompositionAccessor
|
||||
{
|
||||
/// <summary>Mirrors <c>CompositionAccessor.Attributes</c>.</summary>
|
||||
public CompileAttributeAccessor Attributes => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>CompositionAccessor.CallScript</c>.</summary>
|
||||
public Task<object?> CallScript(string scriptName, object? parameters = null) => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>CompositionAccessor.ResolveScript</c>.</summary>
|
||||
public string ResolveScript(string scriptName) => throw new NotSupportedException(CompileOnly);
|
||||
|
||||
/// <summary>Mirrors <c>CompositionAccessor.Path</c>.</summary>
|
||||
public string Path => throw new NotSupportedException(CompileOnly);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user