mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 19:18:26 +00:00
Memory/QMD: warn when scope denies search
This commit is contained in:
committed by
Vignesh
parent
6aedc54bd7
commit
7f7d49aef0
@@ -4,6 +4,12 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const { logWarnMock, logDebugMock, logInfoMock } = vi.hoisted(() => ({
|
||||
logWarnMock: vi.fn(),
|
||||
logDebugMock: vi.fn(),
|
||||
logInfoMock: vi.fn(),
|
||||
}));
|
||||
|
||||
type MockChild = EventEmitter & {
|
||||
stdout: EventEmitter;
|
||||
stderr: EventEmitter;
|
||||
@@ -38,6 +44,18 @@ function createMockChild(params?: { autoClose?: boolean; closeDelayMs?: number }
|
||||
return child;
|
||||
}
|
||||
|
||||
vi.mock("../logging/subsystem.js", () => ({
|
||||
createSubsystemLogger: () => {
|
||||
const logger = {
|
||||
warn: logWarnMock,
|
||||
debug: logDebugMock,
|
||||
info: logInfoMock,
|
||||
child: () => logger,
|
||||
};
|
||||
return logger;
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("node:child_process", () => ({ spawn: vi.fn() }));
|
||||
|
||||
import { spawn as mockedSpawn } from "node:child_process";
|
||||
@@ -57,6 +75,9 @@ describe("QmdMemoryManager", () => {
|
||||
beforeEach(async () => {
|
||||
spawnMock.mockReset();
|
||||
spawnMock.mockImplementation(() => createMockChild());
|
||||
logWarnMock.mockReset();
|
||||
logDebugMock.mockReset();
|
||||
logInfoMock.mockReset();
|
||||
tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), "qmd-manager-test-"));
|
||||
workspaceDir = path.join(tmpRoot, "workspace");
|
||||
await fs.mkdir(workspaceDir, { recursive: true });
|
||||
@@ -459,6 +480,42 @@ describe("QmdMemoryManager", () => {
|
||||
await manager.close();
|
||||
});
|
||||
|
||||
it("logs when qmd scope denies search", async () => {
|
||||
cfg = {
|
||||
...cfg,
|
||||
memory: {
|
||||
backend: "qmd",
|
||||
qmd: {
|
||||
includeDefaultMemory: false,
|
||||
update: { interval: "0s", debounceMs: 60_000, onBoot: false },
|
||||
paths: [{ path: workspaceDir, pattern: "**/*.md", name: "workspace" }],
|
||||
scope: {
|
||||
default: "deny",
|
||||
rules: [{ action: "allow", match: { chatType: "direct" } }],
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
const resolved = resolveMemoryBackendConfig({ cfg, agentId });
|
||||
const manager = await QmdMemoryManager.create({ cfg, agentId, resolved });
|
||||
expect(manager).toBeTruthy();
|
||||
if (!manager) {
|
||||
throw new Error("manager missing");
|
||||
}
|
||||
|
||||
logWarnMock.mockClear();
|
||||
const beforeCalls = spawnMock.mock.calls.length;
|
||||
await expect(
|
||||
manager.search("blocked", { sessionKey: "agent:main:discord:channel:c123" }),
|
||||
).resolves.toEqual([]);
|
||||
|
||||
expect(spawnMock.mock.calls.length).toBe(beforeCalls);
|
||||
expect(logWarnMock).toHaveBeenCalledWith(expect.stringContaining("qmd search denied by scope"));
|
||||
expect(logWarnMock).toHaveBeenCalledWith(expect.stringContaining("chatType=channel"));
|
||||
|
||||
await manager.close();
|
||||
});
|
||||
|
||||
it("blocks non-markdown or symlink reads for qmd paths", async () => {
|
||||
const resolved = resolveMemoryBackendConfig({ cfg, agentId });
|
||||
const manager = await QmdMemoryManager.create({ cfg, agentId, resolved });
|
||||
|
||||
Reference in New Issue
Block a user