Files
openclaw/test/scripts/bundled-plugin-build-entries.test.ts
Peter Steinberger f94a7dc183 feat(codex): supervise native Codex sessions (#104045)
* feat(codex): add native session supervision

* fix(codex): harden supervision integration

* fix(codex): preserve locked harness ownership

* fix(codex): fence native session archive

* fix(codex): revalidate archive binding ownership

* feat(codex): integrate supervision runtime

* feat(sessions): preserve harness-owned execution

* feat(sessions): persist harness ownership invariants

* feat(gateway): enforce harness-owned sessions

* feat(setup): enable detected Codex supervision

* feat(mac): expose supervised Codex sessions

* feat(ui): make Codex sessions actionable

* docs(codex): document session supervision

* test(codex): cover integration ownership

* chore(i18n): refresh supervision inventories

* fix(setup): finalize Codex activation atomically

* test(codex): narrow binding store update

* fix(sessions): preserve legacy model locks

* test(macos): serialize Codex catalog fixtures

* fix(sessions): preserve legacy lock admission

* chore(i18n): reconcile supervision metadata

* test(sessions): mark legacy lock fixture

* fix(macos): drain final Codex catalog frame

* docs: leave supervision note to release

* style(macos): satisfy Codex catalog type length

* chore: record session accessor seam owners

* fix(macos): honor configured Codex supervision

* fix(codex): preserve harness-owned model locks

* fix(codex): satisfy supervision lint gates

* chore(i18n): refresh native supervision inventory

* fix(codex): align supervision validation contracts

* fix(codex): close supervision boundary gaps

* fix(codex): preserve supervision activation contracts

* fix(codex): dispose standalone supervision runtime

* fix(codex): pin supervised source connection

* fix(plugins): bind delegated runs to exact session target

* fix(codex): scope supervised sessions to configured agents

* fix(codex): fingerprint effective supervision home

* fix(codex): normalize supervision plugin policy

* fix(codex): keep supervised bindings stable across upgrades

* fix(codex): guard all supervised binding connections

* fix(codex): preserve catalog filters and pending CAS identity

* fix(codex): preserve supervision identity for diagnostics

* fix(codex): bind uncertain commits to supervision connection

* fix(codex): satisfy supervision type boundaries

* fix(macos): reconcile current main validation

* fix(codex): handle absent runtime config in supervision

* fix(doctor): own local audio acceleration check

* fix(codex): satisfy integration lint gates

* fix(codex): satisfy lifecycle safety guards
2026-07-11 00:12:08 -07:00

453 lines
17 KiB
TypeScript

// Bundled Plugin Build Entries tests cover bundled plugin build entries script behavior.
import fs from "node:fs";
import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
collectRootPackageExcludedExtensionDirs,
DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV,
listBundledPluginBuildEntries,
listBundledPluginPackArtifacts,
} from "../../scripts/lib/bundled-plugin-build-entries.mjs";
import { expectNoNodeFsScans } from "../../src/test-utils/fs-scan-assertions.js";
import { useAutoCleanupTempDirTracker } from "../helpers/temp-dir.js";
const tempDirs = useAutoCleanupTempDirTracker(afterEach);
function expectNoPrefixMatches(values: string[], prefix: string) {
expect(values.filter((value) => value.startsWith(prefix))).toEqual([]);
}
function expectSomePrefixMatch(values: string[], prefix: string) {
expect(values.filter((value) => value.startsWith(prefix))).not.toEqual([]);
}
function pickEntries(entries: Record<string, string>, keys: readonly string[]) {
return Object.fromEntries(keys.map((key) => [key, entries[key]]));
}
describe("bundled plugin build entries", () => {
const bundledChannelEntrySources = ["index.ts", "channel-entry.ts", "setup-entry.ts"];
const forEachBundledChannelEntry = (
visit: (params: { entryPath: string; entry: string; pluginId: string }) => void,
) => {
for (const dirent of fs.readdirSync("extensions", { withFileTypes: true })) {
if (!dirent.isDirectory()) {
continue;
}
for (const sourceEntry of bundledChannelEntrySources) {
const entryPath = path.join("extensions", dirent.name, sourceEntry);
if (!fs.existsSync(entryPath)) {
continue;
}
visit({
entryPath,
entry: fs.readFileSync(entryPath, "utf8"),
pluginId: dirent.name,
});
}
}
};
it("includes manifest-less runtime core support packages in dist build entries", () => {
const entries = listBundledPluginBuildEntries();
const expectedEntries = {
"extensions/image-generation-core/api": "extensions/image-generation-core/api.ts",
"extensions/image-generation-core/runtime-api":
"extensions/image-generation-core/runtime-api.ts",
"extensions/media-understanding-core/runtime-api":
"extensions/media-understanding-core/runtime-api.ts",
};
expect(pickEntries(entries, Object.keys(expectedEntries))).toStrictEqual(expectedEntries);
});
it("keeps the Matrix packaged runtime shim in bundled plugin build entries", () => {
const entries = listBundledPluginBuildEntries();
const expectedEntries = {
"extensions/matrix/plugin-entry.handlers.runtime":
"extensions/matrix/plugin-entry.handlers.runtime.ts",
};
expect(pickEntries(entries, Object.keys(expectedEntries))).toStrictEqual(expectedEntries);
});
it("keeps Codex CLI metadata in bundled build and standalone pack entries", () => {
const entries = listBundledPluginBuildEntries();
const artifacts = listBundledPluginPackArtifacts({ includeRootPackageExcludedDirs: true });
expect(entries["extensions/codex/cli-metadata"]).toBe("extensions/codex/cli-metadata.ts");
expect(artifacts).toContain("dist/extensions/codex/cli-metadata.js");
});
it("filters bundled plugin build entries for bounded script lanes", () => {
const entries = listBundledPluginBuildEntries({
env: {
...process.env,
OPENCLAW_BUNDLED_PLUGIN_BUILD_IDS: "active-memory,acpx",
},
});
const entryKeys = Object.keys(entries);
expect(entryKeys).toEqual(expect.arrayContaining(["extensions/acpx/index"]));
expect(entryKeys.every((entry) => /^extensions\/(?:acpx|active-memory)\//u.test(entry))).toBe(
true,
);
});
it("rejects unknown bounded bundled plugin build ids", () => {
expect(() =>
listBundledPluginBuildEntries({
env: {
...process.env,
OPENCLAW_BUNDLED_PLUGIN_BUILD_IDS: "missing-plugin",
},
}),
).toThrow(
"OPENCLAW_BUNDLED_PLUGIN_BUILD_IDS references unknown bundled plugin id(s): missing-plugin",
);
});
it("keeps the Telegram ingress worker out of bundled plugin public-surface entries", () => {
const entries = listBundledPluginBuildEntries();
expect(entries["extensions/telegram/telegram-ingress-worker.runtime"]).toBeUndefined();
});
it("keeps top-level bundled plugin test helpers out of public-surface entries", () => {
const entries = listBundledPluginBuildEntries();
expect(entries["extensions/browser/test-support"]).toBeUndefined();
expect(entries["extensions/comfy/test-helpers"]).toBeUndefined();
expect(entries["extensions/minimax/provider-http.test-helpers"]).toBeUndefined();
});
it("discovers repo plugin build entries without directory scans", () => {
const payload = expectNoNodeFsScans<{
artifacts: number;
entries: number;
}>(
`
const build = await import("./scripts/lib/bundled-plugin-build-entries.mjs");
const entries = build.listBundledPluginBuildEntries();
const artifacts = build.listBundledPluginPackArtifacts();
return {
artifacts: artifacts.length,
entries: Object.keys(entries).length,
};
`,
{ counters: ["readdirSync"] },
);
expect(payload.entries).toBeGreaterThan(0);
expect(payload.artifacts).toBeGreaterThan(0);
});
it("packs runtime core support packages without requiring plugin manifests", () => {
const artifacts = listBundledPluginPackArtifacts();
expect(artifacts).toContain("dist/extensions/image-generation-core/package.json");
expect(artifacts).toContain("dist/extensions/image-generation-core/runtime-api.js");
expect(artifacts).not.toContain("dist/extensions/image-generation-core/openclaw.plugin.json");
expect(artifacts).toContain("dist/extensions/media-understanding-core/runtime-api.js");
expect(artifacts).not.toContain(
"dist/extensions/media-understanding-core/openclaw.plugin.json",
);
});
it("packs the Matrix packaged runtime shim", () => {
const artifacts = listBundledPluginPackArtifacts({ includeRootPackageExcludedDirs: true });
expect(artifacts).toContain("dist/extensions/matrix/plugin-entry.handlers.runtime.js");
});
it("keeps private QA bundles out of required npm pack artifacts", () => {
const artifacts = listBundledPluginPackArtifacts();
expectNoPrefixMatches(artifacts, "dist/extensions/qa-channel/");
expectNoPrefixMatches(artifacts, "dist/extensions/qa-lab/");
expectNoPrefixMatches(artifacts, "dist/extensions/qa-matrix/");
});
it("keeps explicitly downloadable plugins out of bundled package artifacts", () => {
const entries = listBundledPluginBuildEntries();
const artifacts = listBundledPluginPackArtifacts();
for (const pluginId of ["acpx", "googlechat", "line"]) {
expectSomePrefixMatch(Object.keys(entries), `extensions/${pluginId}/`);
expectNoPrefixMatches(artifacts, `dist/extensions/${pluginId}/`);
}
for (const pluginId of ["qqbot", "whatsapp"]) {
expectNoPrefixMatches(Object.keys(entries), `extensions/${pluginId}/`);
expectNoPrefixMatches(artifacts, `dist/extensions/${pluginId}/`);
}
});
it("keeps external-only providers out of bundled dist entries", () => {
const entries = listBundledPluginBuildEntries();
const artifacts = listBundledPluginPackArtifacts();
for (const pluginId of ["amazon-bedrock", "amazon-bedrock-mantle", "anthropic-vertex"]) {
expectNoPrefixMatches(Object.keys(entries), `extensions/${pluginId}/`);
expectNoPrefixMatches(artifacts, `dist/extensions/${pluginId}/`);
}
});
it("keeps externalized runtime-dependency plugins out of bundled dist entries", () => {
const entries = listBundledPluginBuildEntries();
const artifacts = listBundledPluginPackArtifacts();
for (const pluginId of ["copilot", "openshell", "slack", "tokenjuice"]) {
expectNoPrefixMatches(Object.keys(entries), `extensions/${pluginId}/`);
expectNoPrefixMatches(artifacts, `dist/extensions/${pluginId}/`);
}
});
it("builds explicitly selected external plugins only for Docker", () => {
const baselineEnv = { ...process.env };
delete baselineEnv[DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV];
const dockerEnv = {
...baselineEnv,
[DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV]: "slack clickclack,slack,msteams",
};
const entries = listBundledPluginBuildEntries({ env: dockerEnv });
const baselineArtifacts = listBundledPluginPackArtifacts({ env: baselineEnv });
const artifacts = listBundledPluginPackArtifacts({ env: dockerEnv });
const reorderedEntries = listBundledPluginBuildEntries({
env: {
...baselineEnv,
[DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV]: "msteams,clickclack slack",
},
});
const entryKeys = Object.keys(entries);
expect(entries["extensions/clickclack/index"]).toBe("extensions/clickclack/index.ts");
expect(entries["extensions/slack/index"]).toBe("extensions/slack/index.ts");
expect(entries["extensions/slack/setup-entry"]).toBe("extensions/slack/setup-entry.ts");
expect(entries["extensions/msteams/index"]).toBe("extensions/msteams/index.ts");
expect(entries["extensions/clawrouter/index"]).toBe("extensions/clawrouter/index.ts");
expect(entryKeys.findIndex((entry) => entry.startsWith("extensions/clickclack/"))).toBeLessThan(
entryKeys.findIndex((entry) => entry.startsWith("extensions/slack/")),
);
expect(Object.keys(reorderedEntries)).toEqual(entryKeys);
expect(artifacts).toEqual(baselineArtifacts);
expectNoPrefixMatches(artifacts, "dist/extensions/clickclack/");
expectNoPrefixMatches(artifacts, "dist/extensions/msteams/");
expectNoPrefixMatches(artifacts, "dist/extensions/slack/");
});
it("sorts Docker-selected build entries without git metadata", () => {
const repoDir = tempDirs.make("openclaw-docker-build-entries-");
const extensionsDir = path.join(repoDir, "extensions");
for (const pluginId of ["clickclack", "msteams", "slack"]) {
const pluginDir = path.join(extensionsDir, pluginId);
fs.mkdirSync(pluginDir, { recursive: true });
fs.writeFileSync(path.join(pluginDir, "index.ts"), "export default {};\n");
fs.writeFileSync(
path.join(pluginDir, "openclaw.plugin.json"),
`${JSON.stringify({ id: pluginId })}\n`,
);
fs.writeFileSync(
path.join(pluginDir, "package.json"),
`${JSON.stringify({
name: `@openclaw/${pluginId}`,
openclaw: {
extensions: ["./index.ts"],
build: { bundledDist: false },
},
})}\n`,
);
}
const unsortedDirents = fs.readdirSync(extensionsDir, { withFileTypes: true }).toReversed();
const readdirSpy = vi
.spyOn(fs, "readdirSync")
.mockImplementationOnce(() => unsortedDirents as never);
try {
expect(
Object.keys(
listBundledPluginBuildEntries({
cwd: repoDir,
env: {
...process.env,
[DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV]: "slack,msteams,clickclack",
},
}),
),
).toEqual([
"extensions/clickclack/index",
"extensions/msteams/index",
"extensions/slack/index",
]);
} finally {
readdirSpy.mockRestore();
}
});
it("preserves known dependency-only Docker plugin selections", () => {
const baselineEnv = { ...process.env };
delete baselineEnv[DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV];
const baselineEntries = listBundledPluginBuildEntries({ env: baselineEnv });
const selectedEntries = listBundledPluginBuildEntries({
env: {
...baselineEnv,
[DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV]: "whatsapp,qqbot",
},
});
expect(selectedEntries).toEqual(baselineEntries);
expectNoPrefixMatches(Object.keys(selectedEntries), "extensions/qqbot/");
expectNoPrefixMatches(Object.keys(selectedEntries), "extensions/whatsapp/");
});
it("preserves known package-less bundled Docker plugin selections", () => {
const baselineEnv = { ...process.env };
delete baselineEnv[DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV];
const baselineEntries = listBundledPluginBuildEntries({ env: baselineEnv });
const selectedEntries = listBundledPluginBuildEntries({
env: {
...baselineEnv,
[DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV]: "active-memory",
},
});
expect(selectedEntries).toEqual(baselineEntries);
expect(selectedEntries["extensions/active-memory/index"]).toBe(
"extensions/active-memory/index.ts",
);
});
it("rejects unknown and invalid Docker plugin selections", () => {
for (const [selection, message] of [
[
"missing-plugin",
`${DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV} references unknown plugin id(s): missing-plugin`,
],
[
"../clickclack",
`${DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV} contains invalid plugin id(s): ../clickclack`,
],
] as const) {
expect(() =>
listBundledPluginBuildEntries({
env: {
...process.env,
[DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV]: selection,
},
}),
).toThrow(message);
}
});
it("keeps Cohere bundled through the externalization transition", () => {
const artifacts = listBundledPluginPackArtifacts();
expect(artifacts).toContain("dist/extensions/cohere/index.js");
expect(artifacts).toContain("dist/extensions/cohere/openclaw.plugin.json");
expect(artifacts).toContain("dist/extensions/cohere/package.json");
});
it("keeps bundled channel secret contracts on packed top-level sidecars", () => {
const artifacts = listBundledPluginPackArtifacts();
const excludedPackageDirs = collectRootPackageExcludedExtensionDirs();
const offenders: string[] = [];
const secretBackedPluginIds = new Set<string>();
forEachBundledChannelEntry(({ entryPath, entry, pluginId }) => {
if (!entry.includes('exportName: "channelSecrets"')) {
return;
}
secretBackedPluginIds.add(pluginId);
if (entry.includes("./src/secret-contract.js")) {
offenders.push(entryPath);
}
expect(entry).toContain('specifier: "./secret-contract-api.js"');
});
expect(offenders).toStrictEqual([]);
for (const pluginId of [...secretBackedPluginIds].toSorted()) {
if (excludedPackageDirs.has(pluginId)) {
continue;
}
const secretApiPath = path.join("extensions", pluginId, "secret-contract-api.ts");
expect(fs.readFileSync(secretApiPath, "utf8")).toContain("channelSecrets");
expect(artifacts).toContain(`dist/extensions/${pluginId}/secret-contract-api.js`);
}
});
it("keeps dedicated channel contract exports off broad contract-api sidecars", () => {
const duplicateExportMarkersByArtifact = {
"directory-contract-api.ts": [
"DirectoryContractPlugin",
"DirectoryGroupsFromConfig",
"DirectoryPeersFromConfig",
],
"doctor-contract-api.ts": [
"legacyConfigRules",
"normalizeCompatibilityConfig",
"stateMigrations",
],
"secret-contract-api.ts": [
"channelSecrets",
"collectRuntimeConfigAssignments",
"secretTargetRegistryEntries",
],
"security-audit-contract-api.ts": ["SecurityAuditFindings"],
"security-contract-api.ts": [
"collectUnsupportedSecretRefConfigCandidates",
"unsupportedSecretRefSurfacePatterns",
],
"session-binding-contract-api.ts": [
"ConversationBindingManager",
"ThreadBindingManager",
"ThreadBindingsForTests",
"setMatrixRuntime",
],
} as const;
const offenders: string[] = [];
for (const dirent of fs.readdirSync("extensions", { withFileTypes: true })) {
if (!dirent.isDirectory()) {
continue;
}
const contractApiPath = path.join("extensions", dirent.name, "contract-api.ts");
if (!fs.existsSync(contractApiPath)) {
continue;
}
const contractApi = fs.readFileSync(contractApiPath, "utf8");
for (const [artifact, markers] of Object.entries(duplicateExportMarkersByArtifact)) {
if (!fs.existsSync(path.join("extensions", dirent.name, artifact))) {
continue;
}
for (const marker of markers) {
if (contractApi.includes(marker)) {
offenders.push(`${contractApiPath} duplicates ${artifact}: ${marker}`);
}
}
}
}
expect(offenders).toStrictEqual([]);
});
it("keeps bundled channel entry metadata on packed top-level sidecars", () => {
const offenders: string[] = [];
forEachBundledChannelEntry(({ entryPath, entry }) => {
if (
!entry.includes("defineBundledChannelEntry") &&
!entry.includes("defineBundledChannelSetupEntry")
) {
return;
}
if (/specifier:\s*["']\.\/src\//u.test(entry)) {
offenders.push(entryPath);
}
});
expect(offenders).toStrictEqual([]);
});
});