/** * PowerShellMutationPolicy — blocks PowerShell mutation patterns. * * Checkpoints: pre-tool * * Logic migrated from: * - extensions/kingdee-powershell-tool.ts: powerShellMutationBlockReason */ import type { GateContext, GateFinding } from "../findings.ts"; export const POWERSHELL_MUTATION_POLICY_NAME = "powershell-mutation-policy"; export function evaluatePowerShellMutationPolicy(ctx: GateContext): GateFinding[] { const findings: GateFinding[] = []; const { toolName, command } = ctx; // Only applies to bash/shell tool calls with a command if (toolName !== "bash" || !command) return findings; const reason = powerShellMutationBlockReason(command); if (reason) { findings.push({ id: "PSM-001", severity: "hard-deny", policy: POWERSHELL_MUTATION_POLICY_NAME, message: reason, nextAction: "生产文件修改必须使用 write/edit,并通过 PLAN、Source Anchor、Write Transaction 和后置条件门禁;验证输出请使用对应 evidence 工具或 Harness evidence 文件。", }); } return findings; } // ── Utility functions (reimplemented from extensions/kingdee-powershell-tool.ts) ─ function powerShellMutationBlockReason(command: string): string | undefined { const normalized = command.trim(); if (!normalized) return undefined; const mutatingCommand = /\b(Set-Content|Add-Content|Out-File|New-Item|Remove-Item|Move-Item|Copy-Item|Rename-Item|Clear-Content|Set-Item|Set-ItemProperty|New-ItemProperty|Remove-ItemProperty|Start-Process)\b/i; const mutatingAlias = /(^|[\s;|&])(rm|del|erase|mv|move|cp|copy|ni|mkdir|md|rmdir|rd)\b/i; const redirection = /(^|[^=<>])>>?($|[^>])/; const nestedShellOrScript = /\b(cmd(?:\.exe)?\s*\/c|powershell(?:\.exe)?\s+.*-(?:Command|EncodedCommand)|pwsh\s+.*-(?:Command|EncodedCommand)|python(?:\.exe)?\s+-c|node(?:\.exe)?\s+-e|perl\s+-e)\b/i; const mutatingCli = /\bgit\s+(apply|checkout|restore|reset|clean|commit|merge|rebase|pull|push)\b|\b(?:npm|pnpm|yarn)\s+(install|uninstall|version|publish|add|remove)\b/i; if ( !mutatingCommand.test(normalized) && !mutatingAlias.test(normalized) && !redirection.test(normalized) && !nestedShellOrScript.test(normalized) && !mutatingCli.test(normalized) ) return undefined; return "PowerShell 文件变更命令被 KCode 阻断。"; }