From 3e76833aac4a21c18bc5ee329f10254cdd16f455 Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Thu, 7 May 2026 15:09:02 -0400 Subject: [PATCH] Validate tool inputs and surface tracebacks on errors - import-photo.sh: validate \$SLUG against ^[a-z0-9-]+\$ before writing under content/photography/; rejects '../' and other surprises early. Also fail loudly with a clear message if either 'magick' resize or 'magick mogrify -strip' returns non-zero (prevents shipping a file that still carries EXIF when the strip silently failed). - compress-assets.sh: reject non-numeric MIN_SIZE up front (otherwise the comparison fails later with a cryptic arithmetic error). - extract-dimensions.py / extract-exif.py / extract-palette.py: add traceback.print_exc() after the broad except so a corrupt image produces a stack trace alongside the one-line summary. - extract-exif.py: switch from Pillow's deprecated _getexif() to the public getexif() API; pyproject allows Pillow up to 12 where _getexif may be removed. Co-Authored-By: Claude Opus 4.7 (1M context) --- tools/compress-assets.sh | 5 +++++ tools/extract-dimensions.py | 2 ++ tools/extract-exif.py | 4 +++- tools/extract-palette.py | 2 ++ tools/import-photo.sh | 11 +++++++++-- 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/tools/compress-assets.sh b/tools/compress-assets.sh index f76dea8..f0bf027 100755 --- a/tools/compress-assets.sh +++ b/tools/compress-assets.sh @@ -20,6 +20,11 @@ set -euo pipefail SITE_DIR="${1:-_site}" MIN_SIZE="${MIN_SIZE:-1024}" # bytes +if [[ ! "$MIN_SIZE" =~ ^[0-9]+$ ]]; then + echo "compress-assets: MIN_SIZE must be a positive integer (got '$MIN_SIZE')" >&2 + exit 1 +fi + if [ ! -d "$SITE_DIR" ]; then echo "compress-assets: directory '$SITE_DIR' not found" >&2 exit 1 diff --git a/tools/extract-dimensions.py b/tools/extract-dimensions.py index d6a79d1..04017a4 100755 --- a/tools/extract-dimensions.py +++ b/tools/extract-dimensions.py @@ -99,7 +99,9 @@ def _walk_one_root(root: Path, counters: dict[str, int]) -> None: try: data = _read_dimensions(image) except Exception as e: # noqa: BLE001 — keep walking + import traceback print(f"extract-dimensions: {image}: {e}", file=sys.stderr) + traceback.print_exc(file=sys.stderr) counters["failed"] += 1 continue diff --git a/tools/extract-exif.py b/tools/extract-exif.py index 86078b0..73f7b25 100755 --- a/tools/extract-exif.py +++ b/tools/extract-exif.py @@ -289,7 +289,7 @@ def _read_exif_via_pillow(image: Path) -> dict[str, Any]: out["width"] = width if isinstance(height, int) and height > 0: out["height"] = height - exif = img._getexif() or {} + exif = img.getexif() or {} except Exception: # noqa: BLE001 — corrupt EXIF should not abort the walk return out @@ -422,7 +422,9 @@ def main() -> int: try: data = _read_one(image) except Exception as e: # noqa: BLE001 — keep walking + import traceback print(f"extract-exif: {image}: {e}", file=sys.stderr) + traceback.print_exc(file=sys.stderr) failed += 1 continue diff --git a/tools/extract-palette.py b/tools/extract-palette.py index 7a05a25..601824a 100755 --- a/tools/extract-palette.py +++ b/tools/extract-palette.py @@ -103,7 +103,9 @@ def main() -> int: try: palette = _extract_palette(image) except Exception as e: # noqa: BLE001 — keep walking + import traceback print(f"extract-palette: {image}: {e}", file=sys.stderr) + traceback.print_exc(file=sys.stderr) failed += 1 continue diff --git a/tools/import-photo.sh b/tools/import-photo.sh index c4598e4..45ad38b 100755 --- a/tools/import-photo.sh +++ b/tools/import-photo.sh @@ -52,6 +52,11 @@ ORIGINAL="$1" SLUG="$2" shift 2 +if [[ ! "$SLUG" =~ ^[a-z0-9-]+$ ]]; then + echo "import-photo: invalid slug '$SLUG' (must be lowercase a-z, 0-9, hyphens only)" >&2 + exit 1 +fi + TITLE="" while [ "$#" -gt 0 ]; do case "$1" in @@ -118,7 +123,8 @@ magick "$ORIGINAL" \ -resize '2400x2400>' \ -colorspace sRGB \ -quality 85 \ - "$TARGET" + "$TARGET" \ + || { echo "import-photo: magick resize failed for $ORIGINAL → $TARGET" >&2; exit 1; } chmod 644 "$TARGET" # --------------------------------------------------------------------------- @@ -141,7 +147,8 @@ fi # --------------------------------------------------------------------------- echo "import-photo: stripping EXIF from delivered file..." -magick mogrify -strip "$TARGET" +magick mogrify -strip "$TARGET" \ + || { echo "import-photo: magick mogrify -strip failed for $TARGET (EXIF NOT stripped)" >&2; exit 1; } # --------------------------------------------------------------------------- # Step 4: extract palette (does its own walk; idempotent on already-done photos)