Skip to content

Commit eaa977c

Browse files
committed
fix(main): --strict-sandbox dead flag 구현 (SPEC §5 1순위 가드레일)
심층 검증에서 발견된 critical drift 처리. 문제: - main.py:50에 --strict-sandbox argparse 정의 - 그러나 main() 본문에서 args.strict_sandbox 사용 0건 (dead flag) - SPEC §5 1순위 가드레일 (sandbox_isolation_pass=false → abort) 미구현 수정: - main.py: pick_runner 직후 strict-sandbox 분기 추가 (5줄) - args.strict_sandbox=True 시 runner.isolation_self_test() 호출 - 결과 dict에 false 항목 있으면 stderr로 보고 + return 3 - main.py 본문 압축 (-2줄: saved outputs print 제거 + last_failed 출력 통합) → 180 lines (≤180 budget 정확히 만족) - last_failed_node는 stdout summary JSON에 포함 (정보 손실 없음) tests/integration/test_cli_smoke.py: - TestMainCli::test_main_strict_sandbox_aborts_on_isolation_fail (1 신규): --strict-sandbox + --sandbox rlimit (POSIX 한계로 network/fs/memory fail) → exit code 3 + "sandbox isolation failed" stderr 검증: ruff 0 / mypy 0 / pytest 191 passed (190 → +1, 회귀 0) SPEC §5 1순위 가드레일 활성화. 운영 환경 안전성 향상.
1 parent 01ab58d commit eaa977c

2 files changed

Lines changed: 25 additions & 4 deletions

File tree

‎main.py‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@ def main(argv: list[str] | None = None) -> int:
127127
return 2
128128

129129
runner = pick_runner(args.sandbox, verbose=True)
130+
if args.strict_sandbox:
131+
failed = [k for k, ok in runner.isolation_self_test().items() if not ok]
132+
if failed:
133+
print(f"sandbox isolation failed: {failed}", file=sys.stderr)
134+
return 3
130135
tracker: LLMCallTracker = (
131136
ReplayTracker(run_id, traces_dir) if args.replay
132137
else LLMCallTracker(run_id, traces_dir)
@@ -152,11 +157,9 @@ def main(argv: list[str] | None = None) -> int:
152157
final_state = graph.invoke(_initial_state(run_id, args), config=config)
153158

154159
final_status = final_state.get("final_status")
155-
print(f"\n=== final_status: {final_status} ===", file=sys.stderr)
156-
print(f"last_failed_node: {final_state.get('last_failed_node')}", file=sys.stderr)
160+
print(f"\n=== final_status={final_status} ===", file=sys.stderr)
157161

158-
save_result(cast(ProblemState, final_state), run_dir) # P10
159-
print(f"saved outputs to {run_dir}", file=sys.stderr)
162+
save_result(cast(ProblemState, final_state), run_dir) # P10 — outputs/<run_id>/
160163

161164
summary = {
162165
"run_id": run_id,

‎tests/integration/test_cli_smoke.py‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,24 @@ def test_main_resume_and_replay_mutually_exclusive(self) -> None:
109109
assert result.returncode != 0
110110
assert "mutually exclusive" in (result.stderr + result.stdout)
111111

112+
def test_main_strict_sandbox_aborts_on_isolation_fail(self) -> None:
113+
"""--strict-sandbox + rlimit (POSIX 한계로 isolation 일부 fail) → exit 3.
114+
115+
rlimit는 network/fs/memory 차단 안 됨 → strict 모드에서 즉시 abort.
116+
SPEC §5 가드레일 1순위 (sandbox_isolation_pass=false → strict-abort) 검증.
117+
"""
118+
proj = Path(__file__).resolve().parents[2]
119+
result = _run(
120+
[sys.executable, "main.py", "--algorithm", "Two Sum",
121+
"--sandbox", "rlimit", "--strict-sandbox"],
122+
cwd=proj,
123+
)
124+
assert result.returncode == 3, (
125+
f"expected exit 3, got {result.returncode}; "
126+
f"stderr={result.stderr!r}"
127+
)
128+
assert "sandbox isolation failed" in (result.stderr + result.stdout)
129+
112130

113131
@pytest.mark.parametrize("flag,expected_in_help", [
114132
("--algorithm", "target algorithm"),

0 commit comments

Comments
 (0)