DeepSeek Harness: البرمجة الدفاعية ومراجعة الحوادث
آخر تحديث: 2026-08-31
قوة إطار عمل الوكلاء تعني أن الأخطاء ذات تأثير أكبر أيضًا — مؤقت غير منظَّف قد يتسرب للذاكرة، ومفتاح API مُرمَّز قد يتسرب للسجلات، ونتيجة أداة غير مُتحقَّق منها قد تتسبب بقرار خاطئ من الوكيل. البرمجة الدفاعية ليست اختيارية — إنها إلزامية.
📋 المتطلبات المسبقة: إكمال 13-effect.md و 29-sandbox.md
1. ما ستتعلمه
- أفضل ممارسات إدارة بيانات الاعتماد
- الإبلاغ عن النتائج والتحقق منها
- ضمان التنظيف
- حدود الآثار الجانبية
- ثقافة مراجعة الحوادث
- قائمة تدقيق التدقيق الأمني
2. أفضل ممارسات إدارة بيانات الاعتماد
(1) ▶ مثال 1
// ❌ مفتاح API مُرمَّد
const apiKey = 'sk-abc123def456'
// ❌ مفتاح API مكتوب في السجلات
ctx.logger.info(`connecting with key: ${apiKey}`)
// ❌ مفتاح API في URL
const url = `https://api.example.com?key=${apiKey}`
// ❌ مفتاح API في رسالة الخطأ
throw new Error(`Authentication failed for key: ${apiKey}`)
(2) ▶ مثال 2
// ✅ القراءة من التكوين
export const Config = Schema.object({
apiKey: Schema.string().required().hidden()
})
export function apply(ctx: Context) {
const apiKey = ctx.config.apiKey
// apiKey يُستخدم فقط داخل apply، لا يتسرب للخارج
}
// ✅ استخدام متغيرات البيئة
const apiKey = process.env.MY_PLUGIN_API_KEY
// ✅ التمرير عبر ترويسة الطلب (ليس في URL)
const response = await fetch(url, {
headers: { 'Authorization': `Bearer ${apiKey}` }
})
(3) حماية بيانات الاعتماد في السجلات
// ✅ إخفاء المعلومات الحساسة في السجلات
ctx.logger.info(`جاري الاتصال بـ ${endpoint}`) // لا تسجّل المفتاح
// ✅ فلتر سجلات مخصص
function sanitize(obj: any): any {
const sanitized = { ...obj }
if (sanitized.apiKey) sanitized.apiKey = '***'
if (sanitized.authorization) sanitized.authorization = '***'
return sanitized
}
ctx.logger.info('طلب:', sanitize(request))
(4) تدوير بيانات الاعتماد
export const Config = Schema.object({
apiKey: Schema.string().required().hidden(),
keyRotationDays: Schema.number().default(90)
})
export function apply(ctx: Context) {
ctx.setInterval(() => {
const age = getKeyAge()
if (age > ctx.config.keyRotationDays * 86400000) {
ctx.logger.warn('مفتاح API متأخر عن التدوير')
}
}, 86400000)
}
3. الإبلاغ عن النتائج والتحقق منها
(1) التحقق من قيم إرجاع الأدوات
// ❌ عدم التحقق من نتائج الأداة
async execute({ path }, ctx) {
const result = await ctx.shell.execute(`ls ${path}`)
return result.stdout // قد يكون فارغًا أو مشوّهًا
}
// ✅ التحقق من نتائج الأداة
async execute({ path }, ctx) {
const result = await ctx.shell.execute(`ls ${path}`)
if (result.exitCode !== 0) {
return {
error: true,
message: `فشل ls: ${result.stderr}`,
exitCode: result.exitCode
}
}
if (!result.stdout || result.stdout.trim().length === 0) {
return {
error: true,
message: 'الدليل فارغ أو غير موجود'
}
}
const files = result.stdout.trim().split('\n')
return { count: files.length, files }
}
(2) التحقق من استجابات API
// ❌ عدم التحقق من استجابات API
const data = await response.json()
return data.result
// ✅ التحقق من استجابات API
async function callAPI(ctx: Context, endpoint: string): Promise<any> {
const response = await fetch(endpoint)
if (!response.ok) {
throw new Error(`خطأ API: ${response.status} ${response.statusText}`)
}
let data: any
try {
data = await response.json()
} catch {
throw new Error('API أرجع JSON غير صالح')
}
if (!data || typeof data !== 'object') {
throw new Error('API أرجع صيغة غير متوقعة')
}
return data
}
(3) التحقق من المدخلات
// ❌ عدم التحقق من مدخلات المستخدم
async execute({ command }, ctx) {
return await ctx.shell.execute(command) // خطر حقن الأوامر
}
// ✅ التحقق وتنظيف المدخلات
async execute({ command }, ctx) {
if (!command || typeof command !== 'string') {
return { error: true, message: 'أمر غير صالح' }
}
if (command.length > 1000) {
return { error: true, message: 'الأمر طويل جدًا' }
}
// فحص القائمة البيضاء
const allowed = ['ls', 'cat', 'grep', 'wc', 'head', 'tail']
const baseCommand = command.split(' ')[0]
if (!allowed.includes(baseCommand)) {
return { error: true, message: `أمر غير مسموح: ${baseCommand}` }
}
return await ctx.shell.execute(command)
}
4. ضمان التنظيف
(1) مبدأ ضمان التنظيف
بغض النظر عن كيفية خروج إضافة (إلغاء تحميل طبيعي، تعطّل، إيقاف يدوي)، يجب تنظيف جميع الموارد.
(2) قائمة مراجعة التنظيف
| نوع المورد | طريقة التنظيف | آلية الضمان |
|---|---|---|
| المؤقتات | ctx.setInterval/setTimeout | تنظيف تلقائي |
| مستمعو الأحداث | ctx.on() | تنظيف تلقائي |
| اتصالات الشبكة | ctx.effect() | تسجيل يدوي |
| الملفات المؤقتة | ctx.effect() | تسجيل يدوي |
| العمليات الفرعية | ctx.effect() | تسجيل يدوي |
| الحالة العامة | ctx.effect() | تسجيل يدوي |
(3) نمط ضمان التنظيف
export function apply(ctx: Context) {
// جميع الموارد التي تحتاج تنظيف
const resources: { close: () => void | Promise<void> }[] = []
// سجّل التنظيف فورًا عند اكتساب المورد
function acquireResource<T extends { close: () => void | Promise<void> }>(
resource: T
): T {
resources.push(resource)
return resource
}
// تنظيف موحَّد
ctx.effect(() => {
return async () => {
for (const r of resources.reverse()) {
try {
await r.close()
} catch (e) {
ctx.logger.warn('خطأ في التنظيف:', e)
}
}
}
})
// الاستخدام
const db = acquireResource(openDatabase())
const ws = acquireResource(new WebSocket('ws://localhost:8080'))
}
(4) تنظيف الملفات المؤقتة
export function apply(ctx: Context) {
const tempFiles: string[] = []
ctx.effect(() => {
return async () => {
for (const file of tempFiles.reverse()) {
try {
await ctx.fs.unlink(file)
} catch {}
}
}
})
async function createTempFile(content: string): Promise<string> {
const path = `/tmp/dsh-${Date.now()}-${Math.random().toString(36).slice(2)}`
await ctx.fs.writeFile(path, content)
tempFiles.push(path)
return path
}
}
5. حدود الآثار الجانبية
(1) تصنيف الآثار الجانبية
| النوع | الوصف | مثال | المخاطر |
|---|---|---|---|
| للقراءة فقط | لا يُعدّل الحالة الخارجية | قراءة ملف، استعلام قاعدة بيانات | منخفضة |
| كتابة مُمكِنة | التنفيذ المتكرر له نفس التأثير | إنشاء ملف (الكتابة فوق إن وُجد) | متوسطة |
| كتابة غير مُمكِنة | التنفيذ المتكرر له تأثيرات مختلفة | إرسال بريد، إلحاق سجل | عالية |
| هدّام | عملية لا رجعة فيها | حذف ملف، DROP TABLE | عالية جدًا |
(2) مبادئ حدود الآثار الجانبية
المبدأ 1: قلّل الآثار الجانبية
→ نفِّذ فقط العمليات الضرورية
→ فضِّل للقراءة فقط، ثم الكتابة المُمكِنة
المبدأ 2: الآثار الجانبية يجب أن تكون قابلة للعكس
→ احفظ الحالة الأصلية قبل الكتابة
→ وفّر عمليات تراجع
المبدأ 3: الآثار الجانبية يجب أن تكون قابلة للتدقيق
→ سجّل تفاصيل كل أثر جانبي
→ يمكن للمستخدمين عرض سجل العمليات
المبدأ 4: الآثار الجانبية تتطلب موافقة
→ العمليات الهدّامة يجب أن تحظى بموافقة
→ العمليات غير المُمكِنة يجب أن تحظى بموافقة
(3) نمط التراجع
interface ReversibleAction {
execute(): Promise<void>
rollback(): Promise<void>
}
class FileEditAction implements ReversibleAction {
private originalContent: string | null = null
constructor(
private path: string,
private newContent: string,
private ctx: Context
) {}
async execute() {
try {
this.originalContent = await this.ctx.fs.readFile(this.path)
} catch {
this.originalContent = null
}
await this.ctx.fs.writeFile(this.path, this.newContent)
}
async rollback() {
if (this.originalContent !== null) {
await this.ctx.fs.writeFile(this.path, this.originalContent)
} else {
await this.ctx.fs.unlink(this.path)
}
}
}
(4) تدقيق الآثار الجانبية
const auditLog: AuditEntry[] = []
function audit(action: string, details: any, reversible: boolean) {
auditLog.push({
timestamp: Date.now(),
action,
details,
reversible,
user: 'agent'
})
ctx.emit('audit/action', { action, details, reversible })
}
// الاستخدام
audit('file_edit', { path: 'src/app.ts', operation: 'edit' }, true)
audit('email_send', { to: 'alice@example.com' }, false)
6. ثقافة مراجعة الحوادث
(1) قالب مراجعة الحوادث
# مراجعة حادث: [العنوان]
## معلومات أساسية
- التاريخ: YYYY-MM-DD
- التأثير: [الميزات/المستخدمون المتأثرون]
- الخطورة: P0/P1/P2
- المُعالِج: [الاسم]
## الجدول الزمني
- HH:MM — [الحدث 1]
- HH:MM — [الحدث 2]
- HH:MM — [الإصلاح]
## تحليل السبب الجذري
[تحليل الـ 5 لماذا]
## الإصلاح
- قصير المدى: [الإصلاح الفوري]
- طويل المدى: [إجراء الوقاية]
## الدروس المستفادة
- [الدرس 1]
- [الدرس 2]
(2) أنماط الحوادث الشائعة
| نمط الحادث | السبب الجذري | الوقاية |
|---|---|---|
| تسريب مفتاح API | بيانات الاعتماد مطبوعة في السجلات | تعقيم السجلات |
| تسريب الذاكرة | مؤقتات غير منظَّفة | استخدم ctx.setInterval |
| فقدان البيانات | عمليات حذف بدون تأكيد | سياسة الموافقة |
| حلقة لا نهائية | أدوات تستدعي بعضها | حدود عمق الاستدعاء |
| فشل متسلسل | استثناءات غير معزولة | try-catch + Fiber مستقل |
(3) ▶ مثال 3
حادث: وكيل حذف ملفات مشروع مستخدم
لماذا 1: الوكيل نفّذ rm -rf /project
→ لأن الأداة لم يكن لديها تحقق من المسار
لماذا 2: الأداة لم يكن لديها تحقق من المسار
→ لأن المطور لم ينفّذ فحص القائمة البيضاء
لماذا 3: المطور لم ينفّذ فحص القائمة البيضاء
→ لأنه لم تكن هناك عملية مراجعة أمنية
لماذا 4: لا توجد عملية مراجعة أمنية
→ لأن الفريق لم يُنشئ قائمة تدقيق أمنية
لماذا 5: الفريق لم يُنشئ قائمة تدقيق أمنية
→ بسبب تدريب وعي أمني غير كافٍ
الإصلاح: أنشئ قائمة تدقيق أمنية؛ جميع الإضافات يجب فحصها قبل النشر
7. قائمة تدقيق التدقيق الأمني
(1) قائمة تدقيق أمنية للإضافات
| # | عنصر الفحص | الفئة | الأولوية |
|---|---|---|---|
| 1 | مفتاح API غير مُرمَّد | بيانات الاعتماد | P0 |
| 2 | معلومات حساسة ليست في السجلات | بيانات الاعتماد | P0 |
| 3 | جميع ctx.effect لها دوال تنظيف | التنظيف | P0 |
| 4 | المؤقتات تستخدم ctx.setInterval/setTimeout | التنظيف | P0 |
| 5 | قيم إرجاع الأدوات لديها معالجة أخطاء | التحقق | P1 |
| 6 | مدخلات المستخدم مُتحقَّقة ومنظَّفة | التحقق | P1 |
| 7 | صيغة استجابة API مُتحقَّقة | التحقق | P1 |
| 8 | العمليات الهدّامة لديها سياسة موافقة | الآثار الجانبية | P1 |
| 9 | العمليات غير المُمكِنة قابلة للعكس | الآثار الجانبية | P2 |
| 10 | الآثار الجانبية لديها سجلات تدقيق | الآثار الجانبية | P2 |
| 11 | إعلانات الصلاحيات كاملة | الصلاحيات | P1 |
| 12 | لا طلبات صلاحيات غير ضرورية | الصلاحيات | P2 |
| 13 | إصدارات التبعيات لديها إعلانات توافق | التوافق | P2 |
| 14 | لا ثغرات أمنية معروفة في التبعيات | التبعيات | P1 |
(2) عملية التدقيق
graph TD
CODE[اكتمال تطوير الإضافة] --> SELF[التدقيق الذاتي للمطور]
SELF --> CHECK{جميع عناصر القائمة تجتاز؟}
CHECK -->|لا| FIX[أصلح المشاكل]
FIX --> SELF
CHECK -->|نعم| REVIEW[مراجعة الفريق]
REVIEW --> APPROVE{المراجعة اجتازت؟}
APPROVE -->|لا| FIX2[عدّل الكود]
FIX2 --> REVIEW
APPROVE -->|نعم| PUBLISH[انشر]
(3) التدقيق الآلي
# تشغيل التدقيق الأمني
dsh audit my-plugin
# المخرجات
🔒 Security Audit: my-plugin
✅ No hardcoded credentials
✅ All ctx.effect() have cleanup functions
⚠️ Tool 'db_query' has no input validation
❌ API response not validated in 'fetch_data'
✅ Approval policy configured for destructive operations
⚠️ Permission 'shell.execute' may not be necessary
2 errors, 2 warnings found. Fix before publishing.
❓ أسئلة شائعة
always. العمليات ذات الآثار الجانبية (كتابة ملفات، تنفيذ أوامر، إرسال طلبات) تحتاج موافقة.bash # اختبار حلقي for i in {1..100}; do dsh plugin enable my-plugin dsh plugin disable my-plugin done # تحقق من استقرار الذاكرة وعدد الاتصالات 📖 ملخص
- إدارة بيانات الاعتماد: بلا ترميز ثابت، بلا تسجيل، استخدم التكوين/متغيرات البيئة، درِّر بانتظام
- التحقق من النتائج: تحقق من قيم إرجاع الأدوات، استجابات API، مدخلات المستخدم — لا تثق بأي بيانات خارجية
- ضمان التنظيف: جميع الموارد تسجّل دوال تنظيف، إدارة موحَّدة، الاستثناءات لا تمنع تنظيفًا آخر
- حدود الآثار الجانبية: قلّل الآثار الجانبية، اجعلها قابلة للعكس، اجعلها قابلة للتدقيق، العمليات الهدّامة تحتاج موافقة
- مراجعة الحوادث: تحليل السبب الجذري بـ 5 لماذا، أنشئ إجراءات إصلاح ووقاية
- قائمة تدقيق التدقيق الأمني: 14 عنصر فحص، تدقيق ذاتي للمطور + مراجعة الفريق + مسح آلي
📝 تمارين
1. ⭐ أساسي: راجع كود إضافتك المكتوبة سابقًا مقابل قائمة تدقيق التدقيق الأمني. اذكر المشاكل المكتشفة وخطط الإصلاح.
2. ⭐⭐ متوسط: أضف تحققًا كاملًا من المدخلات إلى أداة — افحص أنواع المعاملات، الطول، الصيغة، ورشّح معاملات Shell بالقائمة البيضاء. اختبر: أدخل معاملات غير قانونية متنوعة وأكد أن جميعها تُرجع رسائل خطأ مفيدة.
3. ⭐⭐⭐ متقدم: نفّذ نظام ReversibleAction — كل عملية ذات آثار جانبية تنشئ كائن ReversibleAction يحفظ الحالة الأصلية عند التنفيذ ويعيدها عند التراجع. اكتب أداة تعديل ملفات تدعم التراجع: بعد تعديل ملف، استدعِ undo_last للعودة عن آخر تعديل. اختبر: عدّل ثلاث مرات متتالية، تراجع بالتتابع، أكد أن الملف يعود لحالته الأصلية.