fix(browser): allow inbound media uploads

Allow the browser upload tool to resolve OpenClaw-managed inbound media refs such as `media://inbound/<id>` and sandbox-relative `media/inbound/<id>` while preserving the existing upload-root path contract.

Keep upload-root files ahead of sandbox-relative inbound fallback, reject nested absolute inbound media files, and validate raw `media://` paths before URL normalization so traversal-shaped refs cannot resolve to direct media ids.

Verification:
- `OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs extensions/browser/src/browser/paths.test.ts --reporter=verbose`
- `OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs extensions/browser/src/browser/paths.test.ts --reporter=dot`
- `OPENCLAW_HEAVY_CHECK_LOCK_SCOPE=worktree node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo`
- `pnpm lint --threads=8`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- `git diff --check`
- GitHub PR checks on be08e6c8a8: dependency-guard, check-lint, check-test-types, check-additional-extension-bundled, checks-fast-contracts-plugins-a, checks-fast-contracts-plugins-b all passed.

Fixes #83544.

Co-authored-by: Zee Zheng <zheng.zuo0@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Zee Zheng
2026-05-31 06:49:07 +08:00
committed by GitHub
parent d05e4a4bc6
commit 8be581cbf8
16 changed files with 736 additions and 61 deletions

View File

@@ -7,9 +7,8 @@ import {
} from "../browser-cli-shared.js";
import {
danger,
DEFAULT_UPLOAD_DIR,
defaultRuntime,
resolveExistingPathsWithinRoot,
resolveExistingUploadPaths,
shortenHomePath,
} from "../core-api.js";
import { resolveBrowserActionContext, withBrowserActionTimeoutSlack } from "./shared.js";
@@ -17,11 +16,7 @@ import { resolveBrowserActionContext, withBrowserActionTimeoutSlack } from "./sh
const DEFAULT_BROWSER_HOOK_TIMEOUT_MS = 120000;
async function normalizeUploadPaths(paths: string[]): Promise<string[]> {
const result = await resolveExistingPathsWithinRoot({
rootDir: DEFAULT_UPLOAD_DIR,
requestedPaths: paths,
scopeLabel: `uploads directory (${DEFAULT_UPLOAD_DIR})`,
});
const result = await resolveExistingUploadPaths({ requestedPaths: paths });
if (!result.ok) {
throw new Error(result.error);
}
@@ -95,7 +90,7 @@ export function registerBrowserFilesAndDownloadsCommands(
.description("Arm file upload for the next file chooser")
.argument(
"<paths...>",
"File paths to upload (must be within OpenClaw temp uploads dir, e.g. /tmp/openclaw/uploads/file.pdf)",
"File paths to upload from OpenClaw temp uploads or managed inbound media (e.g. /tmp/openclaw/uploads/file.pdf or media://inbound/<id>)",
)
.option("--ref <ref>", "Ref id from snapshot to click after arming")
.option("--input-ref <ref>", "Ref id for <input type=file> to set directly")

View File

@@ -27,6 +27,7 @@ export const browserActionExamples = [
"openclaw browser drag 10 11",
"openclaw browser select 9 OptionA OptionB",
"openclaw browser upload /tmp/openclaw/uploads/file.pdf",
"openclaw browser upload media://inbound/file.pdf",
'openclaw browser fill --fields \'[{"ref":"1","value":"Ada"}]\'',
"openclaw browser dialog --accept",
'openclaw browser wait --text "Done"',