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:
Richard
2026-09-25 22:46:49 +02:00
co-authored by Claude Opus 5.5
parent 7d6c2c9495
commit 367ea387f6
40 changed files with 3428 additions and 29 deletions
@@ -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;
}
}