import { requiresExecApproval, type ExecAsk, type ExecSecurity } from "../infra/exec-approvals.js" ;
export type ExecApprovalDecision = "allow-once" | "allow-always" | null ;
export type SystemRunPolicyDecision = {
analysisOk: boolean ;
allowlistSatisfied: boolean ;
shellWrapperBlocked: boolean ;
windowsShellWrapperBlocked: boolean ;
requiresAsk: boolean ;
approvalDecision: ExecApprovalDecision;
approvedByAsk: boolean ;
} & (
| {
allowed: true ;
}
| {
allowed: false ;
eventReason: "security=deny" | "approval-required" | "allowlist-miss" ;
errorMessage: string;
}
);
export function resolveExecApprovalDecision(value: unknown): ExecApprovalDecision {
if (value === "allow-once" || value === "allow-always" ) {
return value;
}
return null ;
}
export function formatSystemRunAllowlistMissMessage(params?: {
shellWrapperBlocked?: boolean ;
windowsShellWrapperBlocked?: boolean ;
}): string {
if (params?.windowsShellWrapperBlocked) {
return (
"SYSTEM_RUN_DENIED: allowlist miss " +
"(Windows shell wrappers like cmd.exe /c require approval; " +
"approve once/always or run with --ask on-miss|always)"
);
}
if (params?.shellWrapperBlocked) {
return (
"SYSTEM_RUN_DENIED: allowlist miss " +
"(shell wrappers like sh/bash/zsh -c require approval; " +
"approve once/always or run with --ask on-miss|always)"
);
}
return "SYSTEM_RUN_DENIED: allowlist miss" ;
}
export function evaluateSystemRunPolicy(params: {
security: ExecSecurity;
ask: ExecAsk;
analysisOk: boolean ;
allowlistSatisfied: boolean ;
durableApprovalSatisfied?: boolean ;
approvalDecision: ExecApprovalDecision;
approved?: boolean ;
isWindows: boolean ;
cmdInvocation: boolean ;
shellWrapperInvocation: boolean ;
}): SystemRunPolicyDecision {
// POSIX node execution intentionally uses `/bin/sh -lc` as a transport wrapper.
// Keep allowlist decisions based on the analyzed inner shell payload there.
// Windows `cmd.exe /c` wrappers still require explicit approval because they
// change execution semantics for builtins and quoting/parsing behavior.
const windowsShellWrapperBlocked =
params.security === "allowlist" &&
params.shellWrapperInvocation &&
params.isWindows &&
params.cmdInvocation;
const shellWrapperBlocked = windowsShellWrapperBlocked;
const analysisOk = shellWrapperBlocked ? false : params.analysisOk;
const allowlistSatisfied = shellWrapperBlocked ? false : params.allowlistSatisfied;
const approvedByAsk = params.approvalDecision !== null || params.approved === true ;
if (params.security === "deny" ) {
return {
allowed: false ,
eventReason: "security=deny" ,
errorMessage: "SYSTEM_RUN_DISABLED: security=deny" ,
analysisOk,
allowlistSatisfied,
shellWrapperBlocked,
windowsShellWrapperBlocked,
requiresAsk: false ,
approvalDecision: params.approvalDecision,
approvedByAsk,
};
}
const requiresAsk = requiresExecApproval({
ask: params.ask,
security: params.security,
analysisOk,
allowlistSatisfied,
durableApprovalSatisfied: params.durableApprovalSatisfied,
});
if (requiresAsk && !approvedByAsk) {
return {
allowed: false ,
eventReason: "approval-required" ,
errorMessage: "SYSTEM_RUN_DENIED: approval required" ,
analysisOk,
allowlistSatisfied,
shellWrapperBlocked,
windowsShellWrapperBlocked,
requiresAsk,
approvalDecision: params.approvalDecision,
approvedByAsk,
};
}
if (params.security === "allowlist" && (!analysisOk || !allowlistSatisfied) && !approvedByAsk) {
if (params.durableApprovalSatisfied) {
return {
allowed: true ,
analysisOk,
allowlistSatisfied,
shellWrapperBlocked,
windowsShellWrapperBlocked,
requiresAsk,
approvalDecision: params.approvalDecision,
approvedByAsk,
};
}
return {
allowed: false ,
eventReason: "allowlist-miss" ,
errorMessage: formatSystemRunAllowlistMissMessage({
shellWrapperBlocked,
windowsShellWrapperBlocked,
}),
analysisOk,
allowlistSatisfied,
shellWrapperBlocked,
windowsShellWrapperBlocked,
requiresAsk,
approvalDecision: params.approvalDecision,
approvedByAsk,
};
}
return {
allowed: true ,
analysisOk,
allowlistSatisfied,
shellWrapperBlocked,
windowsShellWrapperBlocked,
requiresAsk,
approvalDecision: params.approvalDecision,
approvedByAsk,
};
}
Messung V0.5 in Prozent C=93 H=96 G=94
¤ Dauer der Verarbeitung: 0.8 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland