


























@@ -7,6 +7,7 @@ import { isRecord } from "@openclaw/normalization-core/record-coerce";
77import { normalizeStringEntries } from "@openclaw/normalization-core/string-normalization";
88import { describeInterpreterInlineEval } from "../infra/command-analysis/inline-eval.js";
99import { detectPolicyInlineEval } from "../infra/command-analysis/policy.js";
10+import { emitTrustedSecurityEvent } from "../infra/diagnostic-events.js";
1011import {
1112addDurableCommandApproval,
1213commandRequiresSecurityAuditSuppressionApproval,
@@ -250,6 +251,59 @@ function formatDiagnosticsExportSuccess(aggregated: string): string {
250251}
251252}
252253254+function emitGatewayExecApprovalSecurityEvent(params: {
255+action: "exec.approval.requested" | "exec.approval.approved" | "exec.approval.denied";
256+outcome: "success" | "denied" | "error";
257+severity: "low" | "medium" | "high";
258+agentId?: string | null;
259+reason?: string;
260+hostSecurity: ExecSecurity;
261+hostAsk: ExecAsk;
262+host: "gateway";
263+segmentCount: number;
264+trigger?: string;
265+decision?: string | null;
266+}) {
267+emitTrustedSecurityEvent({
268+category: "approval",
269+action: params.action,
270+outcome: params.outcome,
271+severity: params.severity,
272+actor: {
273+kind: "agent",
274+},
275+target: {
276+kind: "tool",
277+name: "system.exec",
278+owner: params.host,
279+},
280+policy: {
281+id: "exec.approval",
282+decision:
283+params.action === "exec.approval.requested"
284+ ? "ask"
285+ : params.outcome === "success"
286+ ? "allow"
287+ : "deny",
288+ ...(params.reason ? { reason: params.reason } : {}),
289+},
290+control: {
291+id: "exec.approval",
292+family: "approval",
293+},
294+ ...(params.reason ? { reason: params.reason } : {}),
295+attributes: {
296+host: params.host,
297+security: params.hostSecurity,
298+ask: params.hostAsk,
299+segment_count: params.segmentCount,
300+has_agent_id: Boolean(params.agentId?.trim()),
301+ ...(params.trigger ? { trigger: params.trigger } : {}),
302+ ...(params.decision ? { decision: params.decision } : {}),
303+},
304+});
305+}
306+253307function formatDiagnosticsExportFailure(params: {
254308outcome: { status: string; reason?: string; aggregated: string };
255309exitLabel: string;
@@ -559,6 +613,17 @@ export async function processGatewayAllowlist(
559613 ...requestArgs,
560614register: registerGatewayApproval,
561615});
616+emitGatewayExecApprovalSecurityEvent({
617+action: "exec.approval.requested",
618+outcome: "success",
619+severity: "low",
620+agentId: params.agentId,
621+ hostSecurity,
622+ hostAsk,
623+host: "gateway",
624+segmentCount: allowlistEval.segments.length,
625+trigger: params.trigger,
626+});
562627if (
563628shouldResolveExecApprovalUnavailableInline({
564629trigger: params.trigger,
@@ -612,6 +677,18 @@ export async function processGatewayAllowlist(
612677 onFailure,
613678});
614679if (decision === undefined) {
680+emitGatewayExecApprovalSecurityEvent({
681+action: "exec.approval.denied",
682+outcome: "error",
683+severity: "high",
684+agentId: params.agentId,
685+reason: "approval-request-failed",
686+ hostSecurity,
687+ hostAsk,
688+host: "gateway",
689+segmentCount: allowlistEval.segments.length,
690+trigger: params.trigger,
691+});
615692return { deniedReason: "approval-request-failed", requestFailed: true };
616693}
617694@@ -678,6 +755,19 @@ export async function processGatewayAllowlist(
678755deniedReason = deniedReason ?? "allowlist-miss";
679756}
680757758+emitGatewayExecApprovalSecurityEvent({
759+action: deniedReason ? "exec.approval.denied" : "exec.approval.approved",
760+outcome: deniedReason ? "denied" : "success",
761+severity: "medium",
762+agentId: params.agentId,
763+reason: deniedReason ?? undefined,
764+ hostSecurity,
765+ hostAsk,
766+host: "gateway",
767+segmentCount: allowlistEval.segments.length,
768+trigger: params.trigger,
769+ decision,
770+});
681771return { deniedReason, requestFailed: false };
682772};
683773此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。