Fremde Laufzeiten: Claude Code und Befehl in der Sandbox, Egress-Proxy, Vorschlag statt Einsatz (#712)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
7d6c2c9495
commit
367ea387f6
@@ -145,6 +145,48 @@ public sealed class McpSocketTests : IDisposable
|
||||
return port;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// #712: The whole way back from a foreign run — a program in the real sandbox starts the
|
||||
/// MCP bridge, which reaches this instance's MCP server through the mounted socket with
|
||||
/// the run's token. Linux with a sandbox and the built application only.
|
||||
/// </summary>
|
||||
[ForeignRunFact]
|
||||
public async Task A_program_in_the_sandbox_reaches_the_mcp_server_as_its_agent()
|
||||
{
|
||||
await using var host = NewHost();
|
||||
await using var web = InstanceHttpHost.TryStart(host, NullLoggerFactory.Instance);
|
||||
web.ShouldNotBeNull();
|
||||
|
||||
var sandbox = (Core.Sandbox.BwrapSandbox)Core.Sandbox.BwrapSandbox.Detect(NullLogger.Instance);
|
||||
var helper = Core.Sandbox.SandboxHelper.For(ForeignRunFactAttribute.HelperPath!);
|
||||
sandbox.Helper = helper;
|
||||
var runner = new Core.Runtimes.ForeignRunner(sandbox, [new Core.Runtimes.CommandRuntime()], host.Mcp,
|
||||
InstanceEndpoint.McpSocketPath(host.InstancePath), helper, NullLogger.Instance);
|
||||
|
||||
var agentDir = Path.Combine(host.InstancePath, "Agents", "Agent-coder");
|
||||
Directory.CreateDirectory(Path.Combine(agentDir, "Workspace"));
|
||||
const string script = """
|
||||
printf '%s\n' \
|
||||
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}' \
|
||||
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
|
||||
'{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"Echo","arguments":{}}}' \
|
||||
| "$CLAWD_HELPER" --mcp-bridge --socket "$CLAWD_MCP_SOCKET"
|
||||
echo done > /work/result.txt
|
||||
""";
|
||||
var agent = new AgentConfig
|
||||
{
|
||||
AgentId = "coder", AgentDir = agentDir, WorkspacePath = Path.Combine(agentDir, "Workspace"),
|
||||
Runtime = new Core.Runtimes.AgentRuntimeConfig { Kind = "command", Command = "/bin/sh", Arguments = ["-c", script], TimeoutMinutes = 2 }
|
||||
};
|
||||
|
||||
var outcome = await runner.RunAsync(new Core.Runtimes.ForeignRunRequest(agent, "run-e2e", null, "brief", "go"), _ => { }, CancellationToken.None);
|
||||
|
||||
outcome.Status.ShouldBe(AgentRunStatus.Completed, outcome.Text);
|
||||
outcome.Text!.ShouldContain("\"name\":\"Echo\"");
|
||||
outcome.Text.ShouldContain("echo");
|
||||
outcome.Text.ShouldContain("added: result.txt");
|
||||
}
|
||||
|
||||
private sealed class EchoTool : IAgentTool
|
||||
{
|
||||
public string Name => "Echo";
|
||||
@@ -168,3 +210,20 @@ public sealed class McpSocketTests : IDisposable
|
||||
public Task DeleteAsync(string key, CancellationToken ct) { _values.TryRemove(key, out _); return Task.CompletedTask; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>#712: Linux with a sandbox, and CLAWD_TEST_HELPER naming the built ClawdDotNet.</summary>
|
||||
public sealed class ForeignRunFactAttribute : FactAttribute
|
||||
{
|
||||
public static string? HelperPath =>
|
||||
Environment.GetEnvironmentVariable("CLAWD_TEST_HELPER") is { Length: > 0 } path && File.Exists(path) ? path : null;
|
||||
|
||||
public ForeignRunFactAttribute()
|
||||
{
|
||||
if (!OperatingSystem.IsLinux())
|
||||
Skip = "Linux only.";
|
||||
else if (HelperPath is null)
|
||||
Skip = "Set CLAWD_TEST_HELPER to the built ClawdDotNet executable.";
|
||||
else if (Core.Sandbox.BwrapSandbox.Detect(NullLogger.Instance).UnavailableReason is { } reason)
|
||||
Skip = "No sandbox here: " + reason;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user