mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 08:00:42 +00:00
test(plugins): harden kitchen sink external install
This commit is contained in:
@@ -17,12 +17,36 @@ const profiles = {
|
||||
packageJson: {
|
||||
name: packageName,
|
||||
version: "0.1.3",
|
||||
type: "module",
|
||||
dependencies: {
|
||||
"is-number": "7.0.0",
|
||||
},
|
||||
peerDependencies: {
|
||||
openclaw: ">=2026.4.11",
|
||||
},
|
||||
peerDependenciesMeta: {
|
||||
openclaw: {
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
openclaw: { extensions: ["./index.js"] },
|
||||
},
|
||||
indexJs: `module.exports = {
|
||||
indexJs: `import isNumber from "is-number";
|
||||
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
||||
|
||||
const dependencyUrl = import.meta.resolve("is-number");
|
||||
const expectedDependencyBaseUrl = new URL("./node_modules/is-number/", import.meta.url).href;
|
||||
if (!dependencyUrl.startsWith(expectedDependencyBaseUrl)) {
|
||||
throw new Error(\`kitchen-sink dependency resolved outside plugin root: \${dependencyUrl}\`);
|
||||
}
|
||||
|
||||
export default definePluginEntry({
|
||||
id: "${pluginId}",
|
||||
name: "OpenClaw Kitchen Sink",
|
||||
register(api) {
|
||||
if (!isNumber(42)) {
|
||||
throw new Error("kitchen-sink dependency sentinel did not load");
|
||||
}
|
||||
api.registerProvider({
|
||||
id: "kitchen-sink-provider",
|
||||
label: "Kitchen Sink Provider",
|
||||
@@ -48,7 +72,7 @@ const profiles = {
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
||||
`,
|
||||
manifest: {
|
||||
id: pluginId,
|
||||
|
||||
@@ -119,6 +119,38 @@ const expectIncludes = (listValue, expected, field) => {
|
||||
}
|
||||
};
|
||||
|
||||
function assertRealPathInside(parentPath, childPath, label) {
|
||||
const parentRealPath = fs.realpathSync(parentPath);
|
||||
const childRealPath = fs.realpathSync(childPath);
|
||||
if (
|
||||
childRealPath !== parentRealPath &&
|
||||
!childRealPath.startsWith(`${parentRealPath}${path.sep}`)
|
||||
) {
|
||||
throw new Error(`${label} resolved outside ${parentPath}: ${childRealPath}`);
|
||||
}
|
||||
}
|
||||
|
||||
function assertClawHubExternalInstallContract(installPath) {
|
||||
const openclawPeerPath = path.join(installPath, "node_modules", "openclaw");
|
||||
if (!fs.existsSync(openclawPeerPath)) {
|
||||
throw new Error(`missing kitchen-sink openclaw peer symlink: ${openclawPeerPath}`);
|
||||
}
|
||||
if (!fs.lstatSync(openclawPeerPath).isSymbolicLink()) {
|
||||
throw new Error(`kitchen-sink openclaw peer is not a symlink: ${openclawPeerPath}`);
|
||||
}
|
||||
const hostRoot = fs.realpathSync(process.cwd());
|
||||
const linkedHostRoot = fs.realpathSync(openclawPeerPath);
|
||||
if (linkedHostRoot !== hostRoot) {
|
||||
throw new Error(`expected kitchen-sink openclaw peer ${linkedHostRoot} to target ${hostRoot}`);
|
||||
}
|
||||
|
||||
const dependencyPackagePath = path.join(installPath, "node_modules", "is-number", "package.json");
|
||||
if (!fs.existsSync(dependencyPackagePath)) {
|
||||
throw new Error(`missing kitchen-sink isolated dependency: ${dependencyPackagePath}`);
|
||||
}
|
||||
assertRealPathInside(installPath, dependencyPackagePath, "kitchen-sink isolated dependency");
|
||||
}
|
||||
|
||||
function assertInstalled() {
|
||||
const pluginId = process.env.KITCHEN_SINK_ID;
|
||||
const spec = process.env.KITCHEN_SINK_SPEC;
|
||||
@@ -270,6 +302,9 @@ function assertInstalled() {
|
||||
if (!fs.existsSync(installPath)) {
|
||||
throw new Error(`kitchen-sink install path missing: ${record.installPath}`);
|
||||
}
|
||||
if (source === "clawhub") {
|
||||
assertClawHubExternalInstallContract(installPath);
|
||||
}
|
||||
fs.writeFileSync(`/tmp/kitchen-sink-${label}-install-path.txt`, installPath, "utf8");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user