| import { |
| analyzeArgvCommand, |
| evaluateExecAllowlist, |
| evaluateShellAllowlist, |
| resolvePlannedSegmentArgv, |
| resolveExecApprovals, |
| type ExecAllowlistEntry, |
| type ExecCommandSegment, |
| type ExecSecurity, |
| type SkillBinTrustEntry, |
| } from "../infra/exec-approvals.js"; |
| import { resolveExecSafeBinRuntimePolicy } from "../infra/exec-safe-bin-runtime-policy.js"; |
| import type { RunResult } from "./invoke-types.js"; |
|
|
| export type SystemRunAllowlistAnalysis = { |
| analysisOk: boolean; |
| allowlistMatches: ExecAllowlistEntry[]; |
| allowlistSatisfied: boolean; |
| segments: ExecCommandSegment[]; |
| }; |
|
|
| export function evaluateSystemRunAllowlist(params: { |
| shellCommand: string | null; |
| argv: string[]; |
| approvals: ReturnType<typeof resolveExecApprovals>; |
| security: ExecSecurity; |
| safeBins: ReturnType<typeof resolveExecSafeBinRuntimePolicy>["safeBins"]; |
| safeBinProfiles: ReturnType<typeof resolveExecSafeBinRuntimePolicy>["safeBinProfiles"]; |
| trustedSafeBinDirs: ReturnType<typeof resolveExecSafeBinRuntimePolicy>["trustedSafeBinDirs"]; |
| cwd: string | undefined; |
| env: Record<string, string> | undefined; |
| skillBins: SkillBinTrustEntry[]; |
| autoAllowSkills: boolean; |
| }): SystemRunAllowlistAnalysis { |
| if (params.shellCommand) { |
| const allowlistEval = evaluateShellAllowlist({ |
| command: params.shellCommand, |
| allowlist: params.approvals.allowlist, |
| safeBins: params.safeBins, |
| safeBinProfiles: params.safeBinProfiles, |
| cwd: params.cwd, |
| env: params.env, |
| trustedSafeBinDirs: params.trustedSafeBinDirs, |
| skillBins: params.skillBins, |
| autoAllowSkills: params.autoAllowSkills, |
| platform: process.platform, |
| }); |
| return { |
| analysisOk: allowlistEval.analysisOk, |
| allowlistMatches: allowlistEval.allowlistMatches, |
| allowlistSatisfied: |
| params.security === "allowlist" && allowlistEval.analysisOk |
| ? allowlistEval.allowlistSatisfied |
| : false, |
| segments: allowlistEval.segments, |
| }; |
| } |
|
|
| const analysis = analyzeArgvCommand({ argv: params.argv, cwd: params.cwd, env: params.env }); |
| const allowlistEval = evaluateExecAllowlist({ |
| analysis, |
| allowlist: params.approvals.allowlist, |
| safeBins: params.safeBins, |
| safeBinProfiles: params.safeBinProfiles, |
| cwd: params.cwd, |
| trustedSafeBinDirs: params.trustedSafeBinDirs, |
| skillBins: params.skillBins, |
| autoAllowSkills: params.autoAllowSkills, |
| }); |
| return { |
| analysisOk: analysis.ok, |
| allowlistMatches: allowlistEval.allowlistMatches, |
| allowlistSatisfied: |
| params.security === "allowlist" && analysis.ok ? allowlistEval.allowlistSatisfied : false, |
| segments: analysis.segments, |
| }; |
| } |
|
|
| export function resolvePlannedAllowlistArgv(params: { |
| security: ExecSecurity; |
| shellCommand: string | null; |
| policy: { |
| approvedByAsk: boolean; |
| analysisOk: boolean; |
| allowlistSatisfied: boolean; |
| }; |
| segments: ExecCommandSegment[]; |
| }): string[] | undefined | null { |
| if ( |
| params.security !== "allowlist" || |
| params.policy.approvedByAsk || |
| params.shellCommand || |
| !params.policy.analysisOk || |
| !params.policy.allowlistSatisfied || |
| params.segments.length !== 1 |
| ) { |
| return undefined; |
| } |
| const plannedAllowlistArgv = resolvePlannedSegmentArgv(params.segments[0]); |
| return plannedAllowlistArgv && plannedAllowlistArgv.length > 0 ? plannedAllowlistArgv : null; |
| } |
|
|
| export function resolveSystemRunExecArgv(params: { |
| plannedAllowlistArgv: string[] | undefined; |
| argv: string[]; |
| security: ExecSecurity; |
| isWindows: boolean; |
| policy: { |
| approvedByAsk: boolean; |
| analysisOk: boolean; |
| allowlistSatisfied: boolean; |
| }; |
| shellCommand: string | null; |
| segments: ExecCommandSegment[]; |
| }): string[] { |
| let execArgv = params.plannedAllowlistArgv ?? params.argv; |
| if ( |
| params.security === "allowlist" && |
| params.isWindows && |
| !params.policy.approvedByAsk && |
| params.shellCommand && |
| params.policy.analysisOk && |
| params.policy.allowlistSatisfied && |
| params.segments.length === 1 && |
| params.segments[0]?.argv.length > 0 |
| ) { |
| execArgv = params.segments[0].argv; |
| } |
| return execArgv; |
| } |
|
|
| export function applyOutputTruncation(result: RunResult): void { |
| if (!result.truncated) { |
| return; |
| } |
| const suffix = "... (truncated)"; |
| if (result.stderr.trim().length > 0) { |
| result.stderr = `${result.stderr}\n${suffix}`; |
| } else { |
| result.stdout = `${result.stdout}\n${suffix}`; |
| } |
| } |
|
|