/** * Per-segment verdict evaluation for Shell AST normalization. * * Evaluates policy per AST segment, aggregates a final compound verdict, * and produces structured denial output with per-segment reasons. * * Each segment verdict is a runtime contract: callers can inspect which * segments were safe vs. unsafe and surface that information to the user. * * @module normalization/verdict */ import type { CommandClassification } from './types.js'; import type { ShellNode, CommandNode } from './ast.js'; /** * Conservative set of classifications for callers that gate by class * WITHOUT a permission layer in front of them (e.g. policy tooling, * standalone analysis). Destructive and escalation are excluded. * * The exec tool does NOT use this set: by the time a command executes, the * permission layer (user settings, prompts, session approvals) has already * approved the call, so the exec layer passes ALL_COMMAND_CLASSES and keeps * only the unconditional catastrophic block. */ export declare const DEFAULT_ALLOWED_CLASSES: ReadonlySet; /** * Every command classification. Passed by callers whose class-level risk * decisions are owned by the permission layer (allow/prompt/deny settings), * leaving only catastrophic and obfuscation checks at this layer. */ export declare const ALL_COMMAND_CLASSES: ReadonlySet; /** * The policy verdict for a single command segment. * * Each verdict is an immutable runtime contract that records why a segment * was allowed or denied, making the decision auditable and explainable. */ export interface SegmentVerdict { /** The raw command string for this segment. */ raw: string; /** Canonical command name. */ command: string; /** Semantic risk classification. */ classification: CommandClassification; /** Whether this segment was allowed by policy. */ allowed: boolean; /** * Human-readable reason for the verdict. * Always set; describes the policy that matched or the safe classification. */ reason: string; /** Whether this segment contains obfuscated content (encoded chars, substitution). */ hasObfuscation: boolean; /** Descriptions of any obfuscation patterns found. */ obfuscationPatterns: string[]; } /** * The aggregated verdict for a compound command. * * Contains the overall allow/deny decision plus per-segment records for * user-facing denial output and audit logging. */ export interface CompoundVerdict { /** The original command string. */ original: string; /** Whether the entire compound command is allowed. */ allowed: boolean; /** The highest-risk classification across all segments. */ highestClassification: CommandClassification; /** Per-segment verdict records (in parse order). */ segments: SegmentVerdict[]; /** * Human-readable denial explanation including per-segment reasons. * Only set when `allowed` is false. */ denialExplanation?: string | undefined; /** Whether any segment contains obfuscated content. */ hasObfuscation: boolean; } /** * Evaluates a single CommandNode against the default policy. * * @param node - The command node to evaluate. * @param allowedClasses - Classification tiers to allow (defaults to read+write+network). * @returns A SegmentVerdict for this node. */ export declare function evaluateSegmentNode(node: CommandNode, allowedClasses?: ReadonlySet): SegmentVerdict; /** * Collapses whitespace runs so an echoed command occupies exactly one line. * * The header used to interpolate `original` verbatim. A multi-line command, a * heredoc above all, therefore put its own newline inside what reads as line * one, so every consumer that summarizes a denial by its first line (for * example exec's `minimal` verbosity, which does `stderr.split('\n')[0]`) * showed `Command denied: "… <<'EOF'` and silently dropped the segment * breakdown, classification and reason. Collapsing here keeps the first line a * real first line, so a denial always names what was denied and why. */ export declare function asSingleLine(text: string): string; export declare function buildDenialExplanation(original: string, verdicts: SegmentVerdict[]): string; /** * Evaluates a ShellNode AST against policy and returns a CompoundVerdict. * * Safe segments are identified alongside unsafe ones. The compound command * is denied if ANY segment is denied. * * @param original - The original command string. * @param ast - The parsed ShellNode AST. * @param allowedClasses - Classification tiers to allow per segment. * @returns A CompoundVerdict with per-segment breakdown. */ export declare function evaluateCommandAST(original: string, ast: ShellNode, allowedClasses?: ReadonlySet): CompoundVerdict; //# sourceMappingURL=verdict.d.ts.map