"""Always-ask path matcher — safety enforcement for intern calls.""" from __future__ import annotations from pathlib import PurePath # Patterns that always require explicit user approval before sending to an intern. ALWAYS_ASK_PATTERNS: list[str] = [ "**/.env", "**/.env.*", "**/secrets/**", "**/projects-secrets/**", "**/credentials*", "**/*.key", "**/*.pem", "**/.ssh/**", "**/.aws/credentials", "**/.aws/config", "**/.netrc", "**/.npmrc", "**/.pypirc", ] ALWAYS_ASK_REASON = ( "Path matched always-ask pattern. " "Sending this file to an external endpoint requires explicit approval." ) def check_paths(paths: list[str], extra_patterns: list[str] | None = None) -> list[dict]: """Check each path against always-ask patterns. Returns list of blocked entries: [{"path": ..., "pattern": ..., "reason": ...}]. Empty list = all paths clear. """ patterns = list(ALWAYS_ASK_PATTERNS) if extra_patterns: patterns.extend(extra_patterns) blocked = [] for p in paths: pp = PurePath(p) for pattern in patterns: if pp.match(pattern): blocked.append({"path": p, "pattern": pattern, "reason": ALWAYS_ASK_REASON}) break return blocked def always_ask_globs() -> list[str]: """Return glob patterns for always-ask paths, suitable for --ignore flags. Used by tool-wrapping interns (e.g. repo_read) to inject --ignore flags into subprocess calls, preventing repomix from packaging sensitive files even if they exist inside the target directory. """ # Convert PurePath-style patterns to glob patterns repomix understands. # Strip leading **/ since repomix --ignore uses gitignore-style patterns. globs = [] for p in ALWAYS_ASK_PATTERNS: if p.startswith("**/"): globs.append(p[3:]) else: globs.append(p) return globs