From 799cceb54a01b79875e92f54cba1da8a8fb1476a Mon Sep 17 00:00:00 2001 From: autonomic-bot Date: Sun, 31 May 2026 10:13:30 +0000 Subject: [PATCH] =?UTF-8?q?fix(3=20U5.3):=20defense-in-depth=20try/except?= =?UTF-8?q?=20around=20the=20screenshot=20capture=20call=20site=20?= =?UTF-8?q?=E2=80=94=20a=20screenshot=20can=20never=20crash/fail=20the=20r?= =?UTF-8?q?un=20even=20if=20capture()'s=20internal=20swallow=20regresses?= =?UTF-8?q?=20or=20a=20SCREENSHOT=20hook=20raises=20(R7);=20proven=20by=20?= =?UTF-8?q?forced-render-kill=20run=20(install=20pass,=20exit=200,=20no=20?= =?UTF-8?q?card/screenshot,=20results.json=20intact)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- runner/run_recipe_ci.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/runner/run_recipe_ci.py b/runner/run_recipe_ci.py index 8ba7988..11fadd0 100644 --- a/runner/run_recipe_ci.py +++ b/runner/run_recipe_ci.py @@ -974,10 +974,19 @@ def main() -> int: # returns None, so this never blocks or fails the run (R7). None → results.json `screenshot` # stays null → the card shows the "no screenshot" placeholder (cosmetics never change verdict). if deploy_ok: - shot = screenshot_mod.capture( - domain, screenshot_mod.screenshot_path(run_artifact_dir), recipe_meta=meta - ) - screenshot_rel = os.path.basename(shot) if shot else None + # capture() already swallows all errors → None; the extra try/except is defense-in-depth + # (U5 R7 hardening) so a screenshot can NEVER fail/crash the run even if that internal + # contract regresses or a recipe SCREENSHOT hook raises. Cosmetics never change the verdict. + try: + shot = screenshot_mod.capture( + domain, screenshot_mod.screenshot_path(run_artifact_dir), recipe_meta=meta + ) + screenshot_rel = os.path.basename(shot) if shot else None + except Exception as e: # noqa: BLE001 — screenshot is cosmetic; never fail a run on it (R7) + print( + f"!! screenshot capture raised (non-fatal, verdict unaffected): {_scrub(str(e))}", + flush=True, + ) # ---- INSTALL tier (always; additive generic + overlay, no op) ---- if "install" in stages: