Fix security, build reproducibility, and correctness issues from code review#89
Merged
Conversation
… review P1 — Security - Escape all map-popup values (name/description/address/type/price/hours) and encodeURIComponent the Google Maps query URL. Live GBFS station data flowed unescaped into Popup.setHTML, allowing HTML/JS injection from the feed. New shared helper src/utils/html.ts (escapeHtml). P2 — Privacy / battery - Stop requesting geolocation on map load. The GPS watch now starts only on explicit user intent (tracking toggle or ride recording). initializeLocationMarker is idempotent and setLocationWatch clears any prior recenter interval before creating a new one (fixes duplicate intervals). P2 — Build reproducibility - Self-host Geist Sans/Mono via next/font/local (vendored variable woff2 in src/app/fonts) instead of next/font/google, which fetched from Google Fonts at build time and broke offline/sandboxed builds. P2 — Dev tooling exposure - Gate the /test fixture/editor page (incl. "Clear All Rides") behind NODE_ENV !== 'production' via notFound(). P2 — Typecheck - Add `typecheck` script (tsc --noEmit) and fold it into `lint`. Fix all pre-existing type errors in tests. Bump tsconfig target ES2017 -> ES2022 (also unblocks the dotAll regex flag in gpx.test.ts). P2 — Trail bounds - calculateTrailBounds now queries MTN_BIKE_SOURCE_ID (the runtime-attached MTB source) instead of the Studio "composite" source, so runtime bounds work without precalculated defaultBounds. Replace dead getNorth()!==undefined checks with bounds.isEmpty(). P2 — Stale trail UI on route select - Map route-click now also dispatches TRAIL_DESELECT (mirrors the sidebar), and ElevationProfile clears any active trail/ride profile on ROUTE_SELECT. P2 — GBFS toggle race + duplication - Guard the rentals layer against re-showing markers after the user toggles off during a slow fetch. Extract shared fetchBikeRentalLocations() used by both Map.tsx and BikeRentalList.tsx (removes a duplicated fetch+join pipeline). P3 — Lint strictness - biome lint now runs with --error-on-warnings. Remove the 4 production non-null assertions (useRideRecording, dem) and allow `!` only in test files via a Biome override. P3 — Accessibility - Re-enable pinch-to-zoom: drop maximum-scale=1/user-scalable=no by moving viewport + theme-color to a Next viewport export. Misc: move eslint-config-prettier and eslint-import-resolver-typescript to devDependencies.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Resolved conflicts: - package.json: take main's dependency bumps; keep eslint-config-prettier and eslint-import-resolver-typescript in devDependencies (my relocation) and the typecheck/lint script changes. - src/app/layout.tsx: keep self-hosted fonts + the viewport export (now using siteConfig.themeColor and pinch-zoom enabled); drop the static manifest link (main provides it via manifest.ts) — superseded main's inline viewport/theme meta tags. - src/app/test/page.tsx: accept main's deletion (supersedes my dev-only gate). - pnpm-lock.yaml: regenerated from the merged package.json. - biome.json: bump $schema to match main's @biomejs/biome 2.4.16. Verified post-merge: tsc --noEmit, eslint, biome --error-on-warnings, 329 tests, and next build all pass.
Owner
Author
|
CR 👍 |
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.
Addresses the prioritized findings from a full code review. All changes are on a fresh branch off
main.Validation
pnpm lint✅ (now includestypecheck+biome lint --error-on-warnings)pnpm test:run→ 325/325 ✅pnpm build✅ — previously failed becausenext/font/googlefetched Geist at build timeChanges
P1 — Security
name/description/address) flowed unescaped intoPopup.setHTML, allowing HTML/JS injection from the feed. Added sharedsrc/utils/html.ts(escapeHtml); every popup value is escaped and the Google Maps query URL isencodeURIComponent'd.P2
initializeLocationMarkeris idempotent andsetLocationWatchclears any prior recenter interval before creating a new one (fixes duplicate intervals).next/font/local(vendored variable woff2 insrc/app/fonts/)./testfixture/editor page (incl. "Clear All Rides") behindNODE_ENV !== 'production'vianotFound().typecheckscript (tsc --noEmit) and fold it intolint; fix all pre-existing type errors in tests; bump tsconfigtargetES2017 → ES2022 (also unblocks the dotAll regex flag ingpx.test.ts).calculateTrailBoundsnow queriesMTN_BIKE_SOURCE_ID(the runtime-attached MTB source) instead of the Studiocompositesource; deadgetNorth() !== undefinedchecks replaced withbounds.isEmpty().TRAIL_DESELECT(mirrors the sidebar) andElevationProfileclears any active trail/ride profile onROUTE_SELECT.fetchBikeRentalLocations()used by bothMap.tsxandBikeRentalList.tsx.P3
biome lintruns with--error-on-warnings. Removed the 4 production non-null assertions (useRideRecording,dem);!is allowed only in test files via a Biome override.maximum-scale=1/user-scalable=noand moving viewport + theme-color into a Nextviewportexport.Misc
eslint-config-prettierandeslint-import-resolver-typescripttodevDependencies.Notes / judgment calls
setLocationWatchtripreact-hooks/exhaustive-depson the once-mount recording effect. It is genuinely ref-stable, so I used a justifiedeslint-disable-next-linepointing at the deferred GPS/compass hook extraction rather than forcing that refactor here.useRideRecording); merging them is the same deferred hook refactor. The privacy win (no watch until intent) is in place regardless.Out of scope (follow-ups from the review)
GBFS fetch timeout/validation +
is_rentinggating, the About-page SVG<Image>rendering issue, deleting the deadsrc/components/ui/tree, pointingadd_trail_bounds.pyatmountain-bike-trails.ts(it currently writes to the barrel), andnoUncheckedIndexedAccess(full strictness was intentionally deferred).