mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 01:31:08 +00:00
refactor: dedupe test helpers and script warning filter
This commit is contained in:
32
scripts/process-warning-filter.mjs
Normal file
32
scripts/process-warning-filter.mjs
Normal file
@@ -0,0 +1,32 @@
|
||||
const warningFilterKey = Symbol.for("openclaw.warning-filter");
|
||||
|
||||
export function installProcessWarningFilter() {
|
||||
if (globalThis[warningFilterKey]?.installed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const originalEmitWarning = process.emitWarning.bind(process);
|
||||
process.emitWarning = (...args) => {
|
||||
const [warningArg, secondArg, thirdArg] = args;
|
||||
const warning =
|
||||
warningArg instanceof Error
|
||||
? {
|
||||
name: warningArg.name,
|
||||
message: warningArg.message,
|
||||
code: warningArg.code,
|
||||
}
|
||||
: {
|
||||
name: typeof secondArg === "string" ? secondArg : secondArg?.type,
|
||||
message: typeof warningArg === "string" ? warningArg : undefined,
|
||||
code: typeof thirdArg === "string" ? thirdArg : secondArg?.code,
|
||||
};
|
||||
|
||||
if (warning.code === "DEP0040" && warning.message?.includes("punycode")) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Reflect.apply(originalEmitWarning, process, args);
|
||||
};
|
||||
|
||||
globalThis[warningFilterKey] = { installed: true };
|
||||
}
|
||||
@@ -2,39 +2,7 @@ import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
|
||||
const warningFilterKey = Symbol.for("openclaw.warning-filter");
|
||||
|
||||
function installProcessWarningFilter() {
|
||||
if (globalThis[warningFilterKey]?.installed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const originalEmitWarning = process.emitWarning.bind(process);
|
||||
process.emitWarning = (...args) => {
|
||||
const [warningArg, secondArg, thirdArg] = args;
|
||||
const warning =
|
||||
warningArg instanceof Error
|
||||
? {
|
||||
name: warningArg.name,
|
||||
message: warningArg.message,
|
||||
code: warningArg.code,
|
||||
}
|
||||
: {
|
||||
name: typeof secondArg === "string" ? secondArg : secondArg?.type,
|
||||
message: typeof warningArg === "string" ? warningArg : undefined,
|
||||
code: typeof thirdArg === "string" ? thirdArg : secondArg?.code,
|
||||
};
|
||||
|
||||
if (warning.code === "DEP0040" && warning.message?.includes("punycode")) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Reflect.apply(originalEmitWarning, process, args);
|
||||
};
|
||||
|
||||
globalThis[warningFilterKey] = { installed: true };
|
||||
}
|
||||
import { installProcessWarningFilter } from "./process-warning-filter.mjs";
|
||||
|
||||
installProcessWarningFilter();
|
||||
|
||||
|
||||
@@ -3,41 +3,9 @@ import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import { installProcessWarningFilter } from "./process-warning-filter.mjs";
|
||||
import { stageBundledPluginRuntime } from "./stage-bundled-plugin-runtime.mjs";
|
||||
|
||||
const warningFilterKey = Symbol.for("openclaw.warning-filter");
|
||||
|
||||
function installProcessWarningFilter() {
|
||||
if (globalThis[warningFilterKey]?.installed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const originalEmitWarning = process.emitWarning.bind(process);
|
||||
process.emitWarning = (...args) => {
|
||||
const [warningArg, secondArg, thirdArg] = args;
|
||||
const warning =
|
||||
warningArg instanceof Error
|
||||
? {
|
||||
name: warningArg.name,
|
||||
message: warningArg.message,
|
||||
code: warningArg.code,
|
||||
}
|
||||
: {
|
||||
name: typeof secondArg === "string" ? secondArg : secondArg?.type,
|
||||
message: typeof warningArg === "string" ? warningArg : undefined,
|
||||
code: typeof thirdArg === "string" ? thirdArg : secondArg?.code,
|
||||
};
|
||||
|
||||
if (warning.code === "DEP0040" && warning.message?.includes("punycode")) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Reflect.apply(originalEmitWarning, process, args);
|
||||
};
|
||||
|
||||
globalThis[warningFilterKey] = { installed: true };
|
||||
}
|
||||
|
||||
installProcessWarningFilter();
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
|
||||
@@ -60,6 +60,38 @@ function createBackendEntry(params: {
|
||||
};
|
||||
}
|
||||
|
||||
function createClaudeCliOverrideConfig(config: CliBackendConfig): OpenClawConfig {
|
||||
return {
|
||||
agents: {
|
||||
defaults: {
|
||||
cliBackends: {
|
||||
"claude-cli": config,
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies OpenClawConfig;
|
||||
}
|
||||
|
||||
const NORMALIZED_CLAUDE_FALLBACK_ARGS = [
|
||||
"-p",
|
||||
"--output-format",
|
||||
"stream-json",
|
||||
"--setting-sources",
|
||||
"user",
|
||||
"--permission-mode",
|
||||
"bypassPermissions",
|
||||
];
|
||||
|
||||
const NORMALIZED_CLAUDE_FALLBACK_RESUME_ARGS = [
|
||||
"-p",
|
||||
"--resume",
|
||||
"{sessionId}",
|
||||
"--setting-sources",
|
||||
"user",
|
||||
"--permission-mode",
|
||||
"bypassPermissions",
|
||||
];
|
||||
|
||||
beforeAll(async () => {
|
||||
vi.doUnmock("../plugins/setup-registry.js");
|
||||
vi.doUnmock("../plugins/cli-backends.runtime.js");
|
||||
@@ -449,79 +481,31 @@ describe("resolveCliBackendConfig claude-cli defaults", () => {
|
||||
});
|
||||
|
||||
it("falls back to user-only setting sources when a custom override leaves the flag without a value", () => {
|
||||
const cfg = {
|
||||
agents: {
|
||||
defaults: {
|
||||
cliBackends: {
|
||||
"claude-cli": {
|
||||
command: "claude",
|
||||
args: ["-p", "--setting-sources", "--output-format", "stream-json"],
|
||||
resumeArgs: ["-p", "--setting-sources", "--resume", "{sessionId}"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies OpenClawConfig;
|
||||
const cfg = createClaudeCliOverrideConfig({
|
||||
command: "claude",
|
||||
args: ["-p", "--setting-sources", "--output-format", "stream-json"],
|
||||
resumeArgs: ["-p", "--setting-sources", "--resume", "{sessionId}"],
|
||||
});
|
||||
|
||||
const resolved = resolveCliBackendConfig("claude-cli", cfg);
|
||||
|
||||
expect(resolved).not.toBeNull();
|
||||
expect(resolved?.config.args).toEqual([
|
||||
"-p",
|
||||
"--output-format",
|
||||
"stream-json",
|
||||
"--setting-sources",
|
||||
"user",
|
||||
"--permission-mode",
|
||||
"bypassPermissions",
|
||||
]);
|
||||
expect(resolved?.config.resumeArgs).toEqual([
|
||||
"-p",
|
||||
"--resume",
|
||||
"{sessionId}",
|
||||
"--setting-sources",
|
||||
"user",
|
||||
"--permission-mode",
|
||||
"bypassPermissions",
|
||||
]);
|
||||
expect(resolved?.config.args).toEqual(NORMALIZED_CLAUDE_FALLBACK_ARGS);
|
||||
expect(resolved?.config.resumeArgs).toEqual(NORMALIZED_CLAUDE_FALLBACK_RESUME_ARGS);
|
||||
});
|
||||
|
||||
it("falls back to bypassPermissions when a custom override leaves permission-mode without a value", () => {
|
||||
const cfg = {
|
||||
agents: {
|
||||
defaults: {
|
||||
cliBackends: {
|
||||
"claude-cli": {
|
||||
command: "claude",
|
||||
args: ["-p", "--permission-mode", "--output-format", "stream-json"],
|
||||
resumeArgs: ["-p", "--permission-mode", "--resume", "{sessionId}"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies OpenClawConfig;
|
||||
const cfg = createClaudeCliOverrideConfig({
|
||||
command: "claude",
|
||||
args: ["-p", "--permission-mode", "--output-format", "stream-json"],
|
||||
resumeArgs: ["-p", "--permission-mode", "--resume", "{sessionId}"],
|
||||
});
|
||||
|
||||
const resolved = resolveCliBackendConfig("claude-cli", cfg);
|
||||
|
||||
expect(resolved).not.toBeNull();
|
||||
expect(resolved?.config.args).toEqual([
|
||||
"-p",
|
||||
"--output-format",
|
||||
"stream-json",
|
||||
"--setting-sources",
|
||||
"user",
|
||||
"--permission-mode",
|
||||
"bypassPermissions",
|
||||
]);
|
||||
expect(resolved?.config.resumeArgs).toEqual([
|
||||
"-p",
|
||||
"--resume",
|
||||
"{sessionId}",
|
||||
"--setting-sources",
|
||||
"user",
|
||||
"--permission-mode",
|
||||
"bypassPermissions",
|
||||
]);
|
||||
expect(resolved?.config.args).toEqual(NORMALIZED_CLAUDE_FALLBACK_ARGS);
|
||||
expect(resolved?.config.resumeArgs).toEqual(NORMALIZED_CLAUDE_FALLBACK_RESUME_ARGS);
|
||||
});
|
||||
|
||||
it("injects bypassPermissions when custom args omit any permission flag", () => {
|
||||
|
||||
@@ -60,6 +60,36 @@ function createOptions(
|
||||
} as unknown as GatewayRequestHandlerOptions;
|
||||
}
|
||||
|
||||
function mockPairedOperatorDevice(): void {
|
||||
getPairedDeviceMock.mockResolvedValue({
|
||||
deviceId: "device-1",
|
||||
role: "operator",
|
||||
roles: ["operator"],
|
||||
scopes: ["operator.pairing"],
|
||||
tokens: {
|
||||
operator: {
|
||||
token: "old-token",
|
||||
role: "operator",
|
||||
scopes: ["operator.pairing"],
|
||||
createdAtMs: 123,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function mockRotateOperatorTokenSuccess(): void {
|
||||
rotateDeviceTokenMock.mockResolvedValue({
|
||||
ok: true,
|
||||
entry: {
|
||||
token: "new-token",
|
||||
role: "operator",
|
||||
scopes: ["operator.pairing"],
|
||||
createdAtMs: 456,
|
||||
rotatedAtMs: 789,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
describe("deviceHandlers", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
@@ -197,30 +227,8 @@ describe("deviceHandlers", () => {
|
||||
});
|
||||
|
||||
it("disconnects active clients after rotating a device token", async () => {
|
||||
getPairedDeviceMock.mockResolvedValue({
|
||||
deviceId: "device-1",
|
||||
role: "operator",
|
||||
roles: ["operator"],
|
||||
scopes: ["operator.pairing"],
|
||||
tokens: {
|
||||
operator: {
|
||||
token: "old-token",
|
||||
role: "operator",
|
||||
scopes: ["operator.pairing"],
|
||||
createdAtMs: 123,
|
||||
},
|
||||
},
|
||||
});
|
||||
rotateDeviceTokenMock.mockResolvedValue({
|
||||
ok: true,
|
||||
entry: {
|
||||
token: "new-token",
|
||||
role: "operator",
|
||||
scopes: ["operator.pairing"],
|
||||
createdAtMs: 456,
|
||||
rotatedAtMs: 789,
|
||||
},
|
||||
});
|
||||
mockPairedOperatorDevice();
|
||||
mockRotateOperatorTokenSuccess();
|
||||
const opts = createOptions(
|
||||
"device.token.rotate",
|
||||
{
|
||||
@@ -262,30 +270,8 @@ describe("deviceHandlers", () => {
|
||||
});
|
||||
|
||||
it("treats normalized device ids as self-owned for token rotation", async () => {
|
||||
getPairedDeviceMock.mockResolvedValue({
|
||||
deviceId: "device-1",
|
||||
role: "operator",
|
||||
roles: ["operator"],
|
||||
scopes: ["operator.pairing"],
|
||||
tokens: {
|
||||
operator: {
|
||||
token: "old-token",
|
||||
role: "operator",
|
||||
scopes: ["operator.pairing"],
|
||||
createdAtMs: 123,
|
||||
},
|
||||
},
|
||||
});
|
||||
rotateDeviceTokenMock.mockResolvedValue({
|
||||
ok: true,
|
||||
entry: {
|
||||
token: "new-token",
|
||||
role: "operator",
|
||||
scopes: ["operator.pairing"],
|
||||
createdAtMs: 456,
|
||||
rotatedAtMs: 789,
|
||||
},
|
||||
});
|
||||
mockPairedOperatorDevice();
|
||||
mockRotateOperatorTokenSuccess();
|
||||
const opts = createOptions(
|
||||
"device.token.rotate",
|
||||
{
|
||||
@@ -317,20 +303,7 @@ describe("deviceHandlers", () => {
|
||||
});
|
||||
|
||||
it("rejects rotating a token for a role that was never approved", async () => {
|
||||
getPairedDeviceMock.mockResolvedValue({
|
||||
deviceId: "device-1",
|
||||
role: "operator",
|
||||
roles: ["operator"],
|
||||
scopes: ["operator.pairing"],
|
||||
tokens: {
|
||||
operator: {
|
||||
token: "old-token",
|
||||
role: "operator",
|
||||
scopes: ["operator.pairing"],
|
||||
createdAtMs: 123,
|
||||
},
|
||||
},
|
||||
});
|
||||
mockPairedOperatorDevice();
|
||||
const opts = createOptions(
|
||||
"device.token.rotate",
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user