الأمان والسلامة
نموذج السلامة في كاظمة بالكامل: البوابات الثلاث المستقلة للموافقة البشرية في الحلقة (HITL)، وقوائم الأدوات الخطيرة الثلاث، وسلوك الفشل المُغلق في كل مكان، والتكامل التشفيري (مهارات HMAC، وتفويض Ed25519)، وتوصيات التحصين. كل ادّعاء موثَّق بمرجع مصدري.
1. البوابات الثلاث للموافقة البشرية في الحلقة (ولماذا ثلاث)
Section titled “1. البوابات الثلاث للموافقة البشرية في الحلقة (ولماذا ثلاث)”تملك كاظمة ثلاث آليات مستقلة للموافقة البشرية في الحلقة. يغطّي كل منها مسار تنفيذ مختلفاً. ويؤدّي كسر أيٍّ منها إلى ثغرة أمنية في الأدوات الخطيرة غير المراقَبة.
flowchart TB subgraph "Gate A: Graph interrupt (single-agent chat)" A1[tool_worker_node] -->|danger tool + hitl_config| A2[interrupt] A2 -->|resume Command| A3[execute with _hitl_approved=True] end subgraph "Gate B: Swarm bus (/swarm dispatch)" B1[ToolRegistry.execute] --> B2[SafetyMiddleware.check] B2 -->|danger tool| B3[bus.request_approval] B3 -->|adapter callback| B4[approve/reject] end subgraph "Gate C: Pipeline checkpoints" C1[pipeline at hitl step] --> C2[CheckpointManager pause] C2 -->|auto-reject timeout| C3[reject] C2 -->|approve_checkpoint| C4[resume_pipeline] end| البوابة | المسار | مكان وجودها | سطح الموافقة |
|---|---|---|---|
| A | محادثة الوكيل الواحد (Web/Telegram/Discord/Slack) | agent/graph_builder.py | POST /api/approve/{thread_id} أو /hitl approve|deny |
| B | إرسال /swarm | swarm/safety.py + tool_registry.py | أزرار محوّل الناقل (Telegram/Discord/Slack) |
| C | مهام السرب PIPELINE | swarm/checkpoint.py + checkpoint_manager.py | POST /api/swarm/tasks/{id}/approve |
2. البوابة A — بوابة الرسم البياني (محادثة الوكيل الواحد)
Section titled “2. البوابة A — بوابة الرسم البياني (محادثة الوكيل الواحد)”2.1 كيف تعمل
Section titled “2.1 كيف تعمل”tool_worker_node (graph_builder.py:336) هو مكان وجود البوابة. عندما يُمرَّر hitl_config:
- يُختبَر كل استدعاء أداة معلَّق بـ
requires_approval(tc["name"], hitl_config)(مستوردة منkazma_core.safety.hitl، السطر 356). تُقسَم الأدوات إلىsafe_tools/danger_tools(الأسطر 418-429). - لكل أداة خطيرة، يُبنى قاموس
approval_input(type: "hitl_approval"، اسم الأداة، الوسائط، الرسالة) ويُستدعىinterrupt(approval_input)(السطر 493) — فيتوقّف الرسم البياني (suspend). - عند الموافقة، يُنسخ استدعاء الأداة ويُحقن
approved_tc_args["_hitl_approved"] = True(الأسطر 495-503) كي يتخطّىtool_registry.execute()فحص الناقل الزائد عن الحاجة. - عند الرفض، يُعاد
ToolResultمعis_error=Trueعبر_denied_result(الأسطر 467-475).
خاملة افتراضياً: إن كان
hitl_configخاطئاً، تنتقل جميع الأدوات إلىsafe_tools(السطر 429). لا تُفعَّل البوابة إلا عند تمريرhitl_configإلىbuild_supervisor_graph().
2.2 مواقع البناء التي تُفعّل البوابة
Section titled “2.2 مواقع البناء التي تُفعّل البوابة”يجب تمرير hitl_config وقت البناء. يوجد ثلاثة مواقع بناء؛ اثنان يمرّرانه (مُفعَّل)، وواحد لا يمرّره (خامل):
| موقع البناء | الملف:السطر | يمرّر hitl_config؟ |
|---|---|---|
KazmaAgent.get_streaming_graph() | agent_runner.py:530-539 | مُفعَّل (مسار محادثة SSE) |
KazmaAgent._ensure_graph() | agent_runner.py:566-576 | مُفعَّل (مسار التشغيل) |
إعادة التجميع عند بدء التشغيل في app.py | kazma-ui/kazma_ui/app.py:741-751 | مُفعَّل |
مصنع create_supervisor_graph() | graph_builder.py:974-985 | خامل (دخول CLI/طرف ثالث) |
تصحيح أرقام أسطر AGENTS.md: تستشهد ملاحظات أقدم بـ “app.py ~line 966”. هذا غير دقيق — فـ
graph_builder.py:966هوaiosqlite.connectغير المرتبط داخلcreate_supervisor_app()، الذي لا يمرّرhitl_config. إعادة التجميع الفعلية عند بدء التشغيل تقع فيkazma-ui/kazma_ui/app.py:741-751.
2.3 آلية الاستئناف
Section titled “2.3 آلية الاستئناف”يستأنف الرسم البياني عبر LangGraph Command(resume=...). نقطة نهاية الموافقة هي POST /api/approve/{thread_id} في kazma-ui/kazma_ui/routes_direct.py:454 (الدالة approve_tool، السطر 455) — وليست في app.py:
# routes_direct.py:525-532from langgraph.types import Commandresume_value = {"approved": approved, "reason": body.get("reason", "")}graph_ref.ainvoke(Command(resume=resume_value), config=config)الأمان على نقطة النهاية هذه:
- عند ضبط
KAZMA_SECRET، تتطلّب ترويسةX-Kazma-Secret(أو كوكي) مطابَقة عبرsecrets.compare_digest(الأسطر 456-465). - إ enforced الملكية (الأسطر 480-522): يُحَلّ المالك عبر المنصّات (
sender_id/owner/session_id/user_id) وتُرفَض الموافقات بين المستخدمين المختلفين بـ 403.
2.4 الاستمرارية
Section titled “2.4 الاستمرارية”تُ persist الأدوار المتوقفة في الـ checkpointer (SQLite WAL) — فتصمد أمام إعادة التشغيل.
3. البوابة B — بوابة ناقل السرب (إرسال /swarm)
Section titled “3. البوابة B — بوابة ناقل السرب (إرسال /swarm)”3.1 مسار التنفيذ
Section titled “3.1 مسار التنفيذ”ToolRegistry.execute() (tool_registry.py:335):
- يُخرج
_hitl_approvedمن الوسائط (السطر 349). - إن لم يكن مُوافَقاً عليه مسبقاً، يستدعي
get_safety()(السطر 395). - للأدوات الخطيرة (
safety.is_danger_tool(tool_name)، السطر 397)، يستدعيawait safety.check(...)(الأسطر 400-405). - إن لم تُوافَق عليها ← يُعيد
is_error=True“denied by HITL approval gate” (الأسطر 406-410). - الفشل المُغلق: أي استثناء في فحص السلامة يُعيد
is_error=True“blocked — SafetyMiddleware unavailable” (الأسطر 411-417).
3.2 SafetyMiddleware
Section titled “3.2 SafetyMiddleware”swarm/safety.py — الصنف SafetyMiddleware (السطر 47). (لا يوجد صنف باسم SafetyGate أو SafetyChecker في أي مكان — تلك التسمية في بعض الوثائق الأقدم غير دقيقة.)
| الدالة | السلوك |
|---|---|
check() (متزامنة، السطر 106) | للأدوات الخطيرة: إن كان NullBusAdapter مُفعّلاً وallow_headless_danger=False ← رفض (الأسطر 147-160)؛ وإلا bus.request_approval(...) وانتظار (الأسطر 162-177). |
check_sync() (السطر 179) | فشل مُغلق افتراضياً. NullBusAdapter + allow_headless_danger=False ← يُعيد False (الأسطر 200-209). حتى مع محوّل حقيقي، لا يستطيع المسار المتزامن الانتظار ← يحجب. أي استثناء في الناقل ← فشل مُغلق ما لم يكن allow_headless_danger=True (الأسطر 214-223). |
is_danger_tool / is_sensitive_read | الأسطر 96، 100. |
add_danger_tool / remove_danger_tool | الأسطر 86-94. |
علم المُنشئ allow_headless_danger: bool = False (السطر 70) هو مخرج الاختبار/التطوير. الافتراضي هو الفشل المُغلق.
3.3 محوّلات الناقل وأولوية المُفرد
Section titled “3.3 محوّلات الناقل وأولوية المُفرد”محوّلات الناقل (جميعها فئة فرعية من BusAdapter، ABC في swarm/bus.py:66):
| المحوّل | الموقع |
|---|---|
TelegramBusAdapter | kazma-gateway/kazma_gateway/adapters/telegram_bus.py:58 |
DiscordBusAdapter | adapters/discord_bus.py:31 |
SlackBusAdapter | adapters/slack_bus.py:31 |
الناقل مُفرد على مستوى الوحدة (get_message_bus()، bus.py:282-287). يكون محوّل واحد فقط مُفعّلاً في كل مرة. توصيل الأولوية في kazma-ui/kazma_ui/app.py:506-556:
- يُجرَّب Telegram أولاً (
_bus_wired = Trueعند السطر 516). - Discord فقط
if not _bus_wired(السطر 524). - Slack فقط
if not _bus_wired(السطر 540).
الأولوية: Telegram > Discord > Slack.
يستحرس pytest (السطر 504) عن قصد من توصيل محوّلات حقيقية أثناء الاختبارات.
3.4 حلّ استدعاء الموافقة
Section titled “3.4 حلّ استدعاء الموافقة”يُحلِّل handle_callback() لكل محوّل مُعرِّف استدعاء المنصّة ويُعيد asyncio.Event:
- Telegram:
swarm_approve_<task_id>/swarm_reject_<task_id>(telegram_bus.py:302-333). - Discord: أزرار components v2 (
discord_bus.py:238). - Slack: استدعاء تفاعلي (
slack_bus.py:270).
4. البوابة C — نقاط حفظ خط المعالجة
Section titled “4. البوابة C — نقاط حفظ خط المعالجة”موثَّقة في تنسيق السرب ← نقاط حفظ خط المعالجة. الملخّص:
_handle_pipeline_checkpoint(engine.py:889) ←CheckpointManager.handle_pipeline_checkpoint.- تُسلَّح مهلة الرفض التلقائي إن كان
checkpoint_timeout > 0. approve_checkpoint(engine.py:920) /reject_checkpoint(engine.py:990).- يُعيد
restore_paused_tasks()تسليح المهل بعد إعادة التشغيل. - نقاط النهاية:
POST /api/swarm/tasks/{id}/approve//reject(routes_tasks.py:612, 657).
5. قوائم الأدوات الخطيرة (ثلاث منها)
Section titled “5. قوائم الأدوات الخطيرة (ثلاث منها)”تستخدم البوابات الثلاث قوائم أدوات خطيرة مختلفة. هذا متعمَّد (لكل مسار دلالات مختلفة) لكنه سهل الخطأ.
5.1 البوابة A (الرسم البياني) — kazma.yaml safety.hitl.require_approval_for
Section titled “5.1 البوابة A (الرسم البياني) — kazma.yaml safety.hitl.require_approval_for”الافتراضي (kazma.yaml:84-94): file_write، file_delete، shell_exec، code_exec، python_exec، spawn_agent، spawn_agents، schedule_task، cancel_scheduled.
الاحتياطي في الكود إن لم يُضبط: DEFAULT_DANGER_TOOLS = ["file_write", "file_delete", "shell_exec"] (safety/hitl.py:41).
5.2 البوابة B (ناقل السرب) — _EXTENDED_DANGER
Section titled “5.2 البوابة B (ناقل السرب) — _EXTENDED_DANGER”swarm/safety.py:23-31: DEFAULT_DANGER_TOOLS (file_write، file_delete، shell_exec) + python_exec، code_exec، spawn_agent، spawn_agents، schedule_task، cancel_scheduled، run_tests (مشغّل اختبارات MCP IDE).
بالإضافة إلى _SENSITIVE_READS = ["sqlite_query", "file_search"] (الأسطر 34-37) — مسموحة لكن مُسجَّلة.
5.3 البوابة C / MCP — classify_mcp_tool()
Section titled “5.3 البوابة C / MCP — classify_mcp_tool()”mcp/manager.py:71-88 — مطابقة ديناميكية لنمط الاسم (أدوات MCP تُكتشَف وقت التشغيل):
- خطر (danger) إن وُجد أيٌّ من:
write, delete, remove, exec, run, shell, bash, command, kill, terminate, install, deploy, upload, download, fetch, request, post, put, patch. - آمنة (safe) إن وُجد أيٌّ من:
read, list, search, get, info, status, check, describe, query, count, exists, help. - غير معروفة (unknown) خلاف ذلك.
غير المعروفة تُعدّ خطرة افتراضياً. يتطلّب
UnifiedToolExecutor.execute()(manager.py:725-727) موافقة لكلٍّ منdangerوunknown. لا تُضعّف هذا أبداً.
6. التكامل التشفيري (ما وراء الموافقة البشرية في الحلقة)
Section titled “6. التكامل التشفيري (ما وراء الموافقة البشرية في الحلقة)”6.1 توقيع HMAC للمهارات (Hub)
Section titled “6.1 توقيع HMAC للمهارات (Hub)”موثَّق في المهارات وMCP والأدوات ← التوقيع التشفيري. الملخّص:
- يكتب
kazma hub signقيمتيchecksum(SHA-256) +signature(HMAC-SHA256 فوق checksum، بمفتاحKAZMA_SECRET) فيskill_manifest.yaml. - يتحقّق
SkillLoader._load_module_from_fileمن كليهما عبرhmac.compare_digest(وقت ثابت) ويرفض تحميل المهارات المُعبَث بها أو غير الموقّعة عند اشتراط ذلك.
6.2 تفويض Ed25519 + AES-256-GCM
Section titled “6.2 تفويض Ed25519 + AES-256-GCM”delegation/security.py (DelegationSecurity، السطر 30):
- التوقيع: Ed25519 (الأسطر 81-119).
- التشفير: اتفاقية مفاتيح X25519 + AES-256-GCM (الأسطر 121-161).
- تُوقَّع الطلبات عند الإرسال (
protocol.py:153)، وتُتحرَّى عند الاستلام مع فشل مُغلق عند التوقيع المفقود/غير الصالح (:179-208).
هذا تفويض بين الوكلاء — لا علاقة له بـ MCP أو المهارات.
6.3 سرّ نقطة نهاية الموافقة البشرية في الحلقة
Section titled “6.3 سرّ نقطة نهاية الموافقة البشرية في الحلقة”نقطة النهاية POST /api/approve/{thread_id} محمية بـ KAZMA_SECRET (ترويسة/كوكي، secrets.compare_digest). مسار التوليد التلقائي: يُحلِّل get_kazma_secret() (config_store.py:36-77) البيئة KAZMA_SECRET ← KAZMA_AUTH_DISABLED ← تخطّي pytest ← security.secret في قاعدة البيانات ← توليد تلقائي عبر secrets.token_hex(16).
7. سلوكيات الفشل المُغلق (الجرد)
Section titled “7. سلوكيات الفشل المُغلق (الجرد)”| المكوّن | سلوك الفشل المُغلق |
|---|---|
SafetyMiddleware.check_sync | يحجب الأدوات الخطيرة عند غياب ناقل حقيقي + allow_headless_danger=False. |
ToolRegistry.execute | أي استثناء في فحص السلامة ← “blocked — SafetyMiddleware unavailable”. |
classify_mcp_tool | unknown ← يتطلّب موافقة. |
SkillLoader | توقيع مُعبَث به/مفقود ← SkillLoadError، دون تحميل. |
| Hub write API | غياب KAZMA_SECRET ← رفض جميع عمليات الكتابة. |
| استلام التفويض | توقيع مفقود/غير صالح ← رفض. |
| نقطة نهاية الموافقة البشرية في الحلقة | موافقة بين مستخدمين ← 403؛ غياب KAZMA_SECRET ← راجع التحذير أدناه. |
⚠ تحذير الإنتاج: إن كان
KAZMA_SECRETغير مضبوط، فقد يُعيدget_kazma_secret()سلسلة فارغة""وتصبح نقاط نهاية الموافقة غير مُصدَّقة. اضبطKAZMA_SECRETدائماً لأي نشر غير محلي. (لا يربطkazma serveعلى0.0.0.0إلا عند ضبطKAZMA_SECRET— وهذا عن قصد.)
8. ملفات إعداد الأمان
Section titled “8. ملفات إعداد الأمان”يُعلن kazma-security.yaml عن الوضعية عبر scanning، وdisclosure، وbug_bounty، وhardening (8 فحوصات: secrets_in_logs، input_validation، rbac_enforcement، tls_required، dependency_audit، least_privilege، audit_trail، config_integrity). راجع الإعداد ← إعداد الأمان. يُعرّف kazma-permissions.yaml قوائم السماح/المنع لأدوات MCP المستندة إلى الأقسام (أقسام ALMuhalab) مع قواعد عبر الأقسام (require_explicit_approval، max_approval_duration_hours: 24، audit_all_access).
8.1 مُشغِّل التحصين (security/hardening.py)
Section titled “8.1 مُشغِّل التحصين (security/hardening.py)”يُشغِّل SecurityHardeningRunner الفحوصات عند بدء التشغيل؛ المفاتيح هي run_on_startup: true، fail_on_critical: true، auto_fix: false. يُعيين كل وسم فحص yaml إلى دالة مُنفَّذة:
| الفحص (وسم yaml) | الدالة المُنفَّذة | الخطورة |
|---|---|---|
secrets_in_logs | check_no_hardcoded_secrets (مسح بالتعبيرات النمطية لـ api_key/secret/token/password/AWS/PRIVATE_KEY) | critical |
tls_required | check_encrypted_communications (مسح TLS/SSL/HTTPS/mTLS) | high |
rbac_enforcement | check_rbac_enforcement | high |
dependency_audit | check_dependency_vulnerabilities ← DependencyScanner | critical |
| (عزل MCP) | check_mcp_sandboxing | high |
| (بيانات مهارات manifest) | check_skill_manifest_validity | medium |
| (تسجيل التدقيق) | check_audit_logging | high |
| (تصعيد الصلاحيات) | check_permission_escalation (os.system، subprocess(...shell=True)، eval، exec، __import__، setattr(...__...)) | critical |
least_privilege، config_integrity | ⚠ خارطة طريق (لا تنفيذ مخصّص) | — |
يستطيع fix_issues(auto_fix) إنشاء ملف .env وتعديل .gitignore لفحص الأسرار.
8.2 مسح التبعيات (security/dependency_scanner.py)
Section titled “8.2 مسح التبعيات (security/dependency_scanner.py)”| الماسح | المصادر | الذاكرة المؤقتة / التاريخ |
|---|---|---|
DependencyScanner | OSV (api.osv.dev) | ذاكرة مؤقتة JSON في kazma-data/vuln_cache.json |
DependabotStyleScanner | OSV + GitHub Advisories + NVD | SQLite في kazma-data/security_scan.db؛ يُلغي التكرار بـ (package, vuln_id) |
كلاهما يحلّل requirements.txt وpyproject.toml. يُشغِّل DependabotStyleScanner إضافياً scan_skill_manifests() (يُعلِّمم إعدادات MCP المشبوهة: eval/exec/system في الأوامر، ومتغيرات البيئة TOKEN/SECRET/KEY، و--privileged، وnetwork: host؛ وأنماط التصعيد مثل sudo/chmod 777/setuid)، وcreate_github_issue() عبر gh CLI، وgenerate_advisory()، وcheck_for_updates().
kazma-security.yaml: فاصل scanning 24 ساعة، severity_threshold: medium، auto_create_issues: true.
8.3 تدفّق الإفصاح (security/disclosure.py)
Section titled “8.3 تدفّق الإفصاح (security/disclosure.py)”يُ forced SQLite kazma-data/disclosure.db سلسلة الانتقال submitted → acknowledged → investigating → confirmed → patched → closed. يُولِّد publish_advisory() رمزاً نائباً لـ CVE + قالب markdown، لكن من حالتي patched/closed فقط. يُوقِّع encrypt_report() حمولة JSON باستخدام HMAC-SHA256 بمفتاح KAZMA_DISCLOSURE_KEY.
kazma-security.yaml: نافذة الاستجابة 48 ساعة، التقييم 7 أيام، عنوان URL لمفتاح PGP، القنوات المُشفَّرة (البريد + Signal)، مكافأة الثغرات 50–2000 دولار أمريكي.
تحقّق من التطبيق وقت التشغيل لفحوصات
kazma-security.yamlمقابل مُشغِّل التحصين قبل الاعتماد عليها. يُعلن الملف عن السياسة؛ أكِّد أن المُشغِّل يُ forced كل فحص عند بدء التشغيل (hardening.run_on_startup: true،fail_on_critical: true).
9. توصيات التحصين
Section titled “9. توصيات التحصين”- اضبط
KAZMA_SECRETدائماً للنشر غير المحلي. ولّده عبرopenssl rand -hex 32. - شغّل خوادم MCP من نوع stdio في بيئة معزولة (sandbox). لا يتمتّع ناقل stdio بأي مصادقة ويرث بيئة العملية.
- فضّل MCP من نوع SSE مع مصادقة bearer لأي خادم MCP بعيد.
- وقّع جميع المهارات (
kazma hub sign) وأبقِKAZMA_SECRETمتّسقاً عبر التحميل — وإلا يفشل التحقّق من التوقيع. - أبقِ بوابات الموافقة البشرية في الحلقة (HITL) الثلاث مُفعّلة. لا تمرّر
hitl_config=Noneفي موقع بناء إنتاجي. - لا تضبط
allow_headless_danger=Trueفي الإنتاج. إنه مخرج الاختبار/التطوير. - اعمل بحساب المستخدم غير الجذري
kazmaفي Docker (يقوم Dockerfile بذلك أصلاً). - اربط على
127.0.0.1ما لم يكن لديك وكيل عكسي +KAZMA_SECRETمُعدّ.
ملاحظات تدقيق التوثيق
Section titled “ملاحظات تدقيق التوثيق”- اسم الصنف: صنف سلامة السرب هو
SafetyMiddleware، وليسSafetyGate/SafetyChecker. حُدِّث في كامل الوثيقة. - موقع نقطة نهاية الموافقة:
POST /api/approve/{thread_id}موجود فيroutes_direct.py:454، وليس فيapp.py. - رقم سطر موقع بناء App.py: إعادة التجميع عند بدء التشغيل تقع في
kazma-ui/kazma_ui/app.py:741-751، وليس ~966. - “مستويات الثقة (Trust tiers)” غير موجودة كميزة أمان — مجرّد علم منطقي
certifiedوسلسلة إعدادtrust: trustedغير مستخدَمة. - MCP من نوع stdio بلا مصادقة. موثَّق صراحةً؛ خطّط للعزل وفق ذلك.
- ثلاث قوائم أدوات خطيرة متميّزة يجب أن تبقى متزامنة مع القصد. إن إضافة أداة خطرة جديدة إلى البوابة A (
kazma.yaml) لا تضيفها إلى البوابة B (_EXTENDED_DANGER) أو البوابة C (المستندة إلى الأنماط).