CodeRabbit flagged several payload-derived int() conversions in composer.py
that could raise ValueError instead of clamping like every other coerced
value in the module (_as_rgb_filter and its callers -- fillR/G/B, outR/G/B,
bgR/G/B, trackR/G/B -- plus min_width, lineSpacing, barWidth/Height,
start/endAngle, borderRadius, pip*, sparkline bar*, marquee gap/scrollSpeed).
Route them all through _safe_int for consistency with the rest of the module
and to avoid the generic 422 a raw ValueError produces.
Also:
- FileReader.onerror was unset in importDesign(), so a failed file read
produced no status message.
- URL.revokeObjectURL() ran synchronously right after link.click() in both
exportDesign() and generateZip(); deferred via setTimeout(..., 0) so the
download reliably starts before the object URL is revoked.
- _module_level_code() (test helper) filtered ast.ImportFrom but not
ast.Import, so a bare `import os` payload wouldn't be caught by the
helper itself, even though downstream assertions still caught it.
Added regression tests for the fillR/G/B injection + clamping path, which
had no coverage (existing tests only covered the r/g/b _rgb_expr path).
Skipped as not worth the churn (CodeRabbit nitpicks, both "Trivial/Low value"):
- test_composer_empty_block.py's branch regex not matching digit-containing
type names -- no such type exists today.
- test_composer_path_containment.py's `C.composer_bp.name and Flask(...)`
truthiness guard -- cosmetic, blueprint name is never falsy.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XKc832xpVEx3C3W5BVqQ5Z