Files
gbrain/scripts/check-engine-dynamic-import.ts
T
945fed6105 fix(engine): enforce static engine-live import boundaries (#3596)
* docs: design engine dynamic-import reconciliation

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(engine): reconcile dynamic import hardening

Co-Authored-By: Claude <noreply@anthropic.com>

* test(engine): guard dynamic import policy

* docs: plan engine dynamic-import reconciliation

Record the approved TDD sequence for selective engine-path hardening,
repository guard wiring, documentation, and local verification. Preserve
the no-version-bump and no-publication boundaries for the remaining work.

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(engine): record static import invariant

* fix(engine): parse block comments in import guard

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(engine): parse dynamic imports with TypeScript

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(engine): close import guard bypasses

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(engine): close parser guard edge cases

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(engine): aggregate parser diagnostics

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(engine): bound dynamic import marker directive

Require the line-level opt-out marker to be standalone inside real comment trivia so negated or incidental longer tokens cannot authorize an import. Preserve the existing general marked-line contract and pin it with focused regression coverage.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(engine): close Unicode marker boundary bypasses

Treat Unicode identifier continuations as marker-token characters and inspect adjacent text by code point so supplementary-plane characters cannot turn longer comment tokens into approvals.\n\nCo-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-29 16:08:08 -07:00

81 lines
2.8 KiB
TypeScript

#!/usr/bin/env bun
import { readFile } from 'node:fs/promises';
import ts from 'typescript';
const MARKER = 'engine-dynamic-import-ok';
const MARKER_TOKEN_CHAR = /[\p{ID_Continue}$-]/u;
const files = process.argv.slice(2);
const violations: string[] = [];
const readErrors: string[] = [];
for (const file of files) {
let sourceText: string;
try {
sourceText = await readFile(file, 'utf8');
} catch (error) {
const detail = error instanceof Error ? error.message : String(error);
readErrors.push(`ERROR: cannot read input file ${file}: ${detail}`);
continue;
}
const sourceFile = ts.createSourceFile(
file,
sourceText,
ts.ScriptTarget.Latest,
true,
ts.ScriptKind.TS,
);
const lines = sourceText.split(/\r?\n/);
const markerLines = new Set<number>();
if (sourceFile.parseDiagnostics.length > 0) {
const diagnostics = sourceFile.parseDiagnostics
.map((diagnostic) => ts.flattenDiagnosticMessageText(diagnostic.messageText, ' '))
.join('; ');
readErrors.push(`ERROR: cannot parse input file ${file}: ${diagnostics}`);
}
for (let markerPos = sourceText.indexOf(MARKER); markerPos >= 0; markerPos = sourceText.indexOf(MARKER, markerPos + MARKER.length)) {
const before = Array.from(sourceText.slice(0, markerPos)).at(-1);
const after = Array.from(sourceText.slice(markerPos + MARKER.length))[0];
const standaloneMarker = (!before || !MARKER_TOKEN_CHAR.test(before))
&& (!after || !MARKER_TOKEN_CHAR.test(after));
const token = ts.getTokenAtPosition(sourceFile, markerPos);
const insideToken = token.getStart(sourceFile) <= markerPos && markerPos < token.end;
if (standaloneMarker && !insideToken) {
markerLines.add(sourceFile.getLineAndCharacterOfPosition(markerPos).line);
}
}
function visit(node: ts.Node): void {
if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
const { line } = sourceFile.getLineAndCharacterOfPosition(node.expression.getStart(sourceFile));
const sourceLine = lines[line] ?? '';
if (!markerLines.has(line)) {
violations.push(` ${file}:${line + 1}:${sourceLine}`);
}
}
ts.forEachChild(node, visit);
}
visit(sourceFile);
}
for (const error of readErrors) console.error(error);
if (violations.length > 0) {
console.error('ERROR: unreviewed dynamic import on an engine-live path:');
console.error();
console.error(violations.join('\n'));
console.error();
console.error('Prefer a static top-level import. If lazy loading is load-bearing,');
console.error("append 'engine-dynamic-import-ok' to that exact line and document");
console.error('the startup or soft-failure boundary that requires it.');
process.exit(1);
}
if (readErrors.length > 0) process.exit(1);
console.log(`check-engine-dynamic-import: ok (${files.length} file(s) scanned)`);