تطوير الويب

دمج SAST + SCA + DAST في خط أنابيب GitLab CI 18 خطوة بخطوة

5 min de lecture

📍 الدليل الرئيسي: Pipeline SAST DAST SCA في 2026: معمارية، أدوات، وتكامل CI/CD
هذا الدرس يُنظِّم في GitLab CI 18 لبنات SAST و SCA و DAST الموصوفة في الدليل الرئيسي.

لماذا تنسيق أمن التطبيقات في GitLab CI

وحّدت GitLab تحت منصة واحدة المستودع Git و runner CI/CD وسجلّ الحاويات وإدارة الثغرات، مما يجعلها بيئة مثالية لتجسيد خط أنابيب DevSecOps من البداية للنهاية. النسخة GitLab 18.8، المتاحة على GitLab.com منذ يناير 2026، و 18.9 لـ Self-Managed منذ فبراير 2026، تُكمل التحسينات التي أدخلتها 18.0 — لا سيما AST_ENABLE_MR_PIPELINES الذي يُفعّل افتراضياً خطوط أنابيب merge request لمسح الأمن.

القوالب الرسمية تغطّي SAST (مُحرَّك بـ Semgrep منذ 2024، بديلاً للمحلّلات اللغوية القديمة)، Secret Detection (مبني على Gitleaks)، Dependency Scanning، Container Scanning (مبني على Trivy في 2026)، Coverage-guided Fuzz Testing، Infrastructure-as-Code Scanning و DAST (مبني على OWASP ZAP، analyzer v4). لوحة Vulnerability Report تُجمِّع النتائج من كل الأدوات، تُكرّر آلياً وتعرض workflow موافقة. يبني هذا الدرس خطوة بخطوة خط أنابيب يجمع SAST + Dependency Scanning + Container Scanning + DAST مع عتبة حجب على الثغرات الجديدة.

المتطلبات المسبقة

  • نسخة GitLab 18.8+ (gitlab.com أو Self-Managed) مع runners CI تعمل.
  • مشروع يحتوي كوداً تطبيقياً (Python, Node, Java, Go، إلخ) و Dockerfile لـ container scanning.
  • ترخيص GitLab Premium أو Ultimate لتفعيل Vulnerability Report وعتبات Merge Request Approval — SAST/Secret Detection متاحة في Free، لكن الفرز المركزي يتطلب Premium على الأقل.
  • المستوى المتوقع: الراحة مع ملف .gitlab-ci.yml، فهم مفهوم stage و job و artefact.
  • الوقت المقدّر: 60 دقيقة لخط الأنابيب الأدنى، 120 للنسخة مع DAST موثَّق.

الخطوة 1 — تفعيل قوالب الأمن بـ include واحد

أسرع نهج هو تضمين قالب Auto DevOps Security الذي تصونه GitLab. هذا التضمين يُضيف عشرات job أمن في الخلفية، تُنفَّذ آلياً عند توفر الشروط (وجود Dockerfile لـ Container Scanning، manifest اعتماديات لـ Dependency Scanning، إلخ). أنشئ أو حرّر ملف .gitlab-ci.yml في جذر المستودع.

stages:
  - test
  - build
  - scan
  - deploy

include:
  - template: Security/SAST.gitlab-ci.yml
  - template: Security/Secret-Detection.gitlab-ci.yml
  - template: Security/Dependency-Scanning.gitlab-ci.yml
  - template: Security/Container-Scanning.gitlab-ci.yml

variables:
  AST_ENABLE_MR_PIPELINES: "true"
  SAST_EXCLUDED_PATHS: "spec, test, tests, tmp, vendor"

المتغير AST_ENABLE_MR_PIPELINES: "true" يضمن تشغيل المسح في خطوط أنابيب merge request، وهو المُحفِّز الموصى به الآن. SAST_EXCLUDED_PATHS يتجنب مسح مجلدات الاختبار التي تحتوي غالباً credentials اختبارية وتُلوّث التقرير. ادفع الـ commit، راقب خط الأنابيب الذي يُشغَّل، ولاحظ في Security & Compliance → Vulnerability Report ظهور النتائج الأولى.

الخطوة 2 — بناء صورة Docker في خط الأنابيب

Container Scanning يحلّل صورة OCI؛ فيجب بناء الصورة قبل خطوة المسح. الممارسة الموصى بها استخدام BuildKit أو Buildah في job مخصص، ثم دفع الصورة إلى GitLab Container Registry المدمج. أضف هذين الـ jobs في stage build.

build_image:
  stage: build
  image: docker:27-cli
  services:
    - docker:27-dind
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
    IMAGE_TAG: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA"
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
    - docker build -t "$IMAGE_TAG" .
    - docker push "$IMAGE_TAG"
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

خدمة docker:27-dind توفّر démon Docker-in-Docker المطلوب لـ docker build. متغيرات $CI_REGISTRY_* تُحقَن آلياً من GitLab وتعطي وصولاً إلى registry المشروع بلا سرّ يدوي. علامة الصورة تتضمّن SHA المختصر للـ commit، مما يسمح للـ job التالي بمسح نفس الصورة التي قد تُنشَر. القاعدة rules: تقصر الـ job على MR و push على الفرع الافتراضي، متجنبةً بناءات لا فائدة منها على فروع الميزة.

الخطوة 3 — ربط Container Scanning على الصورة المبنية

قالب Container Scanning في GitLab يستخدم Trivy في 2026. افتراضياً يمسح $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG، لكن يمكن توجيهه صراحةً على الـ tag الثابت المُنتَج في الخطوة السابقة عبر CS_IMAGE.

container_scanning:
  stage: scan
  variables:
    CS_IMAGE: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA"
    CS_SEVERITY_THRESHOLD: "HIGH"
  needs:
    - build_image

إعلان needs: build_image يسمح بتوازي بقية المسوحات دون انتظار انتهاء build_image لـ SAST أو Dependency Scanning؛ فقط Container Scanning ينتظر الصورة. العتبة CS_SEVERITY_THRESHOLD: "HIGH" تشير إلى أن الـ job يفشل فقط عند العثور على CVE خطورتها ≥ HIGH، لكنه يبقى إعلامياً للـ MEDIUM/LOW. هذه الإستراتيجية تتجنب كسر خط الأنابيب على ضجيج مع حجب الطوارئ الحقيقية.

الخطوة 4 — إضافة DAST على بيئة Review App

DAST يتطلّب تطبيقاً مُنشَراً ومتاحاً. ممارسة GitLab هي ربط DAST ببيئة Review App تُنشَأ ديناميكياً لكل MR: كل MR تنشر preview، يهاجمها DAST، ثم تُهدم البيئة عند إغلاق MR. أضف قالب DAST و job الـ Review App.

include:
  - template: Security/DAST.gitlab-ci.yml

review:
  stage: deploy
  image: alpine:3.20
  script:
    - apk add --no-cache curl bash openssh-client
    - ./scripts/deploy-review.sh "$CI_COMMIT_REF_SLUG"
  environment:
    name: review/$CI_COMMIT_REF_SLUG
    url: https://review-$CI_COMMIT_REF_SLUG.example.com
    on_stop: stop_review
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

dast:
  stage: scan
  variables:
    DAST_WEBSITE: "https://review-$CI_COMMIT_REF_SLUG.example.com"
    DAST_FULL_SCAN_ENABLED: "false"
  needs:
    - review

المتغير DAST_FULL_SCAN_ENABLED: "false" يحوّل إلى الوضع السلبي (baseline scan) الذي لا يُرسل payload هجومياً. لتحليل حقيقي، حوّل إلى true على خطوط أنابيب ليلية عبر قاعدة rules: - if: $CI_PIPELINE_SOURCE == "schedule". الوضع النشط مدمّر: مهاجمته في MR تخاطر بكتابة بيانات في القاعدة، لذا فصله في خط أنابيب scheduled خارج MR ممارسة جيدة.

الخطوة 5 — إعداد مصادقة DAST

أغلب الثغرات المهمة توجد خلف المصادقة. ZAP المُشغَّل عبر DAST template يستطيع المصادقة عبر نموذج أو عبر OAuth/OIDC حسب الإعداد. طريقة النموذج هي الأكثر شيوعاً.

dast:
  variables:
    DAST_WEBSITE: "https://review-$CI_COMMIT_REF_SLUG.example.com"
    DAST_AUTH_URL: "https://review-$CI_COMMIT_REF_SLUG.example.com/login"
    DAST_USERNAME: "qa@example.com"
    DAST_PASSWORD: "$DAST_PASSWORD_SECRET"
    DAST_AUTH_USERNAME_FIELD: "id:email"
    DAST_AUTH_PASSWORD_FIELD: "id:password"
    DAST_AUTH_SUBMIT_FIELD: "css:button[type='submit']"
    DAST_AUTH_VERIFICATION_URL: "https://review-$CI_COMMIT_REF_SLUG.example.com/account"

المُحدِّدات (id:email، css:button[type='submit']) تتبع تركيب ZAP-Selector. كلمة المرور مخزّنة كمتغير CI/CD masked + protected في Settings → CI/CD → Variables. يحاول DAST الاتصال، يتحقق من بلوغه DAST_AUTH_VERIFICATION_URL في الوضع المُصادَق، ثم يهاجم الأسطح المحمية. إذا فشلت المصادقة، يشير التقرير بوضوح وتصبح كل النتائج مشبوهة (تغطية ناقصة)؛ تحقق من المُحدِّدات ومن وجود CAPTCHA يحجب.

الخطوة 6 — تعريف العتبات في Merge Request Approval

الهدف النهائي ليس توليد تقارير بل حجب ما يجب حجبه. GitLab Premium يعرض Merge Request Approval Policies في Security & Compliance → Policies. أنشئ سياسة YAML تشترط موافقة إضافية بمجرد ظهور ثغرة حرجة جديدة في MR.

type: scan_result_policy
name: Block critical SAST findings
description: Require security team approval if a CRITICAL SAST finding appears in a MR
enabled: true
rules:
  - type: scan_finding
    branches: [main]
    scanners: [sast, dependency_scanning, container_scanning]
    vulnerabilities_allowed: 0
    severity_levels: [critical]
    vulnerability_states: [newly_detected]
actions:
  - type: require_approval
    approvals_required: 1
    role_approvers: [security_engineer]

القاعدة تنطلق فقط على النتائج newly_detected، مما يتجنب حجب MR بسبب الدين التاريخي القائم على main. المُحفِّز المعتمد على الخطورة (critical) يُبقي الاحتكاك معتدلاً. الدور security_engineer يجب أن يكون موجوداً في المشروع (مُنشأ عبر Settings → Members بـ custom role). عندما تنطلق السياسة، يصبح زر Merge رمادياً ويُسرد تعليق تلقائي النتائج المعنية.

الخطوة 7 — استيراد التقارير في DefectDojo

Vulnerability Report الخاص بـ GitLab يلائم اليومي الداخلي، لكن فريق أمن متعدد الفرق يفضّل غالباً مُجمِّعاً مركزياً. آثار كل مسح متاحة بصيغة GitLab JSON الأصيلة ويمكن تحويلها إلى SARIF ثم استيرادها في DefectDojo. أضف job نهائياً يدفع التقارير.

push_to_defectdojo:
  stage: scan
  image: python:3.12-slim
  needs:
    - sast
    - dependency_scanning
    - container_scanning
  script:
    - pip install --quiet defectdojo_api_v2
    - python ./scripts/push-to-defectdojo.py
  variables:
    DOJO_URL: "https://defectdojo.example.com"
    DOJO_API_KEY: "$DOJO_API_KEY"
    DOJO_PRODUCT_ID: "42"
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

سكربت push-to-defectdojo.py يستدعي endpoint /api/v2/import-scan/ مع كل artefact JSON من GitLab باختيار نوع الماسح المناسب (GitLab SAST Report، GitLab Dependency Scanning Report، إلخ). DefectDojo يعرف بشكل أصيل أكثر من 160 صيغة، منها الأصيلة لـ GitLab. القاعدة $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH تتجنب تلويث DefectDojo بنتائج عابرة لفروع الميزات، التي تبقى مرئية فقط في Vulnerability Report لـ GitLab.

الخطوة 8 — تفعيل schedules للمسوحات العميقة

بعض المسوحات (DAST full، Coverage-guided Fuzzing، IaC scanning على كل المستودع) تستغرق 30 إلى 60 دقيقة وليس مكانها في MR. خطوط الأنابيب المُجدوَلة تُنفَّذ بفواصل منتظمة على الفرع الافتراضي، خارج تدفق المطورين. اضبط في CI/CD → Schedules cron يومياً عند 02:00 ومرّر الوضع full في متغير.

dast_full:
  extends: dast
  variables:
    DAST_FULL_SCAN_ENABLED: "true"
    DAST_TARGET_AVAILABILITY_TIMEOUT: "600"
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule" && $SCHEDULED_JOB == "dast_full"

المتغير SCHEDULED_JOB: dast_full يُعرَّف على مستوى الـ schedule نفسه، مما يسمح بتمييز schedule الـ DAST عن schedule الـ fuzz. هذه التجزئة تُبقي مصفوفة الـ jobs مقروءة وتتجنب أن تدور كل الـ schedules بالتوازي وتُشبع الـ runners. النتيجة تُغذّي نفس Vulnerability Report الخاص بمسوحات MR، مع tag scheduled لتمييز المصادر.

الأخطاء الشائعة

العَرَض السبب الحل
SAST لا يكتشف أي لغة المستودع أساساً ملفات إعداد افرض القائمة بـ SAST_EXCLUDED_ANALYZERS: "" و SAST_DEFAULT_ANALYZERS: "semgrep"
Container Scanning يفشل بـ image not found CS_IMAGE لا يطابق tag المُدفَع فعلاً وحّد صراحةً بـ $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA في build و scan
مصادقة DAST تفشل مُحدِّد CSS/ID تغيّر بعد refactor frontend اختبر المُحدِّدات في DevTools console، استخدم data-testid ثابت في frontend
خط أنابيب طويل جداً > 30 دقيقة كل المسوحات تسلسلياً في MR واحد استخدم needs: للتوازي، انقل DAST full إلى schedule ليلي
Vulnerability Report يعرض نفس CVE مرتين لا تكرار بين Container Scanning و Dependency Scanning فعّل SECURE_LOG_LEVEL: "info" واضبط dedup في Settings → Security
سياسة MR Approval لا تنطلق أبداً السياسة مُطبَّقة على main بينما MR تستهدف develop وسّع branches: [main, develop] في السياسة

الأسئلة الشائعة

أي قوالب Security مجانية على GitLab Free؟ SAST و Secret Detection متاحتان في Free منذ 2022. Dependency Scanning و Container Scanning و License Compliance و DAST و Vulnerability Report تتطلّب Premium أو Ultimate حسب الميزة. المصفوفة الدقيقة موثّقة في Security & Compliance → Configuration لكل مشروع.

كيف ندمج Trivy بديلاً عن Container Scanning الأصيل؟ عطّل قالب Container Scanning وأضف job trivy يستخدم aquasec/trivy:latest بمخرَج SARIF + GitLab JSON. آثار GitLab JSON مُعترَف بها من Vulnerability Report. انتبه لتثبيت النسخة بعد حادثة مارس 2026: استخدم aquasec/trivy:0.70.0 كحد أدنى، مثالياً عبر digest sha256.

ما مصير AutoDevOps في 2026؟ AutoDevOps يستمر كمُسرِّع (include واحد وكل شيء يعمل)، لكن النهج الموصى به الآن هو تضمين قوالب Security فردياً للاحتفاظ بالسيطرة على المتغيرات. AutoDevOps يبقى نقطة انطلاق جيدة لإثبات القيمة، يُستبدل بإعداد صريح عند اكتساب النضج.

هل يستهلك DAST دقائق CI كثيرة؟ في الوضع السلبي، 5 إلى 10 دقائق لكل MR. في وضع full على تطبيق مُصادَق غير تافه، 30 إلى 90 دقيقة. على GitLab.com مع runners مشتركة، توقّع الأثر على حصة Premium لدقائق CI؛ لـ Self-Managed، احسب حجم runners أو خصّصها للـ scheduled.

كيف نُصدِّر النتائج كـ SBOM CycloneDX؟ job Dependency Scanning يُنتج ملفات gl-sbom-*.cdx.json بصيغة CycloneDX (نسخ 1.4 إلى 1.6 مدعومة). الميزة dependency_scanning_using_sbom_reports رسمية منذ GitLab 17.3 ومُفعّلة افتراضياً منذ 17.5. الـ artefact مُرفق بـ pipeline ويمكن استهلاكه من أي منصة متوافقة.

دروس ذات صلة

  • الاستضافة الذاتية لـ SonarQube Community Build 26.4 على VPS Linux — لربط SonarQube مكملاً لـ SAST الأصيل في GitLab عبر تعليق PR.
  • حجب PR على الثغرات الجديدة دون عرقلة الفريق — منهجية مطبَّقة على Merge Request Approval Policies.

🔝 العودة إلى الدليل الرئيسي: Pipeline SAST DAST SCA في 2026: معمارية، أدوات، وتكامل CI/CD

قراءات موصى بها

Sponsoriser ce contenu

Cet emplacement est à vous

Position premium en fin d'article — c'est l'instant où les lecteurs sont le plus engagés. Réservez cet espace pour votre marque, votre formation ou votre offre.

Recevoir nos tarifs
Publicité