Skip to content

Commit 91063c1

Browse files
dcramercodex
andcommitted
Add sandbox browser smoke diagnostics script
Co-Authored-By: GPT-5 Codex <codex@openai.com>
1 parent 32b18f5 commit 91063c1

1 file changed

Lines changed: 146 additions & 0 deletions

File tree

scripts/browser_sandbox_smoke.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
from __future__ import annotations
2+
3+
import argparse
4+
import asyncio
5+
import json
6+
from urllib.parse import urlparse
7+
8+
from ash.browser import create_browser_manager
9+
from ash.config import load_config
10+
from ash.config.paths import get_config_path
11+
from ash.sandbox.executor import SandboxExecutor
12+
from ash.tools.base import build_sandbox_manager_config
13+
14+
15+
async def _run(url: str, user_id: str, provider: str, session_name: str) -> int:
16+
config = load_config(get_config_path())
17+
sandbox_manager_config = build_sandbox_manager_config(
18+
config.sandbox,
19+
config.workspace,
20+
)
21+
parsed = urlparse(url)
22+
if (
23+
parsed.scheme in {"http", "https"}
24+
and sandbox_manager_config.network_mode == "none"
25+
):
26+
print(
27+
"config_error",
28+
json.dumps(
29+
{
30+
"ok": False,
31+
"reason": (
32+
"sandbox.network_mode is 'none'; external browser navigation "
33+
"requires network_mode='bridge'"
34+
),
35+
"url": url,
36+
},
37+
ensure_ascii=True,
38+
),
39+
)
40+
return 2
41+
42+
print(
43+
"sandbox.config",
44+
json.dumps(
45+
{
46+
"image": sandbox_manager_config.image,
47+
"network_mode": sandbox_manager_config.network_mode,
48+
"runtime": sandbox_manager_config.runtime,
49+
},
50+
ensure_ascii=True,
51+
),
52+
)
53+
executor = SandboxExecutor(config=sandbox_manager_config)
54+
probe = await executor.execute(
55+
"curl -I -sS --max-time 8 https://example.com >/dev/null && echo ok || echo fail",
56+
timeout=15,
57+
reuse_container=True,
58+
)
59+
print(
60+
"sandbox.network_probe",
61+
json.dumps(
62+
{
63+
"exit_code": probe.exit_code,
64+
"success": probe.success,
65+
"stdout": probe.stdout.strip(),
66+
"stderr": probe.stderr.strip(),
67+
},
68+
ensure_ascii=True,
69+
),
70+
)
71+
72+
manager = create_browser_manager(
73+
config,
74+
sandbox_executor=executor,
75+
)
76+
77+
started = await manager.execute_action(
78+
action="session.start",
79+
effective_user_id=user_id,
80+
provider_name=provider,
81+
session_name=session_name,
82+
)
83+
print("session.start", json.dumps(started.to_dict(), ensure_ascii=True))
84+
if not started.ok or not started.session_id:
85+
return 1
86+
87+
session_id = started.session_id
88+
goto = await manager.execute_action(
89+
action="page.goto",
90+
effective_user_id=user_id,
91+
provider_name=provider,
92+
session_id=session_id,
93+
params={"url": url},
94+
)
95+
print("page.goto", json.dumps(goto.to_dict(), ensure_ascii=True))
96+
if not goto.ok:
97+
return 1
98+
99+
extract = await manager.execute_action(
100+
action="page.extract",
101+
effective_user_id=user_id,
102+
provider_name=provider,
103+
session_id=session_id,
104+
params={"mode": "title"},
105+
)
106+
print("page.extract", json.dumps(extract.to_dict(), ensure_ascii=True))
107+
108+
shot = await manager.execute_action(
109+
action="page.screenshot",
110+
effective_user_id=user_id,
111+
provider_name=provider,
112+
session_id=session_id,
113+
)
114+
print("page.screenshot", json.dumps(shot.to_dict(), ensure_ascii=True))
115+
116+
archived = await manager.execute_action(
117+
action="session.archive",
118+
effective_user_id=user_id,
119+
provider_name=provider,
120+
session_id=session_id,
121+
)
122+
print("session.archive", json.dumps(archived.to_dict(), ensure_ascii=True))
123+
return 0 if archived.ok else 1
124+
125+
126+
def main() -> int:
127+
parser = argparse.ArgumentParser(
128+
description="Run sandbox browser smoke via BrowserManager+SandboxExecutor."
129+
)
130+
parser.add_argument("--url", default="https://example.com")
131+
parser.add_argument("--user-id", default="local-test")
132+
parser.add_argument("--provider", default="sandbox")
133+
parser.add_argument("--session-name", default="local-smoke")
134+
args = parser.parse_args()
135+
return asyncio.run(
136+
_run(
137+
url=args.url,
138+
user_id=args.user_id,
139+
provider=args.provider,
140+
session_name=args.session_name,
141+
)
142+
)
143+
144+
145+
if __name__ == "__main__":
146+
raise SystemExit(main())

0 commit comments

Comments
 (0)