> ## Content Index
> Fetch the complete content index at: https://arabroot.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# SonarQube عملياً: بوابة جودة لكود الذكاء الاصطناعي
- URL: https://arabroot.io/articles/sonarqube-عمليا-بوابة-جودة-لكود-الذكاء-الاصطناعي/
- Published: 2026-10-12T20:45:00.000Z
- Updated: 2026-10-12T11:54:13.000Z
- Description: كيف تثبت SonarQube مع PostgreSQL وتضبط قواعده وبوابته، ثم تجعل الوكيل الذكي يقرأ نتيجتها ويصلح كوده حتى تنجح.
- Author: فريق عرب رووت
- Tags: الأدلة التقنية, DevOps والتشغيل, DevOps وCI/CD, الاستضافة الذاتية

في [مقال تحليل الكود الثابت SAST](https://arabroot.io/articles/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D9%83%D9%88%D8%AF-%D8%A7%D9%84%D8%AB%D8%A7%D8%A8%D8%AA-sast-%D9%85%D8%B9-semgrep-%D9%88-sonarqube/#lab-sonarqube) شغلنا SonarQube بأمر واحد وقاعدة بيانات مدمجة، ورأينا بوابة الجودة Quality Gate تفشل بسبب ثغرة واحدة في الكود الجديد. وفي [المقال السابق من هذه السلسلة](https://arabroot.io/articles/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A7%D8%AF%D9%88%D8%A7%D8%AA-%D8%AC%D9%88%D8%AF%D8%A9-%D8%A7%D9%84%D9%83%D9%88%D8%AF/) قارناه بأدوات أخرى، ووجدنا أن إعداده الافتراضي فاته التكرار وابتلاع الخطأ. أما في هذا المقال فسوف نبنيه كما يبنى لفريق حقيقي: مع PostgreSQL، وعدة لغات، وملف قواعد خاص بالفريق، وخط CI، ثم نجرب ما تقدمه Sonar اليوم للوكلاء الأذكياء AI Agents، أي سيرفر MCP وأداة سطر الأوامر، ونترك تعديلاً بأسلوب الوكيل يفشل في بوابة الجودة Quality Gate ثم يصلح حتى تنجح.

المواضيع في السلسلة:

- [ما هي جودة الكود Code Quality وكيف تقيسها؟](https://arabroot.io/articles/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AC%D9%88%D8%AF%D8%A9-%D8%A7%D9%84%D9%83%D9%88%D8%AF-code-quality-%D9%88%D9%83%D9%8A%D9%81-%D8%AA%D9%82%D9%8A%D8%B3%D9%87%D8%A7/): المعنى والمقاييس وبوابات الجودة، ولماذا يحتاج كود الذكاء الاصطناعي إلى انتباه خاص.
- [أدوات جودة الكود: أيها تختار لفريقك؟](https://arabroot.io/articles/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A7%D8%AF%D9%88%D8%A7%D8%AA-%D8%AC%D9%88%D8%AF%D8%A9-%D8%A7%D9%84%D9%83%D9%88%D8%AF/): أدوات كل لغة والمنصات الكاملة وأسعارها وتراخيصها، وتجربة على المستودع نفسه.
- **أداة SonarQube عملياً** (الموضوع الحالي): التثبيت مع PostgreSQL والماسحات وملفات القواعد Quality Profiles والبوابات وCI، وأدوات Sonar للوكلاء الأذكياء.

وسوف نناقش في هذا المقال ما يلي:

- النسخ المتاحة اليوم وما الذي تحتاجه منها، ومزايا الذكاء الاصطناعي وفي أي نسخة توجد كل واحدة.
- كيف يعمل SonarQube من الداخل، ولماذا يحتاج Elasticsearch وقاعدة بيانات.
- التثبيت مع PostgreSQL، والقيمة `vm.max_map_count` دون أن نغير إعدادات الجهاز، ومشكلة حقيقية واجهناها مع PostgreSQL تحت الضغط.
- تحليل مشروع Python مع التغطية واستيراد تقرير Ruff، ومشروع Java عبر Maven وJaCoCo.
- ملف القواعد Quality Profile الخاص بالفريق، وبوابة الجودة Quality Gate، وتعريف الكود الجديد New Code.
- أمثلة CI على GitHub Actions وGitea Actions وJenkins، والربط مع المحرر Connected Mode.
- تجربة الوكيل الذكي: تعديل يفشل في البوابة، ثم سيرفر SonarQube MCP وأداة SonarQube CLI تخبرانه بالمشاكل، ثم إصلاح حتى تنجح بوابة الجودة Quality Gate.
- النسخ الاحتياطي والمراقبة والأمان، والأخطاء الشائعة.

## أي نسخة تحتاج؟ النسخ ومزايا الذكاء الاصطناعي

تغيرت أسماء النسخ مؤخراً، فالنسخة المجانية التي كانت تسمى Community Edition صار اسمها Community Build وتصدر كل شهر، والنسخ التجارية صار اسمها SonarQube Server، والخدمة السحابية التي كانت SonarCloud صار اسمها SonarQube Cloud. والجدول التالي يجمع ما يهمك منها كما هو في صفحات Sonar في 12 أكتوبر 2026:

| النسخة                             | الاستضافة والسعر                                               | أهم ما فيها                                                                             | أهم ما ينقصها                                                   |
| ---------------------------------- | -------------------------------------------------------------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| النسخة المجانية Community Build    | على سيرفرك، مجانية بترخيص LGPL-3.0                             | أكثر من 20 لغة، وملفات القواعد، وبوابة الجودة، والكود الجديد، وسيرفر MCP يعمل معها      | فرع واحد، ولا تحليل لطلبات الدمج، ولا تحليل تلوث Taint Analysis |
| نسخة Developer من SonarQube Server | على سيرفرك، لكل سيرفر في السنة حسب الأسطر، والسعر عبر المبيعات | تحليل الفروع وطلبات الدمج ونتيجتها في GitHub وGitLab، وAI Code Assurance، وتحليل التلوث | لا يوجد AI CodeFix                                              |
| نسختا Enterprise وData Center      | على سيرفرك، السعر عبر المبيعات                                 | كل ما سبق مع AI CodeFix ولغات أكثر، وVortex مع اشتراك منفصل في الإصدار 2026.5           | السعر                                                           |
| الخدمة السحابية SonarQube Cloud    | مجانية حتى 50 ألف سطر خاص، وTeam من 34 دولاراً في الشهر        | تحليل طلبات الدمج دون سيرفر، وفي Team وEnterprise يوجد AI CodeFix وVortex               | الكود يحلل على سيرفرات Sonar                                    |

والمصادر هي [صفحة نسخ SonarQube Server](https://www.sonarsource.com/plans-and-pricing/sonarqube/?ref=arabroot.io) و[صفحة خطط SonarQube Cloud](https://www.sonarsource.com/plans-and-pricing/?ref=arabroot.io)، ولاحظ أن صفحة النسخ التجارية لا تنشر سعراً، وإنما «لكل سيرفر في السنة حسب عدد أسطر الكود».

### مزايا الذكاء الاصطناعي: ماذا يوجد فعلاً، وفي أي نسخة؟

شاهدنا فيديو المطور Milan Jovanović بعنوان [Stop letting AI Agents write bad code. SonarQube CLI solve this](https://www.youtube.com/watch?v=oj6RZIbDm5o&ref=arabroot.io)، وفكرته أن الوكيل الذكي يجب أن يرى نتائج SonarQube أثناء عمله ليصلح ما يكتبه قبل أن يصل إلى طلب الدمج. ولأن أسماء هذه المزايا كثيرة ومتشابهة، تحققنا من كل واحدة في وثائق Sonar الرسمية:

- **سيرفر** [**SonarQube MCP Server**](https://docs.sonarsource.com/sonarqube-mcp-server/?ref=arabroot.io)**:** سيرفر MCP يعطي الوكيل أدوات لقراءة المشاكل وحالة بوابة الجودة Quality Gate والتغطية والتكرار. وتذكر الوثائق أنه يعمل مع SonarQube Cloud ومع SonarQube Server 2025.1 فما فوق ومع Community Build، وشغلناه فعلاً مع Community Build كما سوف ترى. وترخيصه بحسب الوثائق هو SONAR Source-Available License، أي كود متاح للقراءة بشروط وليس ترخيصاً مفتوح المصدر، مع أن صفحة الأسعار تصفه بأنه «Open source and free»، والوثائق هي المرجع هنا.
- **أداة** [**SonarQube CLI**](https://docs.sonarsource.com/sonarqube-cli/?ref=arabroot.io)**:** أمرها اسمه `sonar`، وهي غير الماسح Scanner `sonar-scanner`، وترخيصها LGPL-3.0 في [مستودعها](https://github.com/SonarSource/sonarqube-cli?ref=arabroot.io)، وآخر إصدار 1.9.0\. وفيها أوامر لعرض المشاكل وحالة البوابة، وكشف الأسرار في الملفات دون اتصال، والأمر `sonar integrate` الذي يثبت خطافات Hooks وإعداد MCP في Claude Code وCursor وCodex وCopilot CLI. والوثائق تذكر أنها تحتاج SonarQube Server 2025.1 أو SonarQube Cloud، ولكن الأوامر التي شغلناها عملت مع Community Build 26.9.
- **تحليل Vortex وأمر `sonar remediate`:** تحليل التغييرات المحلية قبل الحفظ ووكيل الإصلاح Remediation Agent يحتاجان بحسب [صفحة التحليل في الوثائق](https://docs.sonarsource.com/sonarqube-cli/analysis/analysis?ref=arabroot.io) خطة Team أو Enterprise في SonarQube Cloud، أو نسخة Enterprise أو Data Center من SonarQube Server 2026.5 مع اشتراك، أي أنهما غير متاحين في النسخة المجانية.
- **ميزة** [**AI Code Assurance**](https://docs.sonarsource.com/sonarqube-server/project-administration/ai-features/set-up-ai-code-assurance?ref=arabroot.io)**:** وسم المشروع بأنه يحتوي كوداً من الذكاء الاصطناعي، وتطبيق بوابة خاصة عليه، وشارة Badge تنشرها، وهي في نسخة Developer فما فوق بحسب صفحة النسخ.
- **ميزة** [**AI CodeFix**](https://docs.sonarsource.com/sonarqube-server/project-administration/ai-features/enable-ai-codefix?ref=arabroot.io)**:** زر يطلب من نموذج لغوي اقتراح إصلاح لمشكلة، وهو في نسختي Enterprise وData Center من SonarQube Server وخطتي Team وEnterprise في SonarQube Cloud، ويمكن ربطه بنموذج تستضيفه بنفسك.
- **ملف القواعد Quality Profile Sonar agentic AI:** تذكر [وثائق ملف القواعد Quality Profile للذكاء الاصطناعي](https://docs.sonarsource.com/sonarqube-cloud/standards/ai-code-assurance/quality-profiles-for-agentic-ai?ref=arabroot.io) أنه ملف مدمج لـ Java وJavaScript وTypeScript وPython يركز على الأخطاء التي يقع فيها الوكيل، ووجدناه موجوداً في Community Build 26.9، وفي Python فيه 306 قواعد كلها من Sonar way الذي فيه 398، أي أنه أضيق منه في هذا الإصدار.

## كيف يعمل SonarQube من الداخل؟

قد يتساءل البعض: لماذا يحتاج SonarQube إلى 4GB من الذاكرة وقاعدة بيانات، بينما المدقق Ruff ملف تنفيذي صغير؟ والإجابة أن SonarQube لا يحلل الكود بنفسه على السيرفر، وإنما يحلله الماسح Scanner على جهاز CI، ثم يرسل التقرير إلى السيرفر الذي يخزنه ويقارنه بما قبله. والصورة التالية تبين الأجزاء:

![أجزاء SonarQube: الماسح SonarScanner يعمل في CI أو على جهاز المطور ويحلل الكود ويرسل التقرير إلى سيرفر SonarQube، وفي السيرفر ثلاث عمليات Java هي خادم الويب Web Server للواجهة وال API، ومحرك المعالجة Compute Engine الذي يعالج التقارير بالترتيب، وElasticsearch للبحث في المشاكل، وكلها تحفظ البيانات في PostgreSQL، وعلى الجانب الآخر المحرر مع SonarQube for IDE والوكيل الذكي عبر سيرفر MCP وأداة sonar يقرأون النتائج من ال API](https://arabroot.io/content/images/2026/10/sonarqube-01-architecture.webp)

الماسح Scanner يحلل في CI، والسيرفر يخزن ويقارن ويقرر، والمحرر والوكيل يقرأان النتيجة

- **الماسح SonarScanner:** يعمل حيث يوجد الكود، ويحمل المحللات Analyzers من السيرفر، ويخرج تقريراً. ولكل نظام بناء ماسح، فهناك SonarScanner CLI العام، وماسح Maven وGradle لـ Java، وماسح .NET.
- **خادم الويب Web Server:** الواجهة وال Web API التي يقرأ منها كل شيء آخر، بما فيه سيرفر MCP.
- **محرك المعالجة Compute Engine:** يستلم تقارير التحليل ويحسب المقاييس والكود الجديد وحكم البوابة، والنسخة المجانية تعالج تقريراً واحداً في الوقت نفسه.
- **محرك Elasticsearch المدمج:** فهرس للبحث السريع في المشاكل والمقاييس، ويعاد بناؤه من قاعدة البيانات عند الحاجة، لذلك ليس هو ما تأخذ منه النسخة الاحتياطية.
- **قاعدة البيانات:** المصدر الوحيد للحقيقة، والمدعوم منها في [وثائق قاعدة البيانات](https://docs.sonarsource.com/sonarqube-community-build/server-installation/installing-the-database?ref=arabroot.io) هو PostgreSQL من الإصدار 15 إلى 18 منذ Community Build 26.8، وMicrosoft SQL Server وOracle، وقاعدة H2 المدمجة للتجربة فقط.

## التثبيت مع PostgreSQL

### قبل التثبيت: القيمة vm.max\_map\_count

لأن SonarQube يحتوي Elasticsearch، تطلب [صفحة التحضير على Linux](https://docs.sonarsource.com/sonarqube-community-build/server-installation/pre-installation/linux?ref=arabroot.io) أن تكون القيمة `vm.max_map_count` في السيرفر 524288 على الأقل، وأن يستطيع المستخدم فتح 131072 ملفاً و8192 Thread. وهذه القيمة في نواة النظام Kernel وليست داخل ال Container، لذلك يجب أن تضبطها في السيرفر نفسه. والطريقة البسيطة التي تجدها في كثير من الشروحات هي أن تطفئ الفحص بالمتغير `SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true`، وهو موجود فعلاً في [صفحة التجربة السريعة](https://docs.sonarsource.com/sonarqube-community-build/try-out-sonarqube?ref=arabroot.io)، ولكنه للتجربة فقط، والسبب أن Elasticsearch يفتح ملفات فهارسه بطريقة تحتاج عدداً كبيراً من مناطق الذاكرة، والفحص موجود ليمنعك من تشغيله بإعداد لا يكفيه.

وفي جهاز التجربة عندنا Docker Desktop على WSL، ولم نغير إعداداته، فقرأنا القيمة الحالية أولاً:

```bash
docker run --rm alpine:3.20 cat /proc/sys/vm/max_map_count
```

والمخرج سوف يكون كما يلي:

```text
262144
```

وهي أقل من 524288 التي تطلبها Sonar، ولكنها تساوي الحد الأدنى الذي يفحصه Elasticsearch نفسه، فبحسب [صفحة فحوص التشغيل في Elasticsearch](https://www.elastic.co/docs/deploy-manage/deploy/self-managed/bootstrap-checks?ref=arabroot.io) يفشل الفحص إذا كانت القيمة أقل من 262144\. لذلك شغلنا السيرفر دون أن نطفئ الفحص، وفي السجل ظهر السطر `explicitly enforcing bootstrap checks` ثم بدأ Elasticsearch بنجاح. أما على سيرفر Linux حقيقي فاضبط القيمة كما في الوثائق، في ملف دائم:

```bash
echo 'vm.max_map_count=524288' | sudo tee /etc/sysctl.d/99-sonarqube.conf
echo 'fs.file-max=131072' | sudo tee -a /etc/sysctl.d/99-sonarqube.conf
sudo sysctl --system
```

### ملف Docker Compose

بنينا الملف على [مثال Sonar الرسمي](https://github.com/SonarSource/docker-sonarqube/tree/master/example-compose-files/sq-with-postgres?ref=arabroot.io) مع إصدارات مثبتة، وأسماء تبدأ بالبادئة `lab-cq-`، والمنفذ على `127.0.0.1` فقط:

```yaml
name: lab-cq

services:
  db:
    image: postgres:18.6
    container_name: lab-cq-postgres
    # tini as PID 1: an orphaned healthcheck process must not be reaped by the postmaster
    init: true
    environment:
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: ${SONAR_DB_PASSWORD:?set SONAR_DB_PASSWORD}
      POSTGRES_DB: sonar
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d sonar -U sonar"]
      interval: 10s
      timeout: 5s
      retries: 5
    volumes:
      - lab-cq-pgdata:/var/lib/postgresql
    networks: [lab-cq-net]

  sonarqube:
    image: sonarqube:26.9.0.129388-community
    container_name: lab-cq-sonarqube
    read_only: true
    depends_on:
      db:
        condition: service_healthy
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: ${SONAR_DB_PASSWORD}
      # vm.max_map_count must be at least 262144 for the Elasticsearch bootstrap check
      # (SonarQube recommends 524288). Set it with sysctl on the host, never disable the check in production.
    volumes:
      - lab-cq-sq-data:/opt/sonarqube/data
      - lab-cq-sq-extensions:/opt/sonarqube/extensions
      - lab-cq-sq-logs:/opt/sonarqube/logs
      - lab-cq-sq-temp:/opt/sonarqube/temp
    tmpfs:
      - /tmp:size=256M,mode=1777
    ports:
      - "127.0.0.1:19900:9000"
    networks: [lab-cq-net]

volumes:
  lab-cq-pgdata:
    name: lab-cq-pgdata
  lab-cq-sq-data:
    name: lab-cq-sq-data
  lab-cq-sq-extensions:
    name: lab-cq-sq-extensions
  lab-cq-sq-logs:
    name: lab-cq-sq-logs
  lab-cq-sq-temp:
    name: lab-cq-sq-temp

networks:
  lab-cq-net:
    name: lab-cq-net
```

في الإعداد أعلاه لاحظ التالي:

- الخيار `read_only: true` مع `tmpfs` على `/tmp` من مثال Sonar نفسه، والسبب كما في وثائق التحضير أن Elasticsearch 9 يحتاج الكتابة في `/tmp`، فنعطيه ذاكرة مؤقتة ونبقي باقي النظام للقراءة فقط.
- ال Volumes الأربعة للبيانات والإضافات والسجلات والملفات المؤقتة، والبيانات الحقيقية في Volume قاعدة البيانات.
- السطر `init: true` لقاعدة البيانات ليس في مثال Sonar، وأضفناه بعد مشكلة حقيقية نشرحها في القسم التالي.

ونشغل الملف بكلمة مرور عشوائية لقاعدة البيانات، ثم ننتظر الحالة `UP`:

```bash
export SONAR_DB_PASSWORD="$(openssl rand -hex 16)"
docker compose up -d
until curl -s http://127.0.0.1:19900/api/system/status | grep -q '"UP"'; do sleep 5; done
curl -s http://127.0.0.1:19900/api/system/status
```

والمخرج سوف يكون كما يلي:

```text
{"id":"243B8A4D-AaEvEYtzsU9lDY9ciEK9","version":"26.9.0.129388","status":"UP"}
```

وفي التشغيل الأول تنفذ المنصة 97 عملية ترحيل Migration لقاعدة البيانات، واستغرقت عندنا قرابة دقيقتين، فلا تقلق إذا بقيت الحالة `STARTING` عدة دقائق.

### مشكلة واجهناها: PostgreSQL يعيد تشغيل نفسه تحت الضغط

بعد ساعتين من التجربة، والجهاز مشغول بمشاريع أخرى، بدأت أوامر SonarQube ترجع الخطأ 500، وفي سجل السيرفر وجدنا `FATAL: the database system is in recovery mode`، وفي سجل PostgreSQL وجدنا السبب:

```text
LOG:  untracked child process (PID 8654) exited with exit code 2
LOG:  terminating any other active server processes
LOG:  all server processes terminated; reinitializing
```

والسبب أن PostgreSQL في ال Docker Image الرسمي هو العملية رقم 1 داخل ال Container، وعندما تتأخر أوامر فحص الصحة Healthcheck تحت الضغط ويقتلها Docker، تتيتم عمليات أبنائها وتصبح أبناء العملية رقم 1، فيرى PostgreSQL عملية لا يعرفها انتهت بخطأ، فيعتبر ذلك عطلاً ويعيد تشغيل كل شيء ويدخل وضع الاسترداد Recovery. والحل كان السطر `init: true`، فيصبح برنامج `docker-init` الصغير هو العملية رقم 1 ويتولى العمليات اليتيمة، وبعده لم تتكرر المشكلة:

```text
    PID COMMAND
      1 docker-init
```

### أول دخول والتوكنات Tokens

كلمة مرور المدير الافتراضية هي `admin`، فغيرها فوراً، ثم أنشئ توكنين من نوعين مختلفين، وهذا الفرق مهم جداً كما سوف ترى:

```bash
curl -s -u admin:admin -X POST http://127.0.0.1:19900/api/users/change_password \
  --data-urlencode "login=admin" --data-urlencode "previousPassword=admin" \
  --data-urlencode "password=$SONAR_ADMIN_PASSWORD"

# for scanners in CI
curl -s -u "admin:$SONAR_ADMIN_PASSWORD" -X POST http://127.0.0.1:19900/api/user_tokens/generate \
  -d "name=lab-scan&type=GLOBAL_ANALYSIS_TOKEN"
# for MCP and the sonar CLI: they require a user token
curl -s -u "admin:$SONAR_ADMIN_PASSWORD" -X POST http://127.0.0.1:19900/api/user_tokens/generate \
  -d "name=lab-agent&type=USER_TOKEN"
```

توكن التحليل Analysis Token يبدأ بالحروف `sqa_` ويصلح للماسح فقط، وتوكن المستخدم User Token يبدأ بالحروف `squ_`، وتقول وثائق MCP وCLI بوضوح إنهما يحتاجان توكن مستخدم. وفي الإنتاج لا تقم بإنشاء توكن المستخدم للمدير، وإنما لمستخدم خاص بالوكيل له صلاحية القراءة على المشاريع التي يحتاجها فقط.

## تحليل المشاريع بعدة لغات

### مشروع Python مع التغطية

نستخدم مستودع المتجر من [المقال الأول](https://arabroot.io/articles/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AC%D9%88%D8%AF%D8%A9-%D8%A7%D9%84%D9%83%D9%88%D8%AF-code-quality-%D9%88%D9%83%D9%8A%D9%81-%D8%AA%D9%82%D9%8A%D8%B3%D9%87%D8%A7/#lab-repo)، ونضع في جذره ملف `sonar-project.properties`:

```ini
sonar.projectKey=shop
sonar.projectName=Demo shop
sonar.projectVersion=1.0
sonar.sources=shop
sonar.tests=tests
sonar.python.version=3.13
sonar.python.coverage.reportPaths=coverage.xml
sonar.python.ruff.reportPaths=ruff-report.json
```

ثم نولد تقرير التغطية بأداة pytest-cov، ونشغل الماسح Scanner في Container على شبكة SonarQube نفسها، والخيار `sonar.qualitygate.wait=true` يجعل الماسح Scanner ينتظر حكم بوابة الجودة Quality Gate ويفشل إذا فشلت، وهذا ما يحتاجه CI:

```bash
python -m pytest -q --cov=shop --cov-branch --cov-report=xml:coverage.xml

docker run --rm --name lab-cq-scanner --network lab-cq-net \
  -v lab-cq-src:/usr/src -v lab-cq-scanner-cache:/opt/sonar-scanner/.sonar \
  -e SONAR_HOST_URL=http://lab-cq-sonarqube:9000 -e SONAR_TOKEN="$SONAR_SCAN_TOKEN" \
  sonarsource/sonar-scanner-cli:12.2.0.4256_8.1.0 -Dsonar.qualitygate.wait=true
```

ومن المخرج نأخذ الأسطر المهمة:

```text
INFO  SonarScanner CLI 8.1.0.6389
INFO  Communicating with SonarQube Community Build 26.9.0.129388
INFO  Quality profile for py: Shop way
INFO  Sensor Import of Ruff issues [python]
INFO  Importing /usr/src/ruff-report.json
INFO  QUALITY GATE STATUS: PASSED - View details on http://lab-cq-sonarqube:9000/dashboard?id=shop
```

في المخرج أعلاه لاحظ التالي:

- الكود في Volume باسم `lab-cq-src` وليس في مجلد من Windows، والسبب أن التحليل الأول من مجلد Windows مشترك كان بطيئاً جداً، ومخبأ الماسح Scanner في Volume آخر حتى لا ينزل المحللات في كل مرة.
- ملف القواعد Quality Profile للغة Python هو Shop way الذي سوف نصنعه بعد قليل، والماسح Scanner استورد تقرير Ruff.
- بوابة الجودة Quality Gate نجحت في التحليل الأول لأنه لا يوجد كود جديد بعد، كما شرحنا في مقال SAST.

وفي التحليل الأول، قبل أن نقلل المصادر إلى مجلد `shop`، كان المشروع يحتوي ملف JavaScript أيضاً، وحلله الماسح Scanner نفسه دون إعداد إضافي لأنه يحمل Node.js مدمجاً. ولكن في تحليل لاحق والجهاز تحت ضغط كبير فشل التحليل بالرسالة `Failed to start the bridge server (300s timeout)`، فمحلل JavaScript يشغل عملية Node.js منفصلة تحتاج ذاكرة ووقتاً، فإذا رأيت هذه الرسالة فابدأ بموارد جهاز CI قبل أي شيء آخر.

### مشروع Java عبر Maven وJaCoCo

لمشاريع Maven لا تستخدم SonarScanner CLI، وإنما ماسح Maven، فهو يعرف مسارات الكود والكلاسات المترجمة من ملف `pom.xml`. وأضفنا إلى المشروع الصغير `invoice-java` إضافة JaCoCo لتقرير التغطية، ثم شغلنا:

```bash
docker run --rm --name lab-cq-maven --network lab-cq-net -v "$PWD/invoice-java:/usr/src/app" \
  -v lab-cq-m2:/root/.m2 -w /usr/src/app -e SONAR_TOKEN="$SONAR_SCAN_TOKEN" maven:3.10.0-eclipse-temurin-21 \
  mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:5.8.0.7211:sonar \
  -Dsonar.host.url=http://lab-cq-sonarqube:9000 -Dsonar.qualitygate.wait=true
```

والمخرج سوف يكون كما يلي، بعد اختيار الأسطر المهمة:

```text
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] Communicating with SonarQube Community Build 26.9.0.129388
[INFO] Sensor JaCoCo XML Report Importer [jacoco]
[INFO] Sensor JaCoCo XML Report Importer [jacoco] (done) | time=62ms
[INFO] QUALITY GATE STATUS: PASSED - View details on http://lab-cq-sonarqube:9000/dashboard?id=shop-invoice-java
[INFO] BUILD SUCCESS
```

ووجد SonarQube مشكلتين في الكلاس `Invoice`: الأولى `java:S2095` بخطورة Blocker لأن `FileWriter` لا يغلق إذا رمى `write` استثناء، والحل هو try-with-resources، والثانية `java:S108` للكتلة `catch` الفارغة، والتغطية 55.6% من تقرير JaCoCo الذي اكتشفه الماسح Scanner تلقائياً. ولاحظ أن محلل Java وجد الكتلة الفارغة، بينما لم يجد محلل Python في Sonar way الكتلة المقابلة في `storage.py`، فقوة القواعد ليست متساوية بين اللغات. أما مشاريع .NET فلها ماسح خاص هو SonarScanner for .NET، ويعمل بثلاث خطوات: begin ثم البناء ثم end، ولم نشغله في هذه التجربة.

## ملف القواعد Quality Profile الخاص بالفريق

لا تقم بتعديل ملف Sonar way المدمج مباشرة، فهو للقراءة فقط وتحدثه Sonar مع كل إصدار. والطريقة الصحيحة أن تنشئ ملفاً يرث Inherit منه، فتأخذ كل تحديثاته وتضيف عليه ما يريده الفريق:

```bash
A="-u admin:$SONAR_ADMIN_PASSWORD"; U=http://127.0.0.1:19900
curl -s $A -X POST "$U/api/qualityprofiles/create" -d "language=py&name=Shop way"
curl -s $A -X POST "$U/api/qualityprofiles/change_parent" \
  -d "language=py&qualityProfile=Shop way&parentQualityProfile=Sonar way"
curl -s $A -X POST "$U/api/qualityprofiles/activate_rule" -d "key=$PROFILE_KEY&rule=python:S1128"
curl -s $A -X POST "$U/api/qualityprofiles/add_project" -d "language=py&qualityProfile=Shop way&project=shop"
```

وبعدها صار في ملف Shop way 399 قاعدة، أي 398 من Sonar way وقاعدة الاستيراد غير المستخدم `python:S1128`. ولكن في التحليل التالي لم تظهر هذه القاعدة على `import os` و`import sys` في `storage.py` في الإصدار 26.9، فلم نعتمد عليها، واعتمدنا على Ruff كما في القسم التالي، وهذا يذكرك بأن تتحقق من أن القاعدة تعمل على كودك بعد تفعيلها، ولا تكتفي برؤيتها مفعلة.

### استيراد تقرير Ruff كمشاكل خارجية

بدلاً من أن تعيد بناء قواعد Ruff داخل SonarQube، تستطيع أن تستورد تقريره كمشاكل خارجية External Issues، كما في [صفحة تقارير المحللات الخارجية](https://docs.sonarsource.com/sonarqube-community-build/analyzing-source-code/importing-external-issues/external-analyzer-reports?ref=arabroot.io) التي تذكر Pylint وBandit وFlake8 وMypy وRuff لـ Python وESLint لـ JavaScript. وفي المحاولة الأولى ولدنا التقرير بالصيغة المختصرة `--output-format concise`، فكان المخرج:

```text
INFO  Importing /usr/src/ruff-report.txt
ERROR No issues information will be saved as the report file '/usr/src/ruff-report.txt' can't be read. ParseException: null
```

والوثائق لا تذكر الصيغة، ولكن في [مستودع محلل Python](https://github.com/SonarSource/sonar-python?ref=arabroot.io) اسم الكلاس الذي يقرأ التقرير `RuffJsonReportReader`، فالصيغة المطلوبة هي JSON:

```bash
ruff check --output-format json --exit-zero shop > ruff-report.json
```

والخيار `--exit-zero` مهم هنا، لأن Ruff يرجع رمز خروج 1 عندما يجد مشاكل، فيتوقف خط CI قبل أن يصل إلى الماسح Scanner. وبعد التصحيح ظهرت في SonarQube تسع مشاكل من Ruff بأسماء مثل `external_ruff:S110` و`external_ruff:BLE001`، أي أن ابتلاع الخطأ Q4 الذي فاته Sonar way صار في اللوحة نفسها.

## بوابة الجودة Quality Gate والكود الجديد New Code

بوابة الجودة Quality Gate الافتراضية Sonar way في Community Build 26.9 فيها أربعة شروط، كما يرجعها ال API:

```text
new_violations GT 0
new_coverage LT 80
new_duplicated_lines_density GT 3
new_security_hotspots_reviewed LT 100
```

أي لا توجد مشاكل جديدة، والتغطية على الكود الجديد 80% على الأقل، والتكرار فيه 3% على الأكثر، وكل نقاط الأمان الحساسة Security Hotspots الجديدة مراجعة. وكل الشروط على الكود الجديد، وتعريف الكود الجديد في مشروعنا هو الافتراضي:

```text
{"projectKey":"shop","type":"PREVIOUS_VERSION","inherited":true}
```

أي أن الكود الجديد هو كل ما تغير منذ آخر تغيير في رقم الإصدار `sonar.projectVersion`، والخيارات الأخرى بحسب [صفحة الكود الجديد](https://docs.sonarsource.com/sonarqube-community-build/user-guide/about-new-code?ref=arabroot.io) هي عدد من الأيام حتى 90 يوماً، أو تحليل محدد، أو فرع مرجعي Reference Branch. والقاعدة العملية: إذا كنت تصدر إصدارات مرقمة فاستخدم الإصدار السابق، وإذا كنت تنشر باستمرار فاستخدم عدد الأيام، وتذكر أن الكود الجديد لا يعمل إلا إذا غيرت رقم الإصدار فعلاً في كل إصدار، وإلا بقي الكود الجديد يكبر إلى الأبد.

## تشغيل التحليل في CI

المبدأ في كل الأنظمة واحد: الاختبارات مع التغطية، ثم الماسح Scanner مع `sonar.qualitygate.wait=true`، والتوكن والعنوان في الأسرار Secrets. وفي GitHub Actions يوجد إجراء رسمي هو [sonarqube-scan-action](https://github.com/SonarSource/sonarqube-scan-action?ref=arabroot.io) وآخر إصدار له 8.3.0:

```yaml
name: quality
on:
  push:
    branches: [main]
jobs:
  sonarqube:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - uses: actions/setup-python@v6
        with:
          python-version: "3.13"
      - run: |
          pip install pytest==9.1.1 pytest-cov==7.1.0 ruff==0.17.0
          python -m pytest -q --cov=shop --cov-branch --cov-report=xml:coverage.xml
          ruff check --output-format json --exit-zero shop > ruff-report.json
      - uses: SonarSource/sonarqube-scan-action@v8.3.0
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}
        with:
          args: -Dsonar.qualitygate.wait=true
```

والخيار `fetch-depth: 0` مهم، لأن الماسح Scanner يستخدم تاريخ Git لينسب كل سطر إلى من كتبه ومتى، وبدون التاريخ الكامل يصبح حساب الكود الجديد أقل دقة. وفي Gitea Actions، الذي شرحناه في [دليل Gitea Actions](https://arabroot.io/articles/gitea-actions-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-ci-cd-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85%D9%83/)، الأبسط أن تشغل ال Docker Image نفسه الذي استخدمناه في التجربة كخطوة، فلا تعتمد على إجراء من GitHub:

```yaml
name: quality
on: [push]
jobs:
  sonarqube:
    runs-on: ubuntu-latest
    container:
      image: sonarsource/sonar-scanner-cli:12.2.0.4256_8.1.0
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - run: sonar-scanner -Dsonar.qualitygate.wait=true
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}
```

أما في Jenkins فتستخدم الخطوة `withSonarQubeEnv` ثم `waitForQualityGate`، مع Webhook من SonarQube إلى العنوان `/sonarqube-webhook/` في Jenkins حتى لا ينتظر الخط بالاستعلام المتكرر، كما في [صفحة إيقاف خط Jenkins](https://docs.sonarsource.com/sonarqube-community-build/analyzing-source-code/ci-integration/jenkins-integration/pipeline-pause?ref=arabroot.io):

```groovy
node {
  stage('SonarQube analysis') {
    withSonarQubeEnv('sonarqube') {
      sh 'mvn clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar'
    }
  }
}
stage('Quality Gate') {
  timeout(time: 1, unit: 'HOURS') {
    def qg = waitForQualityGate()
    if (qg.status != 'OK') {
      error "Pipeline aborted due to quality gate failure: ${qg.status}"
    }
  }
}
```

ولاحظ أن النسخة المجانية تحلل الفرع الرئيسي فقط، فإذا شغلت التحليل على كل فرع فسوف تكتب الفروع فوق بعضها في المشروع نفسه، لذلك في Community Build شغل التحليل على `main` فقط، أو اجعل لكل فرع مهم مفتاح مشروع مختلفاً. وتحليل طلبات الدمج وعرض النتيجة فيها يحتاج نسخة Developer.

## الربط مع المحرر Connected Mode

إضافة SonarQube for IDE مجانية لـ VS Code وJetBrains وVisual Studio وEclipse، وتعمل وحدها بقواعدها الافتراضية، ولكن قيمتها الحقيقية في الوضع المتصل Connected Mode، وتذكر [صفحة الوضع المتصل](https://docs.sonarsource.com/sonarqube-community-build/user-guide/connected-mode?ref=arabroot.io) أنه يعمل مع Community Build: تربط المحرر بالسيرفر وبمفتاح المشروع، فيستخدم المحرر ملف القواعد Quality Profile نفسه الذي يستخدمه CI، ويخفي المشاكل التي قبلها الفريق على السيرفر. والربط يحتاج توكن مستخدم User Token، ويحفظ في ملف `.sonarlint/connectedMode.json` الذي تستطيع حفظه في المستودع ليستخدمه كل الفريق. وهذا الملف نفسه تقرأ منه أداة `sonar` مفتاح المشروع إذا لم تجد ملف `sonar-project.properties`.

## تجربة الوكيل الذكي: من بوابة فاشلة إلى بوابة ناجحة

الآن نصل إلى فكرة الفيديو، وهي أن الوكيل لا يجب أن ينتظر مراجعاً بشرياً ليعرف أن كوده سيئ. والصورة التالية تبين الحلقة التي سوف نجربها:

![حلقة الوكيل الذكي مع SonarQube في خمس خطوات: الوكيل يكتب ميزة بطاقات الهدايا، ثم يعمل الماسح في CI ويرسل التقرير، فتفشل بوابة الجودة بسبب التغطية 0% والتكرار 42.3% وتسع مشاكل جديدة، ثم يقرأ الوكيل حالة البوابة والمشاكل عبر سيرفر MCP أو الأمر sonar quality-gate status الذي يرجع رمز الخروج 51، ثم يصلح الكود ويضيف الاختبارات، فينجح التحليل التالي ويرجع الأمر رمز الخروج 0](https://arabroot.io/content/images/2026/10/sonarqube-02-agent-loop.webp)

الوكيل لا يخمن ما الخطأ، وإنما يقرأ نتيجة بوابة الجودة Quality Gate نفسها ويصلح حتى تنجح

ولم نشغل الأمر `sonar integrate`، والسبب أنه بحسب [صفحة التكاملات](https://docs.sonarsource.com/sonarqube-cli/integrations/integrations?ref=arabroot.io) يثبت الخطافات دائماً في مجلد المستخدم، مثل `~/.claude/`، ولكل المشاريع على الجهاز، وهذا تغيير لا نريده على جهاز التجربة. وبدلاً من ذلك شغلنا ما يستخدمه الوكيل نفسه، أي سيرفر MCP وأوامر `sonar`، ومثلنا دور الوكيل بخطوات واضحة.

### الخطوة الأولى: تعديل بأسلوب الوكيل

طلبنا ميزة بطاقات الهدايا، فكتبنا ملف `shop/giftcards.py` كما يكتبه وكيل يرى ملفاً أو اثنين فقط في سياقه: نسخ منطق الخصم بدل أن يستدعيه، ونسخ `calculate_total` كاملة بدل أن يستدعيها، ولف الكود بـ `try` واسع، ولم يكتب أي اختبار. وهذا جزء من الملف:

```python
"""Gift cards, written by a coding agent in one prompt (lab code)."""
import json
import logging

def gift_card_discount(customer, total, card):
    try:
        if customer is None:
            return 0
        years = customer.get("years", 0)
        rate = 0
        if years >= 5:
            rate = 0.10
        # ... the same lines as member_discount ...
        if card.get("balance", 0) > 0:
            discount = discount + min(card["balance"], total - discount)
        return round(discount, 2)
    except Exception:
        return 0

def load_card(path):
    try:
        with open(path, encoding="utf-8") as f:
            return json.load(f)
    except Exception:
        pass
```

ثم رفعنا رقم الإصدار إلى 1.1 وحفظنا التغيير وحللنا، فكان المخرج:

```text
INFO  SonarScanner CLI 8.1.0.6389
INFO  Communicating with SonarQube Community Build 26.9.0.129388
ERROR QUALITY GATE STATUS: FAILED - View details on http://lab-cq-sonarqube:9000/dashboard?id=shop
INFO  EXECUTION FAILURE
```

### الخطوة الثانية: الوكيل يسأل سيرفر MCP

كتبنا عميل MCP صغيراً بلغة Python، في ملف `lab/mcp_check.py` مع المقال، يفعل ما يفعله الوكيل بعد كل تعديل: يشغل سيرفر SonarQube MCP في Container عبر stdio، ويطلب قائمة الأدوات، ثم يستدعي أداة حالة بوابة الجودة Quality Gate وأداة المشاكل في الكود الجديد. وهذا الجزء الذي يشغل السيرفر:

```python
CMD = [
    "docker", "run", "-i", "--rm", "--init", "--name", "lab-cq-mcp",
    "--network", "lab-cq-net",
    "-e", "SONARQUBE_TOKEN", "-e", "SONARQUBE_URL", "-e", "TELEMETRY_DISABLED",
    "sonarsource/sonarqube-mcp:1.28.0.4397",
]
env = dict(os.environ, SONARQUBE_URL="http://lab-cq-sonarqube:9000", TELEMETRY_DISABLED="true")
```

ونشغله بتوكن المستخدم:

```bash
SONARQUBE_TOKEN="$SONAR_USER_TOKEN" python mcp_check.py shop
```

والمخرج سوف يكون كما يلي، بعد اختصار قائمة المشاكل:

```text
server: sonarqube-mcp-server 1.28.0.4397
tools: 18
  analyze_code_snippet, change_security_hotspot_status, change_sonar_issue_status, get_component_measures, get_duplications, get_file_coverage_details, get_project_quality_gate_status, list_branches, list_pull_requests, list_quality_gates, search_duplicated_files, search_files_by_coverage, search_metrics, search_my_sonarqube_projects, search_security_hotspots, search_sonar_issues_in_projects, show_rule, show_security_hotspot

== get_project_quality_gate_status
{
  "status" : "ERROR",
  "conditions" : [ {
    "metricKey" : "new_coverage",
    "status" : "ERROR",
    "errorThreshold" : "80",
    "actualValue" : "0.0"
  }, {
    "metricKey" : "new_duplicated_lines_density",
    "status" : "ERROR",
    "errorThreshold" : "3",
    "actualValue" : "42.25352"
  }, {
    "metricKey" : "new_violations",
    "status" : "ERROR",
    "errorThreshold" : "0",
    "actualValue" : "9"
  } ]
}

== search_sonar_issues_in_projects (new code only)
{
  "issues" : [ {
    "rule" : "external_ruff:F401",
    "component" : "shop:shop/giftcards.py",
    "message" : "`logging` imported but unused",
    ...
  }, {
    "rule" : "python:S3776",
    "component" : "shop:shop/giftcards.py",
    "message" : "Refactor this function to reduce its Cognitive Complexity from 38 to the 15 allowed.",
    ...
  } ],
  "paging" : { "pageIndex" : 1, "pageSize" : 100, "total" : 9 }
}
```

في المخرج أعلاه لاحظ التالي:

- سيرفر MCP عمل مع Community Build دون أي حساب خارجي، وأظهر 18 أداة عند بدايته، وسجله ذكر أنه يحمل باقي الأدوات في الخلفية، وأدوات Vortex غير موجودة لأنها تحتاج اشتراكاً.
- بوابة الجودة Quality Gate فشلت بثلاثة شروط: التغطية على الكود الجديد 0% لأنه لا يوجد اختبار، والتكرار 42.3% لأن الوكيل نسخ دالتين، وتسع مشاكل جديدة.
- التكرار ظهر هذه المرة لأن الدالة المنسوخة كبيرة وتتجاوز حد 100 رمز Token، بينما النسخة الصغيرة في المقال السابق لم تظهر.
- من المشاكل التسع مشكلة `EXE002` من Ruff سببها أن الملف نسخ من Windows إلى ال Volume بصلاحية التنفيذ، وهي ضجيج من بيئة التجربة وليست من الوكيل، وأصلحناها مع الباقي.

### الخطوة الثالثة: الأداة sonar ورمز الخروج 51

بعض الوكلاء يفضلون أمراً في الطرفية على سيرفر MCP، ورمز خروج واضح يفهمه أي سكربت. ثبتنا SonarQube CLI داخل Container من سكربت التثبيت الرسمي، وعرفنا الاتصال بمتغيرات البيئة كما في [صفحة متغيرات البيئة](https://docs.sonarsource.com/sonarqube-cli/using-sonarqube-cli/environment-variables?ref=arabroot.io)، لأن تسجيل الدخول العادي `sonar auth login` يحفظ التوكن في سلسلة مفاتيح النظام Keychain غير الموجودة في ال Container:

```bash
docker exec -e SONARQUBE_CLI_TOKEN="$SONAR_USER_TOKEN" \
  -e SONARQUBE_CLI_SERVER=http://lab-cq-sonarqube:9000 -e SONAR_USER_HOME=/tmp/sonarhome lab-cq-cli \
  bash -c 'sonar --version; sonar auth status; sonar quality-gate status -p shop; echo "exit=$?"'
```

والمخرج سوف يكون كما يلي:

```text
1.9.0
[✓ Connected]
Server  http://lab-cq-sonarqube:9000
Source  env vars:  SONARQUBE_CLI_TOKEN, SONARQUBE_CLI_SERVER
=== Quality Gate: [✗ Failed] ===
Project:      shop
Branch:       main (default)

Conditions:
    ✗  0.0%   Coverage on New Code              (required ≥ 80%)
    ✗  42.3%  Duplicated Lines (%) on New Code  (required ≤ 3%)
    ✗  9      New Issues                        (required ≤ 0)
        shop/giftcards.py:38  python:S3776           Refactor this function to reduce its Cognitive Complexity from 38 to the 15 allowed.
        shop/giftcards.py:67  python:S108            Either remove or fill this block of code.
        shop/giftcards.py:34  external_ruff:S110     `try`-`except`-`pass` detected, consider logging the exception
        ...
exit=51
```

ورمز الخروج 51 هو ما تذكره [صفحة رموز الخروج](https://docs.sonarsource.com/sonarqube-cli/using-sonarqube-cli/exit-codes?ref=arabroot.io) لفشل البوابة، أي أن خطافاً في الوكيل أو خطوة في سكربت تستطيع أن تقول ببساطة: لا تنته من المهمة حتى يرجع هذا الأمر صفراً.

### الخطوة الرابعة: الإصلاح حتى تنجح بوابة الجودة Quality Gate

بناء على المشاكل، أعاد الوكيل كتابة الملف فاستدعى الدالتين الموجودتين بدل نسخهما، واستبدل `except Exception` باستثناء محدد يرمى للمستدعي، وأضاف خمسة اختبارات:

```python
"""Gift cards, after fixing the issues reported by the quality gate (lab code)."""
import json

from shop.discounts import member_discount
from shop.pricing import calculate_total

class GiftCardError(Exception):
    """The gift card file is missing or unreadable."""

def gift_card_discount(customer, total, card):
    discount = member_discount(customer, total)
    balance = card.get("balance", 0)
    if balance > 0:
        discount += min(balance, total - discount)
    return round(discount, 2)

def load_card(path):
    try:
        with open(path, encoding="utf-8") as f:
            return json.load(f)
    except (OSError, json.JSONDecodeError) as exc:
        raise GiftCardError(f"cannot read gift card {path}") from exc

def calculate_total_with_card(order, customer, card, coupon=None, region="SA"):
    total = calculate_total(order, customer, coupon=coupon, region=region)
    return round(total - gift_card_discount(customer, total, card), 2)
```

ثم شغلنا الاختبارات وRuff والماسح Scanner مرة أخرى، والإصدار ما زال 1.1 فبقيت نقطة البداية نفسها:

```text
shop/giftcards.py      19      0      2      0   100%
TOTAL                 101     51     56     11    45%
9 passed in 3.02s
All checks passed!
INFO  QUALITY GATE STATUS: PASSED - View details on http://lab-cq-sonarqube:9000/dashboard?id=shop
INFO  EXECUTION SUCCESS
```

وسيرفر MCP أعطى بوابة الجودة Quality Gate `"status" : "OK"` بتغطية 100% على الكود الجديد وتكرار 0.0% وصفر مشاكل جديدة، والمشاكل التسع صارت حالتها `CLOSED`، والأمر `sonar quality-gate status -p shop` طبع `[✓ Passed]` ورجع رمز الخروج 0\. ولاحظ أن تغطية المشروع كله ما زالت 45%، والسبب أن الكود القديم بلا اختبارات، وبوابة الجودة Quality Gate لم تطلب منا إصلاحه، وهذه فكرة الكود الجديد بالضبط.

### التجربة الفاصلة: التوكن الخطأ

ماذا يحدث إذا أعطيت الوكيل توكن التحليل الذي يستخدمه CI، لأنه موجود في الأسرار أصلاً؟ شغلنا الأمر نفسه بالتوكن `sqa_`:

```text
❌ Access denied (HTTP 403). Check that the supplied token and organization are valid.
exit=1
```

الرفض هنا لصالحك، فتوكن التحليل لا يملك صلاحية قراءة نتيجة بوابة الجودة Quality Gate عبر هذا المسار، ورمز الخروج 1 وليس 51، أي أن السكربت يستطيع أن يفرق بين «بوابة الجودة Quality Gate فشلت» و«الأمر نفسه فشل». لذلك أنشئ للوكيل مستخدماً خاصاً وتوكن مستخدم بصلاحيات القراءة فقط، ولا تعطه توكن المدير بحجة أنه يعمل.

### ما الذي لا تفعله هذه الحلقة؟

- بوابة الجودة Quality Gate تعرف القواعد فقط، فإذا كتب الوكيل اختباراً يتحقق من نتيجة خاطئة فسوف تنجح البوابة، وهذا ما شرحناه في [مقال الاختبارات التي يكتبها الذكاء الاصطناعي](https://arabroot.io/articles/%D8%A7%D8%AA%D9%85%D8%AA%D8%A9-%D8%A7%D9%84%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A8%D8%A7%D9%84%D8%B0%D9%83%D8%A7%D8%A1-%D8%A7%D9%84%D8%A7%D8%B5%D8%B7%D9%86%D8%A7%D8%B9%D9%8A/).
- الوكيل يستطيع أن يغش، مثل أن يضيف `# noqa` أو يطلب عبر الأداة `change_sonar_issue_status` قبول المشكلة، لذلك أعط توكن الوكيل صلاحية القراءة فقط، وراجع كل استثناء في طلب الدمج.
- كشف الأسرار بالأمر `sonar analyze secrets` يعمل دون سيرفر بحسب الوثائق، ولكنه ينزل برنامجاً إضافياً عند أول تشغيل، وفي تجربتنا انتهت مهلة التنزيل على شبكة بطيئة، فلم نسجل له نتيجة. وأدوات كشف الأسرار المستقلة شرحناها في [مقال اكتشاف الأسرار المسربة](https://arabroot.io/articles/%D8%A7%D9%83%D8%AA%D8%B4%D8%A7%D9%81-%D8%A7%D9%84%D8%A7%D8%B3%D8%B1%D8%A7%D8%B1-%D8%A7%D9%84%D9%85%D8%B3%D8%B1%D8%A8%D8%A9-%D9%85%D8%B9-gitleaks-%D9%88-trufflehog/).
- سيرفر MCP يعطي الوكيل بيانات المشروع، فراجع قسم الأمان في [مقال بروتوكول MCP](https://arabroot.io/articles/%D8%A8%D8%B1%D9%88%D8%AA%D9%88%D9%83%D9%88%D9%84-mcp-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/) قبل أن تربطه بسيرفر فيه مشاريع حساسة.

## التشغيل: النسخ الاحتياطي والمراقبة والأمان

- **النسخ الاحتياطي:** تقول [صفحة النسخ الاحتياطي](https://docs.sonarsource.com/sonarqube-community-build/server-update-and-maintenance/maintenance/backup-and-restore?ref=arabroot.io) إن أدوات قاعدة البيانات هي الطريقة الموصى بها، وإن النسخ أثناء التشغيل مدعوم، فأخذنا نسخة بالأمر `pg_dump -U sonar -Fc sonar` وكان حجمها 6.2MB لمشروعين صغيرين. وعند الاسترجاع تحذف فهارس Elasticsearch ليعاد بناؤها، والوثائق تذكر المجلد `data/es8`، أما في الإصدار 26.9 فاسمه `data/es9` كما وجدناه في ال Container. وطبق قاعدة 3-2-1 من [مقال النسخ الاحتياطي](https://arabroot.io/articles/%D8%A7%D9%84%D9%86%D8%B3%D8%AE-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D9%8A%D8%A7%D8%B7%D9%8A-%D8%A8%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-3-2-1-%D9%88%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D8%A7%D8%AF%D8%A9/).
- **المراقبة:** المسار `/api/monitoring/metrics` يعطي مقاييس بصيغة Prometheus مثل `sonarqube_health_web_status` و`sonarqube_health_elasticsearch_status`، ويرجع 403 دون مصادقة، فاستخدم الرمز السري للنظام System Passcode أو توكناً.
- **الأمان:** لا تقم بنشر المنفذ 9000 مباشرة، وضعه خلف Reverse Proxy مع HTTPS كما في [دليل تطبيقك خلف Reverse Proxy](https://arabroot.io/articles/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D9%83-%D8%AE%D9%84%D9%81-reverse-proxy/)، وغير كلمة مرور المدير في أول دقيقة، واجعل المشاريع خاصة إذا كان الكود خاصاً.
- **التحديث:** النسخة المجانية تصدر كل شهر، وكل إصدار يرحل قاعدة البيانات تلقائياً، فخذ نسخة احتياطية قبل كل تحديث، ولا تستخدم الوسم `community` المتحرك في الإنتاج، وثبت الإصدار الكامل كما في ملف Compose.

ولإزالة التجربة نحذف ما أنشأناه بالأسماء فقط:

```bash
docker compose -p lab-cq down -v
docker rm -f lab-cq-tools lab-cq-cli
docker volume rm lab-cq-src lab-cq-scanner-cache lab-cq-m2
```

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

- **إطفاء فحص Elasticsearch في الإنتاج:** المتغير `SONAR_ES_BOOTSTRAP_CHECKS_DISABLE` للتجربة فقط، فاضبط `vm.max_map_count` على السيرفر.
- **قاعدة H2 المدمجة في الإنتاج:** تذكر وثائق قاعدة البيانات أنها لا تتحمل الاستخدام المتزامن الكثير، وأن النسخ الاحتياطي فيها محدود، فابدأ بـ PostgreSQL من اليوم الأول.
- **توكن خطأ للأداة الخطأ:** الماسح Scanner يريد توكن تحليل، وMCP وCLI والمحرر تريد توكن مستخدم.
- **عدم تغيير رقم الإصدار:** مع تعريف الإصدار السابق، إذا بقي `sonar.projectVersion` كما هو فلن يبدأ كود جديد أبداً.
- **الاعتماد على Sonar way وحده:** رأيت أنه فاته ابتلاع الخطأ في Python، فأضف ملف قواعد للفريق واستورد تقارير المدققات.
- **تحليل كل الفروع في النسخة المجانية:** الفروع تكتب فوق بعضها، فحلل الفرع الرئيسي فقط أو انتقل إلى نسخة Developer.
- **إعطاء الوكيل صلاحيات كتابة:** توكن بصلاحية تغيير حالة المشاكل يسمح للوكيل بإخفاء ما لا يريد إصلاحه.

## الخلاصة

- النسخة المجانية Community Build تكفي لفريق يحلل الفرع الرئيسي على سيرفره، وتحليل طلبات الدمج والفروع وAI Code Assurance في نسخة Developer، وAI CodeFix في Enterprise أو في SonarQube Cloud Team.
- يحتاج SonarQube إلى PostgreSQL من 15 إلى 18 و4GB من الذاكرة، والقيمة `vm.max_map_count` المطلوبة 524288، والحد الذي يفحصه Elasticsearch هو 262144، فلا تطفئ الفحص في الإنتاج.
- ضع `init: true` لقاعدة البيانات في Docker إذا كان الجهاز تحت ضغط، فقد أعاد PostgreSQL تشغيل نفسه في تجربتنا بسبب عملية يتيمة.
- أنشئ ملف قواعد يرث Sonar way، واستورد تقرير Ruff بصيغة JSON، فتجتمع سرعة المدقق ولوحة المنصة.
- سيرفر SonarQube MCP وأداة sonar عملا مع Community Build دون أي حساب خارجي، والوكيل قرأ منهما سبب فشل البوابة، والأمر `sonar quality-gate status` يرجع 51 عند الفشل و0 عند النجاح.
- تحليل Vortex والإصلاح الآلي عبر `sonar remediate` يحتاجان اشتراكاً في Cloud Team أو Enterprise أو Server Enterprise 2026.5.
- بوابة الجودة Quality Gate تحرس القواعد والتغطية والتكرار، ولا تعرف إن كان الاختبار صحيحاً، فالمراجعة البشرية تبقى آخر خطوة.

وبهذا نكون قد أنهينا سلسلة جودة الكود، وهذه مقالات مرتبطة بالموضوع:

[![](https://arabroot.io/content/images/2026/10/code-quality-cover-cover.webp)دليلما هي جودة الكود Code Quality وكيف تقيسها؟ما الذي يجعل الكود سهل التغيير، وماذا تقيس أدوات الفحص فعلاً، ولماذا يحتاج كود الوكلاء الأذكياء إلى بوابة جودة.](https://arabroot.io/articles/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AC%D9%88%D8%AF%D8%A9-%D8%A7%D9%84%D9%83%D9%88%D8%AF-code-quality-%D9%88%D9%83%D9%8A%D9%81-%D8%AA%D9%82%D9%8A%D8%B3%D9%87%D8%A7/)[![](https://arabroot.io/content/images/2026/10/code-quality-tools-cover-cover.webp)دليلأدوات جودة الكود: أيها تختار لفريقك؟مقارنة عملية بين مدققات كل لغة والأدوات الجامعة ومنصات الجودة، بتراخيصها وأسعارها ونتائجها على مستودع واحد.](https://arabroot.io/articles/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A7%D8%AF%D9%88%D8%A7%D8%AA-%D8%AC%D9%88%D8%AF%D8%A9-%D8%A7%D9%84%D9%83%D9%88%D8%AF/)[![](https://arabroot.io/content/images/2026/10/sast-cover-cover.webp)دليلSAST: كيف يجد تحليل الكود الثابت الثغرات قبل التشغيلكيف تقرأ أداة SAST الكود بحثاً عن الثغرات، وما الذي لا تراه أبداً، وكيف تمنع الإنذارات الخاطئة من أن تفقد الفريق ثقته بها.](https://arabroot.io/articles/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D9%83%D9%88%D8%AF-%D8%A7%D9%84%D8%AB%D8%A7%D8%A8%D8%AA-sast-%D9%85%D8%B9-semgrep-%D9%88-sonarqube/)[![](https://arabroot.io/content/images/2026/10/secure-pipeline-cover-cover.webp)دليلخط CI/CD آمن من البداية للنهاية على Gitea Actionsكيف تجمع فحوص الأمن في خط واحد لا يستطيع طلب الدمج تجاوزه، ثم ترسل إلى الإنتاج نفس ال Docker Image الموقعة التي فحصتها.](https://arabroot.io/articles/%D8%AE%D8%B7-ci-cd-%D8%A7%D9%85%D9%86-%D9%85%D9%86-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A9-%D9%84%D9%84%D9%86%D9%87%D8%A7%D9%8A%D8%A9/)[![](https://arabroot.io/content/images/2026/10/mcp-cover-cover.webp)دليلبروتوكول MCP للمبتدئين: كيف تربط النماذج بأدواتك بأمانكيف يربط بروتوكول MCP نماذج اللغة بأنظمتك وبياناتك، ولماذا الأمان أهم ما فيه، مع سيرفر MCP صغير تبنيه بنفسك.](https://arabroot.io/articles/%D8%A8%D8%B1%D9%88%D8%AA%D9%88%D9%83%D9%88%D9%84-mcp-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/)[![](https://arabroot.io/content/images/2026/10/rag-mcp-agents-cover-cover.webp)دليلمن RAG إلى Agents: أي طريقة يحتاجها مساعد شركتك؟ما الذي تحله كل طريقة لبناء مساعد ذكي للموظفين وما الذي لا تحله، ولماذا تبدأ بالأرخص ولا تنتقل إلى الأغلى إلا عند الحاجة.](https://arabroot.io/articles/rag-%D8%A7%D9%85-fine-tuning-%D8%A7%D9%85-mcp-%D8%A7%D9%85-agents/)

## سجل التحديثات

- أكتوبر 2026: كتابة المقال اعتماداً على وثائق SonarQube Community Build وSonarQube Server 2026.5 وSonarQube CLI وSonarQube MCP Server وصفحات الأسعار كما كانت في 12 أكتوبر 2026، مع تجربة حقيقية على SonarQube Community Build 26.9.0.129388 وPostgreSQL 18.6 وSonarScanner CLI 8.1.0 وماسح Maven 5.8.0 وسيرفر MCP 1.28.0.4397 وأداة sonar 1.9.0.