mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
fix(ci): restore release validation after runtime migrations (#107371)
* test(ci): repair plugin prerelease validation * test(zalo): preserve adapter narrowing in sender helpers * test(ci): track current bundled startup metadata * fix(google-meet): refresh plugin shrinkwrap
This commit is contained in:
@@ -181,6 +181,7 @@ Skills own workflows; root owns hard policy and routing.
|
||||
- Sparse-sync temp checkout may claim kept Testbox; repo-path reuse needs `--reclaim`.
|
||||
- GitHub Actions: resolve workflow files from `.github/workflows` or API; never infer filenames from display names.
|
||||
- zsh: quote command globs; unmatched patterns abort before the tool runs.
|
||||
- Nested remote shell: avoid local `$()` expansion; use remote-safe validation.
|
||||
- zsh: don't use `path` as a variable; it rewrites `$PATH`.
|
||||
- `scripts/pr` artifacts: preserve template enum values; validate before prepare.
|
||||
- `scripts/pr` subcommands require a PR number; no subcommand `--help` placeholder.
|
||||
|
||||
@@ -798,8 +798,13 @@ describe("slash-http", () => {
|
||||
}),
|
||||
).resolves.toBe(false);
|
||||
|
||||
expect(log).toHaveBeenCalledTimes(1);
|
||||
const message = firstLogMessage(log);
|
||||
const message = log.mock.calls
|
||||
.map(([entry]) => (typeof entry === "string" ? entry : ""))
|
||||
.find((entry) => entry.includes("using team list fallback"));
|
||||
expect(message).toBeTruthy();
|
||||
if (!message) {
|
||||
throw new Error("expected sanitized Mattermost command lookup fallback log");
|
||||
}
|
||||
expect(message).toBe(
|
||||
`mattermost: slash command lookup by id returned deleted command ${"i".repeat(199)} for /oc_status; using team list fallback`,
|
||||
);
|
||||
|
||||
@@ -43,11 +43,18 @@ vi.mock("node:child_process", async () => {
|
||||
const actual = await vi.importActual<typeof import("node:child_process")>("node:child_process");
|
||||
return {
|
||||
...actual,
|
||||
execFile: execFileMock,
|
||||
execFileSync: execFileSyncMock,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("openclaw/plugin-sdk/process-runtime", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("openclaw/plugin-sdk/process-runtime")>();
|
||||
return {
|
||||
...actual,
|
||||
runExec: execFileMock,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("openclaw/plugin-sdk/provider-auth", async () => {
|
||||
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/provider-auth")>(
|
||||
"openclaw/plugin-sdk/provider-auth",
|
||||
@@ -245,62 +252,35 @@ function buildFoundryRuntimeAuthContext(
|
||||
}
|
||||
|
||||
function mockAzureCliToken(params: { accessToken: string; expiresInMs: number; delayMs?: number }) {
|
||||
execFileMock.mockImplementationOnce(
|
||||
(
|
||||
_file: unknown,
|
||||
_args: unknown,
|
||||
_options: unknown,
|
||||
callback: (error: Error | null, stdout: string, stderr: string) => void,
|
||||
) => {
|
||||
const respond = () =>
|
||||
callback(
|
||||
null,
|
||||
JSON.stringify({
|
||||
accessToken: params.accessToken,
|
||||
expiresOn: new Date(Date.now() + params.expiresInMs).toISOString(),
|
||||
}),
|
||||
"",
|
||||
);
|
||||
if (params.delayMs) {
|
||||
setTimeout(respond, params.delayMs);
|
||||
return;
|
||||
}
|
||||
respond();
|
||||
},
|
||||
);
|
||||
execFileMock.mockImplementationOnce(async () => {
|
||||
if (params.delayMs) {
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(resolve, params.delayMs);
|
||||
});
|
||||
}
|
||||
return {
|
||||
stdout: JSON.stringify({
|
||||
accessToken: params.accessToken,
|
||||
expiresOn: new Date(Date.now() + params.expiresInMs).toISOString(),
|
||||
}),
|
||||
stderr: "",
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function mockAzureCliTokenRaw(stdout: string) {
|
||||
execFileMock.mockImplementationOnce(
|
||||
(
|
||||
_file: unknown,
|
||||
_args: unknown,
|
||||
_options: unknown,
|
||||
callback: (error: Error | null, stdout: string, stderr: string) => void,
|
||||
) => {
|
||||
callback(null, stdout, "");
|
||||
},
|
||||
);
|
||||
execFileMock.mockResolvedValueOnce({ stdout, stderr: "" });
|
||||
}
|
||||
|
||||
function mockAzureCliLoginFailure(delayMs?: number) {
|
||||
execFileMock.mockImplementationOnce(
|
||||
(
|
||||
_file: unknown,
|
||||
_args: unknown,
|
||||
_options: unknown,
|
||||
callback: (error: Error | null, stdout: string, stderr: string) => void,
|
||||
) => {
|
||||
const respond = () => {
|
||||
callback(new Error("az failed"), "", defaultAzureCliLoginError);
|
||||
};
|
||||
if (delayMs) {
|
||||
setTimeout(respond, delayMs);
|
||||
return;
|
||||
}
|
||||
respond();
|
||||
},
|
||||
);
|
||||
execFileMock.mockImplementationOnce(async () => {
|
||||
if (delayMs) {
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(resolve, delayMs);
|
||||
});
|
||||
}
|
||||
throw Object.assign(new Error("az failed"), { stderr: defaultAzureCliLoginError, stdout: "" });
|
||||
});
|
||||
}
|
||||
|
||||
describe("microsoft-foundry plugin", () => {
|
||||
@@ -1849,13 +1829,8 @@ describe("microsoft-foundry plugin", () => {
|
||||
|
||||
it("keeps bounded Azure CLI error details UTF-16 safe", async () => {
|
||||
const prefix = "x".repeat(299);
|
||||
execFileMock.mockImplementationOnce(
|
||||
(
|
||||
_file: unknown,
|
||||
_args: unknown,
|
||||
_options: unknown,
|
||||
callback: (error: Error | null, stdout: string, stderr: string) => void,
|
||||
) => callback(new Error("az failed"), "", `${prefix}😀tail`),
|
||||
execFileMock.mockRejectedValueOnce(
|
||||
Object.assign(new Error("az failed"), { stderr: `${prefix}😀tail`, stdout: "" }),
|
||||
);
|
||||
|
||||
await expect(getAccessTokenResultAsync()).rejects.toMatchObject({
|
||||
|
||||
@@ -4075,7 +4075,7 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
await dispatchWithContext({
|
||||
context: createContext(),
|
||||
streamMode: "progress",
|
||||
telegramCfg: { streaming: { mode: "progress" } },
|
||||
telegramCfg: { streaming: { mode: "progress", progress: { label: "Cracking" } } },
|
||||
});
|
||||
|
||||
expect(answerDraftStream.updatePreview).toHaveBeenCalledWith(
|
||||
@@ -4118,7 +4118,7 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
await dispatchWithContext({
|
||||
context: createContext(),
|
||||
streamMode: "progress",
|
||||
telegramCfg: { streaming: { mode: "progress" } },
|
||||
telegramCfg: { streaming: { mode: "progress", progress: { label: "Cracking" } } },
|
||||
});
|
||||
|
||||
expect(answerDraftStream.update).not.toHaveBeenCalledWith("Terminal block answer");
|
||||
@@ -4142,7 +4142,7 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
await dispatchWithContext({
|
||||
context: createContext(),
|
||||
streamMode: "progress",
|
||||
telegramCfg: { streaming: { mode: "progress" } },
|
||||
telegramCfg: { streaming: { mode: "progress", progress: { label: "Cracking" } } },
|
||||
});
|
||||
|
||||
expect(answerDraftStream.updatePreview).toHaveBeenCalledWith(
|
||||
@@ -4802,7 +4802,7 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
await dispatchWithContext({
|
||||
context: createContext(),
|
||||
streamMode: "progress",
|
||||
telegramCfg: { streaming: { mode: "progress" } },
|
||||
telegramCfg: { streaming: { mode: "progress", progress: { label: "Cracking" } } },
|
||||
});
|
||||
|
||||
expect(answerDraftStream.updatePreview).toHaveBeenCalledWith(
|
||||
|
||||
@@ -29,15 +29,10 @@ vi.mock("./channel.runtime.js", () => ({
|
||||
type ZaloOutbound = NonNullable<typeof zaloPlugin.outbound>;
|
||||
type ZaloSendPayload = NonNullable<ZaloOutbound["sendPayload"]>;
|
||||
|
||||
function requireZaloMessageAdapter(): NonNullable<typeof zaloPlugin.message> {
|
||||
const adapter = zaloPlugin.message;
|
||||
if (!adapter) {
|
||||
throw new Error("Expected Zalo message adapter");
|
||||
}
|
||||
return adapter;
|
||||
const zaloMessageAdapter = zaloPlugin.message;
|
||||
if (!zaloMessageAdapter) {
|
||||
throw new Error("Expected Zalo message adapter");
|
||||
}
|
||||
|
||||
const zaloMessageAdapter = requireZaloMessageAdapter();
|
||||
type ZaloMessageSender = NonNullable<typeof zaloMessageAdapter.send>;
|
||||
|
||||
function requireZaloSendPayload(): ZaloSendPayload {
|
||||
@@ -49,7 +44,7 @@ function requireZaloSendPayload(): ZaloSendPayload {
|
||||
}
|
||||
|
||||
function requireZaloTextSender(): NonNullable<ZaloMessageSender["text"]> {
|
||||
const text = zaloMessageAdapter.send?.text;
|
||||
const text = zaloMessageAdapter?.send?.text;
|
||||
if (!text) {
|
||||
throw new Error("Expected Zalo message adapter text sender");
|
||||
}
|
||||
@@ -57,7 +52,7 @@ function requireZaloTextSender(): NonNullable<ZaloMessageSender["text"]> {
|
||||
}
|
||||
|
||||
function requireZaloMediaSender(): NonNullable<ZaloMessageSender["media"]> {
|
||||
const media = zaloMessageAdapter.send?.media;
|
||||
const media = zaloMessageAdapter?.send?.media;
|
||||
if (!media) {
|
||||
throw new Error("Expected Zalo message adapter media sender");
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"dist/extensions/memory-core/runtime-api.js",
|
||||
"dist/extensions/ollama/runtime-api.js",
|
||||
"dist/extensions/open-prose/runtime-api.js",
|
||||
"dist/extensions/reef/runtime-api.js",
|
||||
"dist/extensions/telegram/runtime-api.js",
|
||||
"dist/extensions/telegram/runtime-setter-api.js",
|
||||
"dist/extensions/webhooks/runtime-api.js",
|
||||
|
||||
@@ -214,12 +214,12 @@ describe("gateway cli backend live helpers", () => {
|
||||
expect(probe.resumePrompt).toBe(
|
||||
"Do not inspect files or run tools. " +
|
||||
"What private session note were you asked to remember earlier? " +
|
||||
"Reply with exactly: CLI backend RESUME OK 445566 <remembered-note>.",
|
||||
"Reply with CLI-RESUME-445566 and the remembered note.",
|
||||
);
|
||||
expect(probe.firstTurnPrompt).not.toContain(memoryToken);
|
||||
expect(probe.resumePrompt).not.toContain(memoryToken);
|
||||
expect(probe.injectedContext).toContain(memoryToken);
|
||||
expect(probe.expectedResumeReply).toBe("CLI backend RESUME OK 445566 CLI-MEM-A1B2C3D4E5F6.");
|
||||
expect(probe.expectedResumeMarker).toBe("CLI-RESUME-445566");
|
||||
});
|
||||
|
||||
it("finds only Claude-imported native session ids", () => {
|
||||
|
||||
@@ -79,7 +79,7 @@ export type ClaudeCliResumeContinuityProbe = {
|
||||
injectedContext: string;
|
||||
resumePrompt: string;
|
||||
expectedFirstReply: string;
|
||||
expectedResumeReply: string;
|
||||
expectedResumeMarker: string;
|
||||
};
|
||||
|
||||
function normalizeCliRuntimeModelTarget(raw: string | undefined): string | undefined {
|
||||
@@ -296,9 +296,9 @@ export function buildClaudeCliResumeContinuityProbe(params: {
|
||||
resumePrompt:
|
||||
"Do not inspect files or run tools. " +
|
||||
"What private session note were you asked to remember earlier? " +
|
||||
`Reply with exactly: CLI backend RESUME OK ${params.resumeNonce} <remembered-note>.`,
|
||||
`Reply with CLI-RESUME-${params.resumeNonce} and the remembered note.`,
|
||||
expectedFirstReply: `${firstTurnMarker}.`,
|
||||
expectedResumeReply: `CLI backend RESUME OK ${params.resumeNonce} ${params.memoryToken}.`,
|
||||
expectedResumeMarker: `CLI-RESUME-${params.resumeNonce}`,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -736,9 +736,8 @@ describeLive("gateway live (cli backend)", () => {
|
||||
if (providerId === "codex-cli") {
|
||||
expect(resumeText).toContain(`CLI-RESUME-${resumeNonce}`);
|
||||
} else if (resumeContinuityProbe) {
|
||||
expect(
|
||||
matchesCliBackendReply(resumeText, resumeContinuityProbe.expectedResumeReply),
|
||||
).toBe(true);
|
||||
expect(resumeText).toContain(resumeContinuityProbe.expectedResumeMarker);
|
||||
expect(resumeText).toContain(memoryToken);
|
||||
if (!continuityOwner || !expectedLiveSessionGeneration) {
|
||||
throw new Error("Claude CLI continuity probe lost its live-session generation");
|
||||
}
|
||||
|
||||
@@ -45,14 +45,17 @@ const EXPECTED_BUNDLED_STARTUP_PLUGIN_IDS = [
|
||||
"diffs-language-pack",
|
||||
"file-transfer",
|
||||
"google-meet",
|
||||
"linux-node",
|
||||
"llm-task",
|
||||
"lobster",
|
||||
"logbook",
|
||||
"memory-wiki",
|
||||
"ollama",
|
||||
"opencode",
|
||||
"openshell",
|
||||
"phone-control",
|
||||
"policy",
|
||||
"reef",
|
||||
"talk-voice",
|
||||
"thread-ownership",
|
||||
"voice-call",
|
||||
@@ -67,8 +70,10 @@ const EXPECTED_EMPTY_CONFIG_GATEWAY_STARTUP_PLUGIN_IDS = [
|
||||
"canvas",
|
||||
"device-pair",
|
||||
"file-transfer",
|
||||
"linux-node",
|
||||
"memory-core",
|
||||
"ollama",
|
||||
"opencode",
|
||||
"phone-control",
|
||||
"talk-voice",
|
||||
] as const;
|
||||
|
||||
+40
-11
@@ -441,8 +441,32 @@ function mockNpmViewMetadata(params: { name: string; version?: string }) {
|
||||
});
|
||||
}
|
||||
|
||||
let actualExecModulePromise: Promise<typeof import("../process/exec.js")> | undefined;
|
||||
|
||||
async function runActualInstallPolicyCommandIfNeeded(
|
||||
args: Parameters<typeof runCommandWithTimeout>[0],
|
||||
options: Parameters<typeof runCommandWithTimeout>[1],
|
||||
): Promise<Awaited<ReturnType<typeof runCommandWithTimeout>> | null> {
|
||||
if (typeof options === "number" || options.input === undefined) {
|
||||
return null;
|
||||
}
|
||||
actualExecModulePromise ??=
|
||||
vi.importActual<typeof import("../process/exec.js")>("../process/exec.js");
|
||||
const actualExecModule = await actualExecModulePromise;
|
||||
return await actualExecModule.runCommandWithTimeout(args, options);
|
||||
}
|
||||
|
||||
function countMockedCommands(executable: string): number {
|
||||
return vi.mocked(runCommandWithTimeout).mock.calls.filter(([args]) => args[0] === executable)
|
||||
.length;
|
||||
}
|
||||
|
||||
function mockSuccessfulManagedNpmInstall(params: { packageName: string; version?: string }) {
|
||||
vi.mocked(runCommandWithTimeout).mockImplementation(async (args, options) => {
|
||||
const policyResult = await runActualInstallPolicyCommandIfNeeded(args, options);
|
||||
if (policyResult) {
|
||||
return policyResult;
|
||||
}
|
||||
if (args[0] !== "npm" || args[1] !== "install") {
|
||||
throw new Error(`unexpected command: ${args.join(" ")}`);
|
||||
}
|
||||
@@ -617,13 +641,18 @@ function expectHookRequest(
|
||||
}
|
||||
|
||||
function mockSuccessfulCommandRun(run: ReturnType<typeof vi.mocked<typeof runCommandWithTimeout>>) {
|
||||
run.mockResolvedValue({
|
||||
code: 0,
|
||||
stdout: "",
|
||||
stderr: "",
|
||||
signal: null,
|
||||
killed: false,
|
||||
termination: "exit",
|
||||
run.mockImplementation(async (args, options) => {
|
||||
const policyResult = await runActualInstallPolicyCommandIfNeeded(args, options);
|
||||
return (
|
||||
policyResult ?? {
|
||||
code: 0,
|
||||
stdout: "",
|
||||
stderr: "",
|
||||
signal: null,
|
||||
killed: false,
|
||||
termination: "exit" as const,
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2645,7 +2674,7 @@ describe("installPluginFromNpmSpec", () => {
|
||||
expect(result.code, result.error).toBe(PLUGIN_INSTALL_ERROR_CODE.SECURITY_SCAN_BLOCKED);
|
||||
expect(result.error).toContain("npm installs are disabled by policy");
|
||||
}
|
||||
expect(vi.mocked(runCommandWithTimeout)).toHaveBeenCalledTimes(1);
|
||||
expect(countMockedCommands("npm")).toBe(1);
|
||||
expect(vi.mocked(runCommandWithTimeout).mock.calls[0]?.[0]).toEqual([
|
||||
"npm",
|
||||
"view",
|
||||
@@ -2698,7 +2727,7 @@ describe("installPluginFromNpmSpec", () => {
|
||||
expect(result.code, result.error).toBe(PLUGIN_INSTALL_ERROR_CODE.SECURITY_SCAN_BLOCKED);
|
||||
expect(result.error).toContain("fresh npm installs are disabled by policy");
|
||||
}
|
||||
expect(vi.mocked(runCommandWithTimeout)).toHaveBeenCalledTimes(1);
|
||||
expect(countMockedCommands("npm")).toBe(1);
|
||||
const requests = readCapturedInstallPolicyRequests(logPath);
|
||||
expect(requests).toHaveLength(1);
|
||||
expect(requests[0]?.request.mode).toBe("install");
|
||||
@@ -2937,7 +2966,7 @@ describe("installPluginFromNpmSpec", () => {
|
||||
expect(result.code, result.error).toBe(PLUGIN_INSTALL_ERROR_CODE.SECURITY_SCAN_BLOCKED);
|
||||
expect(result.error).toContain("npm installs are disabled by policy");
|
||||
}
|
||||
expect(vi.mocked(runCommandWithTimeout)).toHaveBeenCalledTimes(1);
|
||||
expect(countMockedCommands("npm")).toBe(1);
|
||||
await expect(fsPromises.stat(npmDir)).rejects.toThrow();
|
||||
const requests = readCapturedInstallPolicyRequests(logPath);
|
||||
expect(requests).toHaveLength(1);
|
||||
@@ -2997,7 +3026,7 @@ describe("installPluginFromNpmSpec", () => {
|
||||
expect(result.code, result.error).toBe(PLUGIN_INSTALL_ERROR_CODE.SECURITY_SCAN_BLOCKED);
|
||||
expect(result.error).toContain("npm installs are disabled by policy");
|
||||
}
|
||||
expect(vi.mocked(runCommandWithTimeout)).toHaveBeenCalledTimes(1);
|
||||
expect(countMockedCommands("npm")).toBe(1);
|
||||
await expect(fsPromises.stat(npmDir)).rejects.toThrow();
|
||||
const requests = readCapturedInstallPolicyRequests(logPath);
|
||||
expect(requests).toHaveLength(1);
|
||||
|
||||
@@ -277,7 +277,7 @@ describe("migration provider runtime", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("derives a fresh manifest registry so newly bundled migration providers are discoverable", () => {
|
||||
it("discovers newly bundled migration providers from current metadata", () => {
|
||||
const provider = createMigrationProvider("hermes");
|
||||
const active = createEmptyPluginRegistry();
|
||||
const loaded = createEmptyPluginRegistry();
|
||||
@@ -290,55 +290,21 @@ describe("migration provider runtime", () => {
|
||||
mocks.resolveRuntimePluginRegistry.mockImplementation((params?: unknown) =>
|
||||
params === undefined ? active : loaded,
|
||||
);
|
||||
mocks.loadPluginRegistrySnapshot.mockReturnValue(
|
||||
createMockPluginIndex([
|
||||
{
|
||||
pluginId: "migrate-hermes",
|
||||
origin: "bundled",
|
||||
enabled: true,
|
||||
},
|
||||
]),
|
||||
);
|
||||
mocks.loadPluginManifestRegistry.mockImplementation(() => ({
|
||||
diagnostics: [],
|
||||
plugins: [
|
||||
{
|
||||
mocks.listBundledPluginMetadata.mockReturnValue([
|
||||
{
|
||||
manifest: {
|
||||
id: "migrate-hermes",
|
||||
origin: "bundled",
|
||||
contracts: { migrationProviders: ["hermes"] },
|
||||
},
|
||||
],
|
||||
}));
|
||||
},
|
||||
] as never);
|
||||
|
||||
const resolved = resolvePluginMigrationProvider({ providerId: "hermes" });
|
||||
|
||||
expect(resolved).toBe(provider);
|
||||
expect(mocks.loadPluginRegistrySnapshotWithMetadata).toHaveBeenCalledWith({
|
||||
config: {},
|
||||
env: process.env,
|
||||
workspaceDir: undefined,
|
||||
expect(mocks.listBundledPluginMetadata).toHaveBeenCalledWith({
|
||||
includeChannelConfigs: false,
|
||||
});
|
||||
const manifestParams = requireMockCallArg(
|
||||
mocks.loadPluginManifestRegistry,
|
||||
"loadPluginManifestRegistry",
|
||||
) as {
|
||||
index?: MockPluginIndex;
|
||||
config?: OpenClawConfig;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
includeDisabled?: unknown;
|
||||
workspaceDir?: unknown;
|
||||
};
|
||||
expect(manifestParams.index?.plugins).toEqual([
|
||||
{
|
||||
pluginId: "migrate-hermes",
|
||||
origin: "bundled",
|
||||
enabled: true,
|
||||
},
|
||||
]);
|
||||
expect(manifestParams.config).toEqual({});
|
||||
expect(manifestParams.env).toBe(process.env);
|
||||
expect(manifestParams.includeDisabled).toBe(true);
|
||||
expect(manifestParams.workspaceDir).toBeUndefined();
|
||||
expect(mocks.resolveRuntimePluginRegistry).toHaveBeenCalledWith({
|
||||
onlyPluginIds: ["migrate-hermes"],
|
||||
});
|
||||
|
||||
@@ -33,11 +33,10 @@ const REQUIRED_REVIEWED_PUBLISHABLE_CRITICAL_FINDINGS = new Set([
|
||||
"@openclaw/discord:dangerous-exec:src/voice/audio.ts",
|
||||
"@openclaw/google-meet:dangerous-exec:src/node-host.ts",
|
||||
"@openclaw/google-meet:dangerous-exec:src/realtime.ts",
|
||||
"@openclaw/matrix:dangerous-exec:src/matrix/deps.ts",
|
||||
"@openclaw/mxc-sandbox:dangerous-exec:src/readiness.ts",
|
||||
"@openclaw/raft:dangerous-exec:src/gateway.ts",
|
||||
"@openclaw/signal:dangerous-exec:src/daemon.ts",
|
||||
"@openclaw/voice-call:dangerous-exec:src/tunnel.ts",
|
||||
"@openclaw/voice-call:dangerous-exec:src/webhook/tailscale.ts",
|
||||
]);
|
||||
|
||||
const OPTIONAL_REVIEWED_PUBLISHABLE_DIST_CRITICAL_FINDINGS = new Set([
|
||||
|
||||
@@ -14,9 +14,9 @@ const LIVE_RUNTIME_STATE_GUARDS: Record<
|
||||
forbidden: readonly string[];
|
||||
}
|
||||
> = {
|
||||
[bundledPluginFile("whatsapp", "src/connection-controller-registry.ts")]: {
|
||||
required: ["globalThis", 'Symbol.for("openclaw.whatsapp.connectionControllerRegistry")'],
|
||||
forbidden: ["resolveGlobalSingleton"],
|
||||
[bundledPluginFile("whatsapp", "src/connection-controller-runtime-context.ts")]: {
|
||||
required: ["getChannelRuntimeContext", "WHATSAPP_CONNECTION_CONTROLLER_CAPABILITY"],
|
||||
forbidden: ["globalThis", "resolveGlobalSingleton"],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -80,7 +80,12 @@ function listSourceFilesByDirectory(dir: string): string[] {
|
||||
}
|
||||
|
||||
function isProductionTypeScriptFile(path: string): boolean {
|
||||
return path.endsWith(".ts") && !path.endsWith(".test.ts") && !path.endsWith(".test.tsx");
|
||||
return (
|
||||
path.endsWith(".ts") &&
|
||||
!path.endsWith(".test.ts") &&
|
||||
!path.endsWith(".test.tsx") &&
|
||||
!/\.test-(?:fixtures|harness|helpers|mocks|setup|support|utils)\.tsx?$/u.test(path)
|
||||
);
|
||||
}
|
||||
|
||||
describe("runtime plugin registry boundary", () => {
|
||||
|
||||
Reference in New Issue
Block a user