DeepSeek Harness: البرمجة الدفاعية ومراجعة الحوادث

آخر تحديث: 2026-08-31

قوة إطار عمل الوكلاء تعني أن الأخطاء ذات تأثير أكبر أيضًا — مؤقت غير منظَّف قد يتسرب للذاكرة، ومفتاح API مُرمَّز قد يتسرب للسجلات، ونتيجة أداة غير مُتحقَّق منها قد تتسبب بقرار خاطئ من الوكيل. البرمجة الدفاعية ليست اختيارية — إنها إلزامية.

💡 نصيحة: المبدأ الأساسي للبرمجة الدفاعية هو "لا تثق بأي مدخلات خارجية" — مدخلات المستخدم، قيم إرجاع الأدوات، استجابات API جميعها تحتاج تحققًا. تعطّل إضافتك مقبول؛ تسبب إضافتك في فقدان بيانات أو تسرب بيانات اعتماد غير مقبول.

📋 المتطلبات المسبقة: إكمال 13-effect.md و 29-sandbox.md

1. ما ستتعلمه

أنماط البرمجة الدفاعية


2. أفضل ممارسات إدارة بيانات الاعتماد

(1) ▶ مثال 1

TYPESCRIPT
// ❌ مفتاح 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

TYPESCRIPT
// ✅ القراءة من التكوين
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) حماية بيانات الاعتماد في السجلات

TYPESCRIPT
// ✅ إخفاء المعلومات الحساسة في السجلات
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) تدوير بيانات الاعتماد

TYPESCRIPT
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) التحقق من قيم إرجاع الأدوات

TYPESCRIPT
// ❌ عدم التحقق من نتائج الأداة
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

TYPESCRIPT
// ❌ عدم التحقق من استجابات 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) التحقق من المدخلات

TYPESCRIPT
// ❌ عدم التحقق من مدخلات المستخدم
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) نمط ضمان التنظيف

TYPESCRIPT
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) تنظيف الملفات المؤقتة

TYPESCRIPT
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) مبادئ حدود الآثار الجانبية

TEXT 📖 للعرض فقط
المبدأ 1: قلّل الآثار الجانبية
  → نفِّذ فقط العمليات الضرورية
  → فضِّل للقراءة فقط، ثم الكتابة المُمكِنة

المبدأ 2: الآثار الجانبية يجب أن تكون قابلة للعكس
  → احفظ الحالة الأصلية قبل الكتابة
  → وفّر عمليات تراجع

المبدأ 3: الآثار الجانبية يجب أن تكون قابلة للتدقيق
  → سجّل تفاصيل كل أثر جانبي
  → يمكن للمستخدمين عرض سجل العمليات

المبدأ 4: الآثار الجانبية تتطلب موافقة
  → العمليات الهدّامة يجب أن تحظى بموافقة
  → العمليات غير المُمكِنة يجب أن تحظى بموافقة

(3) نمط التراجع

TYPESCRIPT
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) تدقيق الآثار الجانبية

TYPESCRIPT
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) قالب مراجعة الحوادث

MARKDOWN
# مراجعة حادث: [العنوان]

## معلومات أساسية
- التاريخ: 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

TEXT 📖 للعرض فقط
حادث: وكيل حذف ملفات مشروع مستخدم

لماذا 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) عملية التدقيق

100%
graph TD
    CODE[اكتمال تطوير الإضافة] --> SELF[التدقيق الذاتي للمطور]
    SELF --> CHECK{جميع عناصر القائمة تجتاز؟}
    CHECK -->|لا| FIX[أصلح المشاكل]
    FIX --> SELF
    CHECK -->|نعم| REVIEW[مراجعة الفريق]
    REVIEW --> APPROVE{المراجعة اجتازت؟}
    APPROVE -->|لا| FIX2[عدّل الكود]
    FIX2 --> REVIEW
    APPROVE -->|نعم| PUBLISH[انشر]

(3) التدقيق الآلي

BASH
# تشغيل التدقيق الأمني
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. العمليات ذات الآثار الجانبية (كتابة ملفات، تنفيذ أوامر، إرسال طلبات) تحتاج موافقة.
س كيف أتعامل مع إخفاقات التنظيف غير القابلة للاسترداد؟
ج سجّل الخطأ واستمر في تنظيف الموارد الأخرى. Cordis داخليًا يلف كل دالة تنظيف في try-catch؛ إخفاق واحد لا يمنع الأخرى.
س كم مرة يجب إجراء مراجعة الحوادث؟
ج فورًا بعد كل حادث P0/P1. حوادث P2 يمكن تجميعها للمراجعة الدورية. راجع أنماط الحوادث بانتظام (مثلاً شهريًا).
س هل قائمة تدقيق التدقيق الأمني تنطبق على جميع الإضافات؟
ج نعم. عناصر القائمة هي متطلبات أمنية عامة. إضافات مختلفة قد تحتاج فحوصًا إضافية (مثلاً حماية من حقن SQL لإضافات قواعد البيانات).
س كيف أختبر ضمانات التنظيف؟
ج حمّل/ألغِ تحميل الإضافة بشكل متكرر مع مراقبة استخدام الموارد: bash # اختبار حلقي for i in {1..100}; do dsh plugin enable my-plugin dsh plugin disable my-plugin done # تحقق من استقرار الذاكرة وعدد الاتصالات

📖 ملخص


📝 تمارين

1. ⭐ أساسي: راجع كود إضافتك المكتوبة سابقًا مقابل قائمة تدقيق التدقيق الأمني. اذكر المشاكل المكتشفة وخطط الإصلاح.

2. ⭐⭐ متوسط: أضف تحققًا كاملًا من المدخلات إلى أداة — افحص أنواع المعاملات، الطول، الصيغة، ورشّح معاملات Shell بالقائمة البيضاء. اختبر: أدخل معاملات غير قانونية متنوعة وأكد أن جميعها تُرجع رسائل خطأ مفيدة.

3. ⭐⭐⭐ متقدم: نفّذ نظام ReversibleAction — كل عملية ذات آثار جانبية تنشئ كائن ReversibleAction يحفظ الحالة الأصلية عند التنفيذ ويعيدها عند التراجع. اكتب أداة تعديل ملفات تدعم التراجع: بعد تعديل ملف، استدعِ undo_last للعودة عن آخر تعديل. اختبر: عدّل ثلاث مرات متتالية، تراجع بالتتابع، أكد أن الملف يعود لحالته الأصلية.

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%