Files
OneCAD-Draft/scripts/build-web.sh
T
Afonsop c6db94e86f fix: native-bpp decode accounting, GIF frame bombs, streaming remote bodies
A second adversarial round (with empirical reproduction against the
vendored image 0.25) found the budget contract still had holes:

- The probe billed 4 bytes/px, but 16-bit formats allocate their
  native layout during decode (8/px for RGBA16 PNG; TIFF stacks ~3x
  codec scratch on top). In-budget 16-bit images were falsely refused
  with self-contradictory notes, and the decode transient could exceed
  the budget the tiers claimed to enforce. The probe now reads the
  color type alongside the dimensions and bills the real peak (native
  layout + RGBA where they coexist, plus the TIFF codec factor), so
  refusals are honest and per-platform-correct, and the TIFF allowance
  follows the same accounting.
- GIF: the probe reads the LOGICAL SCREEN, but a crafted frame may
  declare itself arbitrarily larger (empirically: a 10x10 probed
  screen with an 8192x8192 frame — 320 MB and 29 s from a
  probe-claimed-400-byte image). The GIF frame buffer is now capped
  to the probed size plus slack; frame bombs refuse like any other
  oversize.
- Remote bodies on web streamed incrementally with the 64 MB cap
  enforced DURING the read (array_buffer() materialized a hostile
  chunked reply in full before any check could fire), aborting and
  cancelling the reader the moment the cap is crossed.
- Degenerate raster entities (zero/non-finite size or vectors) no
  longer produce NaN placement math that aborted whole PDF exports —
  they resolve to the broken-reference placeholder.
- Same-name resolution now has a deterministic winner (newest
  registration, via insertion order) instead of HashMap iteration
  order; URL query strings no longer break by-name matching; the
  image pick matches its refusal note by the quoted file name
  (substring collisions like a.tif/2011.tif attributed errors to the
  wrong file); a dropped remote outcome at the queue cap triggers one
  unconditional catch-up re-resolution instead of waiting for another
  event; the unknown-size refusal says so instead of printing 0x0;
  and the build script fails cleanly when there are no fonts to
  verify.
2026-09-18 06:23:30 +01:00

49 lines
1.9 KiB
Bash

#!/bin/sh
# Canonical web bundle build: Trunk plus a fonts sanity sync.
#
# Trunk's copy-dir pipeline always copies web/fonts in full, but its final
# "apply staging to dist" step wipes the old dist and then moves dist/app/.stage
# into place. If that wipe fails on Windows (typically a transient lock from a
# local file server or antivirus with a file open under dist), the build exits
# non-zero and leaves dist stale with .stage fully populated — easy to miss,
# and a stale bundle would 404 the fonts the app fetches from fonts/*.ttf.
# This wrapper therefore re-syncs web/fonts into dist/app/fonts after a
# successful Trunk build and verifies every font byte-for-byte, so a bundle
# produced through it can never ship without the font set.
#
# Usage: sh scripts/build-web.sh [extra trunk build args]
# local: sh scripts/build-web.sh
# CI: sh scripts/build-web.sh --locked --html-output index.html web-app.html
set -eu
root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
cd "$root"
# Git Bash rewrites leading-slash arguments such as --public-url /app/ into
# Windows paths; keep them verbatim. Harmless on other platforms.
MSYS_NO_PATHCONV=1
export MSYS_NO_PATHCONV
trunk build --release --dist dist/app --public-url /app/ "$@"
# Mirror the font sources over the bundle and verify the copy-dir output.
mkdir -p dist/app/fonts
# Hard-fail with a clear message when there are no fonts to verify.
first_font=$(echo web/fonts/*.ttf)
if [ ! -e "$first_font" ]; then
echo "build-web.sh: no .ttf fonts found under web/fonts — nothing to ship or verify" >&2
exit 1
fi
cp -f web/fonts/* dist/app/fonts/
count=0
for font in web/fonts/*.ttf; do
name=$(basename "$font")
cmp -s "$font" "dist/app/fonts/$name" || {
echo "error: dist/app/fonts/$name differs from $font" >&2
exit 1
}
count=$((count + 1))
done
echo "web bundle built; verified $count fonts in dist/app/fonts"