diff --git a/internal/check-cdn-pins.mjs b/internal/check-cdn-pins.mjs new file mode 100644 index 000000000..20ff43da6 --- /dev/null +++ b/internal/check-cdn-pins.mjs @@ -0,0 +1,57 @@ +#!/usr/bin/env node +/** + * check-cdn-pins — every runtime third-party script/stylesheet is an EXACT version with an integrity hash. + * + * CRITIC-5 (2026-09-26): maplibre-gl@5 and maplibre-gl-geocoder@1 were floating ranges, and no runtime + * loader set `integrity`, so a CDN could serve any bytes to every partner's visitors unnoticed. + * library/constants/cdn.js is now the one registry; loaders set integrity + crossorigin from it. + * + * OFFLINE (default, in gates:post): in shipped code (library/, plugin-designs/ except scripts/, + * internal/generate-tree.mjs) no jsDelivr/unpkg/esm.sh/api.mapbox.com JS or CSS URL is a floating + * range (@7, @1.2, latest), and every such URL is either in the registry or on the reviewed list below. + * --online: also re-fetches every registry URL and requires its sha384 to equal the pinned hash. + * EXIT 0 pass · 1 fail · 75 (online) network unavailable + */ +import { execFileSync } from 'node:child_process' +import { createHash } from 'node:crypto' +import { resolve, dirname } from 'node:path' +import { fileURLToPath } from 'node:url' +import { CDN } from '../library/constants/cdn.js' + +const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..') +const ONLINE = process.argv.includes('--online') +// Loaded through something other than a ` + + ` : `\n\n` + scriptEmbed + ? `\n\n` + scriptEmbed : scriptEmbed, }, ...(instances.length ? { instances } : {}), diff --git a/library/components/map-controls/GeocoderComponent.vue b/library/components/map-controls/GeocoderComponent.vue index 08388ff66..0df933cc5 100644 --- a/library/components/map-controls/GeocoderComponent.vue +++ b/library/components/map-controls/GeocoderComponent.vue @@ -62,6 +62,7 @@ geocoder — the raw MapboxGeocoder instance (for advanced usage) -->