dirge-agent 0.12.5

Minimalistic coding agent written in Rust, optimized for memory footprint and performance
//! Permission classification helpers.
//!
//! Pure functions for classifying tools (is this a path tool? is it
//! high-risk?) and building `Pattern` values with the right `*`
//! semantics for the tool category. Extracted from `checker.rs` so
//! they can be unit-tested independently of the `PermissionChecker`
//! struct's configuration wiring.
//!
//! Used by `checker.rs` (through thin delegating methods) and by
//! `allowlist.rs` (for `pattern_for_tool`).

use crate::permission::pattern::Pattern;

/// Tools that execute external code with broad effects. Accept mode
/// does NOT coerce `Ask → Allow` for these — the "I trust the agent
/// inside cwd" rationale that justifies the coercion for other
/// non-path tools doesn't generalize to shell + MCP servers.
pub(crate) fn is_high_risk_non_path_tool(tool: &str) -> bool {
    matches!(
        tool,
        // Shell / external execution
        "mcp_tool" | "bash"
        // Network exfiltration
        | "webfetch"
        // Recursive agent execution
        | "task"
        // Persistent state mutation (memory, skills, patches)
        // that persists across sessions
        | "memory" | "skill" | "apply_patch"
    )
}

/// Tool names where the input is a filesystem path. For these, `*` keeps
/// classic glob semantics (one segment, doesn't cross `/`). Everything else
/// is treated as shell/text where `*` means "any chars including /".
pub fn is_path_tool_name(tool: &str) -> bool {
    matches!(
        tool,
        "read"
            | "write"
            | "edit"
            | "list_dir"
            | "apply_patch"
            | "lsp"
            // grep / find_files / glob now also receive path-side
            // checks (the search-root path), so their rules use
            // path-glob semantics.
            | "grep"
            | "find_files"
            | "glob"
            // Semantic tools whose primary arg is a file path.
            | "list_symbols"
            | "get_symbol_body"
            | "find_definition"
            | "find_callers"
            | "find_callees"
            // #1 fix: repo_overview's arg is a directory path; user
            // rules like `"/etc/**": "deny"` need path-glob semantics
            // for `**` to span subpaths. Was missed when the tool
            // was added.
            | "repo_overview"
    )
}

/// Build a Pattern with the right `*` semantics for the given tool.
pub fn pattern_for_tool(tool: &str, pat: &str) -> Pattern {
    if is_path_tool_name(tool) {
        Pattern::new(pat)
    } else {
        Pattern::new_command(pat)
    }
}