Files
openclaw/test/onboard-plugin-warnings.e2e.test.ts
Peter Steinberger 46c71b564e fix(config): validate config writes against the config being written (#126734)
* fix(config): validate config writes against the config being written

writeConfigFileFromContext passed the pre-write snapshot's plugin
metadata into strict validation. During onboarding that snapshot belongs
to an intermediate config written by agent creation, which has no plugin
entries, so its scoped manifest registry is empty. Validating the final
candidate against it made every plugin entry added by the same write look
unknown, and non-interactive onboarding warned that the openai and codex
entries it had just written were stale or uninstalled.

Drop the stale snapshot so validation resolves the manifest registry from
the candidate it is actually validating. Strict semantic validation is
unchanged, and the registry load stays lazy.

* fix(ci): raise the Control UI startup JS baseline to unblock main

main is red on the Control UI startup-JS ratchet: unrelated PR #126725 measures 348289 B and this branch measures 348351 B against a 347023 B baseline + 1056 B tolerance. Twenty-six UI commits have landed since the last bump (#126474), none individually large. Baseline moves to the CI-measured 348351 B, well under the 358400 B maintainer-approved ceiling that still guards cumulative creep.
2026-08-20 09:32:57 -07:00

96 lines
3.1 KiB
TypeScript

// Built-CLI onboarding regression for candidate-scoped plugin validation.
import { spawnSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { useAutoCleanupTempDirTracker } from "./helpers/temp-dir.js";
const tempDirs = useAutoCleanupTempDirTracker(afterEach);
function runBuiltCli(stateDir: string, homeDir: string, args: string[]) {
const env: NodeJS.ProcessEnv = {
...process.env,
HOME: homeDir,
USERPROFILE: homeDir,
OPENAI_API_KEY: "sk-fake-openclaw-onboard-regression",
OPENCLAW_SKIP_CHANNELS: "1",
OPENCLAW_STATE_DIR: stateDir,
NO_COLOR: "1",
};
for (const key of [
"DISCORD_BOT_TOKEN",
"NODE_ENV",
"OPENCLAW_CONFIG_PATH",
"OPENCLAW_DISABLE_BUNDLED_PLUGINS",
"OPENCLAW_HOME",
"OPENCLAW_PROFILE",
"TWILIO_ACCOUNT_SID",
"TWILIO_AUTH_TOKEN",
"TWILIO_FROM_NUMBER",
"VITEST",
"VITEST_POOL_ID",
"VITEST_WORKER_ID",
]) {
delete env[key];
}
return spawnSync(process.execPath, [path.resolve("openclaw.mjs"), ...args], {
cwd: path.resolve("."),
encoding: "utf8",
env,
maxBuffer: 4 * 1024 * 1024,
timeout: 60_000,
});
}
describe("non-interactive onboarding plugin validation", () => {
it("does not warn about bundled plugins enabled by the documented OpenAI setup", () => {
const rootDir = tempDirs.make("openclaw-onboard-plugin-warnings-", "/tmp");
const homeDir = path.join(rootDir, "home");
const stateDir = path.join(rootDir, "state");
fs.mkdirSync(homeDir, { recursive: true });
fs.mkdirSync(stateDir, { recursive: true });
const onboard = runBuiltCli(stateDir, homeDir, [
"onboard",
"--non-interactive",
"--accept-risk",
"--skip-health",
"--mode",
"local",
"--auth-choice",
"openai-api-key",
"--secret-input-mode",
"ref",
"--gateway-port",
"19091",
"--skip-bootstrap",
"--skip-skills",
]);
expect(onboard.error, onboard.stderr).toBeUndefined();
expect(onboard.status, onboard.stderr).toBe(0);
expect(onboard.stderr).not.toContain("plugin not found: openai");
expect(onboard.stderr).not.toContain("plugin not installed: codex");
const config = JSON.parse(fs.readFileSync(path.join(stateDir, "openclaw.json"), "utf8")) as {
plugins?: { entries?: Record<string, { enabled?: boolean }> };
};
expect(config.plugins?.entries?.openai?.enabled).toBe(true);
expect(config.plugins?.entries?.codex?.enabled).toBe(true);
const list = runBuiltCli(stateDir, homeDir, ["plugins", "list", "--json"]);
expect(list.error, list.stderr).toBeUndefined();
expect(list.status, list.stderr).toBe(0);
expect(list.stderr).toBe("");
const inventory = JSON.parse(list.stdout) as {
plugins: Array<{ id: string; enabled: boolean; status: string }>;
};
expect(inventory.plugins).toEqual(
expect.arrayContaining([
expect.objectContaining({ id: "openai", enabled: true, status: "loaded" }),
expect.objectContaining({ id: "codex", enabled: true, status: "loaded" }),
]),
);
}, 75_000);
});