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
+117
View File
@@ -7,6 +7,7 @@ mock the network and filesystem boundaries.
from __future__ import annotations
import asyncio
from pathlib import Path
from typing import TYPE_CHECKING
from unittest.mock import AsyncMock, MagicMock, patch
@@ -512,6 +513,122 @@ async def test_create_pr_returns_pr_dict() -> None:
assert out["is_root_pr"] is True
@pytest.mark.asyncio
async def test_create_pr_records_pr_despite_cancellation_after_post() -> None:
"""A cancellation landing after the GitHub POST succeeds but before the
local record commits must not lose the record: asyncio.shield lets
_record_pr_atomically finish, the cancellation still propagates."""
project_id = uuid4()
fake_task = MagicMock(
id=uuid4(),
project_id=project_id,
assigned_to=uuid4(),
title="Add login",
description="A short description",
)
fake_project = MagicMock(slug="roboco")
svc = _service()
_bind(svc, "_task_for_branch", AsyncMock(return_value=fake_task))
_bind(svc, "_workspace_for_branch", AsyncMock(return_value=Path("/tmp/ws")))
_bind(svc, "_get_project_token_or_raise", AsyncMock(return_value="tok"))
_bind(svc, "_parse_github_remote", MagicMock(return_value=("acme", "repo")))
_bind(svc, "_project_default_branch", AsyncMock(return_value="master"))
recorded = {"done": False}
async def _slow_record(*_args: object, **_kwargs: object) -> None:
await asyncio.sleep(0.05)
recorded["done"] = True
_bind(svc, "_record_pr_atomically", _slow_record)
fake_resp = MagicMock()
fake_resp.is_success = True
fake_resp.status_code = 201
fake_resp.json.return_value = {
"number": _EXPECTED_PR_NUMBER,
"html_url": f"https://github.com/acme/repo/pull/{_EXPECTED_PR_NUMBER}",
}
_bind(svc, "_post_pr", AsyncMock(return_value=fake_resp))
with _patch_project_service(fake_project):
task = asyncio.ensure_future(
svc.create_pr("feature/backend/abc12345", parent="master", is_root_pr=True)
)
await asyncio.sleep(0.01) # let create_pr reach the shielded await
task.cancel()
with pytest.raises(asyncio.CancelledError):
await task
# _await_shielded waits the in-flight record out BEFORE re-raising, so
# by the time `await task` raised, the record had already completed.
assert recorded["done"] is True, (
"shield must let the record finish despite cancellation"
)
@pytest.mark.asyncio
async def test_create_pr_cancellation_waits_out_record_before_reraising() -> None:
"""Ordering guard for _await_shielded: on cancellation the in-flight
_record_pr_atomically must run to COMPLETION before CancelledError
re-raises to the caller. A bare asyncio.shield detaches the write and
re-raises immediately — the write then races get_db's rollback on the
same AsyncSession and asyncpg raises InterfaceError ('another operation
is in progress'), escaping as a 500 instead of the middleware's 504."""
project_id = uuid4()
fake_task = MagicMock(
id=uuid4(),
project_id=project_id,
assigned_to=uuid4(),
title="Add login",
description="A short description",
)
fake_project = MagicMock(slug="roboco")
svc = _service()
_bind(svc, "_task_for_branch", AsyncMock(return_value=fake_task))
_bind(svc, "_workspace_for_branch", AsyncMock(return_value=Path("/tmp/ws")))
_bind(svc, "_get_project_token_or_raise", AsyncMock(return_value="tok"))
_bind(svc, "_parse_github_remote", MagicMock(return_value=("acme", "repo")))
_bind(svc, "_project_default_branch", AsyncMock(return_value="master"))
order: list[str] = []
async def _slow_record(*_args: object, **_kwargs: object) -> None:
await asyncio.sleep(0.05)
order.append("record_done")
_bind(svc, "_record_pr_atomically", _slow_record)
fake_resp = MagicMock()
fake_resp.is_success = True
fake_resp.status_code = 201
fake_resp.json.return_value = {
"number": _EXPECTED_PR_NUMBER,
"html_url": f"https://github.com/acme/repo/pull/{_EXPECTED_PR_NUMBER}",
}
_bind(svc, "_post_pr", AsyncMock(return_value=fake_resp))
with _patch_project_service(fake_project):
task = asyncio.ensure_future(
svc.create_pr("feature/backend/abc12345", parent="master", is_root_pr=True)
)
await asyncio.sleep(0.01) # mid-record: cancellation lands in the shield
task.cancel()
# pytest.raises re-raises any OTHER exception type (e.g. the
# InterfaceError a racing rollback would surface), failing the test —
# that is assertion (a): CancelledError and nothing else propagates.
with pytest.raises(asyncio.CancelledError):
await task
# Appended synchronously right after propagation: no other coroutine
# can run in between, so this marker coming SECOND proves the record
# coroutine had already completed before the cancellation re-raised.
order.append("cancel_raised")
assert order == ["record_done", "cancel_raised"], (
f"record must complete BEFORE the cancellation re-raises; got {order}"
)
@pytest.mark.asyncio
async def test_create_pr_raises_when_branch_not_found() -> None:
svc = _service()