Files
openclaw/src/cli/daemon-cli/lifecycle-core.test.ts
Vincent Koc 2c7fb54956 Config: fail closed invalid config loads (#39071)
* Config: fail closed invalid config loads

* CLI: keep diagnostics on explicit best-effort config

* Tests: cover invalid config best-effort diagnostics

* Changelog: note invalid config fail-closed fix

* Status: pass best-effort config through status-all gateway RPCs

* CLI: pass config through gateway secret RPC

* CLI: skip plugin loading from invalid config

* Tests: align daemon token drift env precedence
2026-03-07 17:48:13 -08:00

134 lines
3.6 KiB
TypeScript

import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const loadConfig = vi.fn(() => ({
gateway: {
auth: {
token: "config-token",
},
},
}));
const runtimeLogs: string[] = [];
const defaultRuntime = {
log: (message: string) => runtimeLogs.push(message),
error: vi.fn(),
exit: (code: number) => {
throw new Error(`__exit__:${code}`);
},
};
const service = {
label: "TestService",
loadedText: "loaded",
notLoadedText: "not loaded",
install: vi.fn(),
uninstall: vi.fn(),
stop: vi.fn(),
isLoaded: vi.fn(),
readCommand: vi.fn(),
readRuntime: vi.fn(),
restart: vi.fn(),
};
vi.mock("../../config/config.js", () => ({
loadConfig: () => loadConfig(),
readBestEffortConfig: async () => loadConfig(),
}));
vi.mock("../../runtime.js", () => ({
defaultRuntime,
}));
let runServiceRestart: typeof import("./lifecycle-core.js").runServiceRestart;
describe("runServiceRestart token drift", () => {
beforeAll(async () => {
({ runServiceRestart } = await import("./lifecycle-core.js"));
});
beforeEach(() => {
runtimeLogs.length = 0;
loadConfig.mockReset();
loadConfig.mockReturnValue({
gateway: {
auth: {
token: "config-token",
},
},
});
service.isLoaded.mockClear();
service.readCommand.mockClear();
service.restart.mockClear();
service.isLoaded.mockResolvedValue(true);
service.readCommand.mockResolvedValue({
environment: { OPENCLAW_GATEWAY_TOKEN: "service-token" },
});
service.restart.mockResolvedValue(undefined);
vi.unstubAllEnvs();
vi.stubEnv("OPENCLAW_GATEWAY_TOKEN", "");
vi.stubEnv("CLAWDBOT_GATEWAY_TOKEN", "");
vi.stubEnv("OPENCLAW_GATEWAY_URL", "");
vi.stubEnv("CLAWDBOT_GATEWAY_URL", "");
});
it("emits drift warning when enabled", async () => {
await runServiceRestart({
serviceNoun: "Gateway",
service,
renderStartHints: () => [],
opts: { json: true },
checkTokenDrift: true,
});
expect(loadConfig).toHaveBeenCalledTimes(1);
const jsonLine = runtimeLogs.find((line) => line.trim().startsWith("{"));
const payload = JSON.parse(jsonLine ?? "{}") as { warnings?: string[] };
expect(payload.warnings).toEqual(
expect.arrayContaining([expect.stringContaining("gateway install --force")]),
);
});
it("compares restart drift against config token even when caller env is set", async () => {
loadConfig.mockReturnValue({
gateway: {
auth: {
token: "config-token",
},
},
});
service.readCommand.mockResolvedValue({
environment: { OPENCLAW_GATEWAY_TOKEN: "env-token" },
});
vi.stubEnv("OPENCLAW_GATEWAY_TOKEN", "env-token");
await runServiceRestart({
serviceNoun: "Gateway",
service,
renderStartHints: () => [],
opts: { json: true },
checkTokenDrift: true,
});
const jsonLine = runtimeLogs.find((line) => line.trim().startsWith("{"));
const payload = JSON.parse(jsonLine ?? "{}") as { warnings?: string[] };
expect(payload.warnings).toEqual(
expect.arrayContaining([expect.stringContaining("gateway install --force")]),
);
});
it("skips drift warning when disabled", async () => {
await runServiceRestart({
serviceNoun: "Node",
service,
renderStartHints: () => [],
opts: { json: true },
});
expect(loadConfig).not.toHaveBeenCalled();
expect(service.readCommand).not.toHaveBeenCalled();
const jsonLine = runtimeLogs.find((line) => line.trim().startsWith("{"));
const payload = JSON.parse(jsonLine ?? "{}") as { warnings?: string[] };
expect(payload.warnings).toBeUndefined();
});
});