fix(browser): restore proxy attachment media size cap (#43684)

* browser: honor shared proxy file size cap

* test(browser): cover proxy file size cap

* docs(changelog): note browser proxy size cap fix
This commit is contained in:
Vincent Koc
2026-03-12 01:04:31 -04:00
committed by GitHub
parent 29dc65403f
commit 18f15850e6
3 changed files with 56 additions and 1 deletions

View File

@@ -130,6 +130,7 @@ Docs: https://docs.openclaw.ai
- Telegram/direct delivery: bridge direct delivery sends to internal `message:sent` hooks so internal hook listeners observe successful Telegram deliveries. (#40185) Thanks @vincentkoc.
- Dependencies: refresh workspace dependencies except the pinned Carbon package, and harden ACP session-config writes against non-string SDK values so newer ACP clients fail fast instead of tripping type/runtime mismatches.
- Telegram/polling restarts: clear bounded cleanup timeout handles after `runner.stop()` and `bot.stop()` settle so stall recovery no longer leaves stray 15-second timers behind on clean shutdown. (#43188) thanks @kyohwang.
- Browser/proxy attachments: restore the shared media-store size cap for persisted browser proxy files so oversized payloads are rejected instead of overriding the intended 5 MB limit. (#43684) Thanks @vincentkoc.
## 2026.3.8

View File

@@ -0,0 +1,54 @@
import fs from "node:fs/promises";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { MEDIA_MAX_BYTES } from "../media/store.js";
import { createTempHomeEnv, type TempHomeEnv } from "../test-utils/temp-home.js";
import { persistBrowserProxyFiles } from "./proxy-files.js";
describe("persistBrowserProxyFiles", () => {
let tempHome: TempHomeEnv;
beforeEach(async () => {
tempHome = await createTempHomeEnv("openclaw-browser-proxy-files-");
});
afterEach(async () => {
await tempHome.restore();
});
it("persists browser proxy files under the shared media store", async () => {
const sourcePath = "/tmp/proxy-file.txt";
const mapping = await persistBrowserProxyFiles([
{
path: sourcePath,
base64: Buffer.from("hello from browser proxy").toString("base64"),
mimeType: "text/plain",
},
]);
const savedPath = mapping.get(sourcePath);
expect(typeof savedPath).toBe("string");
expect(path.normalize(savedPath ?? "")).toContain(
`${path.sep}.openclaw${path.sep}media${path.sep}browser${path.sep}`,
);
await expect(fs.readFile(savedPath ?? "", "utf8")).resolves.toBe("hello from browser proxy");
});
it("rejects browser proxy files that exceed the shared media size limit", async () => {
const oversized = Buffer.alloc(MEDIA_MAX_BYTES + 1, 0x41);
await expect(
persistBrowserProxyFiles([
{
path: "/tmp/oversized.bin",
base64: oversized.toString("base64"),
mimeType: "application/octet-stream",
},
]),
).rejects.toThrow("Media exceeds 5MB limit");
await expect(
fs.stat(path.join(tempHome.home, ".openclaw", "media", "browser")),
).rejects.toThrow();
});
});

View File

@@ -13,7 +13,7 @@ export async function persistBrowserProxyFiles(files: BrowserProxyFile[] | undef
const mapping = new Map<string, string>();
for (const file of files) {
const buffer = Buffer.from(file.base64, "base64");
const saved = await saveMediaBuffer(buffer, file.mimeType, "browser", buffer.byteLength);
const saved = await saveMediaBuffer(buffer, file.mimeType, "browser");
mapping.set(file.path, saved.path);
}
return mapping;