fix(packaging): require the code mode worker in shipped tarballs (#115178)

This commit is contained in:
Peter Steinberger
2026-07-28 08:26:30 -04:00
committed by GitHub
parent 2c5aff01f6
commit 981a3dfad3
3 changed files with 94 additions and 2 deletions

View File

@@ -8,6 +8,7 @@ import os from "node:os";
import path from "node:path";
import { performance } from "node:perf_hooks";
import { pathToFileURL } from "node:url";
import { gte as semverGte, valid as validSemver } from "semver";
import { LOCAL_BUILD_METADATA_DIST_PATHS } from "./lib/local-build-metadata-paths.mjs";
import {
collectPackageDistImports,
@@ -323,6 +324,8 @@ const normalized = entries.map((entry) => entry.replace(/^package\//u, ""));
const entrySet = new Set(normalized);
const errors = [];
const warnings = [];
const CODE_MODE_WORKER_PATH = "dist/agents/code-mode.worker.js";
const FIRST_CODE_MODE_WORKER_VERSION = "2026.5.14-beta.2";
const REQUIRED_TARBALL_ENTRIES = ["dist/control-ui/index.html", ...WORKSPACE_TEMPLATE_PACK_PATHS];
const PACKAGE_INSTALL_GUARD_RELATIVE_PATH = "dist/openclaw-install-guard";
const REQUIRED_TARBALL_ENTRY_PREFIXES = ["dist/control-ui/assets/"];
@@ -474,6 +477,12 @@ if (entrySet.has("package.json")) {
packageVersion = "";
}
}
const validPackageVersion = validSemver(packageVersion);
const requiresCodeModeWorker =
validPackageVersion !== null && semverGte(validPackageVersion, FIRST_CODE_MODE_WORKER_VERSION);
if (requiresCodeModeWorker && !entrySet.has(CODE_MODE_WORKER_PATH)) {
errors.push(`missing required tar entry ${CODE_MODE_WORKER_PATH}`);
}
if (entrySet.has("package-lock.json")) {
errors.push("package tarball must not contain package-lock.json");
}
@@ -570,6 +579,9 @@ if (entrySet.has("dist/postinstall-inventory.json")) {
} else {
const normalizedInventory = inventory.map((entry) => entry.replace(/\\/gu, "/"));
const normalizedInventorySet = new Set(normalizedInventory);
if (requiresCodeModeWorker && !normalizedInventorySet.has(CODE_MODE_WORKER_PATH)) {
errors.push(`postinstall inventory omits ${CODE_MODE_WORKER_PATH}`);
}
if (normalizedInventorySet.has(PACKAGE_INSTALL_GUARD_RELATIVE_PATH)) {
errors.push(
`package dist inventory must omit install guard ${PACKAGE_INSTALL_GUARD_RELATIVE_PATH}`,

View File

@@ -16,6 +16,7 @@ import { describe, expect, it } from "vitest";
import { WORKSPACE_TEMPLATE_PACK_PATHS } from "../../scripts/lib/workspace-bootstrap-smoke.mjs";
const CONTROL_UI_INDEX = "dist/control-ui/index.html";
const CODE_MODE_WORKER_PATH = "dist/agents/code-mode.worker.js";
const CONTROL_UI_ASSETS = [
"dist/control-ui/assets/app.js",
"dist/control-ui/assets/app.js.br",
@@ -65,8 +66,13 @@ function withPackedPackage(
}),
}),
);
writeFixtureFile(packageRoot, "dist/postinstall-inventory.json", JSON.stringify(inventory));
writeFixtureFile(
packageRoot,
"dist/postinstall-inventory.json",
JSON.stringify([...new Set([...inventory, CODE_MODE_WORKER_PATH])]),
);
writeFixtureFile(packageRoot, "dist/index.js", "export {};\n");
writeFixtureFile(packageRoot, CODE_MODE_WORKER_PATH, "export {};\n");
writeFixtureFile(
packageRoot,
CONTROL_UI_INDEX,
@@ -215,6 +221,7 @@ describe("packaged Control UI postinstall inventory", () => {
expect(result.stdout).toContain("OpenClaw package tarball integrity passed.");
const installedPackageRoot = installPackedPackage(root, tarball);
expect(existsSync(join(installedPackageRoot, CODE_MODE_WORKER_PATH))).toBe(true);
for (const relativePath of CONTROL_UI_FILES) {
expect(existsSync(join(installedPackageRoot, relativePath))).toBe(true);
}

View File

@@ -11,6 +11,7 @@ import {
} from "node:fs";
import { tmpdir } from "node:os";
import { delimiter, dirname, join } from "node:path";
import { gte as semverGte, valid as validSemver } from "semver";
import { describe, expect, it } from "vitest";
import { LOCAL_BUILD_METADATA_DIST_PATHS } from "../../scripts/lib/local-build-metadata-paths.mjs";
import { PACKAGE_INSTALL_GUARD_RELATIVE_PATH } from "../../scripts/lib/package-dist-inventory.ts";
@@ -18,6 +19,8 @@ import { WORKSPACE_TEMPLATE_PACK_PATHS } from "../../scripts/lib/workspace-boots
const CHECK_SCRIPT = "scripts/check-openclaw-package-tarball.mjs";
const NODE_DEFAULT_SPAWN_MAX_BUFFER_BYTES = 1024 * 1024;
const CODE_MODE_WORKER_PATH = "dist/agents/code-mode.worker.js";
const FIRST_CODE_MODE_WORKER_VERSION = "2026.5.14-beta.2";
const FLAT_PLUGIN_SDK_DECLARATION = "dist/plugin-sdk/provider-entry.d.ts";
const DEEP_PLUGIN_SDK_DECLARATION = "dist/plugin-sdk/src/plugin-sdk/provider-entry.d.ts";
const AI_RUNTIME_PACKAGE_JSON = JSON.stringify({
@@ -55,6 +58,8 @@ function withTarball(
testBody: (tarball: string) => void,
version = "2026.7.2",
options: {
includeCodeModeWorker?: boolean;
includeCodeModeWorkerInInventory?: boolean;
includeControlUi?: boolean;
includeInstallGuard?: boolean;
includeShrinkwrap?: boolean;
@@ -64,6 +69,15 @@ function withTarball(
) {
const root = mkdtempSync(join(tmpdir(), "openclaw-package-tarball-test-"));
try {
const validVersion = validSemver(version);
const includeCodeModeWorker =
options.includeCodeModeWorker ??
(validVersion !== null && semverGte(validVersion, FIRST_CODE_MODE_WORKER_VERSION));
const includeCodeModeWorkerInInventory =
options.includeCodeModeWorkerInInventory ?? includeCodeModeWorker;
const packageInventory = includeCodeModeWorkerInInventory
? [...new Set([...inventory, CODE_MODE_WORKER_PATH])]
: inventory;
const packageRoot = join(root, "package");
mkdirSync(join(packageRoot, "dist"), { recursive: true });
writeFileSync(
@@ -72,7 +86,7 @@ function withTarball(
);
writeFileSync(
join(packageRoot, "dist", "postinstall-inventory.json"),
JSON.stringify(inventory),
JSON.stringify(packageInventory),
);
const workspaceTemplates =
options.includeWorkspaceTemplates === false
@@ -113,6 +127,7 @@ function withTarball(
...controlUiFiles,
...installGuardFile,
...shrinkwrapFile,
...(includeCodeModeWorker ? { [CODE_MODE_WORKER_PATH]: "export {};\n" } : {}),
...files,
};
for (const [relativePath, body] of Object.entries(tarFiles)) {
@@ -349,6 +364,64 @@ describe("check-openclaw-package-tarball", () => {
);
});
it("accepts historical packages published before the Code Mode worker existed", () => {
withTarball(
["dist/index.js"],
{ "dist/index.js": "export {};\n" },
(tarball) => {
const result = spawnSync("node", [CHECK_SCRIPT, tarball], { encoding: "utf8" });
expect(result.status, result.stderr).toBe(0);
expect(result.stdout).toContain("OpenClaw package tarball integrity passed.");
},
"2026.5.14-beta.1",
);
});
it("rejects Code Mode packages that omit the dynamically loaded worker", () => {
withTarball(
["dist/index.js"],
{ "dist/index.js": "export {};\n" },
(tarball) => {
const result = spawnSync("node", [CHECK_SCRIPT, tarball], { encoding: "utf8" });
expect(result.status).not.toBe(0);
expect(result.stderr).toContain(`missing required tar entry ${CODE_MODE_WORKER_PATH}`);
},
FIRST_CODE_MODE_WORKER_VERSION,
{ includeCodeModeWorker: false },
);
});
it("rejects Code Mode workers that postinstall would remove", () => {
withTarball(
["dist/index.js"],
{ "dist/index.js": "export {};\n" },
(tarball) => {
const result = spawnSync("node", [CHECK_SCRIPT, tarball], { encoding: "utf8" });
expect(result.status).not.toBe(0);
expect(result.stderr).toContain(`postinstall inventory omits ${CODE_MODE_WORKER_PATH}`);
},
FIRST_CODE_MODE_WORKER_VERSION,
{ includeCodeModeWorkerInInventory: false },
);
});
it("accepts Code Mode packages whose worker survives postinstall", () => {
withTarball(
["dist/index.js"],
{ "dist/index.js": "export {};\n" },
(tarball) => {
const result = spawnSync("node", [CHECK_SCRIPT, tarball], { encoding: "utf8" });
expect(result.status, result.stderr).toBe(0);
expect(result.stdout).toContain("OpenClaw package tarball integrity passed.");
},
FIRST_CODE_MODE_WORKER_VERSION,
);
});
it("rejects dist files that import missing relative chunks", () => {
withTarball(
["dist/cli/run-main.js"],