mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-03 21:34:06 +00:00
fix(ci): repair phone control and cron schema gates
This commit is contained in:
@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import type { OpenKeyedStoreOptions } from "openclaw/plugin-sdk/plugin-state-runtime";
|
||||
import type { PluginStateKeyedStore } from "openclaw/plugin-sdk/plugin-state-runtime";
|
||||
import {
|
||||
createPluginStateKeyedStoreForTests,
|
||||
resetPluginStateStoreForTests,
|
||||
@@ -101,6 +102,25 @@ function createPhoneControlConfig(): Record<string, unknown> {
|
||||
};
|
||||
}
|
||||
|
||||
function createMockOpenKeyedStore(params: {
|
||||
lookup: ReturnType<typeof vi.fn>;
|
||||
delete?: ReturnType<typeof vi.fn>;
|
||||
}): OpenClawPluginApi["runtime"]["state"]["openKeyedStore"] {
|
||||
return <T>() => {
|
||||
const store: PluginStateKeyedStore<T> = {
|
||||
register: vi.fn(async () => {}),
|
||||
registerIfAbsent: vi.fn(async () => true),
|
||||
update: vi.fn(async () => true),
|
||||
lookup: params.lookup as (key: string) => Promise<T | undefined>,
|
||||
consume: vi.fn(async () => undefined),
|
||||
delete: (params.delete ?? vi.fn(async () => true)) as (key: string) => Promise<boolean>,
|
||||
entries: vi.fn(async () => []),
|
||||
clear: vi.fn(async () => {}),
|
||||
};
|
||||
return store;
|
||||
};
|
||||
}
|
||||
|
||||
async function withRegisteredPhoneControl(
|
||||
run: (params: {
|
||||
command: OpenClawPluginCommandDefinition;
|
||||
@@ -343,7 +363,7 @@ describe("phone-control plugin", () => {
|
||||
it("does not block service startup on the initial expiry check", async () => {
|
||||
const stateDir = await fs.mkdtemp(path.join(os.tmpdir(), PHONE_CONTROL_STATE_PREFIX));
|
||||
try {
|
||||
const lookup = vi.fn(async () => null);
|
||||
const lookup = vi.fn(async () => undefined);
|
||||
let service: OpenClawPluginService | undefined;
|
||||
|
||||
registerPhoneControl.register(
|
||||
@@ -355,12 +375,7 @@ describe("phone-control plugin", () => {
|
||||
registerService: (registeredService) => {
|
||||
service = registeredService;
|
||||
},
|
||||
openKeyedStore: () =>
|
||||
({
|
||||
lookup,
|
||||
delete: vi.fn(),
|
||||
register: vi.fn(),
|
||||
}) as ReturnType<OpenClawPluginApi["runtime"]["state"]["openKeyedStore"]>,
|
||||
openKeyedStore: createMockOpenKeyedStore({ lookup }),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -376,7 +391,9 @@ describe("phone-control plugin", () => {
|
||||
|
||||
expect(lookup).not.toHaveBeenCalled();
|
||||
|
||||
await new Promise<void>((resolve) => setImmediate(resolve));
|
||||
await new Promise<void>((resolve) => {
|
||||
setImmediate(resolve);
|
||||
});
|
||||
|
||||
expect(lookup).toHaveBeenCalledWith("current");
|
||||
|
||||
@@ -425,12 +442,7 @@ describe("phone-control plugin", () => {
|
||||
registerService: (registeredService) => {
|
||||
service = registeredService;
|
||||
},
|
||||
openKeyedStore: () =>
|
||||
({
|
||||
lookup,
|
||||
delete: removeState,
|
||||
register: vi.fn(),
|
||||
}) as ReturnType<OpenClawPluginApi["runtime"]["state"]["openKeyedStore"]>,
|
||||
openKeyedStore: createMockOpenKeyedStore({ lookup, delete: removeState }),
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -35,6 +35,14 @@ type ArmStateFileV2 = {
|
||||
};
|
||||
|
||||
type ArmStateFile = ArmStateFileV1 | ArmStateFileV2;
|
||||
type PhoneControlConfigView = {
|
||||
readonly gateway?: {
|
||||
readonly nodes?: {
|
||||
readonly allowCommands?: readonly string[];
|
||||
readonly denyCommands?: readonly string[];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
const STATE_VERSION = 2;
|
||||
const ARM_STATE_NAMESPACE = "armed";
|
||||
@@ -119,15 +127,15 @@ async function writeArmState(api: OpenClawPluginApi, state: ArmStateFile | null)
|
||||
await store.register(ARM_STATE_KEY, state);
|
||||
}
|
||||
|
||||
function normalizeDenyList(cfg: OpenClawPluginApi["config"]): string[] {
|
||||
function normalizeDenyList(cfg: PhoneControlConfigView): string[] {
|
||||
return uniqSorted([...(cfg.gateway?.nodes?.denyCommands ?? [])]);
|
||||
}
|
||||
|
||||
function normalizeAllowList(cfg: OpenClawPluginApi["config"]): string[] {
|
||||
function normalizeAllowList(cfg: PhoneControlConfigView): string[] {
|
||||
return uniqSorted([...(cfg.gateway?.nodes?.allowCommands ?? [])]);
|
||||
}
|
||||
|
||||
function hasPhoneControlAllowOverride(cfg: OpenClawPluginApi["config"]): boolean {
|
||||
function hasPhoneControlAllowOverride(cfg: PhoneControlConfigView): boolean {
|
||||
const allow = new Set(normalizeAllowList(cfg));
|
||||
return PHONE_CONTROL_COMMANDS.some((cmd) => allow.has(cmd));
|
||||
}
|
||||
|
||||
@@ -64,11 +64,17 @@ function isMissingOrEmptyObject(value: unknown): boolean {
|
||||
}
|
||||
|
||||
function nullableStringSchema(description: string) {
|
||||
return Type.Optional(Type.Union([Type.String(), Type.Null()], { description }));
|
||||
return Type.Optional(Type.Unsafe<string | null>({ type: "string", description }));
|
||||
}
|
||||
|
||||
function nullableStringArraySchema(description: string) {
|
||||
return Type.Optional(Type.Union([Type.Array(Type.String()), Type.Null()], { description }));
|
||||
return Type.Optional(
|
||||
Type.Unsafe<string[] | null>({
|
||||
type: "array",
|
||||
items: { type: "string" },
|
||||
description,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function deliveryStringSchema(params: { description: string; nullableClears: boolean }) {
|
||||
|
||||
@@ -212,7 +212,7 @@ async function prepareCodexHomeForLiveBindTest(tempRoot: string): Promise<void>
|
||||
() => {
|
||||
hasAuthFile = true;
|
||||
},
|
||||
(error) => {
|
||||
(error: unknown) => {
|
||||
if ((error as NodeJS.ErrnoException)?.code !== "ENOENT") {
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -465,8 +465,8 @@ function loadBundledEntryModuleSync(
|
||||
return loaded;
|
||||
}
|
||||
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Dynamic entry export loaders use caller-supplied export types.
|
||||
/** Loads one export from a bundled channel sidecar module through the guarded entry boundary. */
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Dynamic entry export loaders use caller-supplied export types.
|
||||
export function loadBundledEntryExportSync<T>(
|
||||
importMetaUrl: string,
|
||||
reference: BundledEntryModuleRef,
|
||||
|
||||
Reference in New Issue
Block a user