#!/usr/bin/env bash
# Simple pre-commit guard for common mistakes
# - Prevent committing or deleting .env files
# - Block deletions in protected directories (docs/, src/backend/)
set -e
# Get staged name-status
STAGED=$(git diff --cached --name-status)
# Prevent adding/modifying .env files
if echo "$STAGED" | grep -E '^[AM]\s+.*\.env(\.|$)\|^A\s+\.env$' >/dev/null; then
echo "ERROR: .env files must not be added/modified in repository. Keep them local and add to .gitignore." >&2
exit 1
fi
# Prevent deletion of critical/protected files
DELETED=$(echo "$STAGED" | awk '$1 == "D" {print $2}')
if [ -n "$DELETED" ]; then
# Protected list file: list of paths that are considered critical for ongoing development
PROTECTED_FILE=".protected-files"
# If protected-file list exists, only require explicit approval for deletions that match it
if [ -f "$PROTECTED_FILE" ]; then
mapfile -t PROTECTED < <(sed -e 's/^[[:space:]]*//;s/[[:space:]]*$//' "$PROTECTED_FILE" | sed '/^$/d')
else
PROTECTED=()
fi
# Always block deletion/add/modify of .env files
while read -r f; do
case "$f" in
*.env|.env|.env.*)
echo "ERROR: .env files must not be deleted/added/modified in repository. Keep them local and add to .gitignore." >&2
exit 1
;;
esac
done <<< "$DELETED"
# Build a list of deletions that hit the protected list
NEED_APPROVAL=()
while read -r f; do
for p in "${PROTECTED[@]}"; do
# If protected entry ends with '/', treat as prefix (directory)
if [[ "$p" == */ ]]; then
if [[ "$f" == "$p"* ]]; then
NEED_APPROVAL+=("$f")
fi
else
# match exact file or files under directory indicated without trailing slash
if [[ "$f" == "$p" || "$f" == "$p"/* ]]; then
NEED_APPROVAL+=("$f")
fi
fi
done
done <<< "$DELETED"
if [ ${#NEED_APPROVAL[@]} -gt 0 ]; then
APPROVAL_FILE=".deletions-approved"
if [ ! -f "$APPROVAL_FILE" ]; then
echo "ERROR: Deletions of protected files detected but no $APPROVAL_FILE found." >&2
echo "To approve deletions, create $APPROVAL_FILE listing the exact protected paths to delete (one per line), commit it first, then perform deletions." >&2
exit 1
fi
mapfile -t APPROVED < <(sed -e 's/^[[:space:]]*//;s/[[:space:]]*$//' "$APPROVAL_FILE" | sed '/^$/d')
for f in "${NEED_APPROVAL[@]}"; do
ok=0
for a in "${APPROVED[@]}"; do
if [[ "$a" == */ ]]; then
if [[ "$f" == "$a"* ]]; then ok=1; break; fi
else
if [[ "$f" == "$a" ]]; then ok=1; break; fi
fi
done
if [ $ok -ne 1 ]; then
echo "ERROR: Deletion of protected file $f is not listed in $APPROVAL_FILE." >&2
echo "Add the exact path or a directory (with trailing slash) to $APPROVAL_FILE and commit that file first to approve the deletion." >&2
exit 1
fi
done
fi
fi
# All checks passed
exit 0