fix(security): bind system.run approvals to exact argv text

This commit is contained in:
Peter Steinberger
2026-03-11 01:25:19 +00:00
parent 8eac939417
commit 7289c19f1a
17 changed files with 241 additions and 34 deletions

View File

@@ -105,6 +105,7 @@ type ExecApprovalContainerParams = {
title: string;
description?: string;
commandPreview: string;
commandSecondaryPreview?: string | null;
metadataLines?: string[];
actionRow?: Row<Button>;
footer?: string;
@@ -121,6 +122,11 @@ class ExecApprovalContainer extends DiscordUiContainer {
}
components.push(new Separator({ divider: true, spacing: "small" }));
components.push(new TextDisplay(`### Command\n\`\`\`\n${params.commandPreview}\n\`\`\``));
if (params.commandSecondaryPreview) {
components.push(
new TextDisplay(`### Shell Preview\n\`\`\`\n${params.commandSecondaryPreview}\n\`\`\``),
);
}
if (params.metadataLines?.length) {
components.push(new TextDisplay(params.metadataLines.join("\n")));
}
@@ -235,6 +241,16 @@ function formatCommandPreview(commandText: string, maxChars: number): string {
return commandRaw.replace(/`/g, "\u200b`");
}
function formatOptionalCommandPreview(
commandText: string | null | undefined,
maxChars: number,
): string | null {
if (!commandText) {
return null;
}
return formatCommandPreview(commandText, maxChars);
}
function createExecApprovalRequestContainer(params: {
request: ExecApprovalRequest;
cfg: OpenClawConfig;
@@ -243,6 +259,10 @@ function createExecApprovalRequestContainer(params: {
}): ExecApprovalContainer {
const commandText = params.request.request.command;
const commandPreview = formatCommandPreview(commandText, 1000);
const commandSecondaryPreview = formatOptionalCommandPreview(
params.request.request.commandPreview,
500,
);
const expiresAtSeconds = Math.max(0, Math.floor(params.request.expiresAtMs / 1000));
return new ExecApprovalContainer({
@@ -251,6 +271,7 @@ function createExecApprovalRequestContainer(params: {
title: "Exec Approval Required",
description: "A command needs your approval.",
commandPreview,
commandSecondaryPreview,
metadataLines: buildExecApprovalMetadataLines(params.request),
actionRow: params.actionRow,
footer: `Expires <t:${expiresAtSeconds}:R> · ID: ${params.request.id}`,
@@ -267,6 +288,10 @@ function createResolvedContainer(params: {
}): ExecApprovalContainer {
const commandText = params.request.request.command;
const commandPreview = formatCommandPreview(commandText, 500);
const commandSecondaryPreview = formatOptionalCommandPreview(
params.request.request.commandPreview,
300,
);
const decisionLabel =
params.decision === "allow-once"
@@ -288,6 +313,7 @@ function createResolvedContainer(params: {
title: `Exec Approval: ${decisionLabel}`,
description: params.resolvedBy ? `Resolved by ${params.resolvedBy}` : "Resolved",
commandPreview,
commandSecondaryPreview,
footer: `ID: ${params.request.id}`,
accentColor,
});
@@ -300,6 +326,10 @@ function createExpiredContainer(params: {
}): ExecApprovalContainer {
const commandText = params.request.request.command;
const commandPreview = formatCommandPreview(commandText, 500);
const commandSecondaryPreview = formatOptionalCommandPreview(
params.request.request.commandPreview,
300,
);
return new ExecApprovalContainer({
cfg: params.cfg,
@@ -307,6 +337,7 @@ function createExpiredContainer(params: {
title: "Exec Approval: Expired",
description: "This approval request has expired.",
commandPreview,
commandSecondaryPreview,
footer: `ID: ${params.request.id}`,
accentColor: "#99AAB5",
});