تنفيذ التعليمات البرمجية في بيئة معزولة
توفر حزمة adk-sandbox تنفيذًا معزولًا للتعليمات البرمجية لوكلاء ADK، مع مستويين من العزل:
- عزل العمليات — عمليات فرعية مع عزل البيئة وفرض مهلة زمنية
- ملفات تعريف العزل على مستوى نظام التشغيل — قيود على مستوى النواة لنظام الملفات والشبكة وإنشاء العمليات
الواجهات الخلفية
| الواجهة الخلفية | مستوى العزل | اللغات | علامة الميزة |
|---|---|---|---|
ProcessBackend | البيئة + المهلة | Rust، Python، JS، TS، الأوامر | process (افتراضي) |
ProcessBackend + وضع الحماية | على مستوى النواة | نفس ما سبق | process + sandbox-native |
WasmBackend | كامل (الذاكرة، fs، الشبكة) | WASM فقط | wasm |
ما مستوى العزل الذي تحصل عليه؟
يُبلغ عنه ProcessBackend::isolation()، لذا فهذا ليس شيئًا ينبغي استنتاجه من
اسم الحزمة:
| النتيجة | المعنى |
|---|---|
IsolationClass::SubprocessOnly | عملية فرعية ببيئة تمت تهيئتها، ومهلة زمنية، ومجموعة عمليات خاصة بها. لا يطبّق نظام التشغيل أي قيود إضافية: يمكن للتعليمة البرمجية قراءة نظام ملفات المضيف والوصول إلى الشبكة. هذا ما يمنحك إياه ProcessBackend::default(). |
IsolationClass::OsEnforced | تم إرفاق منفّذ وسياسة، ولذلك يقيّد نظام التشغيل العملية الفرعية. |
هناك أمران جديران بالمعرفة حول خلفية العمليات:
- يتم حل البرامج قبل مسح البيئة. يتم البحث عن
python3أوnodeأوrustcغير المسبوق بمسار علىPATHالخاص بالمتصل، ثم يُمرَّر إلى العملية التابعة باعتباره مسارًا مطلقًا. وهذا يعني أن العملية التابعة لا تحتاج إلىPATHخاص بها لبدء التشغيل — إذ كان يتعين سابقًا على المتصل وضعPATHفيExecRequest::env، مما كان يتيح أيضًا للتعليمات البرمجية المنفَّذة إنشاء أي شيء آخر باستخدامه. - يتم التجميع عبر الحدّ الفاصل نفسه المستخدم في التنفيذ. كان مصدر Rust يُجمَّع سابقًا باستخدام أمر يُبنى خارج المسار المشترك، ولذلك لم يكن للتجميع غلاف إنفاذ، ولا مهلة زمنية، ولا مجموعة عمليات. وهذا مهم لأن التجميع ليس خاملًا: يقرأ
include_str!الملفات، وتشغّل وحدات الماكرو الإجرائية تعليمات برمجية عشوائية قبل وجود الملف الثنائي الناتج. وتتلقى مرحلة التجميع قائمة سماح لسلسلة الأدوات خاصة بالمنصة؛ وفي Windows، يشمل ذلك مسارات MSVC وWindows SDK، التي يتم اكتشافها من سلسلة الأدوات المثبّتة عندما لا يكون المتصل موجودًا مسبقًا في جلسة Developer. يستخدم التجميع رابط سلسلة أدوات Rust، وهوrust-lld، ولذلك لا يمكن اختيارlink.exeغير ذي الصلة الموجود في موضع أسبق علىPATH. ويفرض مُنفِّذ على مستوى نظام التشغيل القيود على تلك المرحلة.
أسبقية البيئة
يوفّر SandboxPolicy::env الإعدادات الافتراضية لكل عملية تنفيذ، ويتجاوزها ExecRequest::env لكل استدعاء. وكان يتم تجاهل متغيرات السياسة بالكامل في السابق.
ملفات تعريف عزل نظام التشغيل
يقيّد فرض العزل على مستوى نظام التشغيل العمليات التابعة على مستوى النواة. ويتجاوز ذلك عزل البيئة — إذ يحظر نظام التشغيل نفسه الوصول غير المصرّح به إلى نظام الملفات، واتصالات الشبكة، وإنشاء العمليات.
دعم المنصات
| المنصة | أداة الإنفاذ | كيفية عملها |
|---|---|---|
| macOS | Seatbelt (sandbox-exec) | قواعد على مستوى استدعاءات النظام: «السماح افتراضيًا، وحظر الخطِر» — تحظر عمليات الكتابة، والشبكة، وfork؛ ولا تقيّد عمليات القراءة |
| Linux | bubblewrap (bwrap) | عزل مساحة أسماء نظام الملفات (عمليات تركيب مدرجة في القائمة البيضاء) |
| Windows | AppContainer | غير مُنفّذ — يُبلغ المُنفِّذ عن عدم توفره |
البدء السريع
use adk_sandbox::{
ProcessBackend, ProcessConfig, SandboxBackend,
SandboxPolicyBuilder, get_enforcer,
};
// 1. Define what the sandboxed process can do
let policy = SandboxPolicyBuilder::new()
.allow_read("/usr") // Read system libraries
.allow_read_write("/tmp/work") // Write to work directory
.allow_process_spawn() // Python needs to exec
// Network is denied by default
.env("PATH", "/usr/bin:/usr/local/bin")
.build();
// 2. Get the platform-appropriate enforcer
let enforcer = get_enforcer()?;
// 3. Create a sandboxed backend
let backend = ProcessBackend::with_sandbox(
ProcessConfig::default(),
enforcer,
policy,
);
// 4. Execute code — network is blocked, writes restricted
let result = backend.execute(request).await?;
علامات الميزات
[dependencies]
# Auto-detect platform enforcer
adk-sandbox = { version = "2.1.0", features = ["process", "sandbox-native"] }
# Or pick a specific platform
adk-sandbox = { version = "2.1.0", features = ["process", "sandbox-macos"] }
adk-sandbox = { version = "2.1.0", features = ["process", "sandbox-linux"] }
SandboxPolicy
تحدد السياسة ما يُسمح للعملية المعزولة بتنفيذه:
| الحقل | الافتراضي | الوصف |
|---|---|---|
allowed_paths | [] (رفض الكل) | مسارات نظام الملفات التي تتمتع بوصول للقراءة فقط أو للقراءة والكتابة |
allow_network | false | ما إذا كان الوصول إلى الشبكة مسموحًا |
allow_process_spawn | false | ما إذا كان يُسمح بإنشاء عمليات فرعية |
env | {} | متغيرات البيئة للعملية المعزولة |
الاختلافات بين المنصات
macOS (Seatbelt): يستخدم نهج «السماح افتراضيًا، وحظر الخطِر» — يبدأ بوصول كامل، ثم يحظر الشبكة وعمليات كتابة الملفات وإنشاء العمليات. لا ينجح نهج القائمة البيضاء الخالصة لأن Python يحتاج إلى عشرات الفئات الخاصة بـ macOS من استدعاءات النظام عند بدء التشغيل.
Linux (bubblewrap): يستخدم قائمة بيضاء قائمة على مساحات الأسماء — لا يوجد شيء افتراضيًا، ولا تقوم بتركيب سوى ما هو مطلوب. ثبّته باستخدام apt install bubblewrap أو dnf install bubblewrap.
Windows (AppContainer): غير مُنفّذ. يعتمد التصميم على قوائم ACL المستندة إلى الرموز — معرّف SID مقيّد لا يملك أي وصول افتراضيًا، ثم تُمنح قوائم ACL لمسارات محددة — لكن إنشاء الحاويات وقوائم ACL والإمكانات وتنظيف كائنات المهام غير متوفرة، لذلك يعيد probe() القيمة EnforcerUnavailable. شغّله دون أداة فرض على Windows، أو استخدم macOS أو Linux حيث يكون الفرض فعليًا.
مثال
راجع examples/sandbox_agent/ للاطلاع على مثال كامل مدفوع بواسطة LLM ينفّذ تعليمات Python البرمجية في بيئة معزولة مع حظر الوصول إلى الشبكة بواسطة نواة نظام التشغيل.