mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 12:07:40 +00:00
fix: confine sandbox skill sync destinations
This commit is contained in:
@@ -16,6 +16,7 @@ import type {
|
||||
} from "./types.js";
|
||||
import { createSubsystemLogger } from "../../logging/subsystem.js";
|
||||
import { CONFIG_DIR, resolveUserPath } from "../../utils.js";
|
||||
import { resolveSandboxPath } from "../sandbox-paths.js";
|
||||
import { resolveBundledSkillsDir } from "./bundled-dir.js";
|
||||
import { shouldIncludeSkill } from "./config.js";
|
||||
import {
|
||||
@@ -301,6 +302,45 @@ export function loadWorkspaceSkillEntries(
|
||||
return loadSkillEntries(workspaceDir, opts);
|
||||
}
|
||||
|
||||
function resolveUniqueSyncedSkillDirName(base: string, used: Set<string>): string {
|
||||
if (!used.has(base)) {
|
||||
used.add(base);
|
||||
return base;
|
||||
}
|
||||
for (let index = 2; index < 10_000; index += 1) {
|
||||
const candidate = `${base}-${index}`;
|
||||
if (!used.has(candidate)) {
|
||||
used.add(candidate);
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
let fallbackIndex = 10_000;
|
||||
let fallback = `${base}-${fallbackIndex}`;
|
||||
while (used.has(fallback)) {
|
||||
fallbackIndex += 1;
|
||||
fallback = `${base}-${fallbackIndex}`;
|
||||
}
|
||||
used.add(fallback);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
function resolveSyncedSkillDestinationPath(params: {
|
||||
targetSkillsDir: string;
|
||||
entry: SkillEntry;
|
||||
usedDirNames: Set<string>;
|
||||
}): string | null {
|
||||
const sourceDirName = path.basename(params.entry.skill.baseDir).trim();
|
||||
if (!sourceDirName || sourceDirName === "." || sourceDirName === "..") {
|
||||
return null;
|
||||
}
|
||||
const uniqueDirName = resolveUniqueSyncedSkillDirName(sourceDirName, params.usedDirNames);
|
||||
return resolveSandboxPath({
|
||||
filePath: uniqueDirName,
|
||||
cwd: params.targetSkillsDir,
|
||||
root: params.targetSkillsDir,
|
||||
}).resolved;
|
||||
}
|
||||
|
||||
export async function syncSkillsToWorkspace(params: {
|
||||
sourceWorkspaceDir: string;
|
||||
targetWorkspaceDir: string;
|
||||
@@ -326,8 +366,28 @@ export async function syncSkillsToWorkspace(params: {
|
||||
await fsp.rm(targetSkillsDir, { recursive: true, force: true });
|
||||
await fsp.mkdir(targetSkillsDir, { recursive: true });
|
||||
|
||||
const usedDirNames = new Set<string>();
|
||||
for (const entry of entries) {
|
||||
const dest = path.join(targetSkillsDir, entry.skill.name);
|
||||
let dest: string | null = null;
|
||||
try {
|
||||
dest = resolveSyncedSkillDestinationPath({
|
||||
targetSkillsDir,
|
||||
entry,
|
||||
usedDirNames,
|
||||
});
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
||||
console.warn(
|
||||
`[skills] Failed to resolve safe destination for ${entry.skill.name}: ${message}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if (!dest) {
|
||||
console.warn(
|
||||
`[skills] Failed to resolve safe destination for ${entry.skill.name}: invalid source directory name`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
await fsp.cp(entry.skill.baseDir, dest, {
|
||||
recursive: true,
|
||||
|
||||
Reference in New Issue
Block a user