import http.server
import json
import os
from pathlib import Path
import subprocess
import sys
import threading
repo, scratch, home = map(Path, sys.argv[1:4])
invocations = json.loads(sys.argv[4])
state = {"requests": 0, "command": ""}
def shell_call(tools, namespace=None):
for tool in tools:
if tool["type"] == "namespace":
found = shell_call(tool["tools"], tool["name"])
if found:
return found
name = tool.get("name", "")
short = name.rsplit(".", 1)[-1]
if short in ("exec_command", "shell_command", "shell"):
key = "cmd" if short == "exec_command" else "command"
value = ["/bin/sh", "-c", state["command"]] if short == "shell" else state["command"]
return name, namespace, {key: value}
return None
class Handler(http.server.BaseHTTPRequestHandler):
def log_message(self, *_args):
pass
def do_POST(self):
request = json.loads(self.rfile.read(int(self.headers.get("Content-Length", "0"))))
state["requests"] += 1
if state["requests"] == 1:
name, namespace, arguments = shell_call(request["tools"])
item = {
"type": "function_call", "id": "fc_probe", "call_id": "call_probe",
"name": name, "arguments": json.dumps(arguments),
}
if namespace:
item["namespace"] = namespace
else:
item = {
"type": "message", "id": "msg_probe", "role": "assistant", "status": "completed",
"content": [{"type": "output_text", "text": "native probe complete", "annotations": []}],
}
events = [
{"type": "response.created", "response": {"id": "resp_probe"}},
{"type": "response.output_item.done", "output_index": 0, "item": item},
{"type": "response.completed", "response": {
"id": "resp_probe", "status": "completed", "output": [item],
"usage": {"input_tokens": 1, "output_tokens": 1, "total_tokens": 2},
}},
]
body = "".join("data: " + json.dumps(event) + "\n\n" for event in events).encode()
self.send_response(200)
self.send_header("Content-Type", "text/event-stream")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
server = http.server.ThreadingHTTPServer(("127.0.0.1", 0), Handler)
worker = threading.Thread(target=server.serve_forever, daemon=True)
worker.start()
provider = {
"name": "native-probe", "base_url": f"http://127.0.0.1:{server.server_port}/v1",
"wire_api": "responses", "requires_openai_auth": False,
"request_max_retries": 0, "stream_max_retries": 0,
}
env = dict(os.environ, CODEX_HOME=str(home), NO_PROXY="127.0.0.1,localhost")
env.pop("CODEX_API_KEY", None)
env.pop("OPENAI_API_KEY", None)
session = None
print(subprocess.check_output(["codex", "--version"], text=True).strip(), flush=True)
print("Remote tested HEAD: " + subprocess.check_output(
["git", "rev-parse", "HEAD"], text=True).strip(), flush=True)
try:
for invocation in invocations:
read_only = invocation["read_only"]
(home / "config.toml").write_text(
"sandbox_mode = '" + ("danger-full-access" if read_only else "read-only") + "'\n"
+ '[projects."' + str(repo) + '"]\ntrust_level = "trusted"\n'
)
blocked = repo / "probe-write.txt"
allowed = scratch / "probe-write.txt"
blocked.unlink(missing_ok=True)
allowed.unlink(missing_ok=True)
code = (
"from pathlib import Path\n"
+ f"Path({str(allowed)!r}).write_text('allowed')\n"
+ f"try:\n Path({str(blocked)!r}).write_text('repo')\n"
+ "except PermissionError:\n pass\n"
)
import shlex
state.update(requests=0, command="python3 -c " + shlex.quote(code))
argv = [session if arg == "SESSION" else arg for arg in invocation["argv"]]
settings = "model_providers.native-probe={" + ",".join(
key + "=" + json.dumps(value) for key, value in provider.items()
) + "}"
argv += ["-c", 'model_provider="native-probe"', "-c", settings]
result = subprocess.run(["codex", *argv], cwd=repo, env=env,
capture_output=True, text=True, timeout=60)
assert result.returncode == 0, result.stdout + result.stderr
assert state["requests"] >= 2, result.stdout + result.stderr
assert allowed.exists(), result.stdout + result.stderr
assert blocked.exists() == (not read_only), result.stdout + result.stderr
for line in result.stdout.splitlines():
event = json.loads(line)
if event.get("type") == "thread.started":
session = event["thread_id"]
assert session, result.stdout
print(f"Native read_only={read_only}: scratch writable, repository writable={blocked.exists()}", flush=True)
finally:
server.shutdown()