mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-26 04:35:14 +00:00
Summary: - The branch marks runtime `toolsAllow` sources as enforceable during disabled-tool runs, filters inherited allowlist sources in the guard, adds focused guard coverage, and updates the changelog. - Reproducibility: yes. The linked report gives concrete config and invocation steps, and source inspection on ... sables tools while the guard still treats inherited allowlist sources plus zero callable tools as an error. Automerge notes: - No ClawSweeper repair was needed after automerge opt-in. Validation: - ClawSweeper review passed for head9c3e5f773e. - Required merge gates passed before the squash merge. Prepared head SHA:9c3e5f773eReview: https://github.com/openclaw/openclaw/pull/76686#issuecomment-4366216196 Co-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
54 lines
1.8 KiB
TypeScript
54 lines
1.8 KiB
TypeScript
import { normalizeToolName } from "./tool-policy.js";
|
|
|
|
type ExplicitToolAllowlistSource = {
|
|
label: string;
|
|
entries: string[];
|
|
enforceWhenToolsDisabled?: boolean;
|
|
};
|
|
|
|
export function collectExplicitToolAllowlistSources(
|
|
sources: Array<{ label: string; allow?: string[]; enforceWhenToolsDisabled?: boolean }>,
|
|
): ExplicitToolAllowlistSource[] {
|
|
return sources.flatMap((source) => {
|
|
const entries = (source.allow ?? []).map((entry) => entry.trim()).filter(Boolean);
|
|
if (entries.length === 0) {
|
|
return [];
|
|
}
|
|
return [
|
|
{
|
|
label: source.label,
|
|
entries,
|
|
...(source.enforceWhenToolsDisabled === true ? { enforceWhenToolsDisabled: true } : {}),
|
|
},
|
|
];
|
|
});
|
|
}
|
|
|
|
export function buildEmptyExplicitToolAllowlistError(params: {
|
|
sources: ExplicitToolAllowlistSource[];
|
|
callableToolNames: string[];
|
|
toolsEnabled: boolean;
|
|
disableTools?: boolean;
|
|
}): Error | null {
|
|
const sources =
|
|
params.disableTools === true
|
|
? params.sources.filter((source) => source.enforceWhenToolsDisabled === true)
|
|
: params.sources;
|
|
const callableToolNames = params.callableToolNames.map(normalizeToolName).filter(Boolean);
|
|
if (sources.length === 0 || callableToolNames.length > 0) {
|
|
return null;
|
|
}
|
|
const requested = sources
|
|
.map((source) => `${source.label}: ${source.entries.map(normalizeToolName).join(", ")}`)
|
|
.join("; ");
|
|
const reason =
|
|
params.disableTools === true
|
|
? "tools are disabled for this run"
|
|
: params.toolsEnabled
|
|
? "no registered tools matched"
|
|
: "the selected model does not support tools";
|
|
return new Error(
|
|
`No callable tools remain after resolving explicit tool allowlist (${requested}); ${reason}. Fix the allowlist or enable the plugin that registers the requested tool.`,
|
|
);
|
|
}
|