#!/bin/bash if ! command -v python3 >/dev/null 2>&1; then printf '%s\n' 'BLOCKED: Python 3 is required to inspect this command.' >&2 exit 2 fi exec python3 -c ' import itertools import json import shlex import sys def block(reason): print("BLOCKED: " + reason, file=sys.stderr) sys.exit(2) try: command = json.load(sys.stdin)["tool_input"]["command"] if not isinstance(command, str) or not command.strip(): raise ValueError("missing command") lexer = shlex.shlex(command.replace("\\\n", ""), posix=True, punctuation_chars=";&|()\n") lexer.whitespace = " \t\r" lexer.whitespace_split = True tokens = list(lexer) except (ValueError, KeyError, TypeError): block("Cannot parse the command input.") value_options = {"-C", "-c", "--git-dir", "--work-tree", "--namespace", "--config-env"} flag_options = {"-p", "--paginate", "-P", "--no-pager", "--bare", "--literal-pathspecs"} # ponytail: conservative token inspection; shell expansion and aliases require sandbox enforcement. for separator, group in itertools.groupby(tokens, lambda token: bool(token) and token[0] in ";&|()\n"): if separator: continue words = list(group) for index, word in enumerate(words): if word.rsplit("/", 1)[-1] != "git": continue args = words[index + 1:] while args and args[0].startswith("-"): option = args.pop(0) if option in value_options: if not args: block("Missing Git option value.") args.pop(0) elif option in flag_options or option.split("=", 1)[0] in value_options: continue else: block("Unsupported Git option; inspect this command manually.") if not args: continue operation, *args = args short_flags = "".join(arg[1:] for arg in args if arg.startswith("-") and not arg.startswith("--")) force = "--force" in args or "f" in short_flags dangerous = ( operation == "push" or operation == "reset" and "--hard" in args or operation == "clean" and force or operation == "branch" and ("D" in short_flags or force and ("d" in short_flags or "--delete" in args)) or operation in {"checkout", "restore"} and "." in args ) if dangerous: block("Git " + operation + " is disabled by this hook.") '