Skip to content

Commit dbed24a

Browse files
Kenoclaude
andcommitted
Fix Sandbox.jl integration and type issues
- Fixed SandboxConfig constructor type from Dict{String,Any} to Dict{String,Sandbox.MountInfo} - Added proper mounts for Julia depot and workspace directories - Mounted /tmp as read-write for socket creation in sandbox mode - Fixed Sandbox.jl UUID to correct value (9307e30f-c43e-9ca7-d17c-c2dc59df670d) - Note: Socket passing through fd not yet fully implemented, requires Sandbox.jl modifications 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 71edb67 commit dbed24a

File tree

2 files changed

+146
-77
lines changed

2 files changed

+146
-77
lines changed

Manifest.toml

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,22 @@
22

33
julia_version = "1.13.0-DEV"
44
manifest_format = "2.0"
5-
project_hash = "4b3c2014fa9be900c59f5ea3b2106ed48a689c6d"
5+
project_hash = "39c83b73b84b4ed04a3cf369d85506b2a1714fbf"
6+
7+
[[deps.ArgTools]]
8+
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
9+
version = "1.1.2"
610

711
[[deps.Artifacts]]
812
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
913
version = "1.11.0"
1014

15+
[[deps.Attr_jll]]
16+
deps = ["Artifacts", "JLLWrappers", "Libdl"]
17+
git-tree-sha1 = "b8747cda97b6cedbd8dc9fc6218e1d53ce8de32f"
18+
uuid = "1fd713ca-387f-5abc-8002-d8b8b1623b73"
19+
version = "2.5.3+0"
20+
1121
[[deps.Base64]]
1222
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
1323
version = "1.11.0"
@@ -30,11 +40,31 @@ deps = ["Printf"]
3040
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
3141
version = "1.11.0"
3242

43+
[[deps.Downloads]]
44+
deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"]
45+
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
46+
version = "1.7.0"
47+
48+
[[deps.EnumX]]
49+
git-tree-sha1 = "bddad79635af6aec424f53ed8aad5d7555dc6f00"
50+
uuid = "4e289a0a-7415-4d19-859d-a7e5c4648b56"
51+
version = "1.0.5"
52+
53+
[[deps.FileWatching]]
54+
uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"
55+
version = "1.11.0"
56+
3357
[[deps.InteractiveUtils]]
3458
deps = ["Markdown"]
3559
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
3660
version = "1.11.0"
3761

62+
[[deps.JLLWrappers]]
63+
deps = ["Artifacts", "Preferences"]
64+
git-tree-sha1 = "0533e564aae234aff59ab625543145446d8b6ec2"
65+
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
66+
version = "1.7.1"
67+
3868
[[deps.JSON]]
3969
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
4070
git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a"
@@ -47,7 +77,7 @@ uuid = "ac6e5ff7-fb65-4e79-a425-ec3bc9c03011"
4777
version = "1.12.0"
4878

4979
[[deps.LLMBenchMCPServer]]
50-
deps = ["ClaudeMCPTools", "Dates", "JSON", "LLMBenchSimple", "Sockets", "Test"]
80+
deps = ["ClaudeMCPTools", "Dates", "JSON", "LLMBenchSimple", "Sandbox", "Sockets", "Test"]
5181
path = "."
5282
uuid = "78754875-2f68-464a-ac60-858ac662827f"
5383
version = "0.1.0"
@@ -60,6 +90,21 @@ repo-url = "git@github.com:JuliaComputing/LLMBenchSimple.jl.git"
6090
uuid = "a7b3c4d5-e6f7-8901-2345-678901234567"
6191
version = "0.1.0"
6292

93+
[[deps.LazyArtifacts]]
94+
deps = ["Artifacts", "Pkg"]
95+
uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3"
96+
version = "1.11.0"
97+
98+
[[deps.LibCURL]]
99+
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
100+
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"
101+
version = "0.6.4"
102+
103+
[[deps.LibCURL_jll]]
104+
deps = ["Artifacts", "CompilerSupportLibraries_jll", "LibSSH2_jll", "Libdl", "OpenSSL_jll", "Zlib_jll", "Zstd_jll", "nghttp2_jll"]
105+
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"
106+
version = "8.16.0+0"
107+
63108
[[deps.LibGit2]]
64109
deps = ["LibGit2_jll", "NetworkOptions", "Printf", "SHA"]
65110
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"
@@ -79,6 +124,12 @@ version = "1.11.3+1"
79124
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
80125
version = "1.11.0"
81126

127+
[[deps.Libiconv_jll]]
128+
deps = ["Artifacts", "JLLWrappers", "Libdl"]
129+
git-tree-sha1 = "be484f5c92fad0bd8acfef35fe017900b0b73809"
130+
uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531"
131+
version = "1.18.0+0"
132+
82133
[[deps.Logging]]
83134
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
84135
version = "1.11.0"
@@ -92,6 +143,10 @@ version = "1.11.0"
92143
uuid = "a63ad114-7e13-5084-954f-fe012c677804"
93144
version = "1.11.0"
94145

146+
[[deps.MozillaCACerts_jll]]
147+
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
148+
version = "2025.9.9"
149+
95150
[[deps.NetworkOptions]]
96151
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
97152
version = "1.3.0"
@@ -112,6 +167,17 @@ git-tree-sha1 = "7d2f8f21da5db6a806faf7b9b292296da42b2810"
112167
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
113168
version = "2.8.3"
114169

170+
[[deps.Pkg]]
171+
deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "Random", "SHA", "TOML", "Tar", "UUIDs", "p7zip_jll"]
172+
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
173+
version = "1.13.0"
174+
175+
[deps.Pkg.extensions]
176+
REPLExt = "REPL"
177+
178+
[deps.Pkg.weakdeps]
179+
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
180+
115181
[[deps.PrecompileTools]]
116182
deps = ["Preferences"]
117183
git-tree-sha1 = "07a921781cab75691315adc645096ed5e370cb77"
@@ -138,6 +204,18 @@ version = "1.11.0"
138204
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
139205
version = "0.7.0"
140206

207+
[[deps.Sandbox]]
208+
deps = ["EnumX", "LazyArtifacts", "Libdl", "Preferences", "Random", "SHA", "Scratch", "TOML", "Tar", "Tar_jll", "UserNSSandbox_jll"]
209+
git-tree-sha1 = "560311be5e024eb0777f3dc9beed3c6a08b2a2a7"
210+
uuid = "9307e30f-c43e-9ca7-d17c-c2dc59df670d"
211+
version = "2.1.1"
212+
213+
[[deps.Scratch]]
214+
deps = ["Dates"]
215+
git-tree-sha1 = "9b81b8393e50b7d4e6d0a9f14e192294d3b7c109"
216+
uuid = "6c6a2e73-6563-6170-7368-637461726353"
217+
version = "1.3.0"
218+
141219
[[deps.Serialization]]
142220
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
143221
version = "1.11.0"
@@ -155,6 +233,17 @@ deps = ["Dates"]
155233
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
156234
version = "1.0.3"
157235

236+
[[deps.Tar]]
237+
deps = ["ArgTools", "SHA"]
238+
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
239+
version = "1.10.0"
240+
241+
[[deps.Tar_jll]]
242+
deps = ["Artifacts", "Attr_jll", "JLLWrappers", "Libdl", "Libiconv_jll"]
243+
git-tree-sha1 = "85e7d0ef5248971fbd824f29c52ab6168b895dfd"
244+
uuid = "9b64493d-8859-5bf3-93d7-7c32dd38186f"
245+
version = "1.35.0+0"
246+
158247
[[deps.Test]]
159248
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
160249
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
@@ -169,7 +258,28 @@ version = "1.11.0"
169258
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
170259
version = "1.11.0"
171260

261+
[[deps.UserNSSandbox_jll]]
262+
deps = ["Artifacts", "JLLWrappers", "Libdl"]
263+
git-tree-sha1 = "79dc57555c873394aa67457f9c6022068da7b04a"
264+
uuid = "b88861f7-1d72-59dd-91e7-a8cc876a4984"
265+
version = "2025.1.28+0"
266+
172267
[[deps.Zlib_jll]]
173268
deps = ["Libdl"]
174269
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"
175270
version = "1.3.1+2"
271+
272+
[[deps.Zstd_jll]]
273+
deps = ["CompilerSupportLibraries_jll", "Libdl"]
274+
uuid = "3161d3a3-bdf6-5164-811a-617609db77b4"
275+
version = "1.5.7+1"
276+
277+
[[deps.nghttp2_jll]]
278+
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
279+
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"
280+
version = "1.67.1+0"
281+
282+
[[deps.p7zip_jll]]
283+
deps = ["Artifacts", "Libdl"]
284+
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
285+
version = "17.6.0+0"

src/server.jl

Lines changed: 34 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ function launch_in_sandbox(args::Vector{String}, use_socket::Bool, socket_path::
296296

297297
# Create minimal mounts for the sandbox
298298
# We'll use a minimal Debian rootfs and mount the Julia installation
299-
mounts = Dict{String, Any}(
299+
mounts = Dict{String, Sandbox.MountInfo}(
300300
"/" => Sandbox.MountInfo(Sandbox.debian_rootfs(; platform=host_platform), Sandbox.MountType.Overlayed),
301301
"/workspace" => Sandbox.MountInfo(pwd(), Sandbox.MountType.ReadWrite),
302302
)
@@ -311,6 +311,18 @@ function launch_in_sandbox(args::Vector{String}, use_socket::Bool, socket_path::
311311
# Mount the current project directory (where LLMBenchMCPServer is)
312312
project_dir = dirname(dirname(@__FILE__))
313313
mounts["/opt/llmbench"] = Sandbox.MountInfo(project_dir, Sandbox.MountType.ReadOnly)
314+
315+
# Mount Julia packages/artifacts/compiled directories
316+
julia_depot = get(ENV, "JULIA_DEPOT_PATH", joinpath(homedir(), ".julia"))
317+
if isdir(julia_depot)
318+
mounts["/root/.julia"] = Sandbox.MountInfo(julia_depot, Sandbox.MountType.ReadOnly)
319+
end
320+
321+
# Also mount the workspace root for ClaudeMCPTools and other local packages
322+
workspace_root = dirname(project_dir) # Get /workspace from /workspace/LLMBenchMCPServer
323+
if isdir(workspace_root)
324+
mounts["/opt/workspace"] = Sandbox.MountInfo(workspace_root, Sandbox.MountType.ReadOnly)
325+
end
314326

315327
# Set up environment variables
316328
env = Dict{String, String}(
@@ -325,93 +337,40 @@ function launch_in_sandbox(args::Vector{String}, use_socket::Bool, socket_path::
325337
new_args = copy(args)
326338
push!(new_args, "--direct")
327339

328-
# Handle socket mode differently
329-
server_socket = nothing
340+
# For socket mode in sandbox, we'll mount /tmp as writable
341+
# so the sandboxed process can create its own socket
330342
if use_socket
331-
# Create the socket in the parent process
332-
if isempty(socket_path)
333-
# Generate a unique socket path in /tmp
334-
timestamp = Dates.format(Dates.now(), "yyyymmdd_HHMMSS")
335-
pid = getpid()
336-
socket_path = "/tmp/mcp_$(args[1])_$(timestamp)_$(pid).sock"
337-
end
338-
339-
# Clean up existing socket if it exists
340-
if isfile(socket_path)
341-
rm(socket_path)
342-
end
343-
344-
# Create the Unix socket server
345-
server_socket = Sockets.listen(socket_path)
343+
# Mount /tmp as read-write for socket creation
344+
mounts["/tmp"] = Sandbox.MountInfo("/tmp", Sandbox.MountType.ReadWrite)
346345

347346
if verbose
348-
println("Created socket: $socket_path")
349-
println("Socket will be passed to sandbox as fd 3")
347+
println("Socket mode enabled - /tmp mounted for socket creation")
350348
end
351-
352-
# Add --fd3 flag to tell child to use fd 3
353-
push!(new_args, "--fd3")
354-
355-
# Remove any --socket or --bind-socket flags as they're handled by parent
356-
new_args = filter(arg -> !(arg in ["--socket", "--bind-socket"] || startswith(arg, "/tmp/mcp_")), new_args)
357349
end
358350

359351
# Build the Julia command
360352
cmd = Cmd(["/opt/julia/bin/julia", "--project=/opt/llmbench", "-m", "LLMBenchMCPServer"])
361353
cmd = `$cmd $new_args`
362354

363355
# Create the sandbox configuration
364-
if server_socket !== nothing
365-
# Pass the socket as fd 3 (after stdin, stdout, stderr)
366-
config = Sandbox.SandboxConfig(
367-
mounts,
368-
env;
369-
stdin=Base.stdin,
370-
stdout=Base.stdout,
371-
stderr=Base.stderr,
372-
pwd="/workspace"
373-
)
374-
375-
# Run in the sandbox with the socket passed as an extra fd
376-
exit_code = Cint(0)
377-
try
378-
Sandbox.with_executor() do exe
379-
# Pass server_socket as the 4th argument (fd 3)
380-
run(exe, config, cmd, Base.stdin, Base.stdout, Base.stderr, server_socket)
381-
end
382-
catch e
383-
println(stderr, "Error running in sandbox: $e")
384-
exit_code = Cint(1)
385-
finally
386-
# Clean up socket
387-
close(server_socket)
388-
if isfile(socket_path)
389-
rm(socket_path)
390-
if verbose
391-
println("Cleaned up socket: $socket_path")
392-
end
393-
end
394-
end
395-
else
396-
# No socket, run normally
397-
config = Sandbox.SandboxConfig(
398-
mounts,
399-
env;
400-
stdin=Base.stdin,
401-
stdout=Base.stdout,
402-
stderr=Base.stderr,
403-
pwd="/workspace"
404-
)
356+
config = Sandbox.SandboxConfig(
357+
mounts,
358+
env;
359+
stdin=Base.stdin,
360+
stdout=Base.stdout,
361+
stderr=Base.stderr,
362+
pwd="/workspace"
363+
)
405364

406-
exit_code = Cint(0)
407-
try
408-
Sandbox.with_executor() do exe
409-
run(exe, config, cmd)
410-
end
411-
catch e
412-
println(stderr, "Error running in sandbox: $e")
413-
exit_code = Cint(1)
365+
# Run in the sandbox
366+
exit_code = Cint(0)
367+
try
368+
Sandbox.with_executor() do exe
369+
run(exe, config, cmd)
414370
end
371+
catch e
372+
println(stderr, "Error running in sandbox: $e")
373+
exit_code = Cint(1)
415374
end
416375

417376
return exit_code

0 commit comments

Comments
 (0)