mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 14:20:44 +00:00
perf(test): cache sandbox bind policy paths
This commit is contained in:
@@ -92,12 +92,13 @@ describe("validateBindMounts", () => {
|
||||
});
|
||||
|
||||
it("allows legitimate project directory mounts", () => {
|
||||
const projectRoot = mkdtempSync(join(tmpdir(), "openclaw-sbx-safe-"));
|
||||
expect(() =>
|
||||
validateBindMounts([
|
||||
"/home/user/source:/source:rw",
|
||||
"/home/user/projects:/projects:ro",
|
||||
"/var/data/myapp:/data",
|
||||
"/opt/myapp/config:/config:ro",
|
||||
`${join(projectRoot, "source")}:/source:rw`,
|
||||
`${join(projectRoot, "projects")}:/projects:ro`,
|
||||
`${join(projectRoot, "data")}:/data`,
|
||||
`${join(projectRoot, "config")}:/config:ro`,
|
||||
]),
|
||||
).not.toThrow();
|
||||
});
|
||||
@@ -256,42 +257,46 @@ describe("validateBindMounts", () => {
|
||||
});
|
||||
|
||||
it("blocks bind sources outside allowed roots when allowlist is configured", () => {
|
||||
const allowedRoot = mkdtempSync(join(tmpdir(), "openclaw-sbx-allowed-root-"));
|
||||
const externalRoot = mkdtempSync(join(tmpdir(), "openclaw-sbx-external-"));
|
||||
expect(() =>
|
||||
validateBindMounts(["/opt/external:/data:ro"], {
|
||||
allowedSourceRoots: ["/home/user/project"],
|
||||
validateBindMounts([`${externalRoot}:/data:ro`], {
|
||||
allowedSourceRoots: [allowedRoot],
|
||||
}),
|
||||
).toThrow(/outside allowed roots/);
|
||||
});
|
||||
|
||||
it("allows bind sources in allowed roots when allowlist is configured", () => {
|
||||
const projectRoot = mkdtempSync(join(tmpdir(), "openclaw-sbx-allowed-"));
|
||||
expect(() =>
|
||||
validateBindMounts(["/home/user/project/cache:/data:ro"], {
|
||||
allowedSourceRoots: ["/home/user/project"],
|
||||
validateBindMounts([`${join(projectRoot, "cache")}:/data:ro`], {
|
||||
allowedSourceRoots: [projectRoot],
|
||||
}),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it("allows bind sources outside allowed roots with explicit dangerous override", () => {
|
||||
const allowedRoot = mkdtempSync(join(tmpdir(), "openclaw-sbx-allowed-root-"));
|
||||
const externalRoot = mkdtempSync(join(tmpdir(), "openclaw-sbx-external-"));
|
||||
expect(() =>
|
||||
validateBindMounts(["/opt/external:/data:ro"], {
|
||||
allowedSourceRoots: ["/home/user/project"],
|
||||
validateBindMounts([`${externalRoot}:/data:ro`], {
|
||||
allowedSourceRoots: [allowedRoot],
|
||||
allowSourcesOutsideAllowedRoots: true,
|
||||
}),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it("blocks reserved container target paths by default", () => {
|
||||
const projectRoot = mkdtempSync(join(tmpdir(), "openclaw-sbx-reserved-default-"));
|
||||
expect(() =>
|
||||
validateBindMounts([
|
||||
"/home/user/project:/workspace:rw",
|
||||
"/home/user/project:/agent/cache:rw",
|
||||
]),
|
||||
validateBindMounts([`${projectRoot}:/workspace:rw`, `${projectRoot}:/agent/cache:rw`]),
|
||||
).toThrow(/reserved container path/);
|
||||
});
|
||||
|
||||
it("allows reserved container target paths with explicit dangerous override", () => {
|
||||
const projectRoot = mkdtempSync(join(tmpdir(), "openclaw-sbx-reserved-"));
|
||||
expect(() =>
|
||||
validateBindMounts(["/home/user/project:/workspace:rw"], {
|
||||
validateBindMounts([`${projectRoot}:/workspace:rw`], {
|
||||
allowReservedContainerTargets: true,
|
||||
}),
|
||||
).not.toThrow();
|
||||
@@ -379,9 +384,10 @@ describe("profile hardening", () => {
|
||||
|
||||
describe("validateSandboxSecurity", () => {
|
||||
it("passes with safe config", () => {
|
||||
const projectRoot = mkdtempSync(join(tmpdir(), "openclaw-sbx-safe-config-"));
|
||||
expect(() =>
|
||||
validateSandboxSecurity({
|
||||
binds: ["/home/user/src:/src:rw"],
|
||||
binds: [`${projectRoot}:/src:rw`],
|
||||
network: "none",
|
||||
seccompProfile: "/tmp/seccomp.json",
|
||||
apparmorProfile: "openclaw-sandbox",
|
||||
|
||||
@@ -50,6 +50,12 @@ const BLOCKED_HOME_SUBPATHS = [
|
||||
const BLOCKED_SECCOMP_PROFILES = new Set(["unconfined"]);
|
||||
const BLOCKED_APPARMOR_PROFILES = new Set(["unconfined"]);
|
||||
const RESERVED_CONTAINER_TARGET_PATHS = ["/workspace", SANDBOX_AGENT_WORKSPACE_MOUNT];
|
||||
let blockedHostPathsCache:
|
||||
| {
|
||||
key: string;
|
||||
paths: string[];
|
||||
}
|
||||
| undefined;
|
||||
|
||||
export type ValidateBindMountsOptions = {
|
||||
allowedSourceRoots?: string[];
|
||||
@@ -146,13 +152,22 @@ export function getBlockedReasonForSourcePath(
|
||||
}
|
||||
|
||||
function getBlockedHostPaths(): string[] {
|
||||
const cacheKey = JSON.stringify({
|
||||
home: process.env.HOME,
|
||||
openclawHome: process.env.OPENCLAW_HOME,
|
||||
osHome: os.homedir(),
|
||||
});
|
||||
if (blockedHostPathsCache?.key === cacheKey) {
|
||||
return blockedHostPathsCache.paths;
|
||||
}
|
||||
const blocked = new Set(BLOCKED_HOST_PATHS.map(normalizeHostPath));
|
||||
for (const home of getBlockedHomeRoots()) {
|
||||
for (const suffix of BLOCKED_HOME_SUBPATHS) {
|
||||
blocked.add(normalizeHostPath(path.posix.join(home, suffix)));
|
||||
}
|
||||
}
|
||||
return [...blocked];
|
||||
blockedHostPathsCache = { key: cacheKey, paths: [...blocked] };
|
||||
return blockedHostPathsCache.paths;
|
||||
}
|
||||
|
||||
function getBlockedHomeRoots(): string[] {
|
||||
|
||||
Reference in New Issue
Block a user