mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
fix(release): close the 0.19.0 scan findings — sandbox mongo tag, flow-verb timeout walls, video hardening (#329)
- mongo:8-alpine → mongo:8 (tag never existed; a mongo-opted project could spawn no agents) + a Docker Hub tag-existence e2e guard for every sandbox engine - flow-verb timeouts at both walls: shared SLOW_VERBS policy (i_am_done / submit_up / submit_root / open_pr / i_will_work_on get the 900s server budget); the MCP client now outlasts the server budget (+10s headroom, orchestrator-injected env) so agents receive the middleware's clean 504 envelope instead of dying at the old flat 30s client timeout - cancellation safety: the quality gate kills+reaps its child on CancelledError; create_pr records the PR via a shield-with-wait-out helper so the write can neither be skipped nor race get_db's rollback - video engine: renderer sidecar isolated on a render-only network, 2g/2cpu caps, 570s render watchdog with exit-on-hang, 512MB tar decompression cap, CEO notification on terminal render failure, reject under the approve mutex (fail-closed on Redis-down) - dead python-jose dependency removed (drops ecdsa and its unfixable Minerva advisory PYSEC-2026-1325); panel --font-mono now a real monospace stack Co-authored-by: Renn F <rennf93@users.noreply.github.com>
This commit is contained in:
@@ -431,7 +431,15 @@ async def test_render_video_task_terminal_after_max_attempts(
|
||||
workspace = _fake_workspace()
|
||||
orch = _orch()
|
||||
p1, p2 = _render_patches(renderer, workspace)
|
||||
with p1, p2:
|
||||
notify_svc = AsyncMock()
|
||||
with (
|
||||
p1,
|
||||
p2,
|
||||
patch(
|
||||
"roboco.services.notification.NotificationService",
|
||||
return_value=notify_svc,
|
||||
),
|
||||
):
|
||||
await orch._render_video_task(db_session, task) # tips to terminal
|
||||
calls_at_terminal = len(renderer.calls)
|
||||
await orch._render_video_task(db_session, task) # now a no-op
|
||||
@@ -443,3 +451,47 @@ async def test_render_video_task_terminal_after_max_attempts(
|
||||
assert len(renderer.calls) == calls_at_terminal # not retried after terminal
|
||||
posts = await get_task_service(db_session).list_open_video_posts()
|
||||
assert posts == []
|
||||
# Exactly one CEO alert — the second (no-op) call must not re-notify.
|
||||
notify_svc.send_ack_notification.assert_awaited_once()
|
||||
notify_kwargs = notify_svc.send_ack_notification.await_args.kwargs
|
||||
assert notify_kwargs["to_agent"] == "ceo"
|
||||
assert task.title in notify_kwargs["body"]
|
||||
assert "render blew up" in notify_kwargs["body"]
|
||||
assert notify_kwargs["task_id"] == task.id
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_render_video_task_notify_failure_does_not_raise(
|
||||
db_session: AsyncSession, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""A broken notification path (e.g. the second DB connection is down)
|
||||
must not surface out of the render loop — best-effort, like the
|
||||
strategy-engine failure notifier."""
|
||||
await _seed(db_session)
|
||||
_enable(monkeypatch)
|
||||
task = await _make_completed_video_task(
|
||||
db_session, occasion="notify-fails", composition_id="Intro"
|
||||
)
|
||||
seeded = markers.get_video_draft(task) or {}
|
||||
markers.set_video_draft(
|
||||
task, {**seeded, "render_attempts": _MAX_VIDEO_RENDER_ATTEMPTS - 1}
|
||||
)
|
||||
await db_session.flush()
|
||||
|
||||
renderer = _FakeRenderer(fail=True)
|
||||
workspace = _fake_workspace()
|
||||
orch = _orch()
|
||||
p1, p2 = _render_patches(renderer, workspace)
|
||||
with (
|
||||
p1,
|
||||
p2,
|
||||
patch(
|
||||
"roboco.services.notification.NotificationService",
|
||||
side_effect=RuntimeError("notification DB unreachable"),
|
||||
),
|
||||
):
|
||||
await orch._render_video_task(db_session, task) # must not raise
|
||||
|
||||
draft = markers.get_video_draft(task)
|
||||
assert draft is not None
|
||||
assert draft["render_status"] == "failed"
|
||||
|
||||
Reference in New Issue
Block a user