























@@ -5,6 +5,7 @@ import {
55existsSync,
66lstatSync,
77mkdtempSync,
8+opendirSync,
89readdirSync,
910readFileSync,
1011realpathSync,
@@ -86,6 +87,10 @@ const OPTIONAL_OR_EXTERNALIZED_RUNTIME_IMPORTS = new Set([
8687const require = createRequire(import.meta.url);
8788const acorn = require("acorn") as typeof import("acorn");
888990+type DistJavaScriptFileListResult =
91+| { files: string[]; limitExceeded: false }
92+| { files: string[]; limit: number; limitExceeded: true };
93+8994export type PublishedInstallScenario = {
9095name: string;
9196installSpecs: string[];
@@ -179,11 +184,14 @@ export function normalizeInstalledBinaryVersion(output: string): string {
179184180185function listDistJavaScriptFiles(
181186packageRoot: string,
182-opts: { skipRelativePath?: (relativePath: string) => boolean } = {},
183-): string[] {
187+opts: {
188+maxFiles?: number;
189+skipRelativePath?: (relativePath: string) => boolean;
190+} = {},
191+): DistJavaScriptFileListResult {
184192const distDir = join(packageRoot, "dist");
185193if (!existsSync(distDir)) {
186-return [];
194+return { files: [], limitExceeded: false };
187195}
188196189197const pending = [distDir];
@@ -193,28 +201,56 @@ function listDistJavaScriptFiles(
193201if (!currentDir) {
194202 continue;
195203}
196-for (const entry of readdirSync(currentDir, { withFileTypes: true })) {
197-const entryPath = join(currentDir, entry.name);
198-const relativePath = relative(distDir, entryPath).replaceAll("\\", "/");
199-if (opts.skipRelativePath?.(relativePath)) {
200- continue;
201-}
202-if (entry.isDirectory()) {
203-pending.push(entryPath);
204-continue;
205-}
206-if (entry.isFile() && ROOT_DIST_JAVASCRIPT_MODULE_FILE_RE.test(entry.name)) {
207-files.push(entryPath);
204+const dir = opendirSync(currentDir);
205+try {
206+while (true) {
207+const entry = dir.readSync();
208+if (!entry) {
209+ break;
210+}
211+212+const entryPath = join(currentDir, entry.name);
213+const relativePath = relative(distDir, entryPath).replaceAll("\\", "/");
214+if (opts.skipRelativePath?.(relativePath)) {
215+ continue;
216+}
217+if (entry.isDirectory()) {
218+pending.push(entryPath);
219+continue;
220+}
221+if (entry.isFile() && ROOT_DIST_JAVASCRIPT_MODULE_FILE_RE.test(entry.name)) {
222+files.push(entryPath);
223+if (opts.maxFiles !== undefined && files.length > opts.maxFiles) {
224+return {
225+ files,
226+limit: opts.maxFiles,
227+limitExceeded: true,
228+};
229+}
230+}
208231}
232+} finally {
233+ dir.closeSync();
209234}
210235}
211236212-return files;
237+return { files, limitExceeded: false };
238+}
239+240+function formatInstalledDistFileScanLimitError(scope: string, limit: number): string {
241+return `installed package ${scope} contains more than ${limit} JavaScript files; refusing to scan unbounded package contents.`;
213242}
214243215244export function collectInstalledContextEngineRuntimeErrors(packageRoot: string): string[] {
216245const errors: string[] = [];
217-for (const filePath of listDistJavaScriptFiles(packageRoot)) {
246+const distFiles = listDistJavaScriptFiles(packageRoot, {
247+maxFiles: MAX_INSTALLED_ROOT_DIST_JS_FILES,
248+});
249+if (distFiles.limitExceeded) {
250+return [formatInstalledDistFileScanLimitError("dist", distFiles.limit)];
251+}
252+253+for (const filePath of distFiles.files) {
218254const contents = readFileSync(filePath, "utf8");
219255if (contents.includes(LEGACY_CONTEXT_ENGINE_UNRESOLVED_RUNTIME_MARKER)) {
220256errors.push(
@@ -345,9 +381,11 @@ export function collectInstalledPluginSdkDeclarationErrors(packageRoot: string):
345381return errors;
346382}
347383348-function listInstalledRootDistJavaScriptFiles(packageRoot: string): string[] {
384+function listInstalledRootDistJavaScriptFiles(packageRoot: string): DistJavaScriptFileListResult {
349385return listDistJavaScriptFiles(packageRoot, {
350-skipRelativePath: (relativePath) => relativePath.startsWith("extensions/"),
386+maxFiles: MAX_INSTALLED_ROOT_DIST_JS_FILES,
387+skipRelativePath: (relativePath) =>
388+relativePath === "extensions" || relativePath.startsWith("extensions/"),
351389});
352390}
353391@@ -450,16 +488,14 @@ export function collectInstalledRootDependencyManifestErrors(packageRoot: string
450488 ...Object.keys(rootPackageJson.optionalDependencies ?? {}),
451489]);
452490const distFiles = listInstalledRootDistJavaScriptFiles(packageRoot);
453-if (distFiles.length > MAX_INSTALLED_ROOT_DIST_JS_FILES) {
454-return [
455-`installed package root dist contains ${distFiles.length} JavaScript files, exceeding the ${MAX_INSTALLED_ROOT_DIST_JS_FILES} file scan limit.`,
456-];
491+if (distFiles.limitExceeded) {
492+return [formatInstalledDistFileScanLimitError("root dist", distFiles.limit)];
457493}
458494const missingImporters = new Map<string, Set<string>>();
459495const bundledExtensionRuntimeDependencyOwners =
460496collectBundledExtensionRuntimeDependencyOwners(packageRoot);
461497462-for (const filePath of distFiles) {
498+for (const filePath of distFiles.files) {
463499const fileStat = lstatSync(filePath);
464500if (!fileStat.isFile() || fileStat.size > MAX_INSTALLED_ROOT_DIST_JS_BYTES) {
465501const relativePath = relative(join(packageRoot, "dist"), filePath).replaceAll("\\", "/");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。