From c8d722d093a61b53540a488a615b5ea86623f6b7 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 18 Apr 2026 01:49:54 +0100 Subject: [PATCH] test: fix rebased local gates --- extensions/feishu/src/card-action.ts | 7 +- extensions/webhooks/src/http.ts | 4 +- extensions/xai/web-search.test.ts | 4 +- ...dded-helpers.isbillingerrormessage.test.ts | 9 +-- .../effective-tool-policy.ts | 5 +- src/agents/pi-embedded-runner/run.ts | 2 +- src/auto-reply/reply/get-reply-run.ts | 6 +- src/gateway/server-cron.test.ts | 15 ++-- src/gateway/server-methods/agent.test.ts | 81 ++++++++++--------- src/gateway/server-methods/send.test.ts | 12 +-- src/gateway/server-methods/send.ts | 5 +- .../exec-approval-command-display.test.ts | 10 +-- test/helpers/channels/registry-plugin.ts | 6 +- 13 files changed, 81 insertions(+), 85 deletions(-) diff --git a/extensions/feishu/src/card-action.ts b/extensions/feishu/src/card-action.ts index 0c53e105f40..a47bbb150a6 100644 --- a/extensions/feishu/src/card-action.ts +++ b/extensions/feishu/src/card-action.ts @@ -2,13 +2,13 @@ import type { ClawdbotConfig, RuntimeEnv } from "../runtime-api.js"; import { resolveFeishuRuntimeAccount } from "./accounts.js"; import { handleFeishuMessage, type FeishuMessageEvent } from "./bot.js"; import { decodeFeishuCardAction, buildFeishuCardActionTextFallback } from "./card-interaction.js"; -import { createFeishuClient } from "./client.js"; import { createApprovalCard, FEISHU_APPROVAL_CANCEL_ACTION, FEISHU_APPROVAL_CONFIRM_ACTION, FEISHU_APPROVAL_REQUEST_ACTION, } from "./card-ux-approval.js"; +import { createFeishuClient } from "./client.js"; import { sendCardFeishu, sendMessageFeishu } from "./send.js"; export type FeishuCardActionEvent = { @@ -234,7 +234,10 @@ async function resolveCardActionChatType(params: { normalizeResolvedCardActionChatType(response.data?.chat_mode) ?? normalizeResolvedCardActionChatType(response.data?.chat_type); if (resolvedChatType) { - resolvedChatTypeCache.set(cacheKey, { value: resolvedChatType, expiresAt: now + CHAT_TYPE_CACHE_TTL_MS }); + resolvedChatTypeCache.set(cacheKey, { + value: resolvedChatType, + expiresAt: now + CHAT_TYPE_CACHE_TTL_MS, + }); return resolvedChatType; } params.log( diff --git a/extensions/webhooks/src/http.ts b/extensions/webhooks/src/http.ts index f01d4839e08..365fc5767c5 100644 --- a/extensions/webhooks/src/http.ts +++ b/extensions/webhooks/src/http.ts @@ -724,9 +724,7 @@ export function createTaskFlowWebhookRequestHandler(params: { return false; } const resolvedSecret = await resolveTargetSecret(candidate); - return Boolean( - resolvedSecret && timingSafeEquals(resolvedSecret, presentedSecret), - ); + return Boolean(resolvedSecret && timingSafeEquals(resolvedSecret, presentedSecret)); }, }); if (!target) { diff --git a/extensions/xai/web-search.test.ts b/extensions/xai/web-search.test.ts index 519a479ce84..b9d2208aa08 100644 --- a/extensions/xai/web-search.test.ts +++ b/extensions/xai/web-search.test.ts @@ -1,6 +1,6 @@ import { NON_ENV_SECRETREF_MARKER } from "openclaw/plugin-sdk/provider-auth-runtime"; import { createNonExitingRuntime } from "openclaw/plugin-sdk/runtime-env"; -import { withEnv } from "openclaw/plugin-sdk/testing"; +import { withEnv, withEnvAsync } from "openclaw/plugin-sdk/testing"; import { describe, expect, it, vi } from "vitest"; import { createWizardPrompter } from "../../test/helpers/wizard-prompter.js"; import { resolveXaiCatalogEntry } from "./model-definitions.js"; @@ -79,7 +79,7 @@ describe("xai web search config resolution", () => { }); it("treats unresolved non-env SecretRefs as missing credentials instead of throwing", async () => { - await withEnv({ XAI_API_KEY: undefined }, async () => { + await withEnvAsync({ XAI_API_KEY: undefined }, async () => { const provider = createXaiWebSearchProvider(); const maybeTool = provider.createTool({ config: { diff --git a/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts b/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts index 1404eb5590a..0faace3647e 100644 --- a/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts +++ b/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts @@ -45,12 +45,9 @@ const GROQ_TOO_MANY_REQUESTS_MESSAGE = "429 Too Many Requests: Too many requests were sent in a given timeframe."; const GROQ_SERVICE_UNAVAILABLE_MESSAGE = "503 Service Unavailable: The server is temporarily unable to handle the request due to overloading or maintenance."; // pragma: allowlist secret -const PLAIN_INTERNAL_SERVER_ERROR_STATUS_SAMPLE = - "Proxy notice: Status: Internal Server Error"; -const MIXED_INTERNAL_SERVER_ERROR_STATUS_SAMPLE = - `${PLAIN_INTERNAL_SERVER_ERROR_STATUS_SAMPLE}; upstream connect error`; -const INTERNAL_SERVER_ERROR_STATUS_WITH_500_SAMPLE = - `${PLAIN_INTERNAL_SERVER_ERROR_STATUS_SAMPLE}; code:500`; +const PLAIN_INTERNAL_SERVER_ERROR_STATUS_SAMPLE = "Proxy notice: Status: Internal Server Error"; +const MIXED_INTERNAL_SERVER_ERROR_STATUS_SAMPLE = `${PLAIN_INTERNAL_SERVER_ERROR_STATUS_SAMPLE}; upstream connect error`; +const INTERNAL_SERVER_ERROR_STATUS_WITH_500_SAMPLE = `${PLAIN_INTERNAL_SERVER_ERROR_STATUS_SAMPLE}; code:500`; function expectMessageMatches( matcher: (message: string) => boolean, diff --git a/src/agents/pi-embedded-runner/effective-tool-policy.ts b/src/agents/pi-embedded-runner/effective-tool-policy.ts index 7d1cf085f22..e6598ec6cfd 100644 --- a/src/agents/pi-embedded-runner/effective-tool-policy.ts +++ b/src/agents/pi-embedded-runner/effective-tool-policy.ts @@ -137,7 +137,10 @@ export function applyFinalEffectiveToolPolicy( isSubagentSessionKey(params.sessionKey) && params.sessionKey ? resolveSubagentToolPolicyForSession(params.config, params.sessionKey) : undefined; - const ownerFiltered = applyOwnerOnlyToolPolicy(params.bundledTools, params.senderIsOwner === true); + const ownerFiltered = applyOwnerOnlyToolPolicy( + params.bundledTools, + params.senderIsOwner === true, + ); // Suppress unavailable-core-tool warnings on every step of this pass. // `applyToolPolicyPipeline` infers `coreToolNames` from the `tools` array // it's filtering, and this pass only sees the bundled MCP/LSP subset. diff --git a/src/agents/pi-embedded-runner/run.ts b/src/agents/pi-embedded-runner/run.ts index e4af90a2115..ac17fea0302 100644 --- a/src/agents/pi-embedded-runner/run.ts +++ b/src/agents/pi-embedded-runner/run.ts @@ -10,8 +10,8 @@ import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js"; import { enqueueCommandInLane } from "../../process/command-queue.js"; import { normalizeOptionalString } from "../../shared/string-coerce.js"; import { sanitizeForLog } from "../../terminal/ansi.js"; -import { isMarkdownCapableMessageChannel } from "../../utils/message-channel.js"; import { resolveUserPath } from "../../utils.js"; +import { isMarkdownCapableMessageChannel } from "../../utils/message-channel.js"; import { resolveOpenClawAgentDir } from "../agent-paths.js"; import { hasConfiguredModelFallbacks, diff --git a/src/auto-reply/reply/get-reply-run.ts b/src/auto-reply/reply/get-reply-run.ts index 6943847ccda..c2c0704e03a 100644 --- a/src/auto-reply/reply/get-reply-run.ts +++ b/src/auto-reply/reply/get-reply-run.ts @@ -15,7 +15,11 @@ import type { SessionEntry } from "../../config/sessions/types.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; import { logVerbose } from "../../globals.js"; import { clearCommandLane, getQueueSize } from "../../process/command-queue.js"; -import { isAcpSessionKey, isSubagentSessionKey, normalizeMainKey } from "../../routing/session-key.js"; +import { + isAcpSessionKey, + isSubagentSessionKey, + normalizeMainKey, +} from "../../routing/session-key.js"; import { normalizeOptionalString } from "../../shared/string-coerce.js"; import { isReasoningTagProvider } from "../../utils/provider-utils.js"; import { hasControlCommand } from "../command-detection.js"; diff --git a/src/gateway/server-cron.test.ts b/src/gateway/server-cron.test.ts index c28a8f2bd41..3b83cbd70d4 100644 --- a/src/gateway/server-cron.test.ts +++ b/src/gateway/server-cron.test.ts @@ -154,12 +154,15 @@ describe("buildGatewayCronService", () => { state.cron as unknown as { state?: { deps?: { - enqueueSystemEvent?: (optsText: string, opts?: { - agentId?: string; - sessionKey?: string; - contextKey?: string; - trusted?: boolean; - }) => void; + enqueueSystemEvent?: ( + optsText: string, + opts?: { + agentId?: string; + sessionKey?: string; + contextKey?: string; + trusted?: boolean; + }, + ) => void; }; }; } diff --git a/src/gateway/server-methods/agent.test.ts b/src/gateway/server-methods/agent.test.ts index b22eb368212..159a3a6b2e6 100644 --- a/src/gateway/server-methods/agent.test.ts +++ b/src/gateway/server-methods/agent.test.ts @@ -72,9 +72,9 @@ vi.mock("../../agents/agent-scope.js", () => ({ })); vi.mock("../../auto-reply/reply/session-reset-prompt.js", async () => { - const actual = await vi.importActual( - "../../auto-reply/reply/session-reset-prompt.js", - ); + const actual = await vi.importActual< + typeof import("../../auto-reply/reply/session-reset-prompt.js") + >("../../auto-reply/reply/session-reset-prompt.js"); return { ...actual, resolveBareResetBootstrapFileAccess: mocks.resolveBareResetBootstrapFileAccess, @@ -1278,45 +1278,48 @@ describe("gateway agent handler", () => { }); it("uses request model override when resolving bare /new bootstrap file access", async () => { - await withTempDir({ prefix: "openclaw-gateway-reset-model-override-" }, async (workspaceDir) => { - await fs.writeFile(`${workspaceDir}/BOOTSTRAP.md`, "bootstrap ritual", "utf-8"); - mocks.loadConfigReturn = { - agents: { - defaults: { - workspace: workspaceDir, + await withTempDir( + { prefix: "openclaw-gateway-reset-model-override-" }, + async (workspaceDir) => { + await fs.writeFile(`${workspaceDir}/BOOTSTRAP.md`, "bootstrap ritual", "utf-8"); + mocks.loadConfigReturn = { + agents: { + defaults: { + workspace: workspaceDir, + }, }, - }, - }; - mockSessionResetSuccess({ reason: "new" }); - primeMainAgentRun({ sessionId: "reset-session-id", cfg: mocks.loadConfigReturn }); + }; + mockSessionResetSuccess({ reason: "new" }); + primeMainAgentRun({ sessionId: "reset-session-id", cfg: mocks.loadConfigReturn }); - await invokeAgent( - { - message: "/new", - sessionKey: "agent:main:main", - provider: "openai", - model: "gpt-5.4-mini", - idempotencyKey: "test-idem-new-bootstrap-model-override", - }, - { - reqId: "4-bootstrap-model-override", - client: { - connect: { scopes: ["operator.admin"] }, - internal: { allowModelOverride: true }, - } as AgentHandlerArgs["client"], - }, - ); + await invokeAgent( + { + message: "/new", + sessionKey: "agent:main:main", + provider: "openai", + model: "gpt-5.4-mini", + idempotencyKey: "test-idem-new-bootstrap-model-override", + }, + { + reqId: "4-bootstrap-model-override", + client: { + connect: { scopes: ["operator.admin"] }, + internal: { allowModelOverride: true }, + } as AgentHandlerArgs["client"], + }, + ); - await waitForAssertion(() => - expect(mocks.resolveBareResetBootstrapFileAccess).toHaveBeenCalled(), - ); - expect(mocks.resolveBareResetBootstrapFileAccess).toHaveBeenCalledWith( - expect.objectContaining({ - modelProvider: "openai", - modelId: "gpt-5.4-mini", - }), - ); - }); + await waitForAssertion(() => + expect(mocks.resolveBareResetBootstrapFileAccess).toHaveBeenCalled(), + ); + expect(mocks.resolveBareResetBootstrapFileAccess).toHaveBeenCalledWith( + expect.objectContaining({ + modelProvider: "openai", + modelId: "gpt-5.4-mini", + }), + ); + }, + ); }); it("rejects malformed agent session keys early in agent handler", async () => { diff --git a/src/gateway/server-methods/send.test.ts b/src/gateway/server-methods/send.test.ts index b797cc65bc7..81eb243e40c 100644 --- a/src/gateway/server-methods/send.test.ts +++ b/src/gateway/server-methods/send.test.ts @@ -991,9 +991,7 @@ describe("gateway send mirroring", () => { // forced to false so a non-admin scoped caller cannot unlock owner-only // channel actions. setActivePluginRegistry( - createTestRegistry([ - { pluginId: "whatsapp", source: "test", plugin: reactPlugin }, - ]), + createTestRegistry([{ pluginId: "whatsapp", source: "test", plugin: reactPlugin }]), "send-test-owner-derive-non-admin", ); await runMessageActionRequest( @@ -1011,9 +1009,7 @@ describe("gateway send mirroring", () => { // Full operator (admin-scoped): the trusted runtime is allowed to // forward the real channel-sender ownership bit. Wire true → true. setActivePluginRegistry( - createTestRegistry([ - { pluginId: "whatsapp", source: "test", plugin: reactPlugin }, - ]), + createTestRegistry([{ pluginId: "whatsapp", source: "test", plugin: reactPlugin }]), "send-test-owner-derive-admin-true", ); await runMessageActionRequest( @@ -1031,9 +1027,7 @@ describe("gateway send mirroring", () => { // Full operator forwarding a non-owner sender: wire false → false // (admin scope does not inflate ownership on its own). setActivePluginRegistry( - createTestRegistry([ - { pluginId: "whatsapp", source: "test", plugin: reactPlugin }, - ]), + createTestRegistry([{ pluginId: "whatsapp", source: "test", plugin: reactPlugin }]), "send-test-owner-derive-admin-false", ); await runMessageActionRequest( diff --git a/src/gateway/server-methods/send.ts b/src/gateway/server-methods/send.ts index 426880e5a93..4316dec9653 100644 --- a/src/gateway/server-methods/send.ts +++ b/src/gateway/server-methods/send.ts @@ -26,6 +26,7 @@ import { normalizeOptionalString, readStringValue, } from "../../shared/string-coerce.js"; +import { ADMIN_SCOPE } from "../method-scopes.js"; import { ErrorCodes, errorShape, @@ -34,7 +35,6 @@ import { validatePollParams, validateSendParams, } from "../protocol/index.js"; -import { ADMIN_SCOPE } from "../method-scopes.js"; import { formatForLog } from "../ws-log.js"; import type { GatewayRequestContext, GatewayRequestHandlers } from "./types.js"; @@ -231,8 +231,7 @@ export const sendHandlers: GatewayRequestHandlers = { // from unlocking owner-only channel actions by setting // `senderIsOwner: true` on the request. const callerScopes = client?.connect?.scopes ?? []; - const callerIsFullOperator = - Array.isArray(callerScopes) && callerScopes.includes(ADMIN_SCOPE); + const callerIsFullOperator = Array.isArray(callerScopes) && callerScopes.includes(ADMIN_SCOPE); const senderIsOwner = callerIsFullOperator && request.senderIsOwner === true; const idem = request.idempotencyKey; const dedupeKey = `message.action:${idem}`; diff --git a/src/infra/exec-approval-command-display.test.ts b/src/infra/exec-approval-command-display.test.ts index f6b160f2b64..b3b328ca6dc 100644 --- a/src/infra/exec-approval-command-display.test.ts +++ b/src/infra/exec-approval-command-display.test.ts @@ -9,14 +9,8 @@ describe("sanitizeExecApprovalDisplayText", () => { ["echo hi\u200Bthere", "echo hi\\u{200B}there"], ["date\u3164\uFFA0\u115F\u1160가", "date\\u{3164}\\u{FFA0}\\u{115F}\\u{1160}가"], ["echo safe\n\rcurl https://example.test", "echo safe\\u{A}\\u{D}curl https://example.test"], - [ - "echo ok\u2028curl https://example.test", - "echo ok\\u{2028}curl https://example.test", - ], - [ - "echo ok\u2029curl https://example.test", - "echo ok\\u{2029}curl https://example.test", - ], + ["echo ok\u2028curl https://example.test", "echo ok\\u{2028}curl https://example.test"], + ["echo ok\u2029curl https://example.test", "echo ok\\u{2029}curl https://example.test"], ])("sanitizes exec approval display text for %j", (input, expected) => { expect(sanitizeExecApprovalDisplayText(input)).toBe(expected); }); diff --git a/test/helpers/channels/registry-plugin.ts b/test/helpers/channels/registry-plugin.ts index b04f954361c..f4b02e78001 100644 --- a/test/helpers/channels/registry-plugin.ts +++ b/test/helpers/channels/registry-plugin.ts @@ -1,4 +1,5 @@ import { listBundledChannelPlugins } from "../../../src/channels/plugins/bundled.js"; +import { normalizeChannelMeta } from "../../../src/channels/plugins/meta-normalization.js"; import type { ChannelPlugin } from "../../../src/channels/plugins/types.js"; type PluginContractEntry = { @@ -11,10 +12,7 @@ export function getPluginContractRegistry(): PluginContractEntry[] { id: plugin.id, plugin: { ...plugin, - meta: { - ...plugin.meta, - id: plugin.id, - }, + meta: normalizeChannelMeta({ id: plugin.id, meta: plugin.meta }), }, })); }