#!/bin/bash # ============================================================================= # CI/CD Pipeline for LeoCRM — Quality Gates # ============================================================================= # This script runs all quality checks before a deployment is allowed. # It should be run in CI (GitHub Actions, Forgejo Actions, etc.) or locally. # # Exit codes: # 0 = all checks passed # 1 = one or more checks failed # ============================================================================= set -e RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' PASS=0 FAIL=0 check() { local name="$1" local cmd="$2" echo -e "${YELLOW}[CI] Running: ${name}${NC}" if eval "$cmd" 2>&1 | tail -5; then echo -e "${GREEN}[CI] PASS: ${name}${NC}" PASS=$((PASS + 1)) else echo -e "${RED}[CI] FAIL: ${name}${NC}" FAIL=$((FAIL + 1)) fi } # ── 1. Python Compile Check ────────────────────────────────────────────────── check "Python Compile" "python3 -m compileall app/ alembic/ -q" # ── 2. Cross-Plugin Import Check ───────────────────────────────────────────── check "Cross-Plugin Imports" "python3 scripts/check_cross_plugin_imports.py" # ── 3. Alembic Revision Graph ──────────────────────────────────────────────── check "Alembic Revisions" "alembic heads 2>&1 | grep -c 'head' | grep -q '^1$'" # ── 3b. Alembic Migration Test (only if DATABASE_URL is set) ────────────────── if [ -n "${DATABASE_URL:-}" ]; then check "Alembic Migration Test" "bash scripts/test_migrations.sh ${DATABASE_URL}" else echo -e "${YELLOW}[CI] SKIP: Alembic Migration Test (no DATABASE_URL)${NC}" fi # ── 4. TypeScript Type Check ───────────────────────────────────────────────── check "TypeScript Type Check" "cd frontend && npx tsc --noEmit" # ── 5. Frontend Build ──────────────────────────────────────────────────────── check "Frontend Build" "cd frontend && npm run build" # ── 6. Python Tests (if collectable) ───────────────────────────────────────── check "Test Collection" "python3 -m pytest --collect-only -q tests/ 2>&1 | tail -3" # ── 7. Security: SQL Injection Check ───────────────────────────────────────── check "SQL Injection Check" "! grep -rn 'text(f"SELECT.*{' app/services/ --include='*.py' >/dev/null 2>&1" # ── 8. Security: Jinja2 Sandbox Check ───────────────────────────────────────── check "Jinja2 Sandbox Check" "! grep -rn 'Environment(' app/plugins/builtins/report_generator/ --include='*.py' | grep -v Sandboxed >/dev/null 2>&1" # ── 9. Security: RLS Variable Check ────────────────────────────────────────── check "RLS Variable Check" "grep -q 'app.current_tenant_id' app/core/db/__init__.py" # ── 10. Security: Fail-Closed Plugin Gate ──────────────────────────────────── check "Fail-Closed Plugin Gate" "! grep -A2 'except Exception:' app/deps.py | grep -q 'pass$' >/dev/null 2>&1" # ── Summary ────────────────────────────────────────────────────────────────── echo "" echo "============================================================" echo " CI/CD Summary: ${PASS} passed, ${FAIL} failed" echo "============================================================" if [ $FAIL -gt 0 ]; then echo -e "${RED}[CI] BUILD FAILED — ${FAIL} checks failed${NC}" exit 1 else echo -e "${GREEN}[CI] BUILD PASSED — all ${PASS} checks passed${NC}" exit 0 fi