Media: secure image temp dirs (#58270)

This commit is contained in:
Jacob Tomlinson
2026-03-31 03:12:47 -07:00
committed by GitHub
parent 6be0c7ef09
commit 781775ec08
4 changed files with 48 additions and 5 deletions

View File

@@ -9,10 +9,11 @@ import {
unwrapExpression,
} from "./lib/ts-guard-utils.mjs";
const sourceRoots = [
export const messagingTmpdirGuardSourceRoots = [
"src/channels",
"src/infra/outbound",
"src/line",
"src/media",
"src/media-understanding",
"extensions",
];
@@ -72,7 +73,7 @@ export function findMessagingTmpdirCallLines(content, fileName = "source.ts") {
export async function main() {
await runCallsiteGuard({
importMetaUrl: import.meta.url,
sourceRoots,
sourceRoots: messagingTmpdirGuardSourceRoots,
findCallLines: findMessagingTmpdirCallLines,
skipRelativePath: (relativePath) => allowedRelativePaths.has(relativePath),
header: "Found os.tmpdir()/tmpdir() usage in messaging/channel runtime sources:",

View File

@@ -0,0 +1,35 @@
import fs from "node:fs/promises";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { resolvePreferredOpenClawTmpDir } from "../infra/tmp-openclaw-dir.js";
describe("image-ops temp dir", () => {
let createdTempDir = "";
beforeEach(() => {
process.env.OPENCLAW_IMAGE_BACKEND = "sips";
const originalMkdtemp = fs.mkdtemp.bind(fs);
vi.spyOn(fs, "mkdtemp").mockImplementation(async (prefix) => {
createdTempDir = await originalMkdtemp(prefix);
return createdTempDir;
});
});
afterEach(() => {
delete process.env.OPENCLAW_IMAGE_BACKEND;
vi.restoreAllMocks();
vi.resetModules();
});
it("creates sips temp dirs under the secured OpenClaw tmp root", async () => {
const { getImageMetadata } = await import("./image-ops.js");
const secureRoot = resolvePreferredOpenClawTmpDir();
await getImageMetadata(Buffer.from("image"));
expect(fs.mkdtemp).toHaveBeenCalledTimes(1);
expect(fs.mkdtemp).toHaveBeenCalledWith(path.join(secureRoot, "openclaw-img-"));
expect(createdTempDir.startsWith(path.join(secureRoot, "openclaw-img-"))).toBe(true);
await expect(fs.access(createdTempDir)).rejects.toMatchObject({ code: "ENOENT" });
});
});

View File

@@ -1,6 +1,6 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { resolvePreferredOpenClawTmpDir } from "../infra/tmp-openclaw-dir.js";
import { runExec } from "../process/exec.js";
type Sharp = typeof import("sharp");
@@ -134,7 +134,7 @@ function readJpegExifOrientation(buffer: Buffer): number | null {
}
async function withTempDir<T>(fn: (dir: string) => Promise<T>): Promise<T> {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-img-"));
const dir = await fs.mkdtemp(path.join(resolvePreferredOpenClawTmpDir(), "openclaw-img-"));
try {
return await fn(dir);
} finally {

View File

@@ -1,5 +1,8 @@
import { describe, expect, it } from "vitest";
import { findMessagingTmpdirCallLines } from "../../scripts/check-no-random-messaging-tmp.mjs";
import {
findMessagingTmpdirCallLines,
messagingTmpdirGuardSourceRoots,
} from "../../scripts/check-no-random-messaging-tmp.mjs";
describe("check-no-random-messaging-tmp", () => {
it("finds os.tmpdir calls imported from node:os", () => {
@@ -41,4 +44,8 @@ describe("check-no-random-messaging-tmp", () => {
`;
expect(findMessagingTmpdirCallLines(source)).toEqual([]);
});
it("guards src/media against host tmpdir usage", () => {
expect(messagingTmpdirGuardSourceRoots).toContain("src/media");
});
});