SSD Nodes Learn 🎉 VPS من $5.50/شهر
الأدلة Matt Connorبقلم Matt Connor · آخر تحديث في 2026-08-13

استضافة open-kritt ذاتياً لفحص أمان الذكاء الاصطناعي

شغّل open-kritt على VPS باستخدام Docker Compose، وثبّت إصداراً محدداً، وافتح الواجهة عبر نفق SSH على المنفذ 5173، واضبط ميزانية المزوّد قبل الفحص.

لماذا تستضيف open-kritt ذاتياً على VPS بدلاً من جهازك المحمول

استضف open-kritt ذاتياً على خادم يمكنك حذفه وإعادة بنائه. تشغّل الأداة وكلاء التحليل بصلاحيات root داخل حاويات مهام مؤقتة، وتمنح كل وكيل نسخة قابلة للكتابة من شيفرتك ووصولاً مباشراً إلى الإنترنت، كما تربط مقبس Docker الخاص بالمضيف بخدمة المحرك. هذا تنازل معقول على جهاز مخصص لهذه المهمة. لكنه خيار سيئ على الجهاز الذي يحتفظ بمفاتيح SSH الخاصة بك.

تحدد أربع خصائص في الإعداد الافتراضي سبب هذه التوصية. وجميعها واردة في README وملف compose الخاصين بالمشروع.

صُممت الوكلاء لتكون قوية. يذكر README أن الوكلاء المزوّدين بالأدوات يعملون بصلاحيات root داخل حاويات مهام مؤقتة، مع نسخ مستودعات قابلة للكتابة ووصول مباشر إلى الإنترنت. لذلك يمكنهم تثبيت الأدوات، وتجميع الأهداف، وتشغيل الاختبارات، وبناء نماذج إثبات للمفهوم. الفحص ليس أداة lint تقرأ الملفات. بل هو تنفيذ عشوائي للشيفرة طلبته أنت. وهذا الوصول إلى الإنترنت يعمل في الاتجاهين: أي شيء يجلبه الوكيل أثناء البحث عن هدف هو نص غير موثوق يصل إلى موجّهاته، وهو التعرض نفسه الذي تقبله عندما تمنح الوكيل إمكانية البحث على الويب بنفسه.

يحتفظ المحرك بمقبس Docker. تقوم docker-compose.yml بربط مقبس Docker الخاص بالمضيف بخدمة المحرك، لأن المحرك ينشئ حاوية فحص واحدة ويشغّلها لكل مهمة. ويمكن لأي عملية تصل إلى ذلك المقبس بدء حاوية تربط نظام ملفات المضيف. لذلك يكون المحرك عملياً بصلاحيات root على أي مضيف يعمل عليه.

لا توجد شاشة تسجيل دخول. تُشحن الواجهة الخلفية من دون مصادقة على مستوى التطبيق. ويعني الوصول إلى المنفذ الوصول إلى نتائجك وإلى رصيدك لدى مزود الخدمة.

الشيفرة التي تفحصها ليست ملكك غالباً. توجيه الوكلاء إلى مستودع تابع لجهة خارجية يعني تشغيل عملية البناء الخاصة بذلك المستودع على جهازك، بصلاحيات root ومع الوصول إلى الشبكة.

إذا قرأت لماذا يجب أن تعمل وكلاء البرمجة داخل VM مؤقتة، فهذا هو نموذج التهديد نفسه، لكنه أقوى. امنح open-kritt جهاز VPS لا يشغّل أي شيء آخر، وأدر ذلك الجهاز عبر حساب مستخدم منفصل بأقل الصلاحيات بدلاً من root.

ما الذي يفعله open-kritt فعلياً

يُقسّم open-kritt (المستودع هو Kritt-ai/open-kritt، ومرخّص بموجب AGPL-3.0) أبحاث الثغرات إلى مهام صغيرة، ويشغّل هذه المهام بالتوازي عبر وكلاء الذكاء الاصطناعي، ثم يزيل النتائج المكررة ويرتّب النتائج المتبقية. تعرّف سير العمل كسلسلة من المطالبات المركّزة، وتتلقى كل خطوة سياقاً منظماً من الخطوات السابقة. يمكن أن يكون هدف الفحص مستودع git بعيداً أو محلياً. ومحرك التحليل هو Codex أو Claude Code. بعد ظهور نتيجة محتملة، يمكن لبرامج ما بعد التنفيذ الاختيارية محاولة التحقق منها أو إنشاء إثبات مفهوم لها.

في النهاية، تحصل على قائمة مرتبة من النتائج المحتملة. تعامل معها كقائمة فرز أولي، لا كتقرير.

ما تحتاج إليه قبل البدء

  • VPS يعمل بنظام Ubuntu 24.04 أو Debian 12 أو Rocky Linux 9. تذكر وثائق التثبيت هذه التوزيعات بوصفها التوزيعات المختبرة، على بنيتي x86_64 وARM64.
  • Docker Engine مع إضافة Compose.
  • Node.js 20 أو إصدار أحدث على المضيف، لأن أداة CLI ‏./kritt تعمل على المضيف بدلاً من العمل داخل حاوية.
  • موفّر نموذج واحد: تسجيل دخول Codex، أو OPENAI_API_KEY أو CODEX_API_KEY أو ANTHROPIC_API_KEY أو OPENROUTER_API_KEY.
  • GITHUB_TOKEN فقط إذا كنت تخطط لفحص مستودعات خاصة. توضّح وثائق .env.example المضمّنة ذلك صراحةً: لا يمكن تشغيل عمليات الفحص باستخدام رمز GitHub وحده.

ثبّت Docker وNode 20 أولاً

curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER

سجّل الخروج ثم سجّل الدخول مجدداً لتطبيق عضوية المجموعة الجديدة، ثم تأكد من وجود إضافة Compose.

docker compose version

تعني سلسلة الإصدار أن Compose مثبّت كإضافة. يعني docker: 'compose' is not a docker command أن لديك بدلاً منها الملف التنفيذي المستقل القديم docker-compose، وأن open-kritt يستدعي docker compose. تعادل عضوية مجموعة docker صلاحيات root على المضيف، لذلك أضف إليها الحساب الذي يشغّل open-kritt فقط. للحصول على شرح أطول لهذا الإعداد، راجع تشغيل Docker على VPS.

يأتي Ubuntu 24.04 مع Node 18 في مستودعه الخاص، وتخرج واجهة CLI عند استخدام إصدار أقل من 20. استخدم NodeSource.

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
node -v

يجب أن يطبع node -v القيمة v20. أو قيمة أعلى. في Rocky Linux 9، المكافئ هو sudo dnf module enable nodejs:20 -y متبوعاً بـsudo dnf install -y nodejs.

استنسخ open-kritt وثبّت إصداراً موسوماً

git clone https://github.com/Kritt-ai/open-kritt
cd open-kritt
git fetch --tags
git tag --list
git checkout v1.3.0

يتحرك main معك، أما الوسم فلا يتغير. حتى August 2026، أحدث وسم هو v1.3.0، وقد نُشر في 4 August 2026، بينما يبيّن git tag --list ما هو موجود في يوم الاستنساخ. يؤدي تسجيل الخروج إلى وسم إلى وضع المستودع في حالة HEAD منفصل، وهذا صحيح هنا: فأنت تتعامل مع هذه النسخة المستنسخة كنشر مثبت، وليس كفرع تُجري عليه عمليات commit. للترقية لاحقاً، اقرأ ملاحظات الإصدار، ثم شغّل git fetch --tags، وسجّل الخروج إلى الوسم الجديد، ثم شغّل ./kritt start مرة أخرى، لأن start يعيد بناء الصور.

لا تشغّل ./kritt مع sudo. توضح الوثائق ذلك صراحةً. تدير CLI أدلة بيانات الاعتماد الخاصة بالمشروع ضمن .data/، لذلك يؤدي التشغيل باستخدام root إلى جعل ملكية تلك الأدلة تعود إلى root، ولا يستطيع التشغيل العادي التالي الكتابة فيها.

تهيئة الوصول إلى النماذج باستخدام ./kritt setup

./kritt setup

ينشئ الأمر .env من .env.example إذا لم يكن موجوداً، ويعرض حالة كل بيانات اعتماد، ويتيح لك تعيينها أو إلغاء تعيينها. ولا يعرض قيمها أبداً في الطرفية. يُكتب كل من .env وملف بيانات اعتماد المحرك بالوضع 0600.

إذا كنت تفضّل تنفيذ ذلك يدوياً:

cp .env.example .env
chmod 600 .env
mkdir -p .data/codex
chmod 700 .data/codex

بعد ذلك، أضف مفتاح المزوّد إلى .env واترك الملف بالوضع 0600. في كلتا الحالتين، تصبح بيانات اعتماد صالحة للمزوّد موجودة على ذلك الخادم، وهذا سبب إضافي لعدم وضع أي شيء آخر على الخادم. أنشئ مفتاحاً مخصصاً لهذا المشروع وحده، حتى لا يؤدي إلغاؤه لاحقاً إلى تعطيل أي شيء مهم بالنسبة إليك. يشرح إبعاد الأسرار عن متناول وكلاء الذكاء الاصطناعي هذه الممارسة على نطاق أوسع.

عيّن حدّاً للإنفاق لدى مزوّد الخدمة قبل الفحص الأول

صُمّم open-kritt لتوزيع العمل على عدة مهام، وهذا التوزيع هو ما تدفع تكلفته. الإعدادات الافتراضية في .env.example ضمن الإصدار v1.3.0 محافظة: ENGINE_WORKER_COUNT=2، وهو موصوف في الملف بأنه إعداد افتراضي محافظ لجهاز صغير يضم 2 vCPU، وENGINE_MAX_CONCURRENT_SCANS=1. وفوق هذه الإعدادات يوجد ENGINE_WORKERS_PER_ACCOUNT=15، وهو الحد الأقصى لعدد استدعاءات النموذج الجذر المتزامنة المسموح بها على حساب مزوّد واحد، وENGINE_CODEX_MAX_SUBAGENTS_PER_SESSION=5، لأن جلسة Codex قد تشغّل ما يصل إلى five وكلاء فرعيين. عند زيادة عدد العاملين على VPS أكبر، يزداد معه عدد استدعاءات النموذج الجارية.

لا يفرض المستودع أي حد على إنفاقك. لا يوجد إعداد للميزانية في .env.example. شروط الإيقاف الخاصة بالمحرك هي حدود العاملين هذه إضافة إلى ENGINE_HARNESS_TIMEOUT_SECONDS، الذي تكون قيمته الافتراضية 7200 ثانية لكل تشغيل harness. لذلك يجب أن يكون الحد الأقصى لدى المزوّد. افتح لوحة تحكم المزوّد وعيّن حداً شهرياً صارماً قبل الفحص الأول، لا بعده. يوضّح التحكم في تكلفة وكيل الذكاء الاصطناعي على VPS إعدادات كل مزوّد.

يوجد أيضاً كابح محلي. يؤدي ضبط ENGINE_WORKER_COUNT=0 إلى إيقاف التقاط المهام الجديدة مؤقتاً، ويمكن تغيير قيم العاملين نفسها من شاشة Settings بعد تشغيل المكدس.

لا يذكر هذا الدليل سعراً لكل فحص، لأن التكلفة تعتمد على حجم المستودع، وسير العمل الذي تنشئه، والنموذج الذي يعمل خلفه. شغّل فحصاً واحداً على مستودع صغير واحد، ثم راجع صفحة الاستخدام لدى المزوّد قبل توجيهه إلى أي شيء كبير.

بدء الحزمة والتحقق من سلامتها

./kritt start

يتحقق ذلك من .env ومن بيانات اعتماد واحدة على الأقل، ثم يشغّل docker compose up --build. يستغرق البناء الأول وقتاً طويلاً، لأنه يبني صور الواجهة الأمامية والواجهة الخلفية والمحرك وواجهة المنفّذ وقاعدة البيانات. كما أنه يعمل في الواجهة الأمامية، لذلك يؤدي إغلاق جلسة SSH إلى إيقاف الحزمة. شغّله داخل tmux، أو شغّله في وضع منفصل بعد نجاح البناء الأول. لا يستمر أي من الخيارين بعد إعادة التشغيل تلقائياً. لذلك، إذا أردت إعادة تشغيل الحزمة بعد إعادة تشغيل الخادم، فإن نمط وحدة systemd الوارد في الحفاظ على تشغيل وكيل مستضاف ذاتياً عبر عمليات إعادة التشغيل يُطبَّق مباشرة.

docker compose up -d --build
docker compose ps

يجب أن يعرض docker compose ps كلاً من open-kritt-frontend وopen-kritt-backend وopen-kritt-engine وopen-kritt-executor-view وopen-kritt-db. ثم تحقّق من أن الواجهة الخلفية تستجيب على الخادم نفسه.

curl -s http://127.0.0.1:3002/api/health

تعني استجابة JSON أن الواجهة الخلفية تعمل. ويعني Failed to connect to 127.0.0.1 port 3002: Connection refused أنها لا تعمل، بينما يوضّح docker compose logs backend السبب. أوقف كل شيء باستخدام docker compose down من دليل المستودع.

إضافة اختيارية: يحمّل docker compose exec backend npm run seed بيانات تجريبية. وهذه طريقة بسيطة لإلقاء نظرة على الواجهة قبل إنفاق أي مبلغ على فحص حقيقي.

الوصول إلى واجهة المستخدم على المنفذ 5173 عبر نفق SSH

ترتبط كل خدمة في ملف compose بالعنوان 127.0.0.1 افتراضياً: الواجهة الأمامية على 5173، والواجهة الخلفية على 3002، وعرض المنفّذ على 8090، وPostgres على 5432. اترك هذه الارتباطات كما هي، وأعد توجيه المنفذ عبر SSH من جهازك.

ssh -N -L 5173:127.0.0.1:5173 you@your-server-ip

افتح http://localhost:5173 في المتصفح المحلي أثناء تشغيل ذلك الأمر. يعني -N أن الاتصال ينقل إعادة التوجيه ولا يفتح جلسة shell. أضف -L 8090:127.0.0.1:8090 ثانية إلى الأمر نفسه عندما تريد عرض المنفّذ أيضاً.

قد تميل إلى تعيين FRONTEND_BIND_ADDRESS=0.0.0.0 وتجاوز النفق. لا تفعل ذلك. لا تحتوي الواجهة الخلفية على شاشة تسجيل دخول، لذلك يمكن لأي شخص يصل إلى تلك الصفحة بدء عمليات الفحص وإنفاق رصيد مزود الخدمة. توجد مشكلة ثانية في الخلفية: تتم معالجة منفذ الحاوية المنشور قبل تطبيق السياسة الافتراضية لـ ufw، لذلك تبدو قاعدة ufw deny 5173 صحيحة لكنها لا تحظر شيئاً. يوضّح منافذ Docker التي تتجاوز ufw سلسلة القواعد التي تسبب ذلك.

تحديد حجم VPS

ENGINE_MIN_FREE_STORAGE_GB تكون قيمته الافتراضية 20، ويرفض المحرك بدء حاوية فحص جديدة لكل مهمة عندما تنخفض مساحة التخزين الحرة عن هذه القيمة. توجد الصور المبنية، وذاكرة التخزين المؤقت لنسخ المستودعات، وبيانات Postgres، ومساحات عمل المهام على القرص نفسه، لذلك لا يبدأ VPS بسعة 20 GB أي فحص على الإطلاق. اعتبر 40 GB الحد الأدنى، وزِد السعة إذا كنت تفحص مستودعات كبيرة.

تعتمد الذاكرة على حساب بسيط. يحجز ENGINE_MEMORY_RESERVE_GB=2 جزءاً من الذاكرة للمحرك وقاعدة البيانات وواجهة API والحمولة المؤقتة قصيرة الأجل، ويحصل كل عامل فحص على حجز وحد أقصى صارم مقداره ENGINE_SCAN_RUNNER_MEMORY_MB=1536. لذلك يحتاج عاملان إلى نحو 5 GB قبل تشغيل أي شيء آخر. لا يسمح المحرك إلا بتشغيل العمال الذين تتسع لهم الميزانية المتبقية، لذلك تنتظر عمليات الفحص في قائمة الانتظار بدلاً من الفشل. وهذا أفضل بكثير من إنهاء العمليات بسبب نفاد الذاكرة.

تكون إعدادات التنظيف الافتراضية التالية مضبوطة على true: ENGINE_AUTO_PRUNE_DOCKER_BUILD_CACHE وENGINE_AUTO_PRUNE_UNUSED_DOCKER_IMAGES. بعد اكتمال المهمة، يزيل المحرك ذاكرة التخزين المؤقت غير المستخدمة للبناء، والصور غير المستخدمة، وحاويات الفحص المتوقفة. ويحافظ على الصور التي تشير إليها حاوية قيد التشغيل، وعمليات bind mount، وبيانات قاعدة البيانات، وبيانات الاعتماد، وvolumes. وهذا سبب إضافي لعدم مشاركة الخادم المضيف: إذ يعمل pruner لم تضبطه أنت على Docker daemon نفسه.

إعدادات المحرك التي ينتهي معظم المستخدمين إلى تغييرها
  • ENGINE_WORKER_COUNT: إجمالي خانات العمال المشتركة بين خطوات الفحص والمعالجة اللاحقة. اضبطها على 0 لإيقاف التقاط المهام الجديدة.
  • ENGINE_MAX_CONCURRENT_SCANS: عدد عمليات الفحص التي يُسمح بتشغيلها في الوقت نفسه. تنتظر عمليات الفحص الموجودة في قائمة الانتظار حتى تصبح مجموعة العمليات النشطة فارغة.
  • ENGINE_MAX_WORKERS_PER_SCAN: تؤدي القيمة 0 إلى توزيع الخانات الإجمالية بالتساوي بين عمليات الفحص.
  • ENGINE_HARNESS_TIMEOUT_SECONDS: القيمة الافتراضية هي 7200. وهذه أطول مدة يمكن أن تستمر فيها مهمة منفلتة واحدة.
  • ENGINE_MIN_FREE_STORAGE_GB: الحد الأدنى للتخزين. تؤدي ENGINE_IGNORE_LOW_STORAGE=true إلى تعطيل آلية الحماية، ويحذّر الملف من أن ذلك قد يملأ قرص الخادم المضيف.
  • ENGINE_SCAN_RUNNER_MEMORY_MB: الحد الأقصى الصارم للذاكرة لكل عامل. تؤدي القيمة 0 إلى إزالة الحد الأقصى.

فحص مستودع محلي دون تسريبه

يُضبط LOCAL_REPOS_PATH افتراضياً على ./local_repos، ويُربط تركيبياً داخل حاويتي الواجهة الخلفية ومحرك الفحص في المسار /local_repos. لذلك يظهر أي مستودع تضعه في ذلك المجلد على المضيف داخل الحاويتين فوراً. استخدم نسخة مستنسخة حديثاً، لا شجرة العمل لديك. تحصل حاوية المهمة على نسخة قابلة للكتابة، ويكون لديها حساب root داخلها، كما تملك وصولاً إلى الإنترنت الصادر. وهذا يعني إمكانية تغيير أي شيء موجود في تلك النسخة أو إرساله خارج الخادم. احذف ملفات .env والمفاتيح الخاصة قبل نسخ المشروع إليها.

ما تحصل عليه، وما لا تحصل عليه

تحصل على نتائج مرشحة مرتبة. ولا تحصل على ثغرات مؤكدة. يحدد الترتيب وإزالة التكرارات ترتيب قائمة فرز النتائج. ولا يثبتان أن أي نتيجة حقيقية. يمكن للبرامج اللاحقة محاولة التحقق وإنشاء إثبات مفهوم، وهذا أقوى مؤشر توفره الأداة. لكن فشل برنامج لاحق لا يدل على أن النتيجة زائفة. لا يزال يتعين على شخص قراءة كل نتيجة مرشحة.

لا يقدم هذا الدليل أي ادعاء بشأن عدد الأخطاء الحقيقية التي يعثر عليها open-kritt، لأننا لم نقس ذلك. من يذكر معدل اكتشاف لقاعدة التعليمات البرمجية لديك لم يشغّل الأداة على قاعدة التعليمات البرمجية لديك. افحص مستودعاً تعرفه جيداً أولاً. فالنتائج التي يمكنك تقييمها بنفسك هي أرخص وسيلة معايرة متاحة.

تكتسب الصلاحيات أهمية أكبر هنا مقارنة بمعظم الأدوات ذاتية الاستضافة. يترجم الوكلاء التعليمات البرمجية وينفذونها ويتصلون بالشبكة، لذلك قد تلامس خطوة إثبات المفهوم أنظمة حية. وجّه الأداة إلى تعليمات برمجية تملكها أو أنت متعاقد لاختبارها، واكتب نطاق الهدف قبل تشغيل أي شيء. إذا ضبطت ANTHROPIC_API_KEY واستخدمت محرك Claude Code، فتنطبق على هؤلاء الوكلاء أيضاً ممارسات العزل الواردة في تشغيل Claude Code بأمان على VPS.

FAQ

لماذا يحتاج open-kritt إلى VPS خاص به؟

لأن وكلاء التحليل فيه يعملون بصلاحيات root داخل حاويات مهام مؤقتة تحتوي على نسخ قابلة للكتابة من شيفرتك، وتملك وصولاً مباشراً إلى الإنترنت. كما أن خدمة المحرك تربط Docker socket الخاص بالمضيف حتى تتمكن من تشغيل حاوية لكل مهمة. يمكن لأي عملية تصل إلى ذلك الـsocket تشغيل حاوية تربط نظام ملفات المضيف. لذلك يجب التعامل مع المكدس بالكامل على أنه يعمل بصلاحيات root على مضيفه. يكون هذا مقبولاً على VPS مخصص، كما أن إعادة إنشاء الخادم لا تكلّفك شيئاً. أما على محطة العمل التي تستخدمها يومياً، فسيضع ذلك مفاتيح SSH وملفات تعريف المتصفح ضمن حدود الثقة نفسها التي تضم الشيفرة التي تفحصها.

هل يمكنني تعريض المنفذ 5173 بدلاً من استخدام نفق SSH؟

لا ينبغي لك ذلك. يأتي الـbackend من دون مصادقة على مستوى التطبيق، ولذلك يكون المنفذ هو الحاجز الوحيد بين الإنترنت ونتائج الفحص ورصيد مزود الخدمة. يربط ملف compose كل خدمة بالعنوان 127.0.0.1 لهذا السبب. شغّل ssh -N -L 5173:127.0.0.1:5173 you@your-server-ip وافتح http://localhost:5173 محلياً بدلاً من ذلك. لا تُعد قاعدة ufw بديلاً مناسباً، لأن منفذ Docker المنشور يُعالج قبل تطبيق السياسة الافتراضية لـufw.

كيف أوقف open-kritt عن إنفاق مبلغ يتجاوز ما خططت له؟

عيّن حداً صارماً في وحدة تحكم مزود النموذج قبل إجراء الفحص الأول، لأن open-kritt لا يملك إعداداً خاصاً بالميزانية. استخدم إعدادات التوازي الافتراضية المرفقة في التشغيلات الأولى، ENGINE_WORKER_COUNT=2 وENGINE_MAX_CONCURRENT_SCANS=1، وتذكّر أن حساب مزود واحداً يسمح افتراضياً بما يصل إلى 15 استدعاءً متزامناً لنموذج root، بينما قد تشغّل جلسة Codex ما يصل إلى خمسة وكلاء فرعيين. يوقف ENGINE_WORKER_COUNT=0 التقاط المهام الجديدة، وهو أسرع إجراء إيقاف محلي.

ما الإصدار الذي ينبغي أن أستخرجه؟

استخدم tag، وليس main. يعرض git fetch --tags متبوعاً بـgit tag --list ما هو متاح، ويُعد v1.3.0، المنشور في 4 August 2026، أحدث إصدار حتى وقت كتابة هذا النص. يضمن التثبيت أن تؤدي إعادة البناء بعد أشهر إلى إنتاج المكدس نفسه. كما يجعل الترقية قراراً تتخذه بعد قراءة ملاحظات الإصدار، بدلاً من أن تكون نتيجة جانبية لاستنساخ المشروع في يوم مختلف.

لا يبدأ الفحص مطلقاً. ما الذي ينبغي أن أتحقق منه؟

تحقق أولاً من مساحة القرص الحرة، لأن المحرك لن يشغّل حاوية فحص مستقلة لكل مهمة عندما تنخفض مساحة التخزين الحرة عن ENGINE_MIN_FREE_STORAGE_GB، التي تكون قيمتها الافتراضية 20 GB. ثم تحقق من أن ENGINE_WORKER_COUNT ليست 0، لأن هذه القيمة توقف التقاط المهام الجديدة. بعد ذلك، تأكد من إعداد بيانات اعتماد نموذج فعلياً عبر تشغيل ./kritt setup، لأن GITHUB_TOKEN وحدها لا تستطيع تشغيل عمليات الفحص. يوضح docker compose logs engine سبب تخطي المهمة.