fix: stop serving stale app.js, harden service worker and download names (v1.5.2) - #15
Conversation
Production was serving a year-old app.js: _headers gave the non-fingerprinted app.js and style.css a one-year max-age, so the edge kept a stale build while the origin was current, and no fix from 1.4.0 or 1.5.0 reached visitors. Both now revalidate every request and index.html references them with a ?v=<version> query. - sw.js: app shell is network-first with a cache fallback for offline (was cache-first, which pinned whatever build was cached and would also outlive a one-shot script execution); CDN libs stay cache-first since their URLs are version-pinned; cross-origin requests are no longer intercepted, so a failed Turnstile or analytics request cannot be answered from cache - app.js: strip bidi overrides, control characters and path separators from the download name and cap its length - scripts/check-version-sync.sh: new CI gate failing on version drift between package.json, sw.js and the index.html asset queries - update-version.js keeps the asset query and sw.js APP_VERSION in step - _headers documents the zone-level header overrides seen in production
Deploying easyconvert-website with
|
| Latest commit: |
ce0712c
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://a700168b.easyconvert-website.pages.dev |
| Branch Preview URL: | https://fix-asset-cache-1-5-2.easyconvert-website.pages.dev |
|
Warning Review limit reached
Next review available in: 49 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (10)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
Why
A pentest of
convert.nx1xlab.devfound production serving a year-oldapp.js:The origin was current; the edge was not. So none of the 1.4.0 or 1.5.0 fixes (DoS hardening, stack-overflow fix, RTL rework, CSV CR quoting, filename handling) were reaching a single visitor. The stale copy also lacked
detectColumnIntervals,mergeContainedFragmentsand the xlsx text-format guard.Root cause:
_headersgave/*.jsand/*.cssa one-yearmax-age, butapp.jsandstyle.csscarry no content hash andindex.htmlreferenced them bare (<script src="app.js">). Nothing could ever bust that cache. The service worker then precached the stale copy and pinned it client-side.What changed
Cache correctness
app.jsandstyle.cssnow revalidate on every request (max-age=0, must-revalidate); ETag makes that a cheap 304. Icons and the social card get a one-day cache; the blanket one-year rule is goneindex.htmlreferences both with?v=1.5.2, so a release busts any intermediary cache that ignores the headerscripts/update-version.jsbumps that query andsw.js'sAPP_VERSIONalongsidepackage.jsonscripts/check-version-sync.shfails the build on version drift or a missing cache-busting queryService worker
/app.jsin Cache Storage beyond the patch that fixed itskipWaiting()+clients.claim()so a new worker takes over promptlyDownload filenames
_converted.xlsx/.csv), so this closes the cosmetic save-dialog spoofing angle onlyDocumentation
_headersnow records the zone-level overrides observed in production (X-Frame-Options: SAMEORIGINinstead ofDENY,Referrer-Policy: same-origin, Pages-addedAccess-Control-Allow-Origin: *, deprecatedExpect-CT), so the file is not read as authoritativeTest plan
check-version-sync.shpasses at 1.5.2; negative-tested against a stalesw.js, a staleindex.htmlquery, and a removed query - all three fail correctlycheck-cdn-versions.shandcheck-action-pins.shpassnode --checkonapp.js,sw.js,_worker.jspublic/locally:/,/app.js?v=1.5.2,/style.css?v=1.5.2,/sw.js,/manifest.jsonall 200, index references resolve to the current buildsanitizeFileNameunit-checked: RTL override stripped, traversal neutralised, control chars removed, Hebrew names survive intact, empty input falls back todocumentcurl -sSI https://convert.nx1xlab.dev/app.jsshows the new cache-control and the response body matchesorigin/mainNot fixed here (needs the Cloudflare dashboard)
cf-cache-status: HIT). Caching > Configuration > Purge EverythingX-Frame-Options/Referrer-Policyoverrides come from a zone-level Transform Rule or managed header, not from_headersrobots.txthas Cloudflare Managed Content injectingUser-agent: * / Allow: /ahead of the repo'sDisallow: /, which likely defeats the intent to stay unindexed/.well-known/security.txtis injected at zone level (it is not in the repo and bypasses the_worker.jsallowlist); itsCanonical:points atnx1xlab.devrather than the host serving it