Skip to content
SEO Optimizer is live, Audit on page SEO and AI-search readiness. Try it free
تسجيل الدخول
CI/CD Integration

أدلة

التكامل مع CI/CD

تقبل كل نقطة طرفية للماسح مفتاح API، لذا يمكن تشغيل أيٍّ منها كخطوة ضمن خط الأنابيب. تتناول هذه الصفحة معنى مخرجات كل أداة، وكيفية تحويلها إلى بوابة نجاح/فشل، وأمثلة عملية لأربع منصات CI.

فحص الكود باستخدام GitHub Action

أسرع طريقة لفحص الكود في CI. يشغّل @scanverra/cli على المشغّل (ولا يغادره الكود أبدًا)، ويوقف المهمة عند درجة الخطورة التي تختارها، ويرفع SARIF إلى فحص الكود في GitHub.

on: [push, pull_request]
jobs:
  scanverra:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - uses: scanverra/scan-action@v1
        with:
          api-key: ${{ secrets.SCANVERRA_API_KEY }}
          fail-on: high
أضف مفتاح API كسرّ للمستودع باسم SCANVERRA_API_KEY. تتضمن الخطة المجانية مفتاحًا واحدًا، ويُحتسب كل فحص مرفوع ضمن فحوصات Repo Scanner الشهرية. وتستخدم فحوصات الروابط أدناه واجهة REST API.

أساس احتساب النتائج لكل أداة

ما تُعيده كل نقطة طرفية، وما الذي ينبغي تحديد حد أدنى له.

الأداةالمخرجاتالأساسبوابة مدمجة
تدقيق الموقع الإلكتروني4 نتائج من 0 إلى 100: performance وseo وaccessibility وbestPracticesدرجات الفئات من 0 إلى 100. العُرف المتبع: ≥90 جيد، 50-89 بحاجة إلى تحسين، <50 ضعيف.لا توجد بوابة مدمجة — اختر الحد الأدنى الخاص بك لكل نتيجة.
فحص الأمانriskScore من 0 إلى 100 (كلما ارتفعت القيمة، زادت السلامة)100 مطروحًا منها خصومات مرجّحة حسب الشدة ومحدودة لكل فئة. درجات التقييم: A+ 90 فأكثر … F أقل من 30.لا توجد بوابة مدمجة — اختر الحد الأدنى الخاص بك.
تدقيق المتصفحمصفوفات: jsErrors وbrokenLinks وformIssues وimgIssues (لكل منها severity: "error" | "warning")لا توجد نتيجة إجمالية.بوابة تعتمد على عدد المشكلات، مثل وجود أي severity === "error".
ماسح المستودعاتscore من 0 إلى 100 + qualityGate: "passed" | "failed"100 مطروحًا منها خصومات مرجّحة حسب الشدة، محدودة لكل فئة.بوابة مدمجة — تفشل تلقائيًا عند وجود أي مشكلة حرجة أو نتيجة أقل من 60.
محسّن السيوscore من 0 إلى 100 (سيو داخل الصفحة + إشارات GEO/E-E-A-T)100 مطروحًا منها خصومات مرجّحة حسب الشدة، محدودة لكل فئة، عبر ملاحظات الصفحة وGEO وE-E-A-T.غير مدمجة — حدّد حدك الخاص.

إيقاف خط الأنابيب

آلية عمل CI واحدة بغض النظر عن المنصة: أي خطوة تخرج برمز غير صفري تُفشل المهمة. لمنع طلب سحب (PR) أو طلب دمج فعليًا من الدمج، أضف هذه المهمة كـ فحص مطلوب/إلزامي ضمن إعدادات حماية الفرع أو موافقات طلبات الدمج في مضيف المستودع لديك — فشل خطوة واحدة بمفرده يظهر باللون الأحمر فقط، ولا يمنع الدمج من تلقاء نفسه.

أمثلة على خطوط الأنابيب

الفحوصات الخمسة نفسها — التدقيق، وفحص الأمان، وتدقيق المتصفح، وفحص المستودع، ومحسّن السيو — مكتوبة لأربع منصات. اختر نظام CI الخاص بك أدناه.

name: Scanverra checks
on: [pull_request]

jobs:
  scanverra:
    runs-on: ubuntu-latest
    env:
      API_KEY: ${{ secrets.SCANVERRA_API_KEY }}
      TARGET_URL: https://staging.example.com   # your deployed preview URL
    steps:
      - name: Website Audit (perf/SEO/a11y)
        run: |
          RES=$(curl -sf -X POST https://www.scanverra.com/api/audit \
            -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
            -d "{\"url\":\"$TARGET_URL\"}")
          echo "$RES" | jq .
          PERF=$(echo "$RES" | jq '.performanceScore')
          A11Y=$(echo "$RES" | jq '.accessibilityScore')
          if (( $(echo "$PERF < 50" | bc -l) )) || (( $(echo "$A11Y < 90" | bc -l) )); then
            echo "::error::Audit failed thresholds (perf=$PERF, a11y=$A11Y)"
            exit 1
          fi

      - name: Security Scan
        run: |
          SCAN_ID=$(curl -sf -X POST https://www.scanverra.com/api/security-scan \
            -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
            -d "{\"url\":\"$TARGET_URL\"}" | jq -r .scanId)

          for i in $(seq 1 30); do
            RESULT=$(curl -sf "https://www.scanverra.com/api/security-scan?id=$SCAN_ID" -H "X-API-Key: $API_KEY")
            STATUS=$(echo "$RESULT" | jq -r .status)
            [ "$STATUS" != "running" ] && break
            sleep 10
          done

          RISK=$(echo "$RESULT" | jq '.riskScore')
          echo "riskScore=$RISK"
          [ "$STATUS" = "failed" ] && { echo "::error::Security scan failed to complete"; exit 1; }
          [ "$RISK" -lt 70 ] && { echo "::error::Security risk score too low ($RISK)"; exit 1; }
          true

      - name: Browser Audit (JS errors, broken links)
        run: |
          TEST_ID=$(curl -sf -X POST https://www.scanverra.com/api/browser-test \
            -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
            -d "{\"url\":\"$TARGET_URL\"}" | jq -r .testId)

          for i in $(seq 1 30); do
            RESULT=$(curl -sf "https://www.scanverra.com/api/browser-test?id=$TEST_ID" -H "X-API-Key: $API_KEY")
            STATUS=$(echo "$RESULT" | jq -r .status)
            [ "$STATUS" != "running" ] && break
            sleep 10
          done

          ERRORS=$(echo "$RESULT" | jq '[.jsErrors[]? | select(.severity=="error")] | length')
          [ "$STATUS" = "failed" ] && { echo "::error::Browser audit failed to complete"; exit 1; }
          [ "$ERRORS" -gt 0 ] && { echo "::error::$ERRORS JS errors found"; exit 1; }
          true

      - name: Repo Scan (SAST, secrets, deps, quality gate)
        run: |
          SCAN_ID=$(curl -sf -X POST https://www.scanverra.com/api/repo/scan \
            -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
            -d '{"owner":"your-org","repo":"your-repo","branch":"${{ github.head_ref }}"}' | jq -r .scanId)

          for i in $(seq 1 30); do
            RESULT=$(curl -sf "https://www.scanverra.com/api/repo/result?id=$SCAN_ID" -H "X-API-Key: $API_KEY")
            STATUS=$(echo "$RESULT" | jq -r .status)
            [ "$STATUS" != "running" ] && break
            sleep 10
          done

          echo "$RESULT" | jq '{score, qualityGate}'
          GATE=$(echo "$RESULT" | jq -r .qualityGate)
          [ "$GATE" = "failed" ] && { echo "::error::Repo quality gate failed"; exit 1; }
          true

      - name: SEO Optimizer (on-page, GEO, E-E-A-T)
        run: |
          SCAN_ID=$(curl -sf -X POST https://www.scanverra.com/api/seo-optimizer \
            -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
            -d "{\"url\":\"$TARGET_URL\"}" | jq -r .scanId)

          for i in $(seq 1 30); do
            RESULT=$(curl -sf "https://www.scanverra.com/api/seo-optimizer?id=$SCAN_ID" -H "X-API-Key: $API_KEY")
            STATUS=$(echo "$RESULT" | jq -r .status)
            [ "$STATUS" != "running" ] && break
            sleep 10
          done

          SCORE=$(echo "$RESULT" | jq '.score')
          echo "seoScore=$SCORE"
          [ "$STATUS" = "failed" ] && { echo "::error::SEO scan failed to complete"; exit 1; }
          [ "$SCORE" -lt 70 ] && { echo "::error::SEO score too low ($SCORE)"; exit 1; }
          true

أين تُخزَّن مفتاح API كسرّ (secret)، حسب المنصة:

  • GitHub Actions: سرّ على مستوى المستودع — Settings ← Secrets and variables ← Actions.
  • GitLab CI: متغيّر CI/CD مُخفى (masked) — Settings ← CI/CD ← Variables.
  • Azure Pipelines: متغيّر خط أنابيب سرّي (أيقونة القفل) أو مجموعة متغيرات (Variable Group) ضمن Pipelines ← Library.
  • Bitbucket Pipelines: إعدادات المستودع > Pipelines > متغيرات المستودع، مع تحديدها كمتغيرات محمية.
  • Jenkins: بيانات اعتماد نصية سرية (Secret text credential) — Manage Jenkins ← Credentials — يُشار إليها عبر credentials(). تحتاج صورة الوكيل (agent image) أيضًا إلى تثبيت curl وjq وbc؛ تتضمنها مسبقًا أدوات التشغيل ubuntu-latest المستضافة على GitHub وAzure، بينما لا تتضمنها صورة alpine في GitLab (ومن هنا تأتي خطوة apk add).

تحتاج خطوة ماسح المستودعات إلى ربط حساب GitHub/Bitbucket/Azure الخاص بك مسبقًا في إعدادات Scanverra — فهي تفحص باستخدام الرمز (token) المخزَّن هناك، وليس رمزًا يُرسَل مع كل طلب.

تفضّل عدم ربط حساب؟ تفحص @scanverra/cli الكود المُنزَّل مباشرة داخل العامل (runner) وتحتاج فقط إلى مفتاح API، دون ربط بحساب GitHub أو Bitbucket أو Azure.

مخرجات SARIF لفحص الشيفرة

SARIF (تنسيق تبادل نتائج التحليل الثابت) هو تنسيق JSON القياسي الذي تتبادل به أدوات فحص الشيفرة نتائجها. تكتب واجهة Scanverra CLI ملفات SARIF 2.1.0 باستخدام ‎--sarif، فتظهر النتائج في أي مكان يقرأ SARIF.

  • فحص الشيفرة في GitHub: فعّل sarif: true في scanverra/scan-action لتظهر النتائج في تبويب Security وكتعليقات على طلبات الدمج.
  • يمكن لـ SonarQube والمنصات الأخرى التي تستورد SARIF قراءة الملف نفسه.
  • في Bitbucket وGitLab: احتفظ بملف SARIF كأحد مخرجات خط التنفيذ، أو استخدم ‎--json لخطوة تقارير خاصة بك.
- uses: actions/checkout@v4
- uses: scanverra/scan-action@v1
  with:
    api-key: ${{ secrets.SCANVERRA_API_KEY }}
    sarif: true          # uploads the report to GitHub code scanning
# The job needs: permissions: { security-events: write }
ملاحظة حول الحصة: يخضع مفتاح API الخاص بالخطة المجانية لحدود الحصة نفسها التي يخضع لها حساب الويب المجاني — لا تزال عمليات تشغيل CI تُحتسب ضمن حد الفحص الشهري الخاص بك ويمكن أن تستنفده بسرعة إذا كنت تُجري الفحص مع كل طلب سحب. مفاتيح API الخاصة بخطط Pro وTeam وEnterprise غير مقيدة بحصة. راجع الحدود والسلوك.

ماسح المستودعات فقط هو من يُعيد حقل qualityGate الجاهز. أما بالنسبة للأدوات الأربع الأخرى، فحدّد حدودك الخاصة مسبقًا وحافظ على ثباتها عبر جميع البيئات (على سبيل المثال، لا تقارن نتيجة أمان عنوان URL خاص ببيئة تجريبية بحد ضُبط لبيئة الإنتاج).