
صندوق رمل صغير VM مؤقت لوكلاء الذكاء الاصطناعي مع قائمة السماح بالشبكة، وحقن الأسرار عبر وكيل MITM، وعزل على مستوى VM. يتم التشغيل في أقل من ثانية، ويدعم SDKs لـ Go/Python/TypeScript.
تجريبي: هذا المشروع لا يزال في مرحلة التطوير النشط وقد يتعرض لتغييرات جذرية.
Matchlock هي أداة سطر أوامر لتشغيل وكلاء الذكاء الاصطناعي في أجهزة افتراضية صغيرة عابرة - مع قائمة السماح بالشبكة، حقن الأسرار عبر وكيل MITM، وعزل على مستوى الجهاز الظاهري. أسرارك لا تدخل أبدًا إلى الجهاز الظاهري.
يحتاج وكلاء الذكاء الاصطناعي إلى تشغيل الكود، لكن منحهم وصولًا غير مقيد إلى جهازك يمثل مخاطرة. Matchlock يتيح لك تسليم الوكيل بيئة لينكس كاملة يتم تشغيلها في أقل من ثانية - معزولة وقابلة للتخلص.
عند تمرير --allow-host أو --secret، يقوم Matchlock بإغلاق الشبكة - فقط حركة المرور إلى المضيفين المسموح لهم صراحة تمر، ويتم حظر كل شيء آخر. عندما يقوم وكيلك باستدعاء API، يتم حقن بيانات الاعتماد الحقيقية في الوقت الفعلي بواسطة المضيف. الصندوق الرمل لا يرى أبدًا سوى عنصر نائب. حتى إذا تم خداع الوكيل لتشغيل شيء ضار، فإن مفاتيحك لا تتسرب ولا يوجد مكان لتذهب إليه البيانات. في الداخل، يحصل الوكيل على بيئة لينكس كاملة ليفعل ما يحتاج إليه. يمكنه تثبيت الحزم وكتابة الملفات وإحداث الفوضى. في الخارج، جهازك لا يشعر بشيء. تركيبات التحميل المتداخل للحجم هي لقطات معزولة تختفي عند الانتهاء. نفس واجهة سطر الأوامر ونفس السلوك سواء كنت على خادم لينكس أو ماك بوك.
انظر docs/install.md للحصول على تفاصيل التثبيت الكاملة.
تثبيت سريع
البرنامج النصي أدناه يكتشف نظام التشغيل، ويقوم بتثبيت matchlock باستخدام Homebrew على macOS، و rpm/deb على توزيعات لينكس المبنية على Debian/RHEL
curl -fsSL https://raw.githubusercontent.com/jingkaihe/matchlock/main/scripts/install.sh | bash
# أو تثبيت إصدار معين
curl -fsSL https://raw.githubusercontent.com/jingkaihe/matchlock/main/scripts/install.sh | bash -s -- --version 0.2.4
Homebrew
التثبيت القائم على Homebrew مدعوم على كل من macOS ولينكس:
brew tap jingkaihe/essentials
brew install matchlock
Debian / Ubuntu (.deb)
sudo dpkg -i ./matchlock_<version>_linux_amd64.deb
sudo apt-get install -f
matchlock diagnose
Fedora / RHEL / CentOS Stream (.rpm)
sudo dnf install ./matchlock_<version>_linux_amd64.rpm
matchlock diagnose
إذا أبلغ matchlock diagnose عن إعداد مضيف مفقود، قم بتشغيل:
sudo matchlock setup linux
لتسجيل مستخدم معين بشكل صريح، قم بتشغيل:
sudo matchlock setup user <name>
# أساسي
matchlock run --image alpine:latest cat /etc/os-release
matchlock run --image alpine:latest -it sh
matchlock run --image alpine:latest --no-network -- sh -lc 'echo offline'
# قائمة السماح بالشبكة
matchlock run --image python:3.12-alpine \
--allow-host "api.openai.com" python agent.py
# ابقِ الاعتراض مفعلاً حتى مع قائمة السماح الفارغة،
# بحيث يمكن إضافة/إزالة المضيفين في وقت التشغيل.
matchlock run --image alpine:latest --rm=false --network-intercept
matchlock allow-list add <vm-id> api.openai.com,api.anthropic.com
matchlock allow-list delete <vm-id> api.openai.com
# حقن الأسرار (لا يدخل الجهاز الظاهري أبدًا)
export ANTHROPIC_API_KEY=sk-xxx
matchlock run --image python:3.12-alpine \
--secret [email protected] python call_api.py
# صناديق رمل طويلة الأمد
matchlock run --image alpine:latest --rm=false # يطبع معرف VM
matchlock run --image nginx:latest -d # نفس ما سبق، بشكل منفصل
matchlock exec vm-abc12345 -it sh # الاتصال به
matchlock port-forward vm-abc12345 8080:8080 # توجيه host:8080 -> guest:8080
# نشر المنافذ عند بدء التشغيل
matchlock run --image alpine:latest --rm=false -p 8080:8080
# دورة الحياة
matchlock list | kill | rm | prune
# بناء من Dockerfile (يستخدم BuildKit-in-VM)
matchlock build -f Dockerfile -t myapp:latest .
# بناء مسبق لـ rootfs من صورة السجل (يخبئ لتسريع بدء التشغيل)
matchlock build alpine:latest
# إدارة الصور
matchlock image ls # عرض جميع الصور
matchlock image rm myapp:latest # إزالة صورة محلية
docker save myapp:latest | matchlock image import myapp:latest # استيراد من tarball
Matchlock يوفر SDKs بلغات Go و Python و TypeScript لتضمين الصناديق الرمل مباشرة في تطبيقك. يمكنك تشغيل الأجهزة الافتراضية، تنفيذ الأوامر، بث المخرجات، وإدارة الملفات برمجيًا.
Go
package main
import (
"context"
"fmt"
"os"
"github.com/jingkaihe/matchlock/pkg/sdk"
)
func main() {
ctx := context.Background()
client, err := sdk.NewClient(sdk.DefaultConfig())
if err != nil {
panic(err)
}
defer client.Close(0)
defer client.Remove()
sandbox := sdk.New("alpine:latest").
AllowHost("dl-cdn.alpinelinux.org", "api.anthropic.com").
AddSecret("ANTHROPIC_API_KEY", os.Getenv("ANTHROPIC_API_KEY"), "api.anthropic.com")
if _, err := client.Launch(sandbox); err != nil {
panic(err)
}
if _, err := client.Exec(ctx, "apk add --no-cache curl"); err != nil {
panic(err)
}
// الجهاز الظاهري لا يرى سوى عنصر نائب - المفتاح الحقيقي لا يدخل الصندوق الرمل أبدًا
result, err := client.Exec(ctx, "echo $ANTHROPIC_API_KEY")
if err != nil {
panic(err)
}
fmt.Print(result.Stdout) // يطبع "SANDBOX_SECRET_a1b2c3d4..."
curlCmd := `curl -s --no-buffer https://api.anthropic.com/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{"model":"claude-haiku-4-5-20251001","max_tokens":1024,"stream":true,
"messages":[{"role":"user","content":"Explain TCP to me"}]}'`
if _, err := client.ExecStream(ctx, curlCmd, os.Stdout, os.Stderr); err != nil {
panic(err)
}
}
سلوك عنوان IP الخاص لـ Go SDK (10/8، 172.16/12، 192.168/16):
.WithBlockPrivateIPs(true) (أو .BlockPrivateIPs())..AllowPrivateIPs() أو .WithBlockPrivateIPs(false).sandbox := sdk.New("alpine:latest").
AllowHost("api.openai.com").
AddHost("api.internal", "10.0.0.10").
WithNetworkMTU(1200).
AllowPrivateIPs() // تجاوز صريح: block_private_ips=false
// اعتراض الشبكة SDK (تغيير الطلب/الاستجابة، تشكيل النص، تحويل سطر بيانات SSE)
sandbox = sandbox.WithNetworkInterception(&sdk.NetworkInterceptionConfig{
Rules: []sdk.NetworkHookRule{
{
Phase: sdk.NetworkHookPhaseBefore,
Action: sdk.NetworkHookActionMutate,
Hosts: []string{"api.openai.com"},
SetHeaders: map[string]string{"X-Trace-Id": "trace-123"},
},
{
Phase: sdk.NetworkHookPhaseAfter,
Action: sdk.NetworkHookActionMutate,
Hosts: []string{"api.openai.com"},
BodyReplacements: []sdk.NetworkBodyTransform{
{Find: "internal-id", Replace: "redacted"},
},
},
},
})
إذا استخدمت client.Create(...) مباشرة (بدون المنشئ)، قم بتعيين:
BlockPrivateIPsSet: trueBlockPrivateIPs: false (أو true)للصناديق الرمل غير المتصلة بالإنترنت تمامًا (بدون بطاقة شبكة ضيف / بدون حركة خروج):
--no-network.WithNoNetwork().with_no_network().withNoNetwork()Python (PyPI)
pip install matchlock
# أو
uv add matchlock
import os
import sys
from matchlock import Client, Sandbox
sandbox = (
Sandbox("python:3.12-alpine")
.allow_host(
"dl-cdn.alpinelinux.org",
"files.pythonhosted.org", "pypi.org",
"astral.sh", "github.com", "objects.githubusercontent.com",
"api.anthropic.com",
)
.add_secret(
"ANTHROPIC_API_KEY", os.environ["ANTHROPIC_API_KEY"], "api.anthropic.com"
)
)
SCRIPT = """\
# /// script
# requires-python = ">=3.12"
# dependencies = ["anthropic"]
# ///
import anthropic, os
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
with client.messages.stream(
model="claude-haiku-4-5-20251001",
max_tokens=1024,
messages=[{"role": "user", "content": "Explain TCP/IP."}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
print()
"""
with Client() as client:
client.launch(sandbox)
client.exec("pip install --quiet uv")
client.write_file("/workspace/ask.py", SCRIPT)
client.exec_stream("uv run /workspace/ask.py", stdout=sys.stdout, stderr=sys.stderr)
client.remove()
TypeScript
npm install matchlock-sdk
import { Client, Sandbox } from "matchlock-sdk";
const SCRIPT = `import Anthropic from "@anthropic-ai/sdk";
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});
const stream = anthropic.messages
.stream({
model: "claude-haiku-4-5-20251001",
max_tokens: 1024,
messages: [{ role: "user", content: "Explain TCP/IP." }],
})
.on("text", (text) => {
process.stdout.write(text);
});
await stream.finalMessage();
process.stdout.write("\\n");
`;
const client = new Client();
try {
const sandbox = new Sandbox("node:22-alpine")
.allowHost("registry.npmjs.org", "*.npmjs.org", "api.anthropic.com")
.addSecret("ANTHROPIC_API_KEY", process.env.ANTHROPIC_API_KEY ?? "", "api.anthropic.com");
await client.launch(sandbox);
await client.exec(
"npm init -y >/dev/null 2>&1 && npm install --quiet --no-bin-links @anthropic-ai/sdk",
{ workingDir: "/workspace" },
);
await client.writeFile("/workspace/ask.mjs", SCRIPT);
await client.execStream("node ask.mjs", {
workingDir: "/workspace",
stdout: process.stdout,
stderr: process.stderr,
});
} finally {
await client.close();
await client.remove();
}
المزيد من الأمثلة في دليل examples/:
graph LR
subgraph Host
CLI["Matchlock CLI"]
Policy["Policy Engine"]
Proxy["Transparent Proxy + TLS MITM"]
VFS["VFS Server"]
CLI --> Policy
CLI --> Proxy
Policy --> Proxy
end
subgraph VM["Micro-VM (Firecracker / Virtualization.framework)"]
Agent["Guest Agent"]
FUSE["/workspace (FUSE)"]
Image["Any OCI Image (Alpine, Ubuntu, etc.)"]
Agent --- Image
FUSE --- Image
end
Proxy -- "vsock :5000" --> Agent
VFS -- "vsock :5001" --> FUSE
| المنصة | الوضع |
|---|
MIT
| الوصف | المثال |
|---|
| بث استجابة Anthropic API مع حقن الأسرار (Go) | examples/go/basic/ |
| محطة تفاعلية مع PTY باستخدام ExecInteractive (Go) | examples/go/exec_modes/ |
| حقن مفتاح API عبر خطاف اعتراض الشبكة (Go) | examples/go/network_interception/ |
| خطافات اعتراض VFS لتحوير عمليات الملفات (Go) | examples/go/vfs_hooks/ |
| بث استجابة Anthropic API (Python) | examples/python/basic/ |
| أوضاع تنفيذ البث والأنابيب والتفاعلية (Python) | examples/python/exec_modes/ |
| حقن مفتاح API عبر خطاف اعتراض الشبكة (Python) | examples/python/network_interception/ |
| خطافات اعتراض VFS لتحوير عمليات الملفات (Python) | examples/python/vfs_hooks/ |
| بث استجابة Anthropic API (TypeScript) | examples/typescript/basic/ |
| أوضاع تنفيذ البث والأنابيب والتفاعلية (TypeScript) | examples/typescript/exec_modes/ |
| حقن مفتاح API عبر خطاف اعتراض الشبكة (TypeScript) | examples/typescript/network_interception/ |
| Claude Code CLI في جهاز افتراضي صغير مع إقلاع GitHub | examples/claude-code/ |
| Claude Code مع Docker داخل الصندوق الرمل عبر SDK | examples/claude-code-with-docker/ |
| Claude Code مع اشتراك Claude Pro/Max في الصندوق الرمل | examples/claude-danger/ |
| OpenAI Codex CLI في جهاز افتراضي صغير مع إقلاع GitHub | examples/codex/ |
| خادم Docker داخل الصندوق الرمل مع systemd | examples/docker-in-sandbox/ |
| chatbot Streamlit باستخدام Agent Client Protocol | examples/agent-client-protocol/ |
| أتمتة المتصفح باستخدام Kodelet و Playwright MCP | examples/playwright/ |
| الآلية |
|---|
| لينكس | وكيل شفاف | nftables DNAT على المنفذين 80/443 |
| macOS | NAT (افتراضي) | NAT المدمج في Virtualization.framework |
| macOS | اعتراض (مع --allow-host/--secret) | gVisor في مساحة المستخدم TCP/IP على الطبقة 4 |