fix(core): unify session-key normalization and plugin boundary checks

This commit is contained in:
Peter Steinberger
2026-02-26 12:40:57 +00:00
parent e3385a6578
commit 4b71de384c
13 changed files with 182 additions and 34 deletions

View File

@@ -295,6 +295,32 @@ describe("loadOpenClawPlugins", () => {
expect(Object.keys(registry.gatewayHandlers)).toContain("allowed.ping");
});
it("loads plugins when source and root differ only by realpath alias", () => {
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
const plugin = writePlugin({
id: "alias-safe",
body: `export default { id: "alias-safe", register() {} };`,
});
const realRoot = fs.realpathSync(plugin.dir);
if (realRoot === plugin.dir) {
return;
}
const registry = loadOpenClawPlugins({
cache: false,
workspaceDir: plugin.dir,
config: {
plugins: {
load: { paths: [plugin.file] },
allow: ["alias-safe"],
},
},
});
const loaded = registry.plugins.find((entry) => entry.id === "alias-safe");
expect(loaded?.status).toBe("loaded");
});
it("denylist disables plugins even if allowed", () => {
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
const plugin = writePlugin({

View File

@@ -530,6 +530,10 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
absolutePath: candidate.source,
rootPath: pluginRoot,
boundaryLabel: "plugin root",
// Discovery stores rootDir as realpath but source may still be a lexical alias
// (e.g. /var/... vs /private/var/... on macOS). Canonical boundary checks
// still enforce containment; skip lexical pre-check to avoid false escapes.
skipLexicalRootCheck: true,
});
if (!opened.ok) {
record.status = "error";