المنحة هي المشكلة
تشديد Apple على الوصول الكامل إلى القرص (FDA) في macOS استجابة معقولة لنمط فشل حقيقي: إطار عمل وكيل، أو غلاف طرفية، أو مساعد خلفي يطلب أوسع صلاحية قراءة ممكنة لأن الطلب الضيق أصعب في التحديد. النتيجة قيمة منطقية واحدة تغطي كل ملف يستطيع المستخدم قراءته. الوكيل الذي يحتاج دليل مشروع واحد يحصل على نفس الصلاحية التي يحصل عليها وكيل يحتاج ملف إعداد واحد. الصلاحية رخيصة الإصدار ومكلفة التفكير.
هذا التفاوت هو القصة كاملة. إصدار منحة يكلف نافذة حوار واحدة. التفكير فيها يكلف تدقيقاً لكل سير عمل يعتمد عليها، لأن الإلغاء غير محدد النطاق: إلغاء FDA يبطل سير عمل غير مرتبط كان يشترك في نفس القيمة المنطقية. يستجيب المشغلون بترك المنحة كما هي ومعاملتها كبنية تحتية محيطة، وهذا بالضبط الوضع الذي يهدف التشديد إلى منعه.
المشكلة الأعمق أن نموذج الصلاحيات أقدم من الوكلاء الذين يتصرفون دون إنسان في الحلقة عند كل قراءة. عندما يفتح شخص ملفاً، فالشخص هو المصدر. عندما يقرأ وكيل ملفاً نيابة عن مهمة، فالمهمة هي المصدر، ولا تملك المنصة مكاناً لتسجيله. يستطيع FDA إخبارك أن شيئاً ما قرأ سلسلة مفاتيحك. لا يستطيع إخبارك أي مهمة، أو أي وكيل، أو ما إذا كانت تلك القراءة مشروعة.
فئات البيانات كوحدة تحديد النطاق
الحل الدائم هو التوقف عن معاملة منحة على مستوى نظام الملفات كوحدة تخويل الوكيل. حدد حقوق القراءة لكل فئة بيانات بدلاً من ذلك. فئة البيانات هي مجموعة مسارات تشترك في سياسة قراءة، على سبيل المثال:
- بيانات الاعتماد: سلاسل المفاتيح، ملفات
.env، مواد SSH، إعداد مزود السحابة، مخازن بيانات اعتماد المتصفح - أشجار المصدر: نسخ عمل تحت التحكم بالإصدارات، مستودعات monorepo، تبعيات مُضمَّنة
- الاتصالات الشخصية: مخازن البريد، قواعد بيانات الرسائل، مخازن التقويم وجهات الاتصال
- مخرجات البناء: الناتج المُصرَّف، ذاكرات التخزين المؤقت، طبقات الحاويات، مخازن مدير الحزم
- إعداد النظام:
/etc، وكلاء التشغيل، ملفات تعريف الشبكة
يطلب الوكلاء فئة، لا مساراً. تحل المنصة المسارات إلى فئات عند وقت المنح وتعيد الحل عند وقت القراءة. يطلب وكيل البناء source-trees وbuild-artefacts؛ ويطلب وكيل النشر credentials محدد النطاق لمزود واحد وbuild-artefacts؛ ويطلب وكيل التلخيص personal-communications لحساب واحد. الطلب مقروء لمراجع بشري بطريقة لا يوفرها ~/Projects، لأنه يصرح بالنية لا بالموقع.

الخاصية الحاسمة أن عضوية الفئة تُحسب بواسطة المنصة، لا يعلنها الوكيل. لو استطاع وكيل تأكيد أن "هذا المسار مخرج بناء"، لهزمت إعادة تسمية سر إلى dist/ التصنيف. يجب أن يجمع الحل بين أنماط المسارات وبيانات الملف الوصفية وإشارات المحتوى والنسب: الملف المكتوب بواسطة عملية تحمل بيانات اعتماد يجب أن يرث تصنيفاً مجاوراً لبيانات الاعتماد حتى بعد نسخه. يبقى السر المُعاد تسميته محمياً لأن فئته مشتقة من كيفية وجوده، لا من مكانه الحالي.
تتبع المصدر عند كل قراءة
تحديد النطاق وحده غير كافٍ دون سجل لما حدث. يجب أن يحمل كل حدث قراءة ثلاثة حقول على الأقل:
{
"agent_identity": "build-runner@ci-7",
"task_id": "task-4f9c2a1e",
"resolved_class": "source-trees",
"path": "/Users/dev/work/api/src/main.rs",
"decision": "allow",
"policy_version": "2024-11-03"
}
معرّف المهمة هو الحقل الذي تحذفه معظم الأنظمة، وهو الذي يجعل سجلات التدقيق قابلة للتفسير. بدونه، سطر سجل يظهر قراءة ~/.aws/credentials لا يمكن تمييزه عن خطوة نشر مشروعة وعن مسار تسريب. معه، يستطيع المشغل طرح سؤال مهم: أي المهام قرأت بيانات الاعتماد، وهل قرأ أي منها أيضاً اتصالات شخصية في نفس النافذة؟ هذا السؤال قابل للإجابة فقط إذا كان معرّف المهمة حاضراً عند كل قراءة، ومنقولاً من نقطة دخول الوكيل عبر كل استدعاء أداة وعملية فرعية.
تسجيل قرار الحل لا يقل أهمية عن تسجيل المسار. سجل يقول resolved_class: source-trees لمسار تصنفه السياسة الآن كـ credentials هو إشارة انحراف. بدون القرار، تكون تغييرات السياسة غير مرئية حتى ينكسر شيء. معه، يصبح الانحراف قابلاً للكشف كاستعلام: ابحث عن القراءات التي تختلف فيها الفئة المحلولة عن المصنف الحالي.
آلية حل ملموسة
التنفيذ القابل للعمل له ثلاث مراحل.
التصنيف. يحتفظ مصنف خلفي بتعيين من أنماط المسارات وسجلات النسب إلى فئات. يعمل عند إنشاء الملف وإعا
دار السياسة الساري.

الحل. عند كل قراءة، يحل وقت تشغيل الوكيل الفئة المطلوبة مقابل الرؤية الحالية للمصنف. إذا لم تكن الفئة المحسوبة للمسار ضمن مجموعة الوكيل الممنوحة، تُرفض القراءة بسبب منظم: الفئة المحسوبة، وإصدار السياسة، والمنحة المطلوبة.
إصدار تتبع المصدر. يصدر وقت التشغيل حدث قراءة بالحقول أعلاه إلى مصرف للإضافة فقط. المصرف قابل للاستعلام حسب المهمة والوكيل والفئة، وهو الركيزة لكشف الانحراف.
تفصيلان يحددان ما إذا كان هذا يعمل عملياً. أولاً، يجب أن يكون الحل سريعاً بما يكفي للجلوس على مسار القراءة؛ ذاكرة تخزين مؤقت مفهرسة بـ inode وإصدار السياسة كافية عادة، وتُبطل عند تغيير التصنيف. ثانياً، يجب أن يكون الرفض قابلاً للتنفيذ. رفض يقول computed_class: credentials, required_grant: credentials:aws-prod يخبر المشغل بالضبط ما يجب تغييره. رفض يقول permission denied يعلمه منح FDA.
ما تكلفته
المقايضات الصادقة ثلاث.
زمن الاستجابة والصيانة. يضيف حل الفئة بحثاً على مسار القراءة، ويجب صيانة التصنيف. تنحرف الفئات الخاصة بالمجال مع إعادة تنظيم الفرق لمستودعاتها. التصنيف غير المصان يصبح مصدراً لرفض خاطئ، والرفض الخاطئ يقوّض الثقة أسرع من المنح الواسعة.
الرفض المشروع. سيُرفض عن الوكلاء أحياناً قراءات كان يجب أن تُمنح. خطوة بناء تقرأ ملفاً مُولَّداً صنفه المصنف كمجاور لبيانات الاعتماد ستفشل. يجب أن يجعل التصميم هذا الرفض قابلاً للتنفيذ لا صامتاً: أظهر الفئة المحسوبة، وإصدار السياسة، وأضيق منحة ستفتح المهمة. الرفض الصامت ينتج نفس سلوك الالتفاف الذي تنتجه المنح الواسعة.
مقاومة الموردين. سيقاوم موردو المنصات شحن تصنيفات الفئات لأنها خاصة بالمجال وصعبة التخلف الافتراضي. نظام تشغيل عام لا يستطيع معرفة أن دليل fixtures/ لفريق يحتوي بيانات اصطناعية وآخر يحتوي لقطات إنتاج. المسار الواقعي هو مجموعة صغيرة من الفئات الأساسية المعرفة من المنصة زائد آلية امتداد، مع إدراك أن الامتداد هو حيث تكمن معظم القيمة ومعظم عبء الصيانة.
لا شيء من هذا مجاني، ولا شيء منه إجابة كاملة. لكنه تغيير في وحدة التخويل. يسأل FDA ما إذا كان الوكيل يجوز له قراءة كل شيء. نموذج محدد النطاق بالفئات يسأل أي أنواع البيانات يجوز لهذا الوكيل، في هذه المهمة، قراءتها، ويسجل الإجابة. السؤال الثاني هو ما يحتاج المشغلون فعلاً للإجابة عنه، وهو ما لا يستطيع النموذج الحالي التعبير عنه.
