
ينفّذ Python وJavaScript وBash غير الموثوقة داخل بيئة حماية مُحصّنة بحدود زمنية قدرها 5 ثوانٍ، وذاكرة 128 ميغابايت، ونصف نواة معالجة، وحدود على معرّفات العمليات (PID) والمخرجات.
تنفيذ مفروض على مستوى النواة للشيفرة غير الموثوقة — كل حمولة محبوسة بواسطة cgroups v2 وnamespaces وseccomp-BPF ونظام ملفات جذري للقراءة فقط، وكل تشغيل مُدقَّق في PostgreSQL.
python · javascript · bash → سجن لمدة 5 ثوانٍ، و128 ميغابايت، و0.5 نواة، و32 PID، ومخرجات بحجم 512 كيلوبايت
خدمة تنفيذ معزّزة أمنيًا للشيفرة التي لا تثق بها. يرسل المستدعون الشيفرة المصدرية عبر واجهة REST API صغيرة؛ ويُشغّل الخادم كل حمولة داخل سجن نواة مؤقت حيث تضمن نواة Linux نفسها — وليس منطق التطبيق — الاحتواء:
pivot_root إلى نظام ملفات جذري للقراءة فقط)،lo + seccomp يقتل socket)،PID · MOUNT · NET · IPC · UTS · USER)، وقائمة سماح صارمة في seccomp-BPF، وسجون موارد cgroups v2، ونظام ملفات pivot_root للقراءة فقط مع مساحة مؤقتة tmpfs بحجم 16 ميغابايت.5 s، وسقف ذاكرة 128 MB (التبديل معطّل، قتل فوري عند نفاد الذاكرة OOM)، و0.5 نواة معالج، وpids.max = 32 لمناعة ضد قنابل التفريع، وحدود مخرجات 512 KB على stdout/stderr.execution_runs).flowchart LR
CLI["👤 API Client<br/><i>tenant / CI job</i>"]
subgraph CP["🔐 Trusted Control Plane — Go daemon"]
API["Ingestion Daemon<br/><i>net/http :8080</i>"]
POOL["Warm Runner Pool<br/><i>16 slots · 3 s cap</i>"]
RUN["Process Runner<br/><i>watchdog + pipes</i>"]
ISO["Kernel Isolation<br/><i>cgroups v2 · namespaces · seccomp-BPF</i>"]
end
subgraph JAIL["⛓️ Ephemeral Kernel Jail — untrusted"]
INIT["sandbox_init<br/><i>exec trampoline</i>"]
GUEST["💀 Untrusted Code<br/><i>python · node · bash</i>"]
end
PG[("🗄️ PostgreSQL 16<br/><i>execution_runs</i>")]
RD[("📮 Redis 7 Queue<br/><i>sandbox:jobs</i>")]
CLI -->|"POST /api/v1/execute"| API
API -->|"validate + acquire"| POOL
POOL -->|"spawn + limits"| RUN
RUN -.->|"apply jail"| ISO
ISO ==>|"seccomp · pivot_root"| GUEST
RUN -->|"fork / exec"| INIT
INIT -->|"syscall.Exec"| GUEST
RUN -.->|"stdout / stderr ≤ 512 KB"| POOL
API -.->|"async audit INSERT"| PG
RD -.->|"BRPop drain · worker module"| POOL
style JAIL fill:#2a1215,stroke:#f87171,stroke-width:2px
style CP fill:#0d1b2a,stroke:#38bdf8,stroke-width:1px
| المكوّن | المسؤولية | المصدر |
|---|---|---|
| خدمة الاستقبال (Ingestion Daemon) | واجهة REST: POST /api/v1/execute + /health؛ التحقق من الطلبات؛ إصدار سجلات التدقيق بشكل غير متزامن | cmd/server/main.go |
| مجمع المشغّلات الجاهزة (Warm Runner Pool) | فتحات تنفيذ محدودة بـ semaphore (16) مع مهلة حجز 3 ثوانٍ → ضغط خلفي على شكل استنفاد 503 | internal/runner/pool.go |
| مشغّل العمليات (Process Runner) | يبني أمر اللغة، ويربط الـ cgroup، ويبثّ الأنابيب عبر كتّاب يقتطعون المخرجات، ويفرض مؤقّت المراقبة البالغ 5 ثوانٍ، ويجمع مقاييس cgroup، ويصنّف النتائج | internal/runner/process.go |
| عزل النواة (Kernel Isolation) | محدّد cgroups v2 (memory.max، cpu.max، pids.max)، وأعلام النطاقات (CLONE_NEWPID/NET/NS/IPC/UTS/USER)، ومُصرِّف مرشّح seccomp-BPF | internal/isolation/ |
| sandbox_init | ترامبولين العملية الفرعية: pivot_root للقراءة فقط + tmpfs لـ /dev//tmp، وفصل الشبكة (إيقاف lo)، وتطبيق seccomp، ثم syscall.Exec للهدف | cmd/sandbox_init/main.go |
| الكود غير الموثوق (Untrusted Code) | الحمولة الضيفة. تُجرَّد أجهزة المضيف، ويُخفى /proc (hidepid=2)، وتُقتل جميع استدعاءات النظام غير المدرجة في القائمة المسموحة | صور rootfs في runtimes/ |
| PostgreSQL 16 | سجل تدقيق دائم لكل عملية تشغيل، بما في ذلك انتهاكات الأمان | migrations/001_init_sandbox_schema.sql |
| Redis 7 | قائمة انتظار sandbox:jobs + عامل BRPop يستنزفها إلى المجمع (الوحدة مُنفَّذة، لكنها لم تُوصَّل بعد بالخدمة — راجع القيود المعروفة) | internal/queue/redis_consumer.go |
| الحد | ما يفصله | آلية الفرض |
|---|---|---|
| العميل ↔ الخدمة | إرسال حمولة غير مُصادَق عليها من مستوى التحكم | التحقق من المخطط (tenant_id، language، code) |
| مستوى التحكم ↔ السجن | كود Go موثوق مقابل حمولة عدائية | fork إلى نطاقات خاصة؛ pivot_root؛ seccomp الموروث عند التنفيذ |
| السجن ↔ حدود النواة | استهلاك الضيف للموارد مقابل سعة المضيف | cgroups v2 memory.max=128MB، swap.max=0، cpu.max="50000 100000"، pids.max=32 |
| السجن ↔ الشبكة | أي خروج أو إمكانية وصول من جهة المضيف | نطاق NET خاص، إيقاف lo، قتل استدعاء النظام socket |
🔍 توجد نسخة تفاعلية من هذا المخطط تتكيّف مع السمة (مع تصدير PNG/SVG) مؤلَّفة من المرشّحين المدعومين بالأدلة في
docs/archify/.
sequenceDiagram
autonumber
participant C as Client
participant A as REST API
participant P as Warm Pool
participant R as Process Runner
participant I as sandbox_init
participant G as Untrusted Code
participant DB as PostgreSQL
C->>A: POST /api/v1/execute
A->>P: acquire slot · 16 max, 3 s timeout
P->>R: Run(req, limits)
R->>I: fork under CLONE_NEWPID·NET·NS·IPC·UTS·USER
R->>R: create cgroup scope → attach PID<br/>128 MB · 0.5 CPU · 32 PIDs
I->>I: pivot_root RO rootfs · lo down · seccomp-BPF
I->>G: syscall.Exec target interpreter
G-->>R: stdout / stderr via pipes (512 KB cap)
R->>R: watchdog: SIGKILL at 5 s → exit 137
R-->>P: result + cgroup metrics (peak mem, CPU)
P-->>A: ExecutionResult
A-->>C: 200 JSON
A-)DB: async audit INSERT (non-blocking)
خطوة بخطوة: