mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-18 07:19:35 +00:00
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
134 lines
4.7 KiB
Bash
Executable File
134 lines
4.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# Dealix Pre-Commit Hook
|
||
# Runs linting, secret detection, Arabic consistency, and affected tests.
|
||
set -euo pipefail
|
||
|
||
ROOT_DIR="$(git rev-parse --show-toplevel)"
|
||
BACKEND_DIR="${ROOT_DIR}/backend"
|
||
STAGED_PY_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.py$' || true)
|
||
|
||
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
|
||
|
||
# ── 2. Hardcoded Secrets Detection ─────────────
|
||
echo ""
|
||
echo "[2/4] Checking for hardcoded secrets..."
|
||
|
||
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
|
||
|
||
# ── 3. Arabic String Consistency ────────────────
|
||
echo ""
|
||
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
|
||
|
||
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 "============================================"
|