// SPDX-License-Identifier: MIT // Proves the split: the MIT bundles (dist/, dist-space/uif-space.js, dist-mindx/) contain none of the credential // code, and each build carries the GPL-3.0-only bankml-creds.js beside its page, unchanged. Also: no MIT source // imports src/creds/. Exit 1 with the findings otherwise. node scripts/check-creds-split.mjs import { readFileSync, readdirSync, existsSync, statSync } from 'node:fs'; import { join, relative } from 'node:path'; const root = new URL('..', import.meta.url).pathname; /** Strings only the credential module has: the token's header, the OAuth calls, its storage keys, the token check. */ const MARKERS = ['Authorization', 'Bearer ', 'oauthLoginUrl', 'oauthHandleRedirectIfPresent', 'bankml-creds:session', 'bankml-creds:device', 'whoami-v2', 'accessToken', 'usePastedToken', 'hf_oauth', 'OAUTH_CLIENT_ID']; const walk = d => readdirSync(d).flatMap(f => { const p = join(d, f); return statSync(p).isDirectory() ? walk(p) : [p]; }); const bad = []; const builds = { dist: 'dist', 'dist-space': 'dist-space', 'dist-mindx': 'dist-mindx' }; const creds = join(root, 'dist-creds/bankml-creds.js'); if (!existsSync(creds)) bad.push('dist-creds/bankml-creds.js is missing'); const credsText = existsSync(creds) ? readFileSync(creds, 'utf8') : ''; if (credsText && !credsText.startsWith('/*! bankml-creds.js — SPDX-License-Identifier: GPL-3.0-only')) bad.push('bankml-creds.js lacks its GPL-3.0-only banner'); for (const [name, dir] of Object.entries(builds)) { const d = join(root, dir); if (!existsSync(d)) { bad.push(`${name}: not built`); continue; } const beside = join(d, 'bankml-creds.js'); if (!existsSync(beside)) bad.push(`${name}: bankml-creds.js is not beside the page`); else if (readFileSync(beside, 'utf8') !== credsText) bad.push(`${name}: bankml-creds.js differs from dist-creds/`); const lic = join(d, 'bankml-creds-LICENSE.txt'); if (!existsSync(lic)) bad.push(`${name}: bankml-creds-LICENSE.txt (the GPL-3.0 text) is not beside the page`); else if (!/GNU GENERAL PUBLIC LICENSE\s+Version 3/.test(readFileSync(lic, 'utf8'))) bad.push(`${name}: bankml-creds-LICENSE.txt is not the GPL-3.0 text`); // the MIT bundle: the page's own scripts (not browseML's MIT OR Apache-2.0 files, not the creds module) const mine = walk(d).filter(f => /\.(js|html)$/.test(f) && !/bankml-creds\.js$|browseml[\w-]*\.js$/.test(f)); for (const f of mine) { const t = readFileSync(f, 'utf8'); for (const m of MARKERS) if (t.includes(m)) bad.push(`${relative(root, f)}: contains "${m}"`); } } // no MIT source imports the credential module for (const f of walk(join(root, 'src')).filter(f => /\.(ts|tsx)$/.test(f) && !f.includes('/src/creds/'))) { const t = readFileSync(f, 'utf8'); if (/from\s+['"][^'"]*\/creds(\/|['"])/.test(t) || /import\(\s*['"][^'"]*\/creds\//.test(t)) bad.push(`${relative(root, f)}: imports src/creds/`); } // every credential source file is GPL-3.0-only for (const f of walk(join(root, 'src/creds')).filter(f => /\.(ts|tsx|js)$/.test(f))) { if (!readFileSync(f, 'utf8').startsWith('// SPDX-License-Identifier: GPL-3.0-only')) bad.push(`${relative(root, f)}: not GPL-3.0-only`); } if (bad.length) { console.error('credential split: FAILED\n ' + bad.join('\n ')); process.exit(1); } console.log(`credential split: ok — ${Object.keys(builds).join(', ')} carry no credential code; bankml-creds.js (GPL-3.0-only, ${credsText.length} bytes) beside each page; no MIT source imports src/creds/`);