feat/atlas-scan
needs attentionviewing older commitea51fa0 · incrementalpre-PRreviewed 2026-08-03 19:02 UTC1H · 4M · 4L · 5I- Purpose
- Gate the private atlas (Power Finder, gas pipelines, aquifers, congestion layers) behind Batu platform login — competitive intelligence data that must not be publicly accessible.
- Goal
- Serve atlas-private/ directory exclusively to authenticated platform users via a two-layer defense (middleware + route handler), without disrupting the marketing site's open atlas page.
- Sub-goals
- Authenticated file-serving route handler at /atlas/[[...path]] with path traversal and extension allowlist protection
- Proxy middleware extension: /atlas special-case prevents locale prefix injection on a non-page route
- next.config.ts: outputFileTracingIncludes to bundle atlas-private/ for serverless; locale-stripping redirect for post-login return
- Marketing page: replace iframe embed with auth-required CTA linking to platform
- What
- New route handler, proxy middleware update, next.config changes, marketing page CTA, test coverage, plus static data files in atlas-private/ and Python build scripts in scripts/atlas/
- Why
- The atlas private layers (Power Finder siting data, gas pipeline routing, aquifer boundaries, short-circuit data) are commercially sensitive and should not be publicly accessible even on a preview Vercel URL
- Areas
- apps/platform/src/app/atlas+73−0apps/platform/src/lib/supabase+120−0apps/platform/next.config.ts+12−0apps/web/src/app/(marketing)/atlas+45−30apps/platform/atlas-private+6900−0scripts/atlas+600−29
- Blast
- ~90 code files + hundreds of data/script files. Core platform auth changes are 5 files. Data files are additive (new atlas-private/ directory).
Findings · 14
correctness2
DataDownload contentUrl resolves to 404 on the marketing domain
apps/web/src/app/(marketing)/atlas/page.tsx:85
contentUrl uses SITE=batuenergy.com but the files are served from app.batuenergy.com behind auth. Every download URL is a broken link. Fix: use ATLAS_APP (already on line 12) or remove the distribution block.
isAccessibleForFree: true contradicts the auth gate
apps/web/src/app/(marketing)/atlas/page.tsx:73
The atlas requires a Batu platform login; the page's own UI says so. isAccessibleForFree:true misrepresents the resource to search engines. Set to false or omit.
security2
SVG in TYPES allowlist enables inline script execution (persistent XSS vector)
apps/platform/src/app/atlas/[[...path]]/route.ts:33
image/svg+xml served at a same-origin URL allows embedded <script> execution. No SVGs exist today but the allowlist is open. Remove .svg from TYPES or force Content-Disposition: attachment.
Missing X-Content-Type-Options and X-Frame-Options on all responses
apps/platform/src/app/atlas/[[...path]]/route.ts:62
Route handlers don't inherit Next.js default security headers. Add X-Content-Type-Options: nosniff and X-Frame-Options: DENY to prevent MIME sniffing and clickjacking.
conventions2
Handler comment misattributes proxy behavior
apps/platform/src/app/atlas/[[...path]]/route.ts:17
Says 'el proxy solo presence-checkea cookies' but the proxy also calls getClaims() for full JWT validation. Both layers are proper JWT gates. Update comment to reflect reality.
permanent:false redirect lacks comment explaining why permanent:true would be wrong
apps/platform/next.config.ts:27
This is a routing seam (i18n router adds locale, handler strips it), not a stable URL alias change. A 308 cached by the browser would bypass future proxy auth logic. Add a comment explaining this.
tests5
Non-existent allowed-extension file not tested (404 on fs error)
apps/platform/src/lib/supabase/__tests__/atlas-route-gate.test.ts:99
The fs.readFile error path returns 404, but no test exercises it. Add: call(['data','nonexistent.json']) → expect 404.
.geojson and .csv MIME types not asserted
apps/platform/src/lib/supabase/__tests__/atlas-route-gate.test.ts:99
Core private data layers use .geojson and .csv MIME types, which differ from the tested .json. A TYPES map typo would go undetected.
Tests read real atlas-private files — content-sensitive assertion
apps/platform/src/lib/supabase/__tests__/atlas-route-gate.test.ts:82
toContain('Power Finder') will break if index.html is rebuilt. Mock fs.promises.readFile or use a fixture file.
Proxy gate not tested for /atlas/data/... subpath
apps/platform/src/lib/supabase/__tests__/atlas-route-gate.test.ts:37
The realistic unauthenticated attack vector is a direct GET /atlas/data/pf.json. Add a proxy test for this path.
Nested subdirectory path not exercised
apps/platform/src/lib/supabase/__tests__/atlas-route-gate.test.ts:99
data/demand/today.json exercises the multi-level join+normalize+startsWith guard. Add one test for a nested subpath.
improvement3
/atlas in PROTECTED_ROUTE_PATTERNS is dead code
apps/platform/src/lib/supabase/proxy.ts:12
The special-case block at line 182 intercepts all /atlas* requests before isProtectedRoute() is ever evaluated. Remove the /atlas entry from the array; keep the explanation in the special-case comment.
Handler login redirect is locale-free — extra proxy hop
apps/platform/src/app/atlas/[[...path]]/route.ts:46
Handler redirects to /login (no locale); proxy then adds /es/login. Use /${DEFAULT_LOCALE}/login to match proxy convention and avoid the extra round-trip.
Unnecessary Uint8Array copy for file buffer
apps/platform/src/app/atlas/[[...path]]/route.ts:63
Buffer extends Uint8Array. new Uint8Array(buf) copies the buffer. Pass buf directly to NextResponse to avoid the copy for large GeoJSON/CSV files.
History · 16 commits
- 91aaedfsafeincremental0H · 1M · 1L2026-08-12 17:35
- cb8d915needs attentionincremental2H · 5M · 3L2026-08-12 17:29
- 4cbbe8aneeds attentionincremental0H · 3M · 8L2026-08-12 14:01
- 4aa3c02needs attentionincremental2H · 3M · 3L2026-08-12 02:35
- f5630b2needs attentionincremental0H · 4M · 5L2026-08-12 02:17
- 28fde5bneeds attentionincremental1H · 2M · 2L2026-08-12 01:53
- 0babe51needs attentionincremental1H · 2M · 5L2026-08-12 01:23
- 50e8a8cneeds attentionincremental3H · 5M · 7L2026-08-11 23:58
- 3af4686needs attentionincremental3H · 5M · 5L2026-08-03 20:07
- f5d3266needs attentionincremental0H · 3M · 8L2026-08-03 19:40
- 9f8b61aneeds attentionincremental0H · 2M · 3L2026-08-03 19:15
- ea51fa0needs attentionincremental1H · 4M · 4L2026-08-03 19:02current
- 2b33f2fneeds attentionincremental0H · 1M · 1L2026-07-18 05:09
- 2f8cf79needs attentionincremental1H · 3M · 4L2026-07-18 00:59
- 1616332safeincremental0H · 0M · 1L2026-07-18 00:22
- e997fd8needs attentionfull1H · 4M · 6L2026-07-17 23:53