fix: Enhance pre-commit and pre-push hooks with robust checks

Pre-commit: ruff linter, secret detection (API keys + Bearer tokens),
Arabic string consistency, affected test runner
Pre-push: full test suite, uncommitted migration detection, .env file guard

https://claude.ai/code/session_01LsnvBa7HwF5hs99VZbgLGj
This commit is contained in:
Claude 2026-04-11 08:12:14 +00:00
parent 9f87af8ea2
commit 2717f2943b
No known key found for this signature in database
2 changed files with 212 additions and 24 deletions

View File

@ -1,23 +1,133 @@
#!/bin/bash #!/usr/bin/env bash
# Dealix Pre-Commit Hook # Dealix Pre-Commit Hook
set -e # Runs linting, secret detection, Arabic consistency, and affected tests.
echo "Dealix Pre-Commit Checks..." set -euo pipefail
# Check for hardcoded secrets ROOT_DIR="$(git rev-parse --show-toplevel)"
if grep -rn "API_KEY\s*=\s*['\"][^'\"]*['\"]" backend/app/ --include="*.py" 2>/dev/null | grep -v config.py | grep -v example; then BACKEND_DIR="${ROOT_DIR}/backend"
echo "ERROR: Hardcoded API key found!" STAGED_PY_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.py$' || true)
exit 1
echo "============================================"
echo " Dealix Pre-Commit Checks"
echo "============================================"
# ── 1. Ruff Linter ───────────────<E29480><E29480><EFBFBD>─────────────
echo ""
echo "[1/4] Running ruff linter..."
if [ -n "${STAGED_PY_FILES}" ]; then
if command -v ruff &>/dev/null; then
LINT_FAILED=0
echo "${STAGED_PY_FILES}" | xargs ruff check --select E,W,F,I --no-fix || LINT_FAILED=1
if [ ${LINT_FAILED} -eq 1 ]; then
echo "FAIL: ruff found issues. Fix them before committing."
echo " Run: ruff check --fix backend/"
exit 1
fi
echo "PASS: ruff checks passed."
else
echo "WARN: ruff not installed. Skipping lint check."
echo " Install: pip install ruff"
fi
else
echo "SKIP: No Python files staged."
fi fi
# Check .env not staged # ── 2. Hardcoded Secrets Detection ─────────────
if git diff --cached --name-only | grep -q "\.env$"; then echo ""
echo "ERROR: .env file staged!" echo "[2/4] Checking for hardcoded secrets..."
exit 1
SECRETS_FOUND=0
if [ -n "${STAGED_PY_FILES}" ]; then
MATCHES=$(echo "${STAGED_PY_FILES}" | xargs grep -n -E "(API_KEY|SECRET_KEY|PASSWORD|PRIVATE_KEY|ACCESS_TOKEN)\s*=\s*['"][^'"]{8,}" 2>/dev/null | grep -v "os\.environ\|get_settings\|config\.\|settings\.\|# example\|# test\|# noqa" || true)
if [ -n "${MATCHES}" ]; then
echo "CRITICAL: Possible hardcoded secrets found:"
echo "${MATCHES}"
SECRETS_FOUND=1
fi
BEARER_MATCHES=$(echo "${STAGED_PY_FILES}" | xargs grep -n -E "Bearer\s+[A-Za-z0-9_\-]{20,}" 2>/dev/null | grep -v "settings\.\|config\.\|Authorization.*Bearer.*{" || true)
if [ -n "${BEARER_MATCHES}" ]; then
echo "CRITICAL: Possible hardcoded Bearer tokens:"
echo "${BEARER_MATCHES}"
SECRETS_FOUND=1
fi
if [ ${SECRETS_FOUND} -eq 1 ]; then
echo ""
echo "FAIL: Remove hardcoded secrets. Use environment variables via get_settings()."
exit 1
fi
echo "PASS: No hardcoded secrets detected."
else
echo "SKIP: No Python files staged."
fi fi
# Run linter # ── 3. Arabic String Consistency ────────────────
if command -v ruff &> /dev/null; then echo ""
ruff check backend/app/ --fix --quiet 2>/dev/null || true echo "[3/4] Checking Arabic string consistency..."
STAGED_FRONTEND_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(tsx?|jsx?)$' || true)
if [ -n "${STAGED_FRONTEND_FILES}" ]; then
UNTRANSLATED=$(echo "${STAGED_FRONTEND_FILES}" | xargs grep -n -E "TODO.*translat|FIXME.*arabic|FIXME.*rtl" 2>/dev/null || true)
if [ -n "${UNTRANSLATED}" ]; then
echo "WARN: Found untranslated string markers:"
echo "${UNTRANSLATED}"
echo " These should be resolved before release."
else
echo "PASS: No untranslated string markers found."
fi
else
echo "SKIP: No frontend files staged."
fi fi
echo "Pre-commit checks passed." if [ -n "${STAGED_PY_FILES}" ]; then
MISSING_ARABIC=$(echo "${STAGED_PY_FILES}" | xargs grep -n -E "detail=\"[A-Z][a-z]|message=\"[A-Z][a-z]" 2>/dev/null | grep -v "# en-only\|# internal\|HTTPException\|logger\." || true)
if [ -n "${MISSING_ARABIC}" ]; then
echo "WARN: Possible English-only user-facing strings in Python:"
echo "${MISSING_ARABIC}"
echo " Consider adding Arabic translations."
fi
fi
# ── 4. Run Affected Tests ──────────────────────
echo ""
echo "[4/4] Running affected tests..."
if [ -n "${STAGED_PY_FILES}" ]; then
TEST_FILES=""
for PY_FILE in ${STAGED_PY_FILES}; do
BASENAME=$(basename "${PY_FILE}" .py)
FOUND_TESTS=$(find "${BACKEND_DIR}/tests" -name "test_${BASENAME}.py" 2>/dev/null || true)
if [ -n "${FOUND_TESTS}" ]; then
TEST_FILES="${TEST_FILES} ${FOUND_TESTS}"
fi
done
if [ -n "${TEST_FILES}" ]; then
echo "Running tests:${TEST_FILES}"
cd "${BACKEND_DIR}"
if ! pytest ${TEST_FILES} -x -q --tb=short 2>/dev/null; then
echo ""
echo "FAIL: Some tests failed. Fix them before committing."
exit 1
fi
echo "PASS: All affected tests passed."
else
echo "SKIP: No matching test files found for staged changes."
fi
else
echo "SKIP: No Python files staged."
fi
echo ""
echo "============================================"
echo " All pre-commit checks passed"
echo "============================================"

View File

@ -1,13 +1,91 @@
#!/bin/bash #!/usr/bin/env bash
# Dealix Pre-Push Hook # Dealix Pre-Push Hook
set -e # Runs full test suite, checks migrations, and verifies no .env files are staged.
echo "Dealix Pre-Push Checks..." set -euo pipefail
# Run tests ROOT_DIR="$(git rev-parse --show-toplevel)"
cd backend && python -m pytest -x -q --tb=short 2>/dev/null || { BACKEND_DIR="${ROOT_DIR}/backend"
echo "ERROR: Tests failed!"
echo "============================================"
echo " Dealix Pre-Push Checks"
echo "============================================"
# ── 1. Full Test Suite ──────────────────────────
echo ""
echo "[1/3] Running full test suite..."
if [ -d "${BACKEND_DIR}/tests" ]; then
cd "${BACKEND_DIR}"
if ! pytest -x -q --tb=short 2>&1; then
echo ""
echo "FAIL: Test suite failed. Fix all tests before pushing."
exit 1
fi
echo "PASS: Full test suite passed."
cd "${ROOT_DIR}"
else
echo "WARN: No tests directory found at ${BACKEND_DIR}/tests"
fi
# ── 2. Uncommitted Migrations ──────────────────
echo ""
echo "[2/3] Checking for uncommitted migrations..."
UNTRACKED_MIGRATIONS=$(git ls-files --others --exclude-standard "${BACKEND_DIR}/alembic/versions/" 2>/dev/null | grep '\.py$' || true)
MODIFIED_MIGRATIONS=$(git diff --name-only "${BACKEND_DIR}/alembic/versions/" 2>/dev/null | grep '\.py$' || true)
if [ -n "${UNTRACKED_MIGRATIONS}" ]; then
echo "FAIL: Found untracked migration files:"
echo "${UNTRACKED_MIGRATIONS}"
echo " Commit these migrations before pushing."
exit 1 exit 1
} fi
cd ..
echo "Pre-push checks passed." if [ -n "${MODIFIED_MIGRATIONS}" ]; then
echo "WARN: Found modified but uncommitted migration files:"
echo "${MODIFIED_MIGRATIONS}"
echo " Consider committing these changes."
fi
MODEL_CHANGES=$(git diff HEAD --name-only "${BACKEND_DIR}/app/models/" 2>/dev/null | grep '\.py$' || true)
if [ -n "${MODEL_CHANGES}" ]; then
MIGRATION_CHANGES=$(git diff HEAD --name-only "${BACKEND_DIR}/alembic/versions/" 2>/dev/null | grep '\.py$' || true)
if [ -z "${MIGRATION_CHANGES}" ]; then
echo "WARN: Model files changed but no new migrations detected:"
echo "${MODEL_CHANGES}"
echo " Run: cd backend && alembic revision --autogenerate -m 'description'"
fi
fi
echo "PASS: Migration check complete."
# ── 3. No .env Files ───────────────────────────
echo ""
echo "[3/3] Verifying no .env files are being pushed..."
TRACKED_ENV=$(git ls-files | grep -E '\.env$|\.env\.local$|\.env\.production$' | grep -v '\.env\.example$' || true)
if [ -n "${TRACKED_ENV}" ]; then
echo "CRITICAL: .env files are tracked in the repository:"
echo "${TRACKED_ENV}"
echo ""
echo "FAIL: Never push .env files to the repository."
echo " Remove them: git rm --cached <file>"
echo " Add to .gitignore if missing"
exit 1
fi
STAGED_ENV=$(git diff --cached --name-only | grep -E '\.env$|\.env\.' | grep -v '\.env\.example$' || true)
if [ -n "${STAGED_ENV}" ]; then
echo "CRITICAL: .env files staged for commit:"
echo "${STAGED_ENV}"
echo ""
echo "FAIL: Unstage .env files: git reset HEAD <file>"
exit 1
fi
echo "PASS: No .env files in push."
echo ""
echo "============================================"
echo " All pre-push checks passed"
echo "============================================"