العودة إلى التحديثات
New releaseAug 27, 2026

sandbox-runtime v0.0.74

أداة عزل (sandboxing) خفيفة الوزن لفرض قيود على نظام الملفات والشبكة على أي عملية على مستوى نظام التشغيل، دون الحاجة إلى حاوية (container).

مشاركة

Anthropic Sandbox Runtime (srt)

أداة عزل خفيفة الوزن لفرض قيود على نظام الملفات والشبكة على عمليات عشوائية على مستوى نظام التشغيل، دون الحاجة إلى حاوية.

يستخدم srt أوليات العزل الأصلية لنظام التشغيل (sandbox-exec على macOS، وbubblewrap على Linux) وتصفية الشبكة القائمة على الوكيل. يمكن استخدامه لعزل سلوك الوكلاء، وخوادم MCP المحلية، وأوامر bash، والعمليات العشوائية.

معاينة بحثية تجريبية

Sandbox Runtime هو معاينة بحثية طُوّرت لـ Claude Code لتمكين وكلاء ذكاء اصطناعي أكثر أمانًا. يتم إتاحته كمعاينة مفتوحة المصدر مبكرة لمساعدة النظام البيئي الأوسع على بناء أنظمة وكيلية أكثر أمانًا. نظرًا لأن هذه معاينة بحثية مبكرة، فقد تتطور واجهات البرمجة وصيغ التكوين. نرحب بالملاحظات والمساهمات لجعل وكلاء الذكاء الاصطناعي أكثر أمانًا افتراضيًا!

التثبيت```bash

npm install -g @anthropic-ai/sandbox-runtime

## الاستخدام الأساسي```bash
# Network restrictions
$ srt "curl anthropic.com"
Running: curl anthropic.com
<html>...</html>  # Request succeeds

$ srt "curl example.com"
Running: curl example.com
Connection blocked by network allowlist  # Request blocked

# Filesystem restrictions
$ srt "cat README.md"
Running: cat README.md
# Anthropic Sandb...  # Current directory access allowed

$ srt "cat ~/.ssh/id_rsa"
Running: cat ~/.ssh/id_rsa
cat: /Users/ollie/.ssh/id_rsa: Operation not permitted  # Specific file blocked

نظرة عامة

توفر هذه الحزمة تنفيذًا مستقلًا لبيئة معزولة (sandbox) يمكن استخدامه كأداة سطر أوامر (CLI) ومكتبة برمجية في آنٍ واحد. وقد صُمِّم بفلسفة آمن افتراضيًا (secure-by-default) مُصمَّمة خصيصًا لحالات الاستخدام الشائعة لدى المطورين: تبدأ العمليات بأقل قدر من الصلاحيات، وتقوم أنت بفتح الثغرات التي تحتاجها فقط بشكل صريح.

القدرات الرئيسية:

  • قيود الشبكة: التحكم في المضيفين/النطاقات التي يمكن الوصول إليها عبر HTTP/HTTPS وبروتوكولات أخرى
  • قيود نظام الملفات: التحكم في الملفات/المجلدات التي يمكن قراءتها/كتابتها
  • قيود مقابس Unix: التحكم في الوصول إلى مقابس IPC المحلية
  • مراقبة الانتهاكات: على macOS، الوصول إلى مخزن سجل انتهاكات البيئة المعزولة في النظام للحصول على تنبيهات فورية

مثال على حالة الاستخدام: عزل خوادم MCP

من حالات الاستخدام الرئيسية عزل خوادم بروتوكول سياق النموذج (MCP) لتقييد قدراتها. على سبيل المثال، لعزل خادم MCP الخاص بنظام الملفات:

بدون عزل (.mcp.json):```json { "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem"] } } }

**مع العزل** (`.mcp.json`):```json
{
  "mcpServers": {
    "filesystem": {
      "command": "srt",
      "args": ["npx", "-y", "@modelcontextprotocol/server-filesystem"]
    }
  }
}

ثم قم بتكوين القيود في ~/.srt-settings.json:```json { "filesystem": { "denyRead": [], "allowWrite": ["."], "denyWrite": ["~/sensitive-folder"] }, "network": { "allowedDomains": [], "deniedDomains": [] } }

الآن سيتم حظر خادم MCP من الكتابة إلى المسار المرفوض:```
> Write a file to ~/sensitive-folder
✗ Error: EPERM: operation not permitted, open '/Users/ollie/sensitive-folder/test.txt'

كيف يعمل

يستخدم صندوق الحماية (sandbox) أوليات على مستوى نظام التشغيل لفرض قيود تنطبق على شجرة العمليات بأكملها:

  • macOS: يستخدم sandbox-exec مع ملفات تعريف Seatbelt المُولَّدة ديناميكيًا
  • Linux: يستخدم bubblewrap للحاوية مع عزل مساحة أسماء الشبكة
  • Windows: يشغّل العملية المعزولة تحت حساب مستخدم محلي مخصص srt-sandbox، مع سياج خروج Windows Filtering Platform مرتبط بـ SID ذلك الحساب و ACEs صريحة لكل جلسة على شجرة العمل

0d1c612947c798aef48e6ab4beb7e8544da9d41a-4096x2305

نموذج العزل المزدوج

يُعدّ عزل كلٍّ من نظام الملفات والشبكة ضروريًا لتحقيق حماية فعّالة. فبدون عزل الملفات، قد تتمكن عملية مخترقة من تسريب مفاتيح SSH أو ملفات حساسة أخرى. وبدون عزل الشبكة، قد تتمكن عملية من الهروب من صندوق الحماية والحصول على وصول شبكي غير مقيّد.

عزل نظام الملفات يفرض قيودًا على القراءة والكتابة:

  • القراءة (نمط الرفض ثم السماح): افتراضيًا، يُسمح بالوصول للقراءة في كل مكان. يمكنك رفض مناطق واسعة (مثل /Users) ثم إعادة السماح بمسارات محددة داخلها (مثل .). allowRead لها الأولوية على denyRead — عكس الكتابة، حيث denyWrite لها الأولوية على allowWrite. مدخل denyRead الأكثر تحديدًا من منطقة allowRead التي يقع داخلها (مثل denyRead: ["**/.env"] أو ["./secrets"] مع allowRead: ["."]) يبقى مرفوضًا.
  • الكتابة (نمط السماح فقط): افتراضيًا، يُرفض الوصول للكتابة في كل مكان. يجب عليك السماح بالمسارات صراحةً (مثل .، /tmp). قائمة السماح الفارغة تعني عدم وجود وصول للكتابة.

عزل الشبكة (نمط السماح فقط): افتراضيًا، يُرفض كل وصول شبكي. يجب عليك السماح بالنطاقات صراحةً. قائمة allowedDomains الفارغة تعني عدم وجود وصول شبكي. تُوجَّه حركة الشبكة عبر خوادم وكيلة (proxies) تعمل على المضيف:

  • Linux: تُوجَّه الطلبات عبر نظام الملفات من خلال مقبس نطاق Unix. تُزال مساحة أسماء الشبكة للعملية المعزولة بالكامل، لذا يجب أن تمر كل حركة الشبكة عبر الوكلاء العاملين على المضيف (يستمعون على مقابس Unix المركّبة (bind-mounted) داخل صندوق الحماية)

  • macOS: يسمح ملف تعريف Seatbelt بالاتصال فقط بمنفذ localhost محدد. يستمع الوكلاء على هذا المنفذ، مما ينشئ قناة مُتحكَّمًا بها لكل وصول شبكي

  • Windows: تحجب مجموعة مرشحات WFP على مستوى الجهاز كل الاتصالات الصادرة من حساب srt-sandbox باستثناء loopback إلى نطاق منافذ الوكيل. يستمع الوكلاء داخل ذلك النطاق، مما ينشئ قناة مُتحكَّمًا بها لكل وصول شبكي

يتم توسيط كلٍّ من HTTP/HTTPS (عبر وكيل HTTP) وحركة TCP الأخرى (عبر وكيل SOCKS5) بواسطة هؤلاء الوكلاء، الذين يفرضون قوائم السماح والرفض للنطاقات الخاصة بك.

لمزيد من التفاصيل حول صندوق الحماية في Claude Code، راجع:

البنية```

src/ ├── index.ts # Library exports ├── cli.ts # CLI entrypoint (srt command) ├── utils/ # Shared utilities │ ├── debug.ts # Debug logging │ ├── settings.ts # Settings reader (permissions + sandbox config) │ ├── platform.ts # Platform detection │ └── exec.ts # Command execution utilities └── sandbox/ # Sandbox implementation ├── sandbox-manager.ts # Main sandbox manager ├── sandbox-schemas.ts # Zod schemas for validation ├── sandbox-violation-store.ts # Violation tracking ├── sandbox-utils.ts # Shared sandbox utilities ├── http-proxy.ts # HTTP/HTTPS proxy for network filtering ├── socks-proxy.ts # SOCKS5 proxy for network filtering ├── linux-sandbox-utils.ts # Linux bubblewrap sandboxing ├── macos-sandbox-utils.ts # macOS sandbox-exec sandboxing └── windows-sandbox-utils.ts # Windows srt-win sandboxing

## الاستخدام

### كأداة سطر أوامر (CLI)

يقوم الأمر `srt` (Anthropic Sandbox Runtime) بتغليف أي أمر بحدود أمنية:```bash
# Run a command in the sandbox
srt echo "hello world"

# With debug logging
srt --debug curl https://example.com

# Specify custom settings file
srt --settings /path/to/srt-settings.json npm install

كمكتبة```typescript

import { SandboxManager, type SandboxRuntimeConfig, } from '@anthropic-ai/sandbox-runtime' import { spawn } from 'child_process'

// Define your sandbox configuration const config: SandboxRuntimeConfig = { network: { allowedDomains: ['example.com', 'api.github.com'], deniedDomains: [], }, filesystem: { denyRead: ['~/.ssh'], allowWrite: ['.', '/tmp'], denyWrite: ['.env'], }, }

// Initialize the sandbox (starts proxy servers, etc.) await SandboxManager.initialize(config)

// Wrap a command with sandbox restrictions const sandboxedCommand = await SandboxManager.wrapWithSandbox( 'curl https://example.com', )

// Execute the sandboxed command const child = spawn(sandboxedCommand, { shell: true, stdio: 'inherit' })

// Handle exit and cleanup after child process completes child.on('exit', async code => { console.log(Command exited with code ${code}) // Cleanup when done (optional, happens automatically on process exit) await SandboxManager.reset() })

**إسناد الانتهاكات (`commandId` / `commandText`).** تُخزَّن الانتهاكات المرصودة أثناء تشغيل أمر مُغلَّف (أسطر سجل seatbelt، وأحداث seccomp، وعمليات الرفض من الوكيل) تحت مفتاح إسناد، ويبحث كلٌّ من `annotateStderrWithSandboxFailures(key, stderr)` / `getViolationsForCommand(key)` عنها بواسطة المفتاح نفسه. افتراضيًا يكون المفتاح هو السلسلة المُغلَّفة نفسها. مرِّر `commandId` معتمًا لكل استدعاء (مثل معرّف استخدام أداة) للفهرسة به بدلًا من ذلك — وهو المُوصى به: تُقارَن المفاتيح بأول 100 حرف منها، لذا فإن الأوامر الطويلة التي تشترك في بادئة قد تُسنَد بشكل متقاطع لولا ذلك، كما أن إعادة تشغيل النص نفسه سترث أحداث التشغيل السابق. إذا كانت السلسلة التي *تنفّذها* ليست الأمر الذي *يمثّله* الاستدعاء (مثلًا عندما تغلّف `source <snapshot> && eval '<cmd>'` المُجمَّعة)، فمرِّر أيضًا `commandText: '<cmd>'`: فهو ما تُطابَق ضده أنماط أوامر `ignoreViolations` وما يُبلِّغ عنه كل انتهاك باعتباره `command` الخاص به.```typescript
const wrapped = await SandboxManager.wrapWithSandbox(
  assembledCommand, // what actually runs
  undefined,
  undefined,
  undefined,
  { commandId: invocationId, commandText: rawCommand },
)
// ... run it ...
const annotated = SandboxManager.annotateStderrWithSandboxFailures(invocationId, stderr)

الصادرات المتاحة```typescript

// Main sandbox manager export { SandboxManager } from '@anthropic-ai/sandbox-runtime'

// Violation tracking export { SandboxViolationStore } from '@anthropic-ai/sandbox-runtime'

// TypeScript types export type { SandboxRuntimeConfig, NetworkConfig, FilesystemConfig, IgnoreViolationsConfig, SandboxAskCallback, FsReadRestrictionConfig, FsWriteRestrictionConfig, NetworkRestrictionConfig, } from '@anthropic-ai/sandbox-runtime'

## الإعدادات

### موقع ملف الإعدادات

بشكل افتراضي، يبحث وقت تشغيل البيئة المعزولة عن الإعدادات في `~/.srt-settings.json`. يمكنك تحديد مسار مخصص باستخدام العلامة `--settings`:```bash
srt --settings /path/to/srt-settings.json <command>

مثال إعداد كامل```json

{ "network": { "allowedDomains": [ "github.com", ".github.com", "lfs.github.com", "api.github.com", "npmjs.org", ".npmjs.org" ], "deniedDomains": ["malicious.com"], "allowUnixSockets": ["/var/run/docker.sock"], "allowLocalBinding": false }, "filesystem": { "denyRead": ["~/.ssh"], "allowRead": [], "allowWrite": [".", "src/", "test/", "/tmp"], "denyWrite": [".env", "config/production.json"] }, "ignoreViolations": { "*": ["/usr/bin", "/System"], "git push": ["/usr/bin/nc"], "npm": ["/private/tmp"] }, "enableWeakerNestedSandbox": false, "enableWeakerNetworkIsolation": false, "allowAppleEvents": false }

### خيارات التهيئة

#### تهيئة الشبكة

يستخدم **نمط السماح فقط** - يتم رفض جميع الوصول إلى الشبكة افتراضيًا.

- `network.allowedDomains` - مصفوفة من النطاقات المسموح بها (تدعم أحرف البدل مثل `*.example.com`). مصفوفة فارغة = لا وصول للشبكة. لاحقة `:port` الاختيارية (`api.example.com:443`، `*.example.com:8443`) تقيّد الإدخال بمنفذ الوجهة ذلك؛ الإدخالات بدون منفذ تطابق أي منفذ.
  - يجب وضع عناوين IPv6 الحرفية بين قوسين، بأسلوب RFC 3986: `[::1]`، `[2001:db8::1]:443`. يتم رفض الإدخال متعدد النقاط غير الموضوع بين قوسين باعتباره غامضًا (`2001:db8::1:443` هو بحد ذاته عنوان صالح).
- `network.deniedDomains` - مصفوفة من النطاقات المرفوضة (يتم فحصها أولاً، ولها الأولوية على allowedDomains). نفس لاحقة `:port`، ويُقبل `*` المجرد (أو `*:22`) لرفض الكل.
- `network.deniedDomainReasons` - خريطة اختيارية من إدخال `deniedDomains` (يُطابق بالسلسلة النصية الدقيقة) إلى سبب موجّه للنموذج يظهر في سطر `<sandbox_violations>` عندما يرفض ذلك الإدخال اتصالاً — اذكر ما هو محظور والبديل المصرّح به (مثل `{"github.com:22": "SSH pushes to GitHub are blocked; use an https:// remote"}`). الإدخالات بدون سبب تُبلّغ عن سبب عام. بالنسبة لوجهات SSH (المنفذ 22)، يُسلَّم السبب أيضًا داخل النطاق: عميل SSH الذي يمر عبر نفق SOCKS ProxyCommand بدون مصادقة (مثل BSD `nc -X 5`) يتلقى قطع اتصال SSH قبل تبادل المفاتيح يكون وصفه هو السبب، وهو ما يطبعه OpenSSH حرفيًا — أبقِ هذه الأسباب أقل من ~400 حرف ASCII، بصيغة الأمر أولاً، لأن OpenSSH يقتطع ويُهرّب الأحرف غير ASCII.
- `network.allowLocalBinding` - السماح بالارتباط بالمنافذ المحلية (قيمة منطقية، الافتراضي: false)

**فحص العنوان المُحلَّل.** تطابق قوائم السماح/الرفض حسب _الاسم_، لكن من يتحكم في DNS لاسم مسموح به (أو أي تسمية تحت حرف بدل مسموح) يتحكم في ما يُحلّ إليه. لذلك قبل الاتصال بمضيف **اسم نطاق** مسموح به مباشرةً، يحلّه الوكيل مرة واحدة، ويُسقط أي عنوان في مجموعة مرفوضة، ويتصل بعنوان ناجٍ (العنوان الذي اجتاز الفحص هو الذي يتم الاتصال به — لا يوجد بحث ثانٍ). إذا لم ينجُ شيء، يُرفض الاتصال مثل أي رفض سياسة آخر: HTTP/CONNECT يحصلان على `403` (`X-Proxy-Error: blocked-by-sandbox-runtime`، والسبب في المتن)، وSOCKS يحصل على "connection not allowed by ruleset"، ويُسجَّل سطر `deny network-outbound host:port (resolved to a loopback address)` — يسمّي فئة العنوان (loopback، link-local، هذا المضيف، بيانات وصفية سحابية، مُدرج في قائمة الرفض، مُدرج، …)، وليس العنوان نفسه، الذي لا يحمله إلا سجل التصحيح — في مخزن الانتهاكات.

المجموعة المرفوضة هي: loopback (`127.0.0.0/8`، `::1`)، غير محدد (`0.0.0.0/8`، `::`)، link-local (`169.254.0.0/16`، `fe80::/10`)، multicast (`224.0.0.0/4`، `ff00::/8`)، broadcast، ونقاط نهاية البيانات الوصفية لمثيل السحابة / المنصة التي تقع خارج link-local (`100.100.100.200`، `168.63.129.16`، `192.0.0.192`، `fd00:ec2::/32`، `fd20:ce::254`، `fd00:c1::a9fe:a9fe`، `fd00:42::42`)، وكل عنوان مُعيَّن حاليًا لأحد واجهات الشبكة الخاصة بهذا المضيف (خدمة مرتبطة بـ `0.0.0.0` تستجيب على LAN أو العنوان العام تمامًا كما تفعل على loopback)، وكل عنوان IP حرفي مُدرج في `deniedDomains` (مع مراعاة `:port` الخاص به إن وُجد)، وأي شيء في `deniedResolvedAddresses`. تطابق إدخالات IPv4 أيضًا صيغ IPv6 التي تحمل عنوان IPv4 — العناوين المُعيَّنة لـ IPv4 والمتوافقة مع IPv4 والمُترجَمة من IPv4، وبادئة NAT64 المعروفة (`64:ff9b::/96`) و6to4 (`2002::/16`) تُحكَم بعنوان IPv4 الذي تُضمّنه. بادئة NAT64 للاستخدام المحلي `64:ff9b:1::/48` والبادئات الخاصة بالشبكة لا تُفكّ شفرتها — تخطيطها (يسمح RFC 6052 بوجود IPv4 في عدة مواضع) لا يمكن التعرف عليه من العنوان وحده؛ على مثل هذه الشبكة، أدرج ترجمات البادئة للنطاقات التي ترفضها (مثل `<prefix>::a00:0/104` لـ `10.0.0.0/8`). العناوين التي تصل إلى هذا المضيف دون أن تُعيَّن له — العنوان العام 1:1-NAT لمثيل سحابي، أو إعادة توجيه منفذ من موجّه، أو اسم مستعار لبوابة مضيف حاوية أو جهاز افتراضي — غير مشمولة تلقائيًا؛ أدرجها في `deniedResolvedAddresses`.

ما يتركه الفحص دون مساس: إدخالات قائمة السماح التي **هي** عناوين IP حرفية (إدراج `127.0.0.1:3000` في قائمة السماح هو خيار صريح) — وبالمثل، قد يُحلّ اسم نطاق إلى عنوان مرفوض لولا ذلك عندما يكون ذلك العنوان الحرفي (على ذلك المنفذ) نفسه في `allowedDomains`، لأن الوصول إليه بالاسم لا يمنح شيئًا لا يمنحه الإدخال الحرفي (لا يزال عنوان IP حرفي في `deniedDomains` يفوز، تمامًا كما يفعل لطلب حرفي). لذا فإن إعداد تطوير حيث يُعيَّن `myapp.test` إلى خادم محلي عبر `/etc/hosts` يُدرج في قائمة السماح `["myapp.test", "127.0.0.1:3000"]`؛ لا توجد قائمة استثناء منفصلة. يُحلّ `localhost` والأسماء تحت `.localhost` إلى loopback (أو عنوان حرفي مُدرج في قائمة السماح) ولا شيء آخر. لا يُقيَّم الفحص للاتصالات الموجّهة عبر `parentProxy` (بما في ذلك واحد يُلتقط من `HTTP_PROXY` / `HTTPS_PROXY` في بيئة srt نفسها) أو `mitmProxy` — تلك القفزة تحلّ الاسم وتملك سياسة العناوين الخاصة بها — وهو يحكم فقط ما يتصل به الوكيل: على macOS، يسمح `allowLocalBinding` بشكل منفصل للعملية المعزولة بالاتصال بمنافذ loopback دون المرور عبر الوكيل على الإطلاق.

- `network.deniedResolvedAddresses` - عناوين IP إضافية / نطاقات CIDR (IPv4 أو IPv6، بدون أقواس، أي منفذ) يجب ألا تُحلّ إليها أسماء المضيفين المسموح بها. لا يُرفض نطاق الاستخدام الخاص افتراضيًا لأن إدراج اسم مضيف شبكة داخلية في قائمة السماح مشروع؛ أدرجه هنا عندما يجب أن تبقى الأسماء المُدرجة في قائمة السماح خارجه، مثل `["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "100.64.0.0/10", "fc00::/7"]`. أدرج نطاقات IPv4 وIPv6 بشكل منفصل — نطاق IPv6 واسع بما يكفي لتغطية كتلة IPv4 المُعيَّنة (`::ffff:0:0/96`)، مثل `::/0`، يطابق إجابات IPv4 على بعض بيئات التشغيل دون غيرها، لذا لا تعتمد عليه لرفض IPv4.

**إنهاء TLS** (`network.tlsTerminate`، تجريبي): عند تعيينه، تُنهى اتصالات HTTPS CONNECT داخل العملية حتى يتمكن SRT من رؤية الطلبات المفكوكة (وتصفيتها، عبر `network.filterRequest`). تُوجَّه العملية المعزولة إلى حزمة ثقة تحتوي على شهادة MITM CA (`caCertPath`/`caKeyPath`، أو شهادة CA مؤقتة إن حُذفت) بالإضافة إلى الجذور العادية للمضيف، بحيث تتحقق كل من الشهادات المُصدَرة من الوكيل والشهادات الحقيقية من المصدر الأعلى.

- `network.tlsTerminate.excludeDomains` - أنماط النطاقات (نفس صيغة `allowedDomains`) التي **لا** تُنهى. اتصالات CONNECT المطابقة تُنفَّق بشكل معتم بدلاً من ذلك: لا تزال خاضعة لقائمة النطاقات المسموح بها، لكن العميل داخل العازل يكمل مصافحة TLS الخاصة به مع المصدر الأعلى الحقيقي، ولا ينطبق `filterRequest` / حقن بيانات الاعتماد على حركة HTTPS الخاصة بها. استخدم هذا للحالتين اللتين يكسر إنهاء TLS فيهما بشكل جوهري:
  - **مصادر mTLS الأعلى** - فقط العميل داخل العازل يحمل شهادة العميل، لذا لا يمكن للوكيل إعادة إنشاء الاتصال نيابة عنه.
  - **عملاء تثبيت الشهادات** - العملاء الذين يتحققون من هوية المصدر الأعلى بأنفسهم (شهادات CA مخصصة، تثبيت SAN) ويرفضون شهادة MITM.
- `network.tlsTerminate.extraCaCertPaths` - مسارات ملفات شهادات CA بصيغة PEM التي تُضاف إلى حزمة الثقة تلك، بعد MITM CA وجذور المضيف العادية. يتم التحقق من المضيفين المستثنين (غير المُنهَين) بواسطة العميل داخل العازل، ومتغيرات بيئة الثقة التي يعيّنها SRT (`SSL_CERT_FILE`، `GIT_SSL_CAINFO`، ...) _تستبدل_ تهيئة الثقة الخاصة بكل أداة، لذا يجب أن يكون جذر الموقع المحلي (مثل CA داخلي لـ mTLS) في الحزمة وإلا لا يمكن التحقق من هؤلاء المضيفين أبدًا. تُنسخ فقط كتل `CERTIFICATE` من كل ملف إلى الحزمة (أي شيء آخر، مثل مفتاح خاص في PEM مدمج، لا يُعرَّض أبدًا للعازل)؛ الملفات المفقودة أو غير القابلة للقراءة أو التي لا تحتوي على كتلة `CERTIFICATE` بصيغة PEM تُتخطى، لذا من الآمن إدراج مسارات موجودة على بعض المضيفين فقط.```json
{
  "network": {
    "allowedDomains": ["*.example.com", "internal-mtls.example.net"],
    "deniedDomains": [],
    "tlsTerminate": {
      "excludeDomains": ["internal-mtls.example.net"],
      "extraCaCertPaths": ["/etc/internal-mtls-roots.pem"]
    }
  }
}

إعدادات Unix Socket (سلوك خاص بكل منصة):

الإعدادmacOSLinux
allowUnixSockets: string[]قائمة مسارات sockets المسموح بهايُتجاهل (لا يمكن لـ seccomp التصفية حسب المسار)
allowAllUnixSockets: booleanالسماح بجميع socketsتعطيل حظر seccomp

يتم حظر Unix sockets افتراضيًا على كلتا المنصتين.

  • macOS: استخدم allowUnixSockets للسماح بمسارات محددة (مثل ["/var/run/docker.sock"])، أو allowAllUnixSockets: true للسماح بالجميع.
  • Linux: يستخدم الحظر مرشحات seccomp (x64/arm64 فقط). إذا لم يكن seccomp متاحًا، تكون sockets غير مقيّدة ويظهر تحذير. استخدم allowAllUnixSockets: true لتعطيل الحظر صراحةً.

إعداد نظام الملفات

يستخدم نمطين مختلفين:

قيود القراءة (نمط المنع-ثم-السماح) - جميع عمليات القراءة مسموح بها افتراضيًا:

  • filesystem.denyRead - مصفوفة من المسارات لمنع الوصول للقراءة. مصفوفة فارغة = وصول كامل للقراءة.
  • filesystem.allowRead - مصفوفة من المسارات لإعادة السماح بالوصول للقراءة ضمن المناطق الممنوعة (لها الأولوية على denyRead). ملاحظة: هذا عكس الكتابة، حيث denyWrite لها الأولوية على allowWrite.

قيود الكتابة (نمط السماح فقط) - جميع عمليات الكتابة ممنوعة افتراضيًا:

  • filesystem.allowWrite - مصفوفة من المسارات للسماح بالوصول للكتابة. مصفوفة فارغة = لا وصول للكتابة.
  • filesystem.denyWrite - مصفوفة من المسارات لمنع الوصول للكتابة ضمن المسارات المسموح بها (لها الأولوية على allowWrite)

صيغة المسار (macOS):

تدعم المسارات أنماط glob بنمط git على macOS، مشابهة لصيغة .gitignore:

  • * - يطابق أي أحرف باستثناء / (مثل *.ts يطابق foo.ts ولكن ليس foo/bar.ts)
  • ** - يطابق أي أحرف بما في ذلك / (مثل src/**/*.ts يطابق جميع ملفات .ts في src/)
  • ? - يطابق أي حرف واحد باستثناء / (مثل file?.txt يطابق file1.txt)
  • [abc] - يطابق أي حرف في المجموعة (مثل file[0-9].txt يطابق file3.txt)

أمثلة:

  • "allowWrite": ["src/"] - السماح بالكتابة في دليل src/ بالكامل
  • "allowWrite": ["src/**/*.ts"] - السماح بالكتابة في جميع ملفات .ts في src/ والأدلة الفرعية
  • "denyRead": ["~/.ssh"] - منع القراءة من دليل SSH
  • "denyRead": ["/Users"], "allowRead": ["."] - منع القراءة من كل /Users، ولكن إعادة السماح بالدليل الحالي
  • "denyWrite": [".env"] - منع الكتابة في ملف .env (حتى لو كان الدليل الحالي مسموحًا به)

صيغة المسار (Linux):

لا يدعم Linux حاليًا مطابقة glob. استخدم المسارات الحرفية فقط:

  • "allowWrite": ["src/"] - السماح بالكتابة في دليل src/
  • "denyRead": ["/home/user/.ssh"] - منع القراءة من دليل SSH
  • "denyRead": ["/home"], "allowRead": ["."] - منع القراءة من كل /home، ولكن إعادة السماح بالدليل الحالي

جميع المنصات:

  • يمكن أن تكون المسارات مطلقة (مثل /home/user/.ssh) أو نسبية إلى دليل العمل الحالي (مثل ./src)
  • يتم توسيع ~ إلى دليل المستخدم الرئيسي

إعدادات أخرى

  • ignoreViolations - كائن يربط أنماط الأوامر بمصفوفات من المسارات حيث يجب تجاهل الانتهاكات
  • enableWeakerNestedSandbox - تمكين وضع sandbox أضعف لبيئات Docker (قيمة منطقية، الافتراضي: false)
  • javaAgentJarPath - macOS/Linux: مسار مطلق إلى srt-proxy-agent.jar، وكيل JVM المحقون عبر JAVA_TOOL_OPTIONS (انظر "أدوات JVM" ضمن عزل الشبكة). مطلوب فقط من قبل المستهلكين الذين يضمّنون sandbox-runtime ويشحنون الـ jar بشكل منفصل؛ تثبيت npm العادي يجده تحت vendor/java-proxy-agent/.
  • enableWeakerNetworkIsolation - السماح بالوصول إلى com.apple.trustd.agent في sandbox الخاص بـ macOS (قيمة منطقية، الافتراضي: false). هذا مطلوب لبرامج Go (gh، gcloud، terraform، kubectl، إلخ) للتحقق من شهادات TLS عند استخدام httpProxyPort مع وكيل MITM وشهادة CA مخصصة. تحذير أمني: تمكين هذا يفتح ناقلًا محتملًا لتسريب البيانات عبر خدمة trustd.
  • allowAppleEvents - السماح بإرسال Apple Events وطلبات فتح Launch Services من sandbox الخاص بـ macOS (قيمة منطقية، الافتراضي: false). بدون هذا، تفشل أوامر مثل open وosascript وأي شيء يفتح عناوين URL أو يشغّل تطبيقات أخرى عبر AppleScript بخطأ AppleScript -600 ("Application isn't running") أو أخطاء LaunchServices (-10822، -54). تحذير أمني: تمكين هذا يعني أن sandbox لم يعد يوفر عزل تنفيذ الكود. يمكن لأمر داخل sandbox تشغيل تطبيقات أخرى عبر open دون مطالبة المستخدم، وأي شيء يشغّله يعمل خارج قيود نظام الملفات والشبكة الخاصة بـ sandbox؛ كما أن كتابة سكربتات للتطبيقات قيد التشغيل بالفعل عبر Apple Events تخضع أيضًا لموافقة أتمتة TCC لكل تطبيق الخاصة بالمستخدم. يجب على المضمّنين أخذ هذا الخيار فقط من إعدادات موثوقة على مستوى المستخدم — وليس أبدًا من ملفات محلية للمشروع في مستودع مستنسخ، مما قد يسمح لمشروع من تأليف مهاجم برفع أذونات sandbox الخاصة به.

وصفات الإعداد الشائعة

السماح بالوصول إلى GitHub (جميع نقاط النهاية الضرورية):```json { "network": { "allowedDomains": [ "github.com", "*.github.com", "lfs.github.com", "api.github.com" ], "deniedDomains": [] }, "filesystem": { "denyRead": [], "allowWrite": ["."], "denyWrite": [] } }

**التقييد بمجلدات محددة:**```json
{
  "network": {
    "allowedDomains": [],
    "deniedDomains": []
  },
  "filesystem": {
    "denyRead": ["~/.ssh"],
    "allowWrite": [".", "src/", "test/"],
    "denyWrite": [".env", "secrets/"]
  }
}

الوصول إلى نظام الملفات داخل مساحة العمل فقط (رفض القراءة خارج مساحة العمل):```json { "network": { "allowedDomains": [], "deniedDomains": [] }, "filesystem": { "denyRead": ["/Users"], "allowRead": ["."], "allowWrite": ["."], "denyWrite": [] } }

هذا يمنع قراءة أي شيء تحت `/Users` (أو `/home` على Linux)، ثم يعيد السماح بمجلد العمل الحالي. تبقى مسارات النظام (`/usr`، `/lib`، إلخ) قابلة للقراءة.

### المشكلات الشائعة والنصائح

**تشغيل Jest:** استخدم علامة `--no-watchman` لتجنب انتهاكات الـ sandbox:```bash
srt "jest --no-watchman"

يتجاوز Watchman حدود بيئة العزل للوصول إلى الملفات، مما يؤدي إلى أخطاء في الأذونات. يؤدي تعطيله إلى تمكين Jest من العمل باستخدام مراقب الملفات المدمج بدلاً من ذلك.

دعم المنصات

  • macOS: يستخدم sandbox-exec مع ملفات تعريف مخصصة (بدون تبعيات إضافية)
  • Linux: يستخدم bubblewrap (bwrap) للحاويات
  • Windows: نسخة ألفا — يستخدم أداة مساعدة مرفقة srt-win.exe (بدون تبعيات إضافية). راجع Windows (alpha) أدناه للإعداد ونموذج الأمان والقيود المعروفة

التبعيات الخاصة بكل منصة

يتطلب Linux:

  • bubblewrap - بيئة تشغيل الحاويات
    • Ubuntu/Debian: apt-get install bubblewrap
    • Fedora: dnf install bubblewrap
    • Arch: pacman -S bubblewrap
  • socat - مرحّل المقابس لجسر الوكيل
    • Ubuntu/Debian: apt-get install socat
    • Fedora: dnf install socat
    • Arch: pacman -S socat
  • ripgrep - أداة بحث سريعة لكشف مسارات المنع
    • Ubuntu/Debian: apt-get install ripgrep
    • Fedora: dnf install ripgrep
    • Arch: pacman -S ripgrep

ملاحظة Ubuntu 24.04+: تُفعّل هذه الإصدارات kernel.apparmor_restrict_unprivileged_userns افتراضيًا، مما يسمح بـ unshare(CLONE_NEWUSER) لكنه يزيل القدرات من مساحة الأسماء الناتجة. يحتاج كل من bubblewrap وطبقة عزل seccomp إلى مساحات أسماء مستخدمين تحمل قدرات. عطّل القيد باستخدام:```bash sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0

أو أضف ملف تعريف AppArmor يمنح `userns` للملفات التنفيذية ذات الصلة.

**تبعيات Linux الاختيارية (لاحتياطي seccomp):**

تتضمن الحزمة مرشحات seccomp BPF مُنشأة مسبقًا لمعماريات x86-64 وarm. لا تكون هذه التبعيات مطلوبة إلا إذا كنت تستخدم معمارية مختلفة لا تتوفر فيها المرشحات المُنشأة مسبقًا:

- `gcc` أو `clang` - مترجم C
- `libseccomp-dev` - ملفات تطوير مكتبة Seccomp
  - Ubuntu/Debian: `apt-get install gcc libseccomp-dev`
  - Fedora: `dnf install gcc libseccomp-devel`
  - Arch: `pacman -S gcc libseccomp`

**يتطلب macOS:**

- `ripgrep` - أداة بحث سريعة لاكتشاف مسارات المنع
  - التثبيت عبر Homebrew: `brew install ripgrep`
  - أو التنزيل من: https://github.com/BurntSushi/ripgrep/releases

**يتطلب Windows:**

- لا توجد تبعيات إضافية. أداة المساعدة `srt-win.exe` (x64 وarm64) مضمنة مع حزمة npm. مطلوب خطوة `windows-install` واحدة بصلاحيات مرتفعة — انظر أدناه.

## Windows (ألفا)

دعم Windows في مرحلة **ألفا**. تعمل العملية المعزولة تحت حساب مستخدم محلي مخصص `srt-sandbox`، معزول عن المستخدم المستدعي بواسطة بدائيات الأمان الأصلية في Windows — سياج خروج Windows Filtering Platform (WFP) مرتبط بـ SID حساب العزل، وACEs صريحة لكل جلسة تمنح أو تمنع ذلك SID من الوصول إلى مسارات نظام الملفات المُهيأة.

### الإعداد

شغّل مرة واحدة لكل جهاز (يرفع الصلاحيات تلقائيًا؛ مطالبة UAC واحدة):```powershell
npx @anthropic-ai/sandbox-runtime windows-install

يقوم هذا بتجهيز حساب المستخدم المحلي srt-sandbox (مع كلمة مرور عشوائية مخزّنة مشفّرة بـ DPAPI في HKLM\SOFTWARE\sandbox-runtime — على مستوى الجهاز، بحيث تعمل عمليات التثبيت على مستوى الأسطول التي تعمل بصلاحيات SYSTEM، ويؤدي تدوير كلمة مرور أحد المستخدمين إلى تحديث النسخة التي يقرأها الآخرون)، ومجموعة sandbox-runtime-users المحلية، ويثبّت مجموعة مرشّحات WFP على مستوى الجهاز مرتبطة بـ SID الخاص بـ srt-sandbox. وهو idempotent — فإعادة تشغيله تدوّر كلمة مرور حساب العزل وتوفّق مجموعة المرشّحات.

لا يلزم تسجيل الخروج. ترتبط مرشّحات WFP بـ SID الخاص بحساب العزل المخصّص، لذا تبقى شبكتك الخاصة وخدماتك وكل أصل آخر على الجهاز غير متأثرة.

بعد التثبيت، يعمل SandboxManager.initialize() وواجهة srt CLI كما هو الحال على المنصات الأخرى. يتحقق initialize() من أن حساب العزل وسياج WFP فعّالان، ويفشل بخطأ قابل للتنفيذ إن لم يكن كذلك.

يُصدَّر التثبيت/إلغاء التثبيت البرمجي كـ installWindowsSandbox() / uninstallWindowsSandbox().

نموذج الأمان

يعمل الأمر المعزول بصفة حساب srt-sandbox، وليس بصفة المستخدم المستدعي. يقوم المساعد المضمّن srt-win.exe بإطلاق من مرحلتين: يستدعي الوسيط CreateProcessWithLogonW لتشغيل مشغّل بصفة srt-sandbox، ويولّد المشغّل الهدف تحت رمز مميز مقيّد داخل كائن مهمة (job object). يرث الابن الملف الشخصي المعزول لحساب العزل (%USERPROFILE%، %TEMP%، HKCU) وبيئة جديدة مغطّاة فقط بـ PATH الخاص بالوسيط ومتغيرات الوسيط المولّدة.

يغلق التشغيل تحت SID مستخدم مميّز بنيويًا فئة الهروب عبر التوليد البديل (Task Scheduler، PROC_THREAD_ATTRIBUTE_PARENT_PROCESS على عملية مملوكة للوسيط، BITS، COM خارج العملية مع RunAs="Interactive User"): أي عملية ينجح الابن في توليدها خارج المسار المعتاد تظل تحمل SID الخاص بـ srt-sandbox، فتبقى خاضعة لسياج الخروج WFP وليس لها حقوق على ملفات المستخدم المستدعي.

عزل الشبكة هو مجموعة WFP من مرشّحين عند FWPM_LAYER_ALE_AUTH_CONNECT_V4/V6: PERMIT لوجهات loopback داخل نطاق منفذ الوسيط المُهيّأ (الافتراضي 60080–60089)، وBLOCK لأي اتصال يحمل رمزه المميز SID الخاص بـ srt-sandbox. لا تصل العملية المعزولة إلى الإنترنت إلا عبر وسيطات JS HTTP/SOCKS5 المستمعة في ذلك النطاق؛ وأي عملية تزيل بيئة الوسيط الخاصة بها وتتصل مباشرة تُحجب عند النواة.

عزل نظام الملفات يُفرض عبر قوائم ACL التقديرية لـ NTFS. لا يملك حساب srt-sandbox حقوقًا متأصّلة على ملفات المستخدم المستدعي، لذا عند initialize() يكتب العزل ACEs صريحة إضافية ووارثة لـ SID الخاص بـ srt-sandbox فقط — ولا يعيد أبدًا كتابة أو استبدال واصف الأمان الموجود لمسار ما:

  • filesystem.allowWrite → ACE من نوع ALLOW بقيمة MODIFY وارثة (READ|WRITE|EXECUTE|DELETE، مع حجب FILE_DELETE_CHILD). يمكن للعملية المعزولة إنشاء الملفات وتعديلها وحذفها داخل شجرة العمل؛ وحجب FILE_DELETE_CHILD عن المنح هو دفاع في العمق لأجل طوابع الرفض أدناه، وليس حارسًا على جذر الشجرة.
  • filesystem.allowRead → ACE من نوع ALLOW بقيمة READ|EXECUTE وارثة
  • filesystem.denyRead / filesystem.denyWrite → ACE من نوع DENY وارثة على الهدف، بالإضافة إلى DENY وارثة بقيمة FILE_DELETE_CHILD على أصله — ومع حجب FILE_DELETE_CHILD عن منح شجرة العمل، يمنع هذا العملية المعزولة من إعادة تسمية أو حذف مسار مرفوض عبر دليل أصله

يزيل reset() كل ACE أضافته هذه الجلسة (بعدّ مرجعي عبر المضيفين المتزامنين لهذا المستخدم عبر قاعدة بيانات الجلسة لكل مستخدم؛ وتنظّف مرحلة استرداد بعد الأعطال عند initialize() التالي بعد خروج غير نظيف). تُدعم أهداف الأدلة (ترث ACEs إلى الشجرة الفرعية بأكملها). تُوسَّع أنماط Glob إلى مسارات ملموسة عند وقت initialize() — والمسار المطابق الذي يظهر لاحقًا لا يكون مغطّى.

إنهاء TLS على Windows

يتطلب network.tlsTerminate وجود MITM CA في مخزن شهادات CurrentUser\Root الخاص بـ مستخدم العزل (schannel — الواجهة الخلفية لـ TLS المستخدمة بواسطة System32\curl.exe وPowerShell Invoke-WebRequest و.NET وgit بالواجهة الخلفية الافتراضية — تثق بمخزن نظام التشغيل فقط، وليس بمتغيرات البيئة). هذه خطوة وقت التثبيت، منفصلة عن windows-install:```typescript import { windowsTrustCa } from '@anthropic-ai/sandbox-runtime' windowsTrustCa('/path/to/mitm-ca.crt') // or: srt-win user trust-ca

يقارن `initialize()` بصمة CA الخاصة بالجلسة مع البصمة المثبّتة ويفشل برسالة قابلة للتنفيذ عند عدم التطابق، بحيث لا يمكن لـ CA قديمة من وقت التثبيت أن تكسر TLS بصمت داخل الـ sandbox.

عملاء OpenSSL المدعومون (msys2 `curl`، `git -c http.sslBackend=openssl`، Node، Python، cargo) مغطّون بطبقة الثقة عبر متغيرات البيئة: نفس حزمة الثقة المستخدمة على macOS/Linux تُمرَّر إلى الـ sandbox عبر `NODE_EXTRA_CA_CERTS`، `SSL_CERT_FILE`، `CURL_CA_BUNDLE`، `GIT_SSL_CAINFO`، `CARGO_HTTP_CAINFO`، إلخ، ويُضاف مسار الحزمة إلى منحة `allowRead` الخاصة بالجلسة حتى يتمكن حساب الـ sandbox من فتحها.

### إعدادات خاصة بـ Windows

تنطبق كتلتا `filesystem` و`network` العابرتان للمنصات كما هو موضح أعلاه. الإعدادات الخاصة بـ Windows فقط توجد تحت `windows`:

- `windows.proxyPortRange` — نطاق منافذ `[low, high]` شامل يربط داخله وكلاء JS. **يجب أن يطابق** النطاق المُمرَّر إلى `windows-install --proxy-port-range` (الافتراضي `[60080, 60089]`) — إذ يغطي PERMIT الخاص بـ WFP loopback ذلك النطاق فقط.
- `windows.sublayerGuid` — GUID الطبقة الفرعية لـ WFP التي ثُبِّتت تحتها المرشحات. احذفه لاستخدام الافتراضي وقت الترجمة؛ اضبطه فقط عندما ثبّتت أدوات المؤسسة المرشحات تحت طبقة فرعية مخصصة.
- `windows.srtWin.path` — مسار الملف التنفيذي `srt-win`. احذفه لحل `vendor/srt-win/<arch>/srt-win.exe` المُحزَّم. اضبطه عند تضمين CLI الخاص بـ `srt-win` في ملف تنفيذي متعدد الاستدعاءات؛ حينها تمرر عمليات spawn `--srt-win` كـ `argv[1]` حتى يتمكن موزّع المُضمِّن من التوجيه إلى `srt_win::run_from_args`.

### القيود المعروفة

- **إبطال الشهادات تحت schannel.** يخرج جلب CRL/OCSP الخاص بـ CryptoAPI عبر WinHTTP تحت رمز المستدعي، متجاهلًا بيئة الوكيل، لذا يُحظر بواسطة سياج الخروج WFP. تفشل الأدوات التي تستخدم schannel مع فحص الإبطال مُفعَّلًا افتراضيًا بـ `CRYPT_E_REVOCATION_OFFLINE` (`0x80092013`) ما لم يُعطَّل الإبطال لكل أداة: `curl --ssl-no-revoke`، `git -c http.schannelCheckRevoke=false`، `CARGO_HTTP_CHECK_REVOKE=false`. لا تفحص `Invoke-WebRequest` و.NET `HttpClient` و`gh` الإبطال افتراضيًا وهي غير متأثرة. من المخطط تقديم نقطة توزيع CRL من الوكيل loopback لإزالة هذا التحايل.
- **عمليات تثبيت الأدوات لكل مستخدم غير قابلة للوصول.** تعمل العملية داخل الـ sandbox باسم `srt-sandbox`، لا باسمك، لذا فإن الأدوات المثبّتة تحت ملفك الشخصي (Node المُدار بـ nvm/fnm، حزم `winget`/`Scoop` لكل مستخدم، `pip install --user`، `%LOCALAPPDATA%\Programs\…`) تُحلّ على `PATH` الموروث لكن لا يمكن لحساب الـ sandbox فتحها. فضّل التثبيتات على مستوى الجهاز (`Program Files`، `choco`/`winget --scope machine`)، أو أضف مسارات الملف الشخصي المحددة إلى `filesystem.allowRead`.
- **تجاوزات `filesystem.allowRead` / `filesystem.allowWrite` لكل تنفيذ غير مدعومة.** تعمل `allowRead`/`allowWrite` على مستوى الجلسة (في الإعداد المُمرَّر إلى `initialize()`) كما هو موضح أعلاه؛ أما تمريرها لكل أمر في `customConfig` الخاص بـ `wrapWithSandbox` فيُطلق خطأً — إذ تُطبَّق المنح على مستوى الجلسة عبر `srt-win acl grant` عند `initialize()`، ولا يعرض `srt-win exec` سوى عمليات الرفض لكل تنفيذ.
- **`proxyAuthToken` مرئي في سطر أوامر المشغّل.** تُمرَّر بيئة الوكيل (بما فيها `HTTP_PROXY=http://srt:<token>@127.0.0.1:…`) إلى مشغّل القفزتين كوسائط `--env` على argv الخاص بـ `srt-win exec`، لذا يكون الرمز قابلًا للقراءة من أي أصل محلي يمكنه فتح عملية المشغّل من أجل `PROCESS_QUERY_LIMITED_INFORMATION`. يوجد الرمز حتى تتمكن العملية داخل الـ sandbox من المصادقة على وكيل loopback، لذا فهو ليس سرًا عن الـ sandbox نفسه؛ على جهاز تطوير أحادي المستخدم يُعدّ هذا مقبولًا عمومًا، لكن على مضيف مشترك تعامل مع قائمة السماح للوكيل على أنها قابلة للوصول من أصول أخرى في نفس الجلسة.
- **حل DNS عبر محلّل النظام غير مسيّج.** تُخدَم `getaddrinfo()` بواسطة خدمة `Dnscache` العاملة باسم `NETWORK SERVICE`، لذا ينجح حل الأسماء رغم حظر `connect()` اللاحق من العملية داخل الـ sandbox. الأدوات التي تنفذ UDP/53 بنفسها (`nslookup`، `dig`) مسيّجة. هذا يحاكي سلوك macOS.

### إلغاء التثبيت```powershell
npx @anthropic-ai/sandbox-runtime windows-uninstall

يزيل مجموعة مرشحات WFP، وحساب srt-sandbox وملفه الشخصي، ومجموعة sandbox-runtime-users، ويزيل مفتاح HKLM\SOFTWARE\sandbox-runtime (بيانات الاعتماد، العلامة، سجل CA) — مطالبة UAC واحدة. يُترك %ProgramData%\sandbox-runtime (مادة مفتاح CA) في مكانه؛ احذفه (و %LOCALAPPDATA%\sandbox-runtime لكل مستخدم) يدويًا لإجراء مسح كامل.

التطوير```bash

Install dependencies

npm install

Build the project

npm run build

Run tests

npm test

Type checking

npm run typecheck

Lint code

npm run lint

Format code

npm run format

### بناء ثنائيات Seccomp

يتم تجميع مرشح BPF ومُحمِّل `apply-seccomp` من مصدر C في `vendor/seccomp-src/` عبر `npm run build:seccomp` (على Linux فقط؛ يتطلب `gcc` و`libseccomp-dev`). تشغّله CI قبل الاختبارات على كل معمارية Linux، وتقوم سير عمل الإصدار ببناء كلتا المعماريتين وتضمينهما في الحزمة المنشورة.

## تفاصيل التنفيذ

### معمارية عزل الشبكة

تشغّل بيئة العزل خوادم وكيل HTTP وSOCKS5 على الجهاز المضيف تُرشِّح جميع طلبات الشبكة بناءً على قواعد الأذونات:

1. **حركة HTTP/HTTPS**: يعترض خادم وكيل HTTP الطلبات ويتحقق منها مقابل النطاقات المسموح بها/المحظورة
2. **حركة الشبكة الأخرى**: يتعامل وكيل SOCKS5 مع جميع اتصالات TCP الأخرى (SSH، اتصالات قواعد البيانات، إلخ)
3. **فرض الأذونات**: تفرض الوكلاء قواعد `permissions` من إعداداتك

**التواصل مع الوكلاء الخاص بكل منصة:**

- **Linux**: تُوجَّه الطلبات عبر نظام الملفات من خلال مقابس نطاق Unix (باستخدام `socat` للجسر). تُزال مساحة أسماء الشبكة من حاوية bubblewrap، مما يضمن أن تمر جميع حركة الشبكة عبر الوكلاء.

- **macOS**: يسمح ملف تعريف Seatbelt بالتواصل فقط مع منافذ localhost محددة يستمع عليها الوكلاء. يُحظر كل وصول شبكي آخر.

- **Windows**: يحظر مرشح WFP `ALE_AUTH_CONNECT` كل اتصال صادر من حساب `srt-sandbox` باستثناء loopback إلى نطاق منافذ الوكيل المُهيَّأ. يرتبط الوكلاء داخل ذلك النطاق. تشير متغيرات البيئة (`HTTP_PROXY`، `HTTPS_PROXY`، `ALL_PROXY`، …) بالأدوات إلى الوكلاء، لكن مرشح WFP هو الحد الفاصل — فالعملية التي تتجاهلها أو تلغي تعيينها تظل محاصرة.

**أدوات JVM (macOS/Linux):** يتجاهل JVM متغيرات `HTTPS_PROXY`/`NO_PROXY` وليس لديه متغير بيئة لبيانات اعتماد الوكيل — يأتي اختيار الوكيل من خصائص النظام `https.proxyHost` ولا يمكن توفير بيانات الاعتماد إلا عبر `java.net.Authenticator`. لذا فإن الأدوات المبنية على JVM (ذاكرة gRPC البعيدة في Bazel، وGradle، وMaven، …) ستتصل بالهدف مباشرة وتفشل، أو تصل إلى الوكيل دون رمزه المميز وتتلقى 407. لسد هذه الفجوة، يحقن srt وكيل `-javaagent` صغيرًا عبر `JAVA_TOOL_OPTIONS` (يحمل متغير البيئة مسار jar فقط، وتبقى بيانات الاعتماد في `HTTPS_PROXY`). عند بدء JVM، يضبط الوكيل `http[s].proxyHost`/`Port` و`http.nonProxyHosts` من متغيرات بيئة الوكيل، ويعيد تمكين مصادقة Basic لنفقات CONNECT، ويثبّت Authenticator لنقطة نهاية الوكيل. لا تزال خصائص الوكيل الصريحة `-D` على سطر أوامر JVM هي الغالبة، ويُحتفظ بأي `JAVA_TOOL_OPTIONS` موروث (ما لم يكن متغير بيئة لبيانات اعتماد محظورة). ونتيجة لذلك، يطبع كل JVM سطر `Picked up JAVA_TOOL_OPTIONS: …` إلى stderr؛ ولا يمكن لبيئة تشغيل مبنية بـ jlink بدون وحدة `java.instrument` تحميل الوكلاء وسترفض البدء تحت بيئة العزل — ألغِ تعيين `JAVA_TOOL_OPTIONS` في الأمر لمثل هذه الأداة. تُشحن حزمة jar في حزمة npm باسم `vendor/java-proxy-agent/srt-proxy-agent.jar` (المصدر: `vendor/java-proxy-agent-src/`؛ يُبنى بواسطة سير عمل الإصدار، أو محليًا عبر `npm run build:java-agent` — يتطلب JDK ≥ 17). إذا لم يُعثر عليه، يُترك `JAVA_TOOL_OPTIONS` دون تغيير وتتصرف آلات JVM كما في السابق؛ ويمكن لمُجمِّعي الحزم الإشارة إلى نسختهم الخاصة عبر `javaAgentJarPath`.

### عزل نظام الملفات

تُفرض قيود نظام الملفات على مستوى نظام التشغيل:

- **macOS**: يستخدم `sandbox-exec` مع ملفات تعريف Seatbelt المُولَّدة ديناميكيًا التي تحدد مسارات القراءة/الكتابة المسموح بها
- **Linux**: يستخدم `bubblewrap` مع عمليات ربط (bind mounts)، ويضع علامة على الأدلة كقراءة فقط أو قراءة-كتابة بناءً على الإعدادات
- **Windows**: يكتب ACEs صريحة إضافية `(OI)(CI)` لمعرّف SID الخاص بـ `srt-sandbox` على المسارات المُهيَّأة (ALLOW على `allowRead`/`allowWrite`، وDENY على `denyRead`/`denyWrite`)، ثم يزيلها عند `reset()`

**أذونات نظام الملفات الافتراضية:**

- **القراءة** (منع-ثم-سماح): مسموح بها في كل مكان افتراضيًا. يمكنك منع مناطق واسعة، ثم إعادة السماح بمسارات محددة داخلها. `allowRead` لها الأولوية على `denyRead`.

  - مثال: `denyRead: ["~/.ssh"]` لحظر الوصول إلى مفاتيح SSH
  - مثال: `denyRead: ["/Users"], allowRead: ["."]` لحظر كل `/Users` باستثناء مساحة العمل
  - `denyRead: []` فارغة = وصول قراءة كامل (لا شيء محظور)

- **الكتابة** (سماح فقط): محظورة في كل مكان افتراضيًا. يجب عليك السماح بالمسارات صراحةً.
  - مثال: `allowWrite: [".", "/tmp"]` للسماح بالكتابة إلى الدليل الحالي و/tmp
  - `allowWrite: []` فارغة = لا وصول للكتابة (لا شيء مسموح)
  - `denyWrite` ينشئ استثناءات داخل المسارات المسموح بها (المنع له الأولوية)

**الأولوية معاكسة عمدًا بين القراءات والكتابات:** `allowRead` تتجاوز `denyRead`، بينما `denyWrite` تتجاوز `allowWrite`. يتيح لك ذلك اقتطاع مناطق قابلة للقراءة داخل المناطق المحظورة، واقتطاع مناطق محمية داخل المناطق القابلة للكتابة.

### مسارات المنع الإلزامية (الملفات المحمية تلقائيًا)

بعض الملفات والأدلة الحساسة **محظورة دائمًا من الكتابة**، حتى لو كانت ضمن مسار كتابة مسموح به. يوفر ذلك دفاعًا متعدد الطبقات ضد الهروب من بيئة العزل والتلاعب بالإعدادات.

**الملفات المحظورة دائمًا:**

- ملفات إعدادات الصدفة: `.bashrc`، `.bash_profile`، `.zshrc`، `.zprofile`، `.profile`
- ملفات إعدادات Git: `.gitconfig`، `.gitmodules`
- ملفات حساسة أخرى: `.ripgreprc`، `.mcp.json`

**الأدلة المحظورة دائمًا:**

- أدلة IDE: `.vscode/`، `.idea/`
- أدلة إعدادات Claude: `.claude/commands/`، `.claude/agents/`
- خطافات وإعدادات Git: `.git/hooks/`، `.git/config`

تُحظر هذه المسارات تلقائيًا - لا تحتاج إلى إضافتها إلى `denyWrite`. على سبيل المثال، حتى مع `allowWrite: ["."]`، ستفشل الكتابة إلى `.bashrc` أو `.git/hooks/pre-commit`:```bash
$ srt 'echo "malicious" >> .bashrc'
/bin/bash: .bashrc: Operation not permitted

$ srt 'echo "bad" > .git/hooks/pre-commit'
/bin/bash: .git/hooks/pre-commit: Operation not permitted

ملاحظة (Linux): على Linux، تحجب مسارات المنع الإلزامية فقط الملفات الموجودة بالفعل. لا يمكن حظر الملفات غير الموجودة ضمن هذه الأنماط بواسطة نهج الربط (bind-mount) الخاص بـ bubblewrap. يستخدم macOS أنماط glob التي تحجب الملفات الموجودة والجديدة معًا.

عمق البحث في Linux: على Linux، تستخدم البيئة المعزولة ripgrep لفحص الملفات الخطرة في الأدلة الفرعية ضمن مسارات الكتابة المسموح بها. افتراضيًا، تبحث حتى عمق 3 مستويات لتحسين الأداء. يمكنك تكوين ذلك باستخدام mandatoryDenySearchDepth:```json { "mandatoryDenySearchDepth": 5, "filesystem": { "allowWrite": ["."] } }

- الافتراضي: `3` (يبحث حتى 3 مستويات في العمق)
- النطاق: `1` إلى `10`
- القيم الأعلى توفر حماية أكبر لكن أداءً أبطأ
- الملفات في CWD (العمق 0) محمية دائمًا بغض النظر عن هذا الإعداد

### قيود Unix Socket (لينكس)

على لينكس، تستخدم البيئة المعزولة **seccomp BPF (Berkeley Packet Filter)** لحظر إنشاء Unix domain socket على مستوى استدعاء النظام. يوفر هذا طبقة أمان إضافية لمنع العمليات من إنشاء Unix domain sockets جديدة للاتصال المحلي بين العمليات (IPC) (ما لم يُسمح بذلك صراحةً).

**كيف يعمل:**

1. **مرشح BPF مدمج**: تشحن الحزمة ملفًا ثنائيًا ثابتًا `apply-seccomp` لمعماريتي x64 و arm64 مع ترجمة مرشح seccomp BPF داخله. المرشح خاص بالمعمارية لكنه مستقل عن libc، لذا يعمل الملف الثنائي مع كل من glibc و musl.

2. **الكشف عند التشغيل**: تكتشف البيئة المعزولة تلقائيًا معمارية نظامك وتستخدم ملف `apply-seccomp` الثنائي المطابق.

3. **تصفية استدعاءات النظام**: يعترض مرشح BPF استدعاء النظام `socket()` ويحظر إنشاء sockets من نوع `AF_UNIX` بإرجاع `EPERM`. يمنع هذا الكود المعزول من إنشاء Unix domain sockets جديدة.

4. **تطبيق على مرحلتين باستخدام ملف apply-seccomp الثنائي**:
   - ينشئ bwrap الخارجي البيئة المعزولة مع قيود نظام الملفات والشبكة ومساحة أسماء PID
   - تبدأ عمليات جسر الشبكة (socat) داخل البيئة المعزولة (تحتاج إلى Unix sockets)
   - ينشئ apply-seccomp مساحة أسماء متداخلة للمستخدم + PID + mount ويعيد تركيب `/proc`
   - داخل مساحة الأسماء المتداخلة، يعمل apply-seccomp كـ PID 1 (init/reaper غير قابل للتفريغ)
   - يتفرع apply-seccomp، ويطبق مرشح seccomp عبر `prctl()`، وينفذ أمر المستخدم
   - يعمل أمر المستخدم مع جميع قيود البيئة المعزولة بالإضافة إلى حظر إنشاء Unix socket

**عزل مساحة أسماء PID**: تضمن مساحة أسماء PID المتداخلة أن أمر المستخدم لا يمكنه رؤية أو مخاطبة أي عملية تعمل بدون مرشح seccomp (init الخاص بـ bwrap، أو غلاف shell، أو مساعدات socat). يحافظ هذا على سلامة حدود seccomp بغض النظر عن `kernel.yama.ptrace_scope`، لأن المساعدات غير المفلترة لا يمكن الوصول إليها عبر `ptrace` أو `/proc/N/mem`. يضبط PID 1 الداخلي `PR_SET_DUMPABLE=0` بحيث لا يكون قابلًا للـ ptrace أيضًا. إذا فشل إنشاء مساحة الأسماء المتداخلة، يجهض apply-seccomp بدلًا من العمل بدون عزل.

**قيود الأمان**: يحظر المرشح `socket(AF_UNIX, ...)` واستدعاءات النظام `io_uring_setup`/`io_uring_enter`/`io_uring_register` (الثلاثة الأخيرة لأن `IORING_OP_SOCKET` على لينكس 5.19+ كان سيتجاوز قاعدة `socket()` بخلاف ذلك). لا يمنع العمليات على واصفات ملفات Unix socket الموروثة من العمليات الأصلية أو الممررة عبر `SCM_RIGHTS`. في معظم سيناريوهات العزل، يكفي حظر إنشاء socket لمنع الاتصال غير المصرح به بين العمليات.

**صفر تبعيات عند التشغيل**: تُضمَّن ملفات apply-seccomp الثنائية الثابتة مسبقة البناء ومرشحات BPF المولدة مسبقًا لمعماريتي x64 و arm64. لا حاجة لأدوات ترجمة أو تبعيات خارجية عند التشغيل.

**دعم المعماريات**: معماريتا x64 و arm64 مدعومتان بالكامل بملفات ثنائية مسبقة البناء. المعماريات الأخرى غير مدعومة حاليًا. لاستخدام العزل بدون حظر Unix socket على المعماريات غير المدعومة، اضبط `allowAllUnixSockets: true` في إعداداتك.

### كشف الانتهاكات والمراقبة

عندما تحاول عملية معزولة الوصول إلى مورد مقيّد:

1. **يحظر العملية** على مستوى نظام التشغيل (يرجع خطأ `EPERM`)
2. **يسجل الانتهاك** (آليات خاصة بالمنصة)
3. **يخطر المستخدم** (في Claude Code، يؤدي هذا إلى طلب إذن)

**macOS**: يتصل وقت تشغيل البيئة المعزولة بمخزن سجل انتهاكات البيئة المعزولة في نظام macOS. يوفر هذا إشعارات فورية بمعلومات مفصلة حول ما تمت محاولته ولماذا تم حظره. هذه هي نفس الآلية التي يستخدمها Claude Code لكشف الانتهاكات.```bash
# View sandbox violations in real-time
log stream --predicate 'process == "sandbox-exec"' --style syslog

Linux: لا يوفر Bubblewrap تقارير مدمجة عن الانتهاكات. استخدم strace لتتبع استدعاءات النظام وتحديد العمليات المحظورة:```bash

Trace all denied operations

strace -f srt 2>&1 | grep EPERM

Trace specific file operations

strace -f -e trace=open,openat,stat,access srt 2>&1 | grep EPERM

Trace network operations

strace -f -e trace=network srt 2>&1 | grep EPERM

### متقدم: أحضر وكيلك الخاص

لتصفية شبكة أكثر تطوراً، يمكنك تكوين البيئة المعزولة لاستخدام وكيلك الخاص بدلاً من الوكلاء المدمجين. يتيح ذلك:

- **فحص حركة المرور**: استخدم أدوات مثل [mitmproxy](https://mitmproxy.org/) لفحص حركة المرور وتعديلها
- **منطق تصفية مخصص**: نفّذ قواعد معقدة تتجاوز قوائم النطاقات المسموح بها البسيطة
- **تسجيل التدقيق**: سجّل جميع طلبات الشبكة للامتثال أو لتصحيح الأخطاء

**مثال مع mitmproxy:**```bash
# Start mitmproxy with custom filtering script
mitmproxy -s custom_filter.py --listen-port 8888

ملاحظة: لم يتم بعد دعم تكوين الوكيل المخصص في تنسيق التكوين الجديد. ستُضاف هذه الميزة في إصدار مستقبلي.

اعتبار أمني مهم: حتى مع قوائم النطاقات المسموح بها، قد توجد نواقل تسريب. على سبيل المثال، السماح بـ github.com يتيح لعملية ما الدفع إلى أي مستودع. باستخدام وكيل MITM مخصص وإعداد شهادات مناسب، يمكنك فحص وتصفية استدعاءات API محددة لمنع ذلك.

قيود الأمان

  • قيود عزل الشبكة: يعمل نظام تصفية الشبكة عن طريق تقييد النطاقات المسموح للعمليات بالاتصال بها. وهو لا يفحص بخلاف ذلك حركة المرور المارة عبر الوكيل، ويتحمل المستخدمون مسؤولية ضمان أنهم يسمحون فقط بالنطاقات الموثوقة في سياستهم. كما يتم فحص أسماء المضيفين المسموح بها مقابل مجموعة مرفوضة من العناوين المُحلَّلة قبل الاتصال المباشر (انظر فحص العنوان المُحلَّل أعلاه)، لذا لا يمكن توجيه اسم مسموح به إلى loopback أو link-local أو عناوين هذا المضيف نفسه أو عنوان IP أدرجته في deniedDomains؛ أما النطاقات الخاصة الأخرى فلا تُغطى إلا إذا أدرجتها في deniedResolvedAddresses (وإلا فقد يُوجَّه إدخال بادئة شاملة على نطاق لا تتحكم في DNS الخاص به نحو خدمات على شبكتك المحلية)، وتعتمد الاتصالات التي تخرج عبر parentProxy/mitmProxy على تلك القفزة لإجراء الفحص المكافئ.
ينبغي أن يكون المستخدمون على دراية بالمخاطر المحتملة الناشئة عن السماح بنطاقات واسعة مثل `github.com` التي قد تتيح تسريب البيانات. كذلك، في بعض الحالات قد يكون من الممكن تجاوز تصفية الشبكة عبر [domain fronting](https://en.wikipedia.org/wiki/Domain_fronting).
  • تصعيد الامتيازات عبر Unix Sockets: قد يمنح تكوين allowUnixSockets عن غير قصد وصولاً إلى خدمات نظام قوية قد يؤدي إلى تجاوزات في العزل. على سبيل المثال، إذا استُخدم للسماح بالوصول إلى /var/run/docker.sock فسيؤدي ذلك فعلياً إلى منح وصول إلى نظام المضيف عبر استغلال docker socket. يُشجَّع المستخدمون على النظر بعناية في أي unix sockets يسمحون بها عبر العزل.
  • تصعيد أذونات نظام الملفات: قد تتيح أذونات الكتابة الواسعة المفرطة في نظام الملفات هجمات تصعيد الامتيازات. السماح بالكتابة إلى أدلة تحتوي على ملفات تنفيذية في $PATH، أو أدلة تكوين النظام، أو ملفات تكوين shell للمستخدم (.bashrc، .zshrc) قد يؤدي إلى تنفيذ شيفرة في سياقات أمنية مختلفة عندما تصل مستخدمون آخرون أو عمليات نظام إلى هذه الملفات.
  • قوة العزل على Linux: يوفر تنفيذ Linux عزلاً قوياً لنظام الملفات والشبكة لكنه يتضمن وضع enableWeakerNestedSandbox الذي يمكّنه من العمل داخل بيئات Docker دون namespaces مميزة. هذا الخيار يُضعف الأمان بشكل كبير وينبغي استخدامه فقط في الحالات التي يُفرض فيها عزل إضافي بخلاف ذلك.
  • عزل شبكة أضعف (macOS): يعيد خيار enableWeakerNetworkIsolation تمكين الوصول إلى com.apple.trustd.agent، وهو مطلوب لبرامج Go للتحقق من شهادات TLS عبر إطار عمل Security في macOS. يفتح هذا ناقل تسريب بيانات محتمل عبر خدمة trustd وينبغي تمكينه فقط عند الحاجة إلى تحقق Go TLS (مثلاً عند استخدام httpProxyPort مع وكيل MITM و CA مخصص).
  • Apple Events (macOS): يعيد خيار allowAppleEvents تمكين إرسال Apple Events وطلبات فتح Launch Services ((allow appleevent-send)، (allow lsopen)، وmach-lookups لـ com.apple.coreservices.appleevents، com.apple.CoreServices.coreservicesd، وcom.apple.coreservices.quarantine-resolver)، وهي مطلوبة لـ open وosascript ومساعدات فتح URL. مع السماح بهذه، يمكن لأمر معزول تشغيل تطبيقات عشوائية دون أي مطالبة للمستخدم، والتطبيقات المُشغَّلة تعمل خارج العزل بالكامل — لذا يزيل هذا الخيار عزل تنفيذ الشيفرة، وليس مجرد إضعافه. كما أن كتابة سكربتات لتطبيقات قيد التشغيل بالفعل عبر Apple Events مقيّدة إضافياً بموافقة أتمتة TCC في macOS، لكن التشغيل عبر open ليس كذلك. لا تمكّن هذا إلا عندما تحتاج الأوامر داخل العزل فعلاً إلى فتح URLs أو تطبيقات.

القيود المعروفة والعمل المستقبلي

تجاوز الوكيل على Linux: يستخدم حالياً متغيرات البيئة (HTTP_PROXY، HTTPS_PROXY، ALL_PROXY) لتوجيه حركة المرور عبر الوكلاء. يعمل هذا مع معظم التطبيقات لكن قد تتجاهله برامج لا تحترم هذه المتغيرات، مما يؤدي إلى عدم قدرتها على الاتصال بالإنترنت.

تحسينات مستقبلية:

  • دعم Proxychains: إضافة دعم لـ proxychains مع LD_PRELOAD على Linux لاعتراض استدعاءات الشبكة على مستوى أدنى، مما يجعل التجاوز أكثر صعوبة

  • مراقبة الانتهاكات على Linux: تنفيذ كشف تلقائي للانتهاكات قائم على strace لـ Linux، مدمج مع مخزن الانتهاكات. حالياً، يجب على مستخدمي Linux تشغيل strace يدوياً لرؤية الانتهاكات، بخلاف macOS الذي يمتلك مراقبة تلقائية للانتهاكات عبر مخزن سجل النظام

الفئات