feat/atlas-scan
needs attentionviewing older commit3af4686 · incrementalpre-PRreviewed 2026-08-03 20:07 UTC3H · 5M · 5L · 4I- Purpose
- Build and serve the Batu private atlas (Power Finder siting suite) behind platform authentication — spatial layers for gas, substations, industrial parks, and short-circuit data accessible only to logged-in users
- Goal
- Private atlas with full layer set at /atlas, gated by the platform session, served via a route handler in /api/atlas
- Sub-goals
- Move atlas handler from /atlas to /api/atlas (Vercel routing fix)
- Use 307 redirect from proxy instead of edge rewrite
- Extract serveAtlas utility shared by root + catch-all routes
- Update outputFileTracingIncludes and tests for new paths
- What
- Route handlers moved from /atlas to /api/atlas; proxy now issues a 307 redirect for authenticated requests instead of passing through; serveAtlas extracted to lib/atlas/serve.ts; next.config.ts tracing keys updated; tests updated for new paths
- Why
- Top-level /atlas routes conflicted with Next.js [locale] routing tree and edge rewrites didn't apply in Vercel; /api namespace routes reliably (proven pattern: /api/v1/openapi.json)
- Areas
- apps/platform/src/lib/atlas/serve.ts+89−0apps/platform/src/app/api/atlas/+18−0apps/platform/src/lib/supabase/proxy.ts+15−1apps/platform/src/lib/supabase/__tests__/atlas-route-gate.test.ts+125−0apps/platform/next.config.ts+15−0
- Blast
- 6 files, +262/-1 in this increment; no domain logic, no data model, no API contract changes — atlas serving path only
Findings · 16
correctness3
Proxy redirect /atlas → /api/atlas omits trailing slash — may break relative URL resolution before <base> is parsed
apps/platform/src/lib/supabase/proxy.ts:183
pathname.slice('/atlas'.length) is '' for root /atlas, so redirect lands on /api/atlas (no slash). The injected <base href> is /api/atlas/ (with slash). Relative asset fetches that fire before the <base> tag is parsed resolve against /api/atlas → /api/<asset>. Fix: redirect /atlas → /api/atlas/ (add trailing slash).
base href injection via string.replace fragile for malformed HTML (<!-- <head> --> before real head)
apps/platform/src/lib/atlas/serve.ts:38
If <head> appears in a comment before the real <head> element, the base tag injects into the comment and the real head gets no base href. Low probability on a controlled artifact.
MIME allowlist missing .js and .css — atlas script/style assets will 404
apps/platform/src/lib/atlas/serve.ts:9
Only .html .json .geojson .csv .png .svg allowed. Any SPA .js or .css asset will be extension-blocked. Verify atlas bundle extensions and extend TYPES.
security4
Symlink inside atlas-private/ bypasses path-traversal guard
apps/platform/src/lib/atlas/serve.ts:40
fs.readFile follows symlinks. A symlink atlas-private/escape -> /etc/passwd passes the startsWith(BASE+sep) check. Fix: fs.realpath(abs) and re-check against fs.realpath(BASE).
SVG served same-origin can execute inline scripts
apps/platform/src/lib/atlas/serve.ts:26
SVG files loaded directly (not via <img>) execute scripts in the platform origin. Add Content-Security-Policy: script-src 'none' on SVG responses.
No explicit null-byte guard in path segments
apps/platform/src/lib/atlas/serve.ts:37
Node ≥ v7 throws on null bytes, but defense-in-depth: add segs.some(s => s.includes('\0')) guard.
Missing X-Content-Type-Options: nosniff
apps/platform/src/lib/atlas/serve.ts:56
Standard hardening for authenticated file-serving endpoints.
conventions2
JSDoc (/** */) style used for non-public-API function
apps/platform/src/lib/atlas/serve.ts:6
WHY content is correct per policy; use plain /* */ instead of JSDoc.
outputFileTracingIncludes second entry targets wrong source path
apps/platform/next.config.ts:18
'/api/atlas/**': ['./api/atlas/**'] should be './atlas-private/**/*'. Route handler source is bundled by Next.js — only atlas-private/ runtime files need explicit tracing. No-op but misleads editors.
tests5
Path-traversal guard has zero test coverage
apps/platform/src/lib/supabase/__tests__/atlas-route-gate.test.ts
Security-critical guard with no tests. Add cases for ../../../etc/passwd, ..%2F encoding, and null-byte, all asserting 404.
Extension allowlist has zero test coverage
apps/platform/src/lib/supabase/__tests__/atlas-route-gate.test.ts
No test asserting .env or .ts requests are rejected. Accidental allowlist removal would go undetected.
Sub-path redirect not tested (/atlas/layer/data.json → /api/atlas/layer/data.json)
apps/platform/src/lib/supabase/__tests__/atlas-route-gate.test.ts
Only root /atlas path tested. Deep path redirect correctness is untested.
404 for non-existent file not tested
apps/platform/src/lib/supabase/__tests__/atlas-route-gate.test.ts
A broken catch/ENOENT branch returning 500 instead of 404 would go undetected.
Trailing-slash / empty-segments edge case not tested (/api/atlas/)
apps/platform/src/lib/supabase/__tests__/atlas-route-gate.test.ts
Verify segs derived from a trailing slash still resolve to index.html.
improvement2
Redundant Buffer→Uint8Array conversion
apps/platform/src/lib/atlas/serve.ts:47
Node Buffer IS a Uint8Array subclass — pass buf directly to NextResponse; the wrapping copy is unnecessary.
Likely redundant outputFileTracingIncludes glob pair
apps/platform/next.config.ts
Once the second entry is corrected to ./atlas-private/**/*, verify whether both /api/atlas and /api/atlas/** are needed or one covers both.
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:07current
- f5d3266needs attentionincremental0H · 3M · 8L2026-08-03 19:40
- 9f8b61aneeds attentionincremental0H · 2M · 3L2026-08-03 19:15
- ea51fa0needs attentionincremental1H · 4M · 4L2026-08-03 19:02
- 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