Merge wt/step-logs-t7: Task 7 Log on compile surface, sandboxes, editor hosts
This commit is contained in:
+68
@@ -574,6 +574,40 @@ public class ScriptAnalysisServiceTests
|
||||
Assert.Contains("hello-sandbox", result.ConsoleOutput);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RunInSandbox_LogGlobal_WritesToConsoleOutput()
|
||||
{
|
||||
// Flow Debugger step logs (design 2026-09-09 D4): the sandbox `Log` mirror exists so
|
||||
// a script that logs BINDS in the Test Run editor, and its lines land in the console
|
||||
// pane (the sandbox has no audit trail — nothing here is written to AuditLog).
|
||||
var result = await _svc.RunInSandboxAsync(
|
||||
new SandboxRunRequest(
|
||||
"Log.Info(\"hello\"); return 1;",
|
||||
Parameters: null,
|
||||
TimeoutSeconds: null),
|
||||
CancellationToken.None);
|
||||
|
||||
Assert.True(result.Success, result.Error);
|
||||
Assert.Contains("[info] hello", result.ConsoleOutput);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RunInSandbox_InboundScript_LogGlobal_WritesToConsoleOutput()
|
||||
{
|
||||
// Same mirror on the inbound Test Run host (SandboxInboundScriptHost) — an API
|
||||
// method script's Log.* calls must bind and surface in the console pane too.
|
||||
var result = await _svc.RunInSandboxAsync(
|
||||
new SandboxRunRequest(
|
||||
"Log.Info(\"hello\"); return 1;",
|
||||
Parameters: null,
|
||||
TimeoutSeconds: null,
|
||||
Kind: ScriptKind.InboundApi),
|
||||
CancellationToken.None);
|
||||
|
||||
Assert.True(result.Success, result.Error);
|
||||
Assert.Contains("[info] hello", result.ConsoleOutput);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RunInSandbox_ConcurrentRuns_DoNotCrossContaminateConsoleOutput()
|
||||
{
|
||||
@@ -661,6 +695,40 @@ public class ScriptAnalysisServiceTests
|
||||
Assert.DoesNotContain(resp.Markers, m => m.Code.StartsWith("SCADA"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InboundScript_Log_DiagnosesClean()
|
||||
{
|
||||
// Flow Debugger step logs (design 2026-09-09 D4): `Log` is a shipped inbound-script
|
||||
// global (InboundScriptContext.Log). The EDITOR host is a third mirror alongside the
|
||||
// compile surface and the Test Run sandbox — without `Log` on InboundScriptHost a
|
||||
// logging method script shows a spurious CS0103 while deploying and running fine.
|
||||
var resp = _svc.Diagnose(new DiagnoseRequest(
|
||||
Code: "Log.Info(\"x\");\n"
|
||||
+ "Log.Debug(\"d\");\n"
|
||||
+ "Log.Warn(\"w\", new System.Exception(\"boom\"));\n"
|
||||
+ "Log.Error(\"e\");",
|
||||
Kind: ScriptKind.InboundApi));
|
||||
|
||||
Assert.DoesNotContain(resp.Markers, m => m.Code.StartsWith("CS"));
|
||||
Assert.DoesNotContain(resp.Markers, m => m.Code.StartsWith("SCADA"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SiteScript_Log_DiagnosesClean()
|
||||
{
|
||||
// The other half of GlobalsTypeFor: every non-inbound kind analyses against
|
||||
// SandboxScriptHost, so the same `Log` global must resolve there too — both at
|
||||
// the top level and via `Instance.Log`.
|
||||
var resp = _svc.Diagnose(new DiagnoseRequest(
|
||||
Code: "Log.Info(\"x\");\n"
|
||||
+ "Log.Warn(\"w\", new System.Exception(\"boom\"));\n"
|
||||
+ "Instance.Log.Info(\"via instance\");",
|
||||
Kind: ScriptKind.Template));
|
||||
|
||||
Assert.DoesNotContain(resp.Markers, m => m.Code.StartsWith("CS"));
|
||||
Assert.DoesNotContain(resp.Markers, m => m.Code.StartsWith("SCADA"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InboundScript_Database_DiagnosesClean()
|
||||
{
|
||||
|
||||
@@ -139,6 +139,25 @@ public class RoslynScriptCompilerTests
|
||||
Assert.Empty(diagnostics);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompilesCleanly_ForTheLogGlobal()
|
||||
{
|
||||
// Flow Debugger step logs (design 2026-09-09 D4): `Log` is a script-reachable
|
||||
// global on the runtime ScriptGlobals AND on ScriptRuntimeContext, so both the
|
||||
// top-level `Log` and `Instance.Log` must bind at design time — otherwise a
|
||||
// script that logs would pass the editor but fail the deploy gate.
|
||||
const string code = """
|
||||
Log.Info("a");
|
||||
Log.Warn("b", new System.Exception("x"));
|
||||
Log.Error("c");
|
||||
Log.Debug("d");
|
||||
Instance.Log.Info("e");
|
||||
""";
|
||||
|
||||
var diagnostics = RoslynScriptCompiler.Compile(code, typeof(ScriptCompileSurface));
|
||||
Assert.Empty(diagnostics);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Compile_TwiceWithSharedResolver_StillCompilesCleanly()
|
||||
{
|
||||
|
||||
@@ -212,6 +212,24 @@ public class ScriptTrustValidatorTests
|
||||
Assert.Empty(ScriptTrustValidator.FindViolations(code));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Allows_TheLogGlobal()
|
||||
{
|
||||
// Flow Debugger step logs (design 2026-09-09 D4). The trust model is a DENY-list
|
||||
// over API roots, not an allow-list of context members, so the `Log` global needs
|
||||
// no policy entry — including the overload that attaches a System.Exception, which
|
||||
// is a permitted BCL type. This pins that a logging script is not blocked.
|
||||
const string code = """
|
||||
Log.Info("x");
|
||||
Log.Debug("d");
|
||||
Log.Warn("w", new System.Exception("boom"));
|
||||
Log.Error("e");
|
||||
Instance.Log.Info("via instance");
|
||||
""";
|
||||
|
||||
Assert.Empty(ScriptTrustValidator.FindViolations(code));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ForbiddenScopes_DoNotCover_TheCommonsScriptSurface()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user