FE-1220: Harden and document Petrinaut optimization execution isolation#9058
Conversation
Petrinaut Optimizer (apps/petrinaut-opt): - Apply resource.prlimit bounds (Linux) to every spawned CLI process: RLIMIT_CPU, RLIMIT_AS, and RLIMIT_NPROC, each configurable via HASH_PETRINAUT_OPT_CLI_* environment variables with zero disabling. - Sweep the CLI's process group with SIGKILL at the end of every close path, so descendants that remain in the group cannot outlive the study even when the CLI itself exits gracefully on stdin EOF. - Enforce a per-study wall-clock ceiling (HASH_PETRINAUT_OPT_MAX_STUDY_SECONDS, default 900 s) in both stream loops, emitting a terminal error frame and closing the CLI promptly; a study whose terminal sentinel is already queued when the deadline lapses is still reported as completed. - Run tini as PID 1 in the Docker image so orphaned descendants are reaped instead of accumulating as zombies. Documentation: - New apps/petrinaut-opt/docs/threat-model.md: execution-path threat model, per-layer mitigations, known limitations (per-UID RLIMIT_NPROC accounting, setsid escape from the group sweep, prlimit timing, pgid recycling), required out-of-repo deployment configuration (read-only rootfs, task memory sized against RLIMIT_AS, deny-all egress, pidsLimit), and the decision that no additional V8 sandbox is needed. - README documents the new environment variables; the CLI's OPTIMIZATION_INTEGRATION.md documents the cancellation and shutdown contract. Tests cover the grandchild sweep (real subprocess, mutation-verified), prompt-vs-graceful shutdown ordering, rlimit application and parsing, ceiling-based termination, and the completed-at-the-boundary case. Real subprocess tests pin the limits off so per-UID NPROC accounting on busy hosts cannot fail them.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Runtime hardening ( Documentation: new Tests cover group sweep, rlimit application/parsing, study ceiling vs. boundary completion, and disabling limits in real-subprocess tests. Reviewed by Cursor Bugbot for commit 47f2fea. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 47f2fea. Configure here.
| f"{json.dumps({'state': 'ERROR', 'message': message})}" | ||
| f"\n\n" | ||
| ) | ||
| break |
There was a problem hiding this comment.
Pending sentinel misclassified as timeout
Medium Severity
When the study wall-clock deadline is reached, timeout handling treats an empty events queue as proof the study is still running. The worker always enqueues the completion sentinel via call_soon_threadsafe, so a study that just finished can look idle until that callback runs, triggering a false execution-limit error instead of the normal done path.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 47f2fea. Configure here.


Closes FE-1220 (part of FE-1217).
Stacked on #9057 — the base is
cf/fe-1218-petrinaut-optimization-streaming-cancellation; only the last commit is new here.What
Process/resource hardening (
apps/petrinaut-opt)close()path now ends with aSIGKILLsweep of the CLI's process group. Previously the graceful (EOF) path never signalled the group at all, and the escalation path stopped once the group leader exited — descendants could survive, reparent to uvicorn as PID 1, and accumulate as zombies.tininow runs as PID 1 to reap orphans.resource.prlimit(Linux):RLIMIT_CPU(default 900 s),RLIMIT_AS(default 2 GiB — the actual resident-memory bound;--max-old-space-sizecaps only the V8 heap),RLIMIT_NPROC(default 256). All configurable throughHASH_PETRINAUT_OPT_CLI_*env vars,0disables. Applied from the parent, so no fork-unsafepreexec_fn.HASH_PETRINAUT_OPT_MAX_STUDY_SECONDS, default 900 s): a study can no longer hold one of the 4 admission slots fortrials × 240 s. On expiry the stream emits a terminal error frame and the CLI is terminated promptly; a study whose completion sentinel is already queued when the deadline lapses is still reported as completed, not timed out.Threat model and documentation
apps/petrinaut-opt/docs/threat-model.md: execution path, attacker model, per-layer mitigations (verified against the code), known limitations (per-real-UIDRLIMIT_NPROCaccounting,setsid()escape from the group sweep, prlimit timing window, pgid recycling), required out-of-repo deployment configuration (read-only rootfs, task memory sized againstRLIMIT_AS, deny-all egress security group,pidsLimit), and the documented decision that no additional V8 sandbox is required — the hot code surfaces already go through the restricted HIR compiler and FE-1219 removes the remaining raw scenario-expression execution.OPTIMIZATION_INTEGRATION.mdnow documents the cancellation/shutdown contract (signal-first for busy CLIs, group signalling, escalation).Tests
RLIMIT_NPROCaccounting on busy hosts cannot fail them.apps/petrinaut-opt: 55 pytest tests pass.Production infrastructure follow-ups
ECS task definitions live outside this repository; the required settings are enumerated in the threat model's Required deployment configuration section (read-only rootfs + tmpfs, memory sizing, egress policy, pidsLimit).
🤖 Generated with Claude Code