























@@ -3,9 +3,12 @@ import path from "node:path";
33import { describe, expect, it } from "vitest";
44import { withTempDir } from "../test-helpers/temp-dir.js";
55import {
6+assertNoBundledRuntimeDepsStagingDebris,
7+collectBundledRuntimeDepsStagingDebrisPaths,
68collectPackageDistInventoryErrors,
79PACKAGE_DIST_INVENTORY_RELATIVE_PATH,
810collectPackageDistInventory,
11+isBundledRuntimeDepsInstallStagePath,
912writePackageDistInventory,
1013} from "./package-dist-inventory.js";
1114@@ -152,6 +155,165 @@ describe("package dist inventory", () => {
152155]);
153156});
154157});
158+159+it("ignores runtime-created install staging dirs during installed dist verification", async () => {
160+await withTempDir({ prefix: "openclaw-dist-inventory-stage-" }, async (packageRoot) => {
161+const realFile = path.join(packageRoot, "dist", "real-AbC123.js");
162+await fs.mkdir(path.dirname(realFile), { recursive: true });
163+await fs.writeFile(realFile, "export {};\n", "utf8");
164+await writePackageDistInventory(packageRoot);
165+166+const bareStageFile = path.join(
167+packageRoot,
168+"dist",
169+"extensions",
170+"brave",
171+".openclaw-install-stage",
172+"node_modules",
173+"typebox",
174+"build",
175+"compile",
176+"code.mjs",
177+);
178+const suffixedStageFile = path.join(
179+packageRoot,
180+"dist",
181+"extensions",
182+"browser",
183+".openclaw-install-stage-AbC123",
184+"node_modules",
185+"playwright-core",
186+"package.json",
187+);
188+await fs.mkdir(path.dirname(bareStageFile), { recursive: true });
189+await fs.writeFile(bareStageFile, "// staged\n", "utf8");
190+await fs.mkdir(path.dirname(suffixedStageFile), { recursive: true });
191+await fs.writeFile(suffixedStageFile, "{}", "utf8");
192+193+await expect(collectPackageDistInventoryErrors(packageRoot)).resolves.toEqual([]);
194+});
195+});
196+197+it("matches install-stage paths case-insensitively across path segments", () => {
198+expect(
199+isBundledRuntimeDepsInstallStagePath(
200+"dist/extensions/brave/.openclaw-install-stage/node_modules/typebox/package.json",
201+),
202+).toBe(true);
203+expect(
204+isBundledRuntimeDepsInstallStagePath(
205+"dist/Extensions/browser/.OPENCLAW-INSTALL-STAGE-AbC123/node_modules/playwright-core/package.json",
206+),
207+).toBe(true);
208+expect(
209+isBundledRuntimeDepsInstallStagePath(
210+"Dist/Extensions/browser/.OpenClaw-Install-Stage/package.json",
211+),
212+).toBe(true);
213+expect(
214+isBundledRuntimeDepsInstallStagePath(
215+"dist/extensions/browser/.openclaw-runtime-deps-copy-AbC123/package.json",
216+),
217+).toBe(false);
218+expect(isBundledRuntimeDepsInstallStagePath("dist/extensions/.openclaw-install-stage")).toBe(
219+false,
220+);
221+});
222+223+it("rejects pre-populated install-stage debris at publish time", async () => {
224+await withTempDir({ prefix: "openclaw-dist-inventory-stage-publish-" }, async (packageRoot) => {
225+const seededStagePackageJson = path.join(
226+packageRoot,
227+"dist",
228+"extensions",
229+"evil",
230+".openclaw-install-stage",
231+"package.json",
232+);
233+const suffixedSeed = path.join(
234+packageRoot,
235+"dist",
236+"extensions",
237+"browser",
238+".openclaw-install-stage-AbC123",
239+"node_modules",
240+"playwright-core",
241+"package.json",
242+);
243+await fs.mkdir(path.dirname(seededStagePackageJson), { recursive: true });
244+await fs.writeFile(seededStagePackageJson, "{}", "utf8");
245+await fs.mkdir(path.dirname(suffixedSeed), { recursive: true });
246+await fs.writeFile(suffixedSeed, "{}", "utf8");
247+248+await expect(collectBundledRuntimeDepsStagingDebrisPaths(packageRoot)).resolves.toEqual([
249+"dist/extensions/browser/.openclaw-install-stage-AbC123",
250+"dist/extensions/evil/.openclaw-install-stage",
251+]);
252+await expect(assertNoBundledRuntimeDepsStagingDebris(packageRoot)).rejects.toThrow(
253+/unexpected bundled-runtime-deps install staging debris/,
254+);
255+await expect(writePackageDistInventory(packageRoot)).rejects.toThrow(
256+/unexpected bundled-runtime-deps install staging debris/,
257+);
258+});
259+});
260+261+it("rejects mixed-case install-stage debris on case-sensitive release builders", async () => {
262+await withTempDir(
263+{ prefix: "openclaw-dist-inventory-stage-extensions-case-" },
264+async (packageRoot) => {
265+const mixedCaseStage = path.join(
266+packageRoot,
267+"dist",
268+"Extensions",
269+"evil",
270+".OpenClaw-Install-Stage",
271+"package.json",
272+);
273+await fs.mkdir(path.dirname(mixedCaseStage), { recursive: true });
274+await fs.writeFile(mixedCaseStage, "{}", "utf8");
275+276+await expect(collectBundledRuntimeDepsStagingDebrisPaths(packageRoot)).resolves.toEqual([
277+"dist/Extensions/evil/.OpenClaw-Install-Stage",
278+]);
279+await expect(writePackageDistInventory(packageRoot)).rejects.toThrow(
280+/unexpected bundled-runtime-deps install staging debris/,
281+);
282+},
283+);
284+285+await withTempDir(
286+{ prefix: "openclaw-dist-inventory-stage-root-case-" },
287+async (packageRoot) => {
288+const mixedCaseStage = path.join(
289+packageRoot,
290+"Dist",
291+"Extensions",
292+"browser",
293+".OPENCLAW-INSTALL-STAGE-AbC123",
294+"package.json",
295+);
296+await fs.mkdir(path.dirname(mixedCaseStage), { recursive: true });
297+await fs.writeFile(mixedCaseStage, "{}", "utf8");
298+299+await expect(collectBundledRuntimeDepsStagingDebrisPaths(packageRoot)).resolves.toEqual([
300+"Dist/Extensions/browser/.OPENCLAW-INSTALL-STAGE-AbC123",
301+]);
302+await expect(writePackageDistInventory(packageRoot)).rejects.toThrow(
303+/unexpected bundled-runtime-deps install staging debris/,
304+);
305+},
306+);
307+});
308+309+it("treats a missing dist/extensions tree as no staging debris", async () => {
310+await withTempDir({ prefix: "openclaw-dist-inventory-no-extensions-" }, async (packageRoot) => {
311+await fs.mkdir(path.join(packageRoot, "dist"), { recursive: true });
312+await expect(collectBundledRuntimeDepsStagingDebrisPaths(packageRoot)).resolves.toEqual([]);
313+await expect(assertNoBundledRuntimeDepsStagingDebris(packageRoot)).resolves.toBeUndefined();
314+});
315+});
316+155317it("fails closed when the inventory is missing", async () => {
156318await withTempDir({ prefix: "openclaw-dist-inventory-missing-" }, async (packageRoot) => {
157319await fs.mkdir(path.join(packageRoot, "dist"), { recursive: true });
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。