mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-30 01:08:42 +00:00
fix(ollama): bypass managed proxy for loopback embeddings (#85707)
* fix(ollama): bypass proxy for local embeddings * fix(ollama): keep managed proxy bypass loopback-only * fix(ollama): keep proxy bypass internal * fix(ollama): keep proxy bypass private * fix(ollama): harden internal proxy bypass * chore(plugin-sdk): refresh api baseline * fix(ollama): keep internal bypass out of qa aliases * test(ollama): keep ssrf runtime mock complete * fix(ollama): keep dist sdk aliases public-only * fix(ollama): keep fetch bypass out of infra runtime * fix(ollama): preserve packaged private sdk alias * test(ollama): harden private ssrf alias coverage * test(ollama): cover private ssrf resolver edges * fix(ollama): scope private sdk native aliases * test(ollama): audit blocked loopback bypasses * fix(plugins): keep staged sdk aliases public-only * test(ollama): harden proxy bypass proof * test(ollama): cover origin mismatch proxy path * test(ollama): cover ipv6 and batch bypass paths * fix lint findings in Ollama proxy tests * refactor: tighten Ollama proxy bypass * fix: widen private sdk owner registry type * test: stabilize Ollama proxy PR checks --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -74,6 +74,7 @@
|
||||
"talk-config-runtime",
|
||||
"ssrf-policy",
|
||||
"ssrf-runtime",
|
||||
"ssrf-runtime-internal",
|
||||
"media-runtime",
|
||||
"media-store",
|
||||
"media-mime",
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
"qa-channel-protocol",
|
||||
"qa-lab",
|
||||
"qa-runtime",
|
||||
"ssrf-runtime-internal",
|
||||
"test-utils"
|
||||
]
|
||||
|
||||
@@ -73,22 +73,132 @@ function writeJsonFile(targetPath, value) {
|
||||
fs.writeFileSync(targetPath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
||||
}
|
||||
|
||||
const PRIVATE_LOCAL_ONLY_PLUGIN_SDK_DIST_FILE_NAME_FALLBACK = [
|
||||
"codex-mcp-projection.js",
|
||||
"codex-native-task-runtime.js",
|
||||
"qa-channel.js",
|
||||
"qa-channel-protocol.js",
|
||||
"qa-lab.js",
|
||||
"qa-runtime.js",
|
||||
"ssrf-runtime-internal.js",
|
||||
"test-utils.js",
|
||||
];
|
||||
|
||||
function tryReadJsonFile(targetPath) {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(targetPath, "utf8"));
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function isSafePluginSdkSubpathSegment(subpath) {
|
||||
return /^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(subpath);
|
||||
}
|
||||
|
||||
function readPrivateLocalOnlyPluginSdkDistFileNames(repoRoot) {
|
||||
const privateFileNames = new Set(PRIVATE_LOCAL_ONLY_PLUGIN_SDK_DIST_FILE_NAME_FALLBACK);
|
||||
const subpaths = tryReadJsonFile(
|
||||
path.join(repoRoot, "scripts", "lib", "plugin-sdk-private-local-only-subpaths.json"),
|
||||
);
|
||||
if (!Array.isArray(subpaths)) {
|
||||
return privateFileNames;
|
||||
}
|
||||
for (const subpath of subpaths) {
|
||||
if (typeof subpath === "string" && isSafePluginSdkSubpathSegment(subpath)) {
|
||||
privateFileNames.add(`${subpath}.js`);
|
||||
}
|
||||
}
|
||||
return privateFileNames;
|
||||
}
|
||||
|
||||
function collectLegacyPublicPluginSdkDistFileNames(params) {
|
||||
const privateFileNames = readPrivateLocalOnlyPluginSdkDistFileNames(params.repoRoot);
|
||||
const fileNames = new Set();
|
||||
for (const dirent of fs.readdirSync(params.pluginSdkDir, { withFileTypes: true })) {
|
||||
if (!dirent.isFile() || path.extname(dirent.name) !== ".js") {
|
||||
continue;
|
||||
}
|
||||
if (privateFileNames.has(dirent.name)) {
|
||||
continue;
|
||||
}
|
||||
fileNames.add(dirent.name);
|
||||
}
|
||||
return fileNames.size > 0 ? fileNames : undefined;
|
||||
}
|
||||
|
||||
function readPublicPluginSdkDistFileNames(params) {
|
||||
const packageJson = tryReadJsonFile(path.join(params.repoRoot, "package.json"));
|
||||
if (!packageJson || typeof packageJson !== "object" || Array.isArray(packageJson)) {
|
||||
return collectLegacyPublicPluginSdkDistFileNames(params);
|
||||
}
|
||||
const packageExports = packageJson.exports;
|
||||
if (!packageExports || typeof packageExports !== "object" || Array.isArray(packageExports)) {
|
||||
return collectLegacyPublicPluginSdkDistFileNames(params);
|
||||
}
|
||||
|
||||
const fileNames = new Set();
|
||||
for (const exportKey of Object.keys(packageExports)) {
|
||||
if (exportKey === "./plugin-sdk") {
|
||||
fileNames.add("index.js");
|
||||
continue;
|
||||
}
|
||||
if (!exportKey.startsWith("./plugin-sdk/")) {
|
||||
continue;
|
||||
}
|
||||
const subpath = exportKey.slice("./plugin-sdk/".length);
|
||||
if (isSafePluginSdkSubpathSegment(subpath)) {
|
||||
fileNames.add(`${subpath}.js`);
|
||||
}
|
||||
}
|
||||
|
||||
return fileNames.size > 0 ? fileNames : collectLegacyPublicPluginSdkDistFileNames(params);
|
||||
}
|
||||
|
||||
function buildRuntimePluginSdkPackageExports(publicDistFileNames) {
|
||||
if (!publicDistFileNames) {
|
||||
return {
|
||||
"./plugin-sdk": "./plugin-sdk/index.js",
|
||||
};
|
||||
}
|
||||
|
||||
const sortedFileNames = [...publicDistFileNames].toSorted((left, right) => {
|
||||
if (left === "index.js") {
|
||||
return -1;
|
||||
}
|
||||
if (right === "index.js") {
|
||||
return 1;
|
||||
}
|
||||
return left.localeCompare(right);
|
||||
});
|
||||
return Object.fromEntries(
|
||||
sortedFileNames.map((fileName) => {
|
||||
const subpath = fileName.slice(0, -".js".length);
|
||||
return [
|
||||
subpath === "index" ? "./plugin-sdk" : `./plugin-sdk/${subpath}`,
|
||||
`./plugin-sdk/${fileName}`,
|
||||
];
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function ensureOpenClawExtensionAlias(params) {
|
||||
const pluginSdkDir = path.join(params.repoRoot, "dist", "plugin-sdk");
|
||||
if (!fs.existsSync(pluginSdkDir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const publicDistFileNames = readPublicPluginSdkDistFileNames({
|
||||
repoRoot: params.repoRoot,
|
||||
pluginSdkDir,
|
||||
});
|
||||
const aliasDir = path.join(params.distExtensionsRoot, "node_modules", "openclaw");
|
||||
const pluginSdkAliasPath = path.join(aliasDir, "plugin-sdk");
|
||||
fs.mkdirSync(aliasDir, { recursive: true });
|
||||
writeJsonFile(path.join(aliasDir, "package.json"), {
|
||||
name: "openclaw",
|
||||
type: "module",
|
||||
exports: {
|
||||
"./plugin-sdk": "./plugin-sdk/index.js",
|
||||
"./plugin-sdk/*": "./plugin-sdk/*.js",
|
||||
},
|
||||
exports: buildRuntimePluginSdkPackageExports(publicDistFileNames),
|
||||
});
|
||||
removePathIfExists(pluginSdkAliasPath);
|
||||
fs.mkdirSync(pluginSdkAliasPath, { recursive: true });
|
||||
@@ -96,6 +206,9 @@ function ensureOpenClawExtensionAlias(params) {
|
||||
if (!dirent.isFile() || path.extname(dirent.name) !== ".js") {
|
||||
continue;
|
||||
}
|
||||
if (publicDistFileNames && !publicDistFileNames.has(dirent.name)) {
|
||||
continue;
|
||||
}
|
||||
writeRuntimeModuleWrapper(
|
||||
path.join(pluginSdkDir, dirent.name),
|
||||
path.join(pluginSdkAliasPath, dirent.name),
|
||||
|
||||
Reference in New Issue
Block a user