test: refresh fs-safe boundary expectations

This commit is contained in:
Peter Steinberger
2026-05-06 02:50:23 +01:00
parent a6a4140ee7
commit 8294229592
6 changed files with 21 additions and 33 deletions

View File

@@ -246,19 +246,19 @@ describe("MemoryIndexManager.readFile", () => {
await fs.mkdir(path.dirname(absPath), { recursive: true });
await fs.writeFile(absPath, "first\nsecond", "utf-8");
const realReadFile = fs.readFile;
const realOpen = fs.open;
let injected = false;
const readSpy = vi
.spyOn(fs, "readFile")
.mockImplementation(async (...args: Parameters<typeof realReadFile>) => {
const [target, options] = args;
const openSpy = vi
.spyOn(fs, "open")
.mockImplementation(async (...args: Parameters<typeof realOpen>) => {
const [target, flags, mode] = args;
if (!injected && typeof target === "string" && path.resolve(target) === absPath) {
injected = true;
const err = new Error("missing") as NodeJS.ErrnoException;
err.code = "ENOENT";
throw err;
}
return realReadFile(target, options);
return realOpen(target, flags, mode);
});
try {
@@ -269,7 +269,7 @@ describe("MemoryIndexManager.readFile", () => {
});
expect(result).toEqual({ text: "", path: relPath });
} finally {
readSpy.mockRestore();
openSpy.mockRestore();
}
});

View File

@@ -450,8 +450,8 @@ describe("zalouser credential persistence", () => {
await withEnvAsync({ OPENCLAW_STATE_DIR: stateDir }, async () => {
const started = await startZaloQrLogin({ profile, timeoutMs: 1000 });
const waited = await waitForZaloQrLogin({ profile, timeoutMs: 1000 });
expect(`${started.message} ${waited.message}`).toContain(
"Refusing to write Zalo credentials to symlinked path",
expect(`${started.message} ${waited.message}`).toMatch(
/Refusing to write Zalo credentials to symlinked path|private store target must be a regular file/,
);
});

View File

@@ -451,7 +451,9 @@ describe("applyPatch", () => {
symlinkTarget: outside,
timing: "before-realpath",
run: async () => {
await expect(applyPatch(patch, { cwd: dir })).rejects.toThrow(/under root/i);
await expect(applyPatch(patch, { cwd: dir })).rejects.toThrow(
/under root|unable to resolve opened file path/i,
);
},
});
await expect(fs.stat(path.join(outside, "nested"))).rejects.toMatchObject({

View File

@@ -328,7 +328,7 @@ describe("subagent registry persistence", () => {
expect(after.version).toBe(2);
});
it("reuses unchanged persisted registry snapshots without reparsing runs.json", async () => {
it("returns isolated clones for unchanged persisted registry snapshots", async () => {
const registryPath = await writePersistedRegistry(
{
version: 2,
@@ -349,8 +349,6 @@ describe("subagent registry persistence", () => {
},
{ seedChildSessions: false },
);
const readSpy = vi.spyOn(fsSync, "readFileSync");
const first = loadSubagentRegistryFromDisk();
first.clear();
const cachedEntry = loadSubagentRegistryFromDisk().get("run-cached");
@@ -373,9 +371,6 @@ describe("subagent registry persistence", () => {
});
expect(second.get("run-cached")?.endedAt).toBeUndefined();
expect(second.get("run-cached")?.cleanupHandled).toBeUndefined();
expect(
readSpy.mock.calls.filter(([pathname]) => String(pathname) === registryPath),
).toHaveLength(1);
await fs.writeFile(
registryPath,
@@ -398,24 +393,17 @@ describe("subagent registry persistence", () => {
);
expect(loadSubagentRegistryFromDisk().has("run-updated")).toBe(true);
expect(
readSpy.mock.calls.filter(([pathname]) => String(pathname) === registryPath),
).toHaveLength(2);
});
it("reuses unchanged invalid persisted registry snapshots as empty", async () => {
it("returns empty maps for unchanged invalid persisted registry snapshots", async () => {
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-subagent-"));
process.env.OPENCLAW_STATE_DIR = tempStateDir;
const registryPath = path.join(tempStateDir, "subagents", "runs.json");
await fs.mkdir(path.dirname(registryPath), { recursive: true });
await fs.writeFile(registryPath, "{invalid", "utf8");
const readSpy = vi.spyOn(fsSync, "readFileSync");
expect(loadSubagentRegistryFromDisk()).toEqual(new Map());
expect(loadSubagentRegistryFromDisk()).toEqual(new Map());
expect(
readSpy.mock.calls.filter(([pathname]) => String(pathname) === registryPath),
).toHaveLength(1);
});
it("normalizes persisted and newly registered session keys to canonical trimmed values", async () => {

View File

@@ -228,19 +228,16 @@ describe("archive utils", () => {
symlinkTarget: outsideDir,
timing: "after-realpath",
run: async () => {
await expect(
extractArchive({
archivePath,
destDir: extractDir,
timeoutMs: ARCHIVE_EXTRACT_TIMEOUT_MS,
}),
).rejects.toMatchObject({
code: "destination-symlink-traversal",
} satisfies Partial<ArchiveSecurityError>);
await extractArchive({
archivePath,
destDir: extractDir,
timeoutMs: ARCHIVE_EXTRACT_TIMEOUT_MS,
});
},
});
await expect(fs.readFile(outsideTarget, "utf8")).resolves.toBe("SAFE");
await expect(fs.readFile(path.join(slotDir, "target.txt"), "utf8")).resolves.toBe("owned");
});
});

View File

@@ -56,6 +56,7 @@ const MEMORY_HOST_SDK_EXPORTS = [
"./status",
] as const;
const MEMORY_HOST_SDK_ALLOWED_CORE_BRIDGE_FILES = [
"packages/memory-host-sdk/src/host/fs-utils.ts",
"packages/memory-host-sdk/src/host/openclaw-runtime.ts",
] as const;
const MEMORY_HOST_SDK_RUNTIME_ADAPTER_FILES = [