diff --git a/scripts/plugin-sdk-surface-report.mjs b/scripts/plugin-sdk-surface-report.mjs index 6b05a465304..c292777ea51 100644 --- a/scripts/plugin-sdk-surface-report.mjs +++ b/scripts/plugin-sdk-surface-report.mjs @@ -20,19 +20,44 @@ const deprecatedPublicEntrypointSet = new Set(deprecatedPublicPluginSdkEntrypoin const deprecatedBarrelEntrypointSet = new Set(deprecatedBarrelPluginSdkEntrypoints); const forbiddenPublicSubpaths = new Set(["test-utils"]); -const budgets = { - publicEntrypoints: Number(process.env.OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_ENTRYPOINTS ?? 303), - publicExports: Number(process.env.OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_EXPORTS ?? 8449), - publicFunctionExports: Number( - process.env.OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_FUNCTION_EXPORTS ?? 4656, - ), - publicDeprecatedExports: Number( - process.env.OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_DEPRECATED_EXPORTS ?? 2800, - ), - publicWildcardReexports: Number( - process.env.OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_WILDCARD_REEXPORTS ?? 207, - ), -}; +function readBudgetEnv(name, fallback) { + const raw = process.env[name]; + if (raw === undefined) { + return fallback; + } + const value = raw.trim(); + if (!/^\d+$/u.test(value)) { + throw new Error(`${name} must be a non-negative integer`); + } + const parsed = Number(value); + if (!Number.isSafeInteger(parsed)) { + throw new Error(`${name} must be a safe non-negative integer`); + } + return parsed; +} + +let budgets; +try { + budgets = { + publicEntrypoints: readBudgetEnv("OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_ENTRYPOINTS", 308), + publicExports: readBudgetEnv("OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_EXPORTS", 9920), + publicFunctionExports: readBudgetEnv( + "OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_FUNCTION_EXPORTS", + 5031, + ), + publicDeprecatedExports: readBudgetEnv( + "OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_DEPRECATED_EXPORTS", + 3143, + ), + publicWildcardReexports: readBudgetEnv( + "OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_WILDCARD_REEXPORTS", + 215, + ), + }; +} catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); +} function entrypointPath(entrypoint) { return path.join(repoRoot, "src", "plugin-sdk", `${entrypoint}.ts`); diff --git a/test/scripts/plugin-sdk-surface-report.test.ts b/test/scripts/plugin-sdk-surface-report.test.ts new file mode 100644 index 00000000000..478581cdc7a --- /dev/null +++ b/test/scripts/plugin-sdk-surface-report.test.ts @@ -0,0 +1,41 @@ +import { spawnSync } from "node:child_process"; +import { describe, expect, it } from "vitest"; + +function runSurfaceReport(env: Record) { + return spawnSync(process.execPath, ["scripts/plugin-sdk-surface-report.mjs", "--check"], { + cwd: process.cwd(), + encoding: "utf8", + env: { + ...process.env, + ...env, + }, + }); +} + +describe("plugin SDK surface report", () => { + it("rejects loose numeric budget env vars before collecting SDK stats", () => { + const result = runSurfaceReport({ + OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_EXPORTS: "1e9", + }); + + expect(result.status).toBe(1); + expect(result.stdout).toBe(""); + expect(result.stderr).toContain( + "OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_EXPORTS must be a non-negative integer", + ); + expect(result.stderr).not.toContain("at "); + }); + + it("rejects unsafe budget env vars before collecting SDK stats", () => { + const result = runSurfaceReport({ + OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_EXPORTS: "9007199254740992", + }); + + expect(result.status).toBe(1); + expect(result.stdout).toBe(""); + expect(result.stderr).toContain( + "OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_EXPORTS must be a safe non-negative integer", + ); + expect(result.stderr).not.toContain("at "); + }); +});