fix(templates): valid reading-list gallery covers + integrity guard#129
Merged
Conversation
The reading-list template set `coverPropertyId` on its gallery view but seeded no covers, so the gallery shipped with empty/broken cover slots. Seed three tiny (<300 B) raster-PNG book covers as inline `data:` URLs on the files-typed `p_cover` cells — one per shelf, so every gallery group leads with a real card. The `files` property and the gallery cover render a URL string straight into `<img src>` with no asset-store resolution seam, so covers are inlined rather than routed through the content-addressed asset store (a store `assetId` would not load there). This seeds identically on both transports (web PGlite + desktop IPC) with no upload call. PNG, never SVG — honouring the store's image allowlist even though nothing is stored. Teach `isImageUrl` to recognise `data:image/*` URLs so `coverImageUrl` / `firstImageUrl` resolve the inline covers (and the files-cell thumbnail renders them). Display-only; unrelated to the asset upload allowlist. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KFk2T9k3p7ghCjdzMfkA5w
The seeded COVER_TEAL data-URI shipped a corrupt PNG: its IDAT zlib stream failed the Adler-32 check, so "Thinking, Fast and Slow" (the lead card of the To-read shelf) rendered as colour-noise instead of a cover. The existing tests false-greened on it — a bare toBeVisible() never decodes the image. - Regenerate all three covers with a reliable encoder (zlib.deflateSync IDAT + correct per-chunk CRC-32 + valid Adler-32), verified to decode before embedding; consistent teal/orange/blue book-cover layout. - Add a per-cover IDAT-integrity unit assertion (inflate + exact scanline size + recomputed Adler-32 match) so a corrupt cover can't silently rot again. - e2e now asserts naturalWidth > 0 on the first rendered cover so a decode failure reddens the suite. - Tighten isImageUrl's data-URI match to exclude the svg subtype (/^data:image\/(?!svg)/i), matching the code's "PNG, never SVG" intent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KFk2T9k3p7ghCjdzMfkA5w
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The Reading list template's Gallery view names a
coverPropertyId, but itsseeded rows shipped no covers — so the gallery rendered as empty cover slots
(placeholder document icons), looking broken out of the box. A first pass seeded
inline PNG covers, but one of the three (
COVER_TEAL, on "Thinking, Fast andSlow" — the lead card of the To read shelf) was a corrupt PNG: its IDAT
zlib stream failed its Adler-32 check, so it rendered as colour-noise instead of a
book cover. The existing tests false-greened on it — a bare
toBeVisible()never decodes the image.
Notion epic: Epic: Templates that showcase OpenBook — interactive + slides (IA 2026-07) · closes TPL-7.
Solution
orange / blue), regenerated with a reliable encoder (
zlib.deflateSyncIDAT +correct per-chunk CRC-32 + a valid Adler-32) and verified to decode before
embedding. Consistent layout: colored fill + darker left spine + light title
band + small author-label block.
isImageUrlso adata:image/*cover renders straight into thegallery/thumbnail
<img src>— display-only, no asset-store write, no uploadallowlist change. Tightened to exclude the
svgsubtype(
/^data:image\/(?!svg)/i), matching the code's own "PNG, never SVG" intent(Quinn's optional hardening).
seeded cover is base64-decoded, its IDAT inflated, and checked for the exact
raw-scanline byte count plus a recomputed Adler-32 match.
fflatedependency).The 50/50 coverage per shelf (one covered card + one placeholder) is intentional —
it keeps the placeholder/fallback path exercised and reads as a realistic library.
Before / After
empty cover slot (placeholder icon); the teal cover was a corrupt PNG rendering as colour-noise
a proper teal book cover (spine + title band)
every card a placeholder slot
teal / orange / blue covers, one per shelf
Test procedure
pnpm verify— green: sdk 171 + ui 968 + server 645 unit tests pass; MCP e2e 40 checks pass; typecheck + lint clean.templates.spec.ts) — green: covers render as<img>and the first cover assertsnaturalWidth > 0(a decode failure now reddens the suite).height*(width*3+1)bytes with a matching Adler-32. (Fed the old corrupt teal it fails — 21,812 ≠ 28,920 decoded bytes + Adler mismatch — proving the guard bites.)Operational notes
data:URIs, notasset-store objects — they seed identically on both transports (web PGlite +
desktop IPC) with no upload call.
isImageUrlchange is a display-only broadening of which URL stringsrender in an
<img src>; adata:URL in an<img>executes no script, andthe
svg-subtype exclusion keeps it in step with the store's image allowlist —no new XSS/exfil surface (Quinn's security-lens verdict).
design review ✓ Devon (after the corrupt-cover fix).
pnpm verifygreen · gates: code ✓ Quinn · design ✓ Devon🤖 Generated with Claude Code
https://claude.ai/code/session_01KFk2T9k3p7ghCjdzMfkA5w