في مقال تحليل الكود الثابت SAST شغلنا SonarQube بأمر واحد وقاعدة بيانات مدمجة، ورأينا بوابة الجودة Quality Gate تفشل بسبب ثغرة واحدة في الكود الجديد. وفي المقال السابق من هذه السلسلة قارناه بأدوات أخرى، ووجدنا أن إعداده الافتراضي فاته التكرار وابتلاع الخطأ. أما في هذا المقال فسوف نبنيه كما يبنى لفريق حقيقي: مع PostgreSQL، وعدة لغات، وملف قواعد خاص بالفريق، وخط CI، ثم نجرب ما تقدمه Sonar اليوم للوكلاء الأذكياء AI Agents، أي سيرفر MCP وأداة سطر الأوامر، ونترك تعديلاً بأسلوب الوكيل يفشل في بوابة الجودة Quality Gate ثم يصلح حتى تنجح.
المواضيع في السلسلة:
- ما هي جودة الكود Code Quality وكيف تقيسها؟: المعنى والمقاييس وبوابات الجودة، ولماذا يحتاج كود الذكاء الاصطناعي إلى انتباه خاص.
- أدوات جودة الكود: أيها تختار لفريقك؟: أدوات كل لغة والمنصات الكاملة وأسعارها وتراخيصها، وتجربة على المستودع نفسه.
- أداة 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 وصفحة خطط SonarQube Cloud، ولاحظ أن صفحة النسخ التجارية لا تنشر سعراً، وإنما «لكل سيرفر في السنة حسب عدد أسطر الكود».
مزايا الذكاء الاصطناعي: ماذا يوجد فعلاً، وفي أي نسخة؟
شاهدنا فيديو المطور Milan Jovanović بعنوان Stop letting AI Agents write bad code. SonarQube CLI solve this، وفكرته أن الوكيل الذكي يجب أن يرى نتائج SonarQube أثناء عمله ليصلح ما يكتبه قبل أن يصل إلى طلب الدمج. ولأن أسماء هذه المزايا كثيرة ومتشابهة، تحققنا من كل واحدة في وثائق Sonar الرسمية:
- سيرفر SonarQube MCP Server: سيرفر MCP يعطي الوكيل أدوات لقراءة المشاكل وحالة بوابة الجودة Quality Gate والتغطية والتكرار. وتذكر الوثائق أنه يعمل مع SonarQube Cloud ومع SonarQube Server 2025.1 فما فوق ومع Community Build، وشغلناه فعلاً مع Community Build كما سوف ترى. وترخيصه بحسب الوثائق هو SONAR Source-Available License، أي كود متاح للقراءة بشروط وليس ترخيصاً مفتوح المصدر، مع أن صفحة الأسعار تصفه بأنه «Open source and free»، والوثائق هي المرجع هنا.
- أداة SonarQube CLI: أمرها اسمه
sonar، وهي غير الماسح Scannersonar-scanner، وترخيصها LGPL-3.0 في مستودعها، وآخر إصدار 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 يحتاجان بحسب صفحة التحليل في الوثائق خطة Team أو Enterprise في SonarQube Cloud، أو نسخة Enterprise أو Data Center من SonarQube Server 2026.5 مع اشتراك، أي أنهما غير متاحين في النسخة المجانية. - ميزة AI Code Assurance: وسم المشروع بأنه يحتوي كوداً من الذكاء الاصطناعي، وتطبيق بوابة خاصة عليه، وشارة Badge تنشرها، وهي في نسخة Developer فما فوق بحسب صفحة النسخ.
- ميزة AI CodeFix: زر يطلب من نموذج لغوي اقتراح إصلاح لمشكلة، وهو في نسختي Enterprise وData Center من SonarQube Server وخطتي Team وEnterprise في SonarQube Cloud، ويمكن ربطه بنموذج تستضيفه بنفسك.
- ملف القواعد Quality Profile Sonar agentic AI: تذكر وثائق ملف القواعد Quality Profile للذكاء الاصطناعي أنه ملف مدمج لـ Java وJavaScript وTypeScript وPython يركز على الأخطاء التي يقع فيها الوكيل، ووجدناه موجوداً في Community Build 26.9، وفي Python فيه 306 قواعد كلها من Sonar way الذي فيه 398، أي أنه أضيق منه في هذا الإصدار.
كيف يعمل SonarQube من الداخل؟
قد يتساءل البعض: لماذا يحتاج SonarQube إلى 4GB من الذاكرة وقاعدة بيانات، بينما المدقق Ruff ملف تنفيذي صغير؟ والإجابة أن SonarQube لا يحلل الكود بنفسه على السيرفر، وإنما يحلله الماسح Scanner على جهاز CI، ثم يرسل التقرير إلى السيرفر الذي يخزنه ويقارنه بما قبله. والصورة التالية تبين الأجزاء:

- الماسح SonarScanner: يعمل حيث يوجد الكود، ويحمل المحللات Analyzers من السيرفر، ويخرج تقريراً. ولكل نظام بناء ماسح، فهناك SonarScanner CLI العام، وماسح Maven وGradle لـ Java، وماسح .NET.
- خادم الويب Web Server: الواجهة وال Web API التي يقرأ منها كل شيء آخر، بما فيه سيرفر MCP.
- محرك المعالجة Compute Engine: يستلم تقارير التحليل ويحسب المقاييس والكود الجديد وحكم البوابة، والنسخة المجانية تعالج تقريراً واحداً في الوقت نفسه.
- محرك Elasticsearch المدمج: فهرس للبحث السريع في المشاكل والمقاييس، ويعاد بناؤه من قاعدة البيانات عند الحاجة، لذلك ليس هو ما تأخذ منه النسخة الاحتياطية.
- قاعدة البيانات: المصدر الوحيد للحقيقة، والمدعوم منها في وثائق قاعدة البيانات هو PostgreSQL من الإصدار 15 إلى 18 منذ Community Build 26.8، وMicrosoft SQL Server وOracle، وقاعدة H2 المدمجة للتجربة فقط.
التثبيت مع PostgreSQL
قبل التثبيت: القيمة vm.max_map_count
لأن SonarQube يحتوي Elasticsearch، تطلب صفحة التحضير على Linux أن تكون القيمة vm.max_map_count في السيرفر 524288 على الأقل، وأن يستطيع المستخدم فتح 131072 ملفاً و8192 Thread. وهذه القيمة في نواة النظام Kernel وليست داخل ال Container، لذلك يجب أن تضبطها في السيرفر نفسه. والطريقة البسيطة التي تجدها في كثير من الشروحات هي أن تطفئ الفحص بالمتغير SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true، وهو موجود فعلاً في صفحة التجربة السريعة، ولكنه للتجربة فقط، والسبب أن Elasticsearch يفتح ملفات فهارسه بطريقة تحتاج عدداً كبيراً من مناطق الذاكرة، والفحص موجود ليمنعك من تشغيله بإعداد لا يكفيه.
وفي جهاز التجربة عندنا Docker Desktop على WSL، ولم نغير إعداداته، فقرأنا القيمة الحالية أولاً:
docker run --rm alpine:3.20 cat /proc/sys/vm/max_map_countوالمخرج سوف يكون كما يلي:
262144وهي أقل من 524288 التي تطلبها Sonar، ولكنها تساوي الحد الأدنى الذي يفحصه Elasticsearch نفسه، فبحسب صفحة فحوص التشغيل في Elasticsearch يفشل الفحص إذا كانت القيمة أقل من 262144. لذلك شغلنا السيرفر دون أن نطفئ الفحص، وفي السجل ظهر السطر explicitly enforcing bootstrap checks ثم بدأ Elasticsearch بنجاح. أما على سيرفر Linux حقيقي فاضبط القيمة كما في الوثائق، في ملف دائم:
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 الرسمي مع إصدارات مثبتة، وأسماء تبدأ بالبادئة lab-cq-، والمنفذ على 127.0.0.1 فقط:
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:
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والمخرج سوف يكون كما يلي:
{"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 وجدنا السبب:
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 ويتولى العمليات اليتيمة، وبعده لم تتكرر المشكلة:
PID COMMAND
1 docker-initأول دخول والتوكنات Tokens
كلمة مرور المدير الافتراضية هي admin، فغيرها فوراً، ثم أنشئ توكنين من نوعين مختلفين، وهذا الفرق مهم جداً كما سوف ترى:
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 مع التغطية
نستخدم مستودع المتجر من المقال الأول، ونضع في جذره ملف sonar-project.properties:
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:
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ومن المخرج نأخذ الأسطر المهمة:
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 لتقرير التغطية، ثم شغلنا:
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والمخرج سوف يكون كما يلي، بعد اختيار الأسطر المهمة:
[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 منه، فتأخذ كل تحديثاته وتضيف عليه ما يريده الفريق:
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، كما في صفحة تقارير المحللات الخارجية التي تذكر Pylint وBandit وFlake8 وMypy وRuff لـ Python وESLint لـ JavaScript. وفي المحاولة الأولى ولدنا التقرير بالصيغة المختصرة --output-format concise، فكان المخرج:
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 اسم الكلاس الذي يقرأ التقرير RuffJsonReportReader، فالصيغة المطلوبة هي JSON:
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:
new_violations GT 0
new_coverage LT 80
new_duplicated_lines_density GT 3
new_security_hotspots_reviewed LT 100أي لا توجد مشاكل جديدة، والتغطية على الكود الجديد 80% على الأقل، والتكرار فيه 3% على الأكثر، وكل نقاط الأمان الحساسة Security Hotspots الجديدة مراجعة. وكل الشروط على الكود الجديد، وتعريف الكود الجديد في مشروعنا هو الافتراضي:
{"projectKey":"shop","type":"PREVIOUS_VERSION","inherited":true}أي أن الكود الجديد هو كل ما تغير منذ آخر تغيير في رقم الإصدار sonar.projectVersion، والخيارات الأخرى بحسب صفحة الكود الجديد هي عدد من الأيام حتى 90 يوماً، أو تحليل محدد، أو فرع مرجعي Reference Branch. والقاعدة العملية: إذا كنت تصدر إصدارات مرقمة فاستخدم الإصدار السابق، وإذا كنت تنشر باستمرار فاستخدم عدد الأيام، وتذكر أن الكود الجديد لا يعمل إلا إذا غيرت رقم الإصدار فعلاً في كل إصدار، وإلا بقي الكود الجديد يكبر إلى الأبد.
تشغيل التحليل في CI
المبدأ في كل الأنظمة واحد: الاختبارات مع التغطية، ثم الماسح Scanner مع sonar.qualitygate.wait=true، والتوكن والعنوان في الأسرار Secrets. وفي GitHub Actions يوجد إجراء رسمي هو sonarqube-scan-action وآخر إصدار له 8.3.0:
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/[email protected]
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، الأبسط أن تشغل ال Docker Image نفسه الذي استخدمناه في التجربة كخطوة، فلا تعتمد على إجراء من GitHub:
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:
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، وتذكر صفحة الوضع المتصل أنه يعمل مع Community Build: تربط المحرر بالسيرفر وبمفتاح المشروع، فيستخدم المحرر ملف القواعد Quality Profile نفسه الذي يستخدمه CI، ويخفي المشاكل التي قبلها الفريق على السيرفر. والربط يحتاج توكن مستخدم User Token، ويحفظ في ملف .sonarlint/connectedMode.json الذي تستطيع حفظه في المستودع ليستخدمه كل الفريق. وهذا الملف نفسه تقرأ منه أداة sonar مفتاح المشروع إذا لم تجد ملف sonar-project.properties.
تجربة الوكيل الذكي: من بوابة فاشلة إلى بوابة ناجحة
الآن نصل إلى فكرة الفيديو، وهي أن الوكيل لا يجب أن ينتظر مراجعاً بشرياً ليعرف أن كوده سيئ. والصورة التالية تبين الحلقة التي سوف نجربها:

ولم نشغل الأمر sonar integrate، والسبب أنه بحسب صفحة التكاملات يثبت الخطافات دائماً في مجلد المستخدم، مثل ~/.claude/، ولكل المشاريع على الجهاز، وهذا تغيير لا نريده على جهاز التجربة. وبدلاً من ذلك شغلنا ما يستخدمه الوكيل نفسه، أي سيرفر MCP وأوامر sonar، ومثلنا دور الوكيل بخطوات واضحة.
الخطوة الأولى: تعديل بأسلوب الوكيل
طلبنا ميزة بطاقات الهدايا، فكتبنا ملف shop/giftcards.py كما يكتبه وكيل يرى ملفاً أو اثنين فقط في سياقه: نسخ منطق الخصم بدل أن يستدعيه، ونسخ calculate_total كاملة بدل أن يستدعيها، ولف الكود بـ try واسع، ولم يكتب أي اختبار. وهذا جزء من الملف:
"""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 وحفظنا التغيير وحللنا، فكان المخرج:
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 وأداة المشاكل في الكود الجديد. وهذا الجزء الذي يشغل السيرفر:
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")ونشغله بتوكن المستخدم:
SONARQUBE_TOKEN="$SONAR_USER_TOKEN" python mcp_check.py shopوالمخرج سوف يكون كما يلي، بعد اختصار قائمة المشاكل:
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 من سكربت التثبيت الرسمي، وعرفنا الاتصال بمتغيرات البيئة كما في صفحة متغيرات البيئة، لأن تسجيل الدخول العادي sonar auth login يحفظ التوكن في سلسلة مفاتيح النظام Keychain غير الموجودة في ال Container:
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=$?"'والمخرج سوف يكون كما يلي:
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 هو ما تذكره صفحة رموز الخروج لفشل البوابة، أي أن خطافاً في الوكيل أو خطوة في سكربت تستطيع أن تقول ببساطة: لا تنته من المهمة حتى يرجع هذا الأمر صفراً.
الخطوة الرابعة: الإصلاح حتى تنجح بوابة الجودة Quality Gate
بناء على المشاكل، أعاد الوكيل كتابة الملف فاستدعى الدالتين الموجودتين بدل نسخهما، واستبدل except Exception باستثناء محدد يرمى للمستدعي، وأضاف خمسة اختبارات:
"""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 فبقيت نقطة البداية نفسها:
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_:
❌ Access denied (HTTP 403). Check that the supplied token and organization are valid.
exit=1الرفض هنا لصالحك، فتوكن التحليل لا يملك صلاحية قراءة نتيجة بوابة الجودة Quality Gate عبر هذا المسار، ورمز الخروج 1 وليس 51، أي أن السكربت يستطيع أن يفرق بين «بوابة الجودة Quality Gate فشلت» و«الأمر نفسه فشل». لذلك أنشئ للوكيل مستخدماً خاصاً وتوكن مستخدم بصلاحيات القراءة فقط، ولا تعطه توكن المدير بحجة أنه يعمل.
ما الذي لا تفعله هذه الحلقة؟
- بوابة الجودة Quality Gate تعرف القواعد فقط، فإذا كتب الوكيل اختباراً يتحقق من نتيجة خاطئة فسوف تنجح البوابة، وهذا ما شرحناه في مقال الاختبارات التي يكتبها الذكاء الاصطناعي.
- الوكيل يستطيع أن يغش، مثل أن يضيف
# noqaأو يطلب عبر الأداةchange_sonar_issue_statusقبول المشكلة، لذلك أعط توكن الوكيل صلاحية القراءة فقط، وراجع كل استثناء في طلب الدمج. - كشف الأسرار بالأمر
sonar analyze secretsيعمل دون سيرفر بحسب الوثائق، ولكنه ينزل برنامجاً إضافياً عند أول تشغيل، وفي تجربتنا انتهت مهلة التنزيل على شبكة بطيئة، فلم نسجل له نتيجة. وأدوات كشف الأسرار المستقلة شرحناها في مقال اكتشاف الأسرار المسربة. - سيرفر MCP يعطي الوكيل بيانات المشروع، فراجع قسم الأمان في مقال بروتوكول MCP قبل أن تربطه بسيرفر فيه مشاريع حساسة.
التشغيل: النسخ الاحتياطي والمراقبة والأمان
- النسخ الاحتياطي: تقول صفحة النسخ الاحتياطي إن أدوات قاعدة البيانات هي الطريقة الموصى بها، وإن النسخ أثناء التشغيل مدعوم، فأخذنا نسخة بالأمر
pg_dump -U sonar -Fc sonarوكان حجمها 6.2MB لمشروعين صغيرين. وعند الاسترجاع تحذف فهارس Elasticsearch ليعاد بناؤها، والوثائق تذكر المجلدdata/es8، أما في الإصدار 26.9 فاسمهdata/es9كما وجدناه في ال Container. وطبق قاعدة 3-2-1 من مقال النسخ الاحتياطي. - المراقبة: المسار
/api/monitoring/metricsيعطي مقاييس بصيغة Prometheus مثلsonarqube_health_web_statusوsonarqube_health_elasticsearch_status، ويرجع 403 دون مصادقة، فاستخدم الرمز السري للنظام System Passcode أو توكناً. - الأمان: لا تقم بنشر المنفذ 9000 مباشرة، وضعه خلف Reverse Proxy مع HTTPS كما في دليل تطبيقك خلف Reverse Proxy، وغير كلمة مرور المدير في أول دقيقة، واجعل المشاريع خاصة إذا كان الكود خاصاً.
- التحديث: النسخة المجانية تصدر كل شهر، وكل إصدار يرحل قاعدة البيانات تلقائياً، فخذ نسخة احتياطية قبل كل تحديث، ولا تستخدم الوسم
communityالمتحرك في الإنتاج، وثبت الإصدار الكامل كما في ملف Compose.
ولإزالة التجربة نحذف ما أنشأناه بالأسماء فقط:
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 تحرس القواعد والتغطية والتكرار، ولا تعرف إن كان الاختبار صحيحاً، فالمراجعة البشرية تبقى آخر خطوة.
وبهذا نكون قد أنهينا سلسلة جودة الكود، وهذه مقالات مرتبطة بالموضوع:
دليلما هي جودة الكود Code Quality وكيف تقيسها؟ما الذي يجعل الكود سهل التغيير، وماذا تقيس أدوات الفحص فعلاً، ولماذا يحتاج كود الوكلاء الأذكياء إلى بوابة جودة.
دليلأدوات جودة الكود: أيها تختار لفريقك؟مقارنة عملية بين مدققات كل لغة والأدوات الجامعة ومنصات الجودة، بتراخيصها وأسعارها ونتائجها على مستودع واحد.
دليلSAST: كيف يجد تحليل الكود الثابت الثغرات قبل التشغيلكيف تقرأ أداة SAST الكود بحثاً عن الثغرات، وما الذي لا تراه أبداً، وكيف تمنع الإنذارات الخاطئة من أن تفقد الفريق ثقته بها.
دليلخط CI/CD آمن من البداية للنهاية على Gitea Actionsكيف تجمع فحوص الأمن في خط واحد لا يستطيع طلب الدمج تجاوزه، ثم ترسل إلى الإنتاج نفس ال Docker Image الموقعة التي فحصتها.
دليلبروتوكول MCP للمبتدئين: كيف تربط النماذج بأدواتك بأمانكيف يربط بروتوكول MCP نماذج اللغة بأنظمتك وبياناتك، ولماذا الأمان أهم ما فيه، مع سيرفر MCP صغير تبنيه بنفسك.
دليلمن RAG إلى 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.