doxa-maps/internal/check-nested-token-delivery.mjs
doxa-maps 70df4f00f6
Some checks are pending
build-gate / build (push) Waiting to run
Gate that every shipped leaf carries its own map token
A cap-5 shell nests its children as iframes, and window.MAP_TOKEN does not cross
an iframe boundary — each frame is its own window. A nested map cannot inherit
the parent's token, so it works only because the child leaf carries its own baked
copy. Proven in a browser: all thirteen nested frames in the cap-5 shell hold a
real token, including a map two levels deep. That was a one-off run; this makes
it standing.

The existing smokes cannot catch this. Both inject window.MAP_TOKEN with
addInitScript before the page runs, which is right for what they test but means
the test supplies the thing under test. A user opening a shipped leaf has nothing
injecting a token for them.

Also asserts the reverse: no token may be compiled into a .js bundle. Bundles are
cached, SRI-pinned and reused across hosts, so a token baked into one cannot be
rotated without a rebuild and leaks into every embed.

Reads the built manifest rather than walking directories, so it checks the set
that actually ships. Counted 43 leaves, matching an independent filesystem count.
Negative-tested both directions: stripping a leaf's token and planting one in a
bundle each fail with the artifact named.
2026-09-22 07:56:34 +00:00

146 lines
7.2 KiB
JavaScript

#!/usr/bin/env node
/**
* check-nested-token-delivery.mjs — every shipped leaf must carry its OWN map token.
*
* WHY THIS IS NOT COVERED BY THE EXISTING SMOKES. Both `smoke:embeds` and `verify:5-caps` open a
* page with `page.addInitScript(tk => { window.MAP_TOKEN = tk })` — they INJECT the token before
* the page runs. That is correct for what those checks test (does the element mount, does the
* capability hold), but it means the test SUPPLIES the very thing under test. A real user opening
* a shipped leaf has no Playwright injecting anything: the leaf must already carry a baked token.
* So no gate currently proves the delivery path itself. This one does, and it needs no browser.
*
* ★ WHY DELIVERY IS A SEPARATE PROPERTY FROM PAINT. A token can be present and the basemap still
* blank (this build box has no WebGL; Mapbox's URL restriction can also 403 the tiles). Those are
* CONSUMPTION failures. This gate asserts DELIVERY only — "does the token reach the page?" — which
* is the half that is our fault when it breaks, deterministic, and checkable offline.
*
* ★ WHY IT MATTERS FOR NESTING (the card this came from). A cap-5 SPA nests its children as
* iframes, and `window.MAP_TOKEN` does NOT cross an iframe boundary — each frame is its own
* window. A nested map therefore cannot inherit the parent's token; it works only because the
* CHILD LEAF carries its own baked copy. Proven live 2026-09-22: 13 of 13 nested frames in the
* cap-5 SPA reported a real pk. token, including a map nested two levels deep (SPA -> cap-4
* composite -> cap-3 map). That proof was a one-off browser run; this makes it a standing gate.
*
* WHAT IT CHECKS: every leaf the manifest actually ships (profile leaves and instance leaves)
* contains a real `pk.` token. It reads the BUILT manifest rather than walking directories, so it
* checks the set that is published, not whatever happens to be on disk.
*
* ★ AND IT ENFORCES THE INVARIANT IN BOTH DIRECTIONS: a token belongs in leaf HTML and must NEVER
* appear in a `.js` bundle. A bundle is cached, SRI-pinned and reused across hosts; a token baked
* into one cannot be rotated without a rebuild, and it leaks into every embed. The leaf is the
* right place precisely because it is regenerated on every build.
*
* NEGATIVE-TESTED: stripping the token from one leaf makes this FAIL naming that leaf; planting a
* pk. string in a .js bundle makes this FAIL naming the bundle; restoring returns PASS. A manifest
* with no leaves FAILS (vacuous guard).
*/
import { readFileSync, existsSync } from 'node:fs'
import { resolve, dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
let treeName = 'doxa-maps'
try {
const cfg = JSON.parse(readFileSync(join(ROOT, 'vite.1040-maps-build-config.json'), 'utf8'))
if (cfg?.name) treeName = cfg.name
} catch { /* default */ }
const TREE = join(ROOT, 'public', treeName)
const MANIFEST = join(TREE, 'manifest.json')
if (!existsSync(MANIFEST)) {
console.log(`NESTED-TOKEN: SKIP — no built manifest at public/${treeName}/manifest.json.`)
console.log(' Run `bun run build` first. An absent tree is not evidence either way.')
process.exit(0)
}
let manifest
try {
manifest = JSON.parse(readFileSync(MANIFEST, 'utf8'))
} catch (e) {
console.error(`NESTED-TOKEN: FAIL — manifest does not parse (${String(e.message).slice(0, 60)}).`)
process.exit(1)
}
// A real Mapbox public token. Deliberately strict about the `pk.` prefix and a minimum body: an
// empty string or a placeholder like "REPLACE_ME" must NOT read as delivered.
const TOKEN_RE = /pk\.[A-Za-z0-9._-]{20,}/
// Collect every leaf URL the manifest publishes. Profiles carry iframeUrl; instances nest one
// level deeper and carry their own. Reading the manifest (not the filesystem) keeps this aligned
// with what is actually served.
const leaves = []
for (const b of manifest.bundles || []) {
for (const p of b.profiles || []) {
if (p.iframeUrl) leaves.push({ bundle: b.bundle, profile: p.profile, url: p.iframeUrl })
for (const inst of p.instances || []) {
if (inst.iframeUrl) leaves.push({ bundle: b.bundle, profile: `${p.profile}/${inst.id || inst.instance}`, url: inst.iframeUrl })
}
}
}
// Vacuous guard: "0 leaves" must never read as "0 problems".
const MIN_LEAVES = 20
if (leaves.length < MIN_LEAVES) {
console.error(`NESTED-TOKEN: FAIL — manifest lists only ${leaves.length} leaf page(s) (expected >= ${MIN_LEAVES}).`)
console.error(' The manifest is truncated or the shape changed. Refusing to pass vacuously.')
process.exit(1)
}
const missing = []
let checked = 0
for (const leaf of leaves) {
const rel = leaf.url.replace(/^\.\//, '')
const abs = join(TREE, rel)
if (!existsSync(abs)) {
missing.push({ ...leaf, why: 'leaf file does not exist in the built tree' })
continue
}
checked++
const html = readFileSync(abs, 'utf8')
if (!TOKEN_RE.test(html)) {
missing.push({ ...leaf, why: 'no pk. token baked into the leaf — a nested map here would get NOTHING' })
}
}
// The other direction: a token must never be compiled into a .js bundle.
const inBundles = []
for (const b of manifest.bundles || []) {
const rel = (b.scriptUrl || '').replace(/^\.\//, '')
if (!rel) continue
const abs = join(TREE, rel)
if (!existsSync(abs)) continue
if (TOKEN_RE.test(readFileSync(abs, 'utf8'))) inBundles.push(b.bundle)
}
console.log(`NESTED-TOKEN: ${checked} shipped leaf page(s) checked, ${(manifest.bundles || []).length} bundle(s) scanned.`)
if (missing.length || inBundles.length) {
if (missing.length) {
console.error(`\nNESTED-TOKEN: FAIL — ${missing.length} leaf page(s) ship without a token:`)
for (const m of missing.slice(0, 20)) console.error(` ✗ ${m.bundle}/${m.profile}\n ${m.url}\n ${m.why}`)
if (missing.length > 20) console.error(` … +${missing.length - 20} more`)
console.error(
'\n window.MAP_TOKEN does NOT cross an iframe boundary — each frame is its own window. A cap-5\n' +
' SPA nests its children as iframes, so a nested map cannot inherit the parent\'s token: it\n' +
' works only because the CHILD leaf carries its own baked copy. A leaf without one is a map\n' +
' that silently renders nothing for every user who opens it directly or through a shell.'
)
}
if (inBundles.length) {
console.error(`\nNESTED-TOKEN: FAIL — ${inBundles.length} bundle(s) have a token COMPILED IN:`)
for (const b of inBundles) console.error(` ✗ ${b}`)
console.error(
'\n A token belongs in leaf HTML, never in a .js bundle. Bundles are cached, SRI-pinned and\n' +
' reused across hosts, so a baked-in token cannot be rotated without a rebuild and leaks into\n' +
' every embed. Leaves are regenerated on every build, which is exactly why they are the right\n' +
' place. Check whether a source file reads the token at module scope instead of at mount.'
)
}
process.exit(1)
}
console.log('NESTED-TOKEN: PASS — every shipped leaf carries its own token, and no bundle does.')
console.log(' This is DELIVERY only. It does not prove a basemap paints: that needs a real GPU and')
console.log(' a token whose URL restrictions allow the serving host (see verify:map-paint).')