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:
Renzo F
2026-07-08 03:26:12 +02:00
committed by GitHub
co-authored by Renn F
parent 2a9d9e25d9
commit 0bf0cd69b3
36 changed files with 865 additions and 55 deletions
+37 -2
View File
@@ -5,9 +5,10 @@ i_am_done, blocking a red submit before it reaches QA. Full tests stay on CI.
from __future__ import annotations
import asyncio
import os
from types import SimpleNamespace
from typing import TYPE_CHECKING
from unittest.mock import AsyncMock, MagicMock
from typing import TYPE_CHECKING, Any
from unittest.mock import AsyncMock, MagicMock, patch
if TYPE_CHECKING:
import pathlib
@@ -128,6 +129,40 @@ async def test_run_one_reaps_killed_timeout_process(
fake_proc.wait.assert_awaited_once()
@pytest.mark.asyncio
async def test_run_one_kills_child_on_outer_cancellation(
tmp_path: pathlib.Path,
) -> None:
"""An outer cancellation (e.g. FlowVerbTimeoutMiddleware's own
asyncio.timeout firing around the whole i_am_done submit) throws
CancelledError into the wait_for, bypassing the TimeoutError handler
above. Without a dedicated handler the child is orphaned and keeps
running past the cancelled request; _run_one must kill + reap it and
re-raise.
"""
real_create_subprocess_shell = asyncio.create_subprocess_shell
spawned: dict[str, asyncio.subprocess.Process] = {}
async def _capturing_create(*args: Any, **kwargs: Any) -> Any:
proc = await real_create_subprocess_shell(*args, **kwargs)
spawned["proc"] = proc
return proc
with patch.object(asyncio, "create_subprocess_shell", _capturing_create):
task = asyncio.ensure_future(quality_gate._run_one(tmp_path, "sleep 30"))
while "proc" not in spawned:
await asyncio.sleep(0.01)
await asyncio.sleep(0.1) # let the shell actually exec sleep
task.cancel()
with pytest.raises(asyncio.CancelledError):
await task
proc = spawned["proc"]
assert proc.returncode is not None, "child was not reaped after cancellation"
with pytest.raises(ProcessLookupError):
os.kill(proc.pid, 0)
# --- GitService command selection -------------------------------------------