أساسيات التكامل المستمر

التحليل الساكن وبوابات الجودة

22 دقيقة الدرس 5 من 28

التحليل الساكن وبوابات الجودة

كل خط CI يُشغّل الاختبارات — لكن الاختبارات تُغطّي فقط المسارات التي فكّرت في اختبارها. التحليل الساكن يفحص الكود المصدري دون تشغيله، ويكتشف فئة مختلفة تماماً من المشاكل: مخالفات الأسلوب، وأخطاء الأنواع، والأنماط الأمنية الخطيرة، والكود الميت، وتعقيد الديون التقنية. بوابات الجودة هي طبقة السياسات فوق ذلك: مجموعة حدود يجب أن تجتازها جميعاً قبل السماح لخط الـ pipeline بالدمج. معاً يُشكّلان آلية التطبيق التي تمنع قاعدة الكود الكبيرة من التدهور بينما يُودع مئات المهندسين يومياً.

في Google وMeta وAmazon، التحليل الساكن ليس اختيارياً أو استشارياً — إنه بوابة pipeline صارمة. الـ commit الذي يُسقط تغطية الاختبارات دون الحد المتفق عليه، أو الذي يُدخل نمطاً أمنياً سيئاً معروفاً، يُحجب تلقائياً. لا يحتاج إنسان للمراجعة ليقول لا؛ يقول خط الـ pipeline لا.

فكرة جوهرية: التحليل الساكن يكتشف العيوب في أرخص لحظة ممكنة — قبل تشغيل الكود، وقبل مراجعته، وقبل إرساله. تكلفة إصلاح خطأ في CI أقل بنحو 100 مرة من تكلفة إصلاحه بعد وصوله للإنتاج. بوابات الجودة تضمن أن لا أحد يتجاوز هذه الخطوة تحت ضغط الجداول الزمنية.

المُدقِّقات (Linters): تطبيق الأسلوب والصحة

المُدقِّق (Linter) يُحلل كودك ويُبلّغ عن الانحرافات عن مجموعة قواعد محددة. تنقسم القواعد إلى فئتين: أسلوبية (المسافات البادئة، طول السطر، اتفاقيات التسمية) وصحية (استخدام واجهات برمجية مهملة، متغيرات غير مستخدمة، كود غير قابل للوصول). تشغيل المُدقِّق في CI — لا مجرد في IDE — يضمن تطبيق القواعد على كل مهندس، لا على الواعيين منهم فقط.

اختيارات المُدقِّقات الشائعة حسب البيئة:

  • JavaScript/TypeScript: eslint مع مجموعة قواعد الفريق (Airbnb أو Google أو مخصصة)
  • Python: ruff (بديل سريع مكتوب بـ Rust لـ flake8 + isort + pyupgrade)
  • Go: golangci-lint — مُدقِّق شامل يُشغّل 50+ مُدقِّقاً بالتوازي
  • Java: Checkstyle + SpotBugs
  • البنية التحتية: tflint لـ Terraform، وhadolint لملفات Dockerfile

في بيئات big-tech، فشل التدقيق يُوقف خط الـ pipeline، وليس مجرد تحذير. يخرج job CI بكود غير صفري ولا يمكن دمج الـ PR. أي قاعدة تسمح بأن تكون "استشارية" سيتجاهلها نصف الفريق في نهاية المطاف.

# .github/workflows/ci.yml — job تدقيق (مثال مشروع Node.js) name: CI on: pull_request: push: branches: [main] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - run: npm ci # ESLint — يخرج بكود 1 عند أي مخالفة (--max-warnings 0 = لا تحذيرات استشارية) - run: npx eslint . --ext .ts,.tsx --max-warnings 0 # فحص أنواع TypeScript (tsc لا يُنتج JS؛ يتحقق من الأنواع فقط) - run: npx tsc --noEmit # تدقيق Dockerfile - uses: hadolint/hadolint-action@v3.1.0 with: dockerfile: Dockerfile failure-threshold: warning
ممارسة احترافية: ثبّت إصدارات مُدقِّقاتك في package.json أو requirements.txt واحفظ التثبيت في ذاكرة التخزين المؤقت بـ CI. إصدار latest متحرك لمُدقِّق يكتسب قاعدة جديدة يُعطّل بنائك في يوم الجمعة مساءً دون أي تغيير في الكود — تنبيه زائف كلاسيكي يُضعف الثقة في خط الـ pipeline.

المُنسِّقات (Formatters): القضاء على نقاشات الأسلوب

المُنسِّق (Formatter) أقوى من المُدقِّق للأسلوب — يُعيد كتابة الكود إلى شكل قياسي بدلاً من الإشارة إليه فقط. أكثر تأثير لاعتماد مُنسِّق هو اختفاء نقاشات الأسلوب من مراجعة الكود. لا أحد يتجادل حول موضع الأقواس حين يكون المُنسِّق السلطة الوحيدة.

المُنسِّقات الشائعة: prettier (JS/TS/CSS/HTML)، وblack (Python)، وgofmt (Go، مدمج في سلسلة الأدوات)، وrustfmt (Rust). في CI تُشغّل المُنسِّق في وضع الفحص (يخرج بكود غير صفري إذا كان أي ملف سيتغير) لا في وضع إعادة الكتابة:

# فحص التنسيق دون تعديل الملفات — آمن لـ CI # Prettier (JavaScript/TypeScript) npx prettier --check "src/**/*.{ts,tsx,css}" # Black (Python) black --check --diff . # gofmt (Go) — لا يوجد --check أصلي؛ استخدم هذا النمط test -z "$(gofmt -l .)" || (gofmt -l . && exit 1) # Terraform terraform fmt -check -recursive

حدود التغطية: تطبيق الاستثمار في الاختبارات

تغطية الاختبارات تقيس نسبة قاعدة الكود التي تمارسها حزمة اختباراتك. تتبّعها أمر أساسي؛ تطبيق حدّ أدنى كبوابة جودة هو ما يمنع التغطية من التدهور فعلياً بمرور الوقت.

تعمل البوابة هكذا: إذا كان PR سيُسقط التغطية الإجمالية دون الحدّ (مثلاً 80%)، يفشل job CI. يجب على المؤلف إضافة اختبارات قبل أن يمكن دمج الـ PR. هذا يخلق دورة فضيلة — الكود الجديد يُشحن دائماً مع اختبارات، ولا يمكن لأرضية التغطية أن تنخفض.

خطأ إنتاجي شائع: تغطية الأسطر سهلة التزوير — يمكنك الوصول إلى 100% تغطية أسطر دون اختبار أي سلوك. على نطاق big-tech، تتطلب سياسة التغطية عادةً تغطية الفروع (اختبار كل فرع if/else) و، للمسارات الحرجة، اختبار الطفرات (يجب أن تكتشف الاختبارات الأخطاء المُدخلة عمداً). لا تعامل رقم التغطية كدليل على الجودة؛ عامله كأرضية تحتها الجودة على الأرجح سيئة.

أمثلة تطبيق التغطية حسب البيئة:

# Jest (JavaScript) — تطبيق 80% على كل الأبعاد # jest.config.js module.exports = { coverageThreshold: { global: { branches: 80, functions: 85, lines: 85, statements: 85, }, // حدّ لكل ملف للوحدات الحرجة './src/payments/**': { branches: 95, lines: 95, }, }, }; # التشغيل في CI: npx jest --coverage --ci # Jest يخرج بكود 1 إذا لم يُستوف أي حدّ # -------------------------------------------------- # pytest + pytest-cov (Python) # pytest.ini [tool:pytest] addopts = --cov=src --cov-report=term-missing --cov-fail-under=80 # التشغيل: pytest # يخرج بكود 1 إذا كانت التغطية < 80% # -------------------------------------------------- # Go (أداة التغطية المدمجة) go test ./... -coverprofile=coverage.out go tool cover -func=coverage.out | tail -1 # تطبيق الحدّ في سكريبت CI: COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | tr -d '%') if [ "$(echo "$COVERAGE < 80" | bc)" -eq 1 ]; then echo "Coverage ${COVERAGE}% is below 80% threshold" exit 1 fi

SAST: الأمان داخل خط الـ Pipeline

اختبار أمان التطبيقات الساكن (SAST) يُطبّق قواعد أمنية محددة على كودك المصدري. يكتشف أنماطاً مثل SQL injection، وبيانات الاعتماد المُضمّنة في الكود، والتسلسل غير الآمن، وحقن الأوامر، واستخدام واجهات التشفير المهملة — قبل أن يصل أيٌّ منها إلى بيئة تشغيل.

أدوات SAST حسب اللغة:

  • متعددة اللغات: Semgrep (قائم على القواعد، سريع جداً، إخراج SARIF لـ GitHub)، وCodeQL (GitHub Advanced Security، تحليل تدفق البيانات العميق)
  • Python: Bandit
  • Java/Kotlin: SpotBugs + مكوِّن Find Security Bugs، وقواعد Semgrep Java
  • JavaScript: npm audit (ثغرات CVE للتبعيات) + Semgrep
  • Containers: Trivy (فحص صورة + نظام الملفات بحثاً عن CVEs والأسرار)

GitHub يوفر CodeQL مجاناً للمستودعات العامة وكجزء من GitHub Advanced Security للمستودعات الخاصة. Semgrep Community مجاني لأي مستودع. كحدٍّ أدنى، يجب أن يُشغّل كل pipeline فحص CVE للتبعيات (npm audit --audit-level=high، وpip-audit، وtrivy fs .) وأداة SAST واحدة.

# GitHub Actions — job SAST باستخدام Semgrep وTrivy sast: runs-on: ubuntu-latest permissions: security-events: write # مطلوب لرفع نتائج SARIF steps: - uses: actions/checkout@v4 # Semgrep — SAST مفتوح المصدر، أكثر من 1000 قاعدة - uses: returntocorp/semgrep-action@v1 with: config: >- p/owasp-top-ten p/secrets p/ci generateSarif: '1' - uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: semgrep.sarif # Trivy — فحص ثغرات container + نظام الملفات - uses: aquasecurity/trivy-action@master with: scan-type: 'fs' scan-ref: '.' format: 'sarif' output: 'trivy.sarif' severity: 'HIGH,CRITICAL' exit-code: '1' # يُفشل الـ job عند HIGH/CRITICAL - uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: trivy.sarif
SARIF (تنسيق التبادل لنتائج التحليل الساكن) هو تنسيق JSON القياسي لإخراج أدوات الأمان. GitHub وGitLab وAzure DevOps يستهلكونه بشكل أصلي ويعرضون النتائج كتعليقات على الـ diff — يرى المراجعون بالضبط أي سطر يحتوي على SQL injection محتمل، دون مغادرة واجهة الـ PR.

تجميع خط بوابة الجودة

بوابة الجودة لا تُجدي إلا بقدر تطبيقها. النمط في شركات big-tech: تشغيل جميع jobs التحليل الساكن بالتوازي، واشتراط نجاحها جميعاً قبل السماح بالدمج، وتهيئة قواعد حماية الفروع بحيث لا يستطيع أحد — ولا أصحاب المستودع أنفسهم — تجاوزها.

Quality Gate Pipeline — parallel static analysis jobs feeding a merge gate Pull Request push / sync Lint eslint / ruff / golangci-lint Format Check prettier --check black --check Coverage Gate jest --coverage threshold >= 80% SAST Semgrep / CodeQL HIGH/CRIT = fail Dep Audit trivy / npm audit known CVEs Quality Gate ALL jobs must pass Merge allowed branch protection PASS PR blocked fix & re-push FAIL تعمل الـ jobs الخمسة بالتوازي — الوقت الكلي = أبطأ job (~2-4 دقائق) قواعد حماية الفروع تُطبّق: الفحوصات المطلوبة + لا تجاوز للمسؤولين
خط بوابة الجودة: خمسة jobs تحليل ساكن تعمل بالتوازي؛ زر الدمج مقفل حتى تكون كل الفحوصات المطلوبة خضراء.

أنماط الفشل الشائعة وكيفية تجنبها

1. معاملة تحذيرات التدقيق على أنها استشارية. إذا خرج مُدقِّقك بكود 0 مع تحذيرات، يتعلم المهندسون تجاهلها. اضبط --max-warnings 0 أو ما يعادله من البداية. التحذير الذي يُتجاهل صامتاً ستة أشهر ليس تحذيراً — إنه دين تقني بلا صاحب.

2. حدّ تغطية إجمالي يُكافئ الحشو. الفرق تحت الضغط تكتب اختبارات تستدعي دوالاً دون تأكيد أي شيء، ما يُضخّم أرقام التغطية دون إضافة أي قيمة. قاوم ذلك بدمج التغطية مع نقاط المُطفِّر (mutation score)، وبمراجعة التغطية على الوحدات الحرجة لا على الإجمالي فقط.

3. ضجيج SAST يُسبّب إرهاق التنبيهات. أداة SAST بمعدل إيجابية كاذبة 30% ستُكتم من المهندسين في غضون أسبوع. ابدأ بمجموعة قواعد صغيرة عالية الدقة (OWASP Top 10، الأسرار المُضمّنة) ووسّعها تدريجياً. كل قاعدة تُضيفها يجب التحقق منها: شغّلها على تاريخ مستودعك وقِس معدل الإيجابية الكاذبة قبل تطبيقها.

4. بوابات جودة يمكن تجاوزها. قواعد حماية الفروع مفيدة فقط إذا كان خيار تجاوز المسؤول مُعطَّلاً — أو إذا كانت التجاوزات مُسجَّلة ومُراجَعة. "سندمج مباشرة تحت الضغط" هو كيف تنهار كل بوابة جودة في نهاية المطاف. أتمتة عملية الاستثناء: سير عمل لحالات الطوارئ يتطلب موافقاً ثانياً ويُرسل تنبيهاً لمدير الهندسة.

المعيار في big-tech — hooks ما قبل الـ commit كخط دفاع أول: شغّل المُدقِّقات والمُنسِّقات محلياً عبر pre-commit (أداة Python تُدير hooks لأي لغة). هذا يكتشف غالبية المخالفات قبل الـ push، فيكون CI للتطبيق لا الاكتشاف. يحصل المهندسون على ردود أفعال أسرع، ولا يُهدر وقت CI على فشل التنسيق.
# .pre-commit-config.yaml — مُشغِّل hooks محلي (التثبيت: pip install pre-commit) repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.6.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: detect-private-key # يكتشف الأسرار المُودَعة عن طريق الخطأ - repo: https://github.com/psf/black rev: 24.4.2 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.4.4 hooks: - id: ruff args: [--fix] - repo: https://github.com/returntocorp/semgrep rev: 1.73.0 hooks: - id: semgrep args: ['--config', 'p/secrets', '--error'] # التثبيت: pre-commit install # التشغيل اليدوي: pre-commit run --all-files

في الدرس 6 ستنتقل من جودة الكود إلى إدارة الأدوات المُنتَجة (artifacts) — ما تبنيه في CI، وكيف تُصدره بإصدار، وكيف تُخزّنه بحيث يمكن لمراحل النشر اللاحقة استهلاكه بشكل موثوق.