מנועי ארגז חול
סקירת הבקאנדים
קטע בשם “סקירת הבקאנדים”| בקאנד | ערך | פלטפורמה | זמינות |
|---|---|---|---|
| VM מסוגר | microvm |
macOS, Linux, Windows (היפרוויזר microVM) | מותנה בבדיקה של סביבת הריצה של microVM; חל על מסופים אינטראקטיביים — המעטפת רצה בתוך תחנה, לא על המארח |
| מקורי | native |
macOS (Seatbelt), Linux ו-WSL2 (bubblewrap) | נבדק באתחול; Linux מסרב להרצה שדורשת דחיות כתיבה לפי תבניות גלוב של שמות קבצים, שאין ביכולתו של bubblewrap לאכוף |
| ללא | none |
הכול | ברירת המחדל של הפענוח, ברירת המחדל של המסוף והנסיגה כשאף בקאנד אינו זמין או כשמוגדר --sandbox off |
SandboxBackend.fromName מחזיר none עבור ערך שמור שהוא null או שאינו מזוהה. ערך שמור של "docker" ממופה ל-native.
microvm הוא הבקאנד היחיד עם גבול קרנל — עומס העבודה
באמת אינו רץ על המארח. הוא לעולם אינו נסיגה שקטה לאף אחד
מהכיוונים: בקשה מפורשת שלו במארח שאינו יכול להעלות VM נכשלת
בקול רם (“ביקשתי VM וקיבלתי את הלפטופ שלי” היא ההידרדרות היחידה
שהמתחם הסגור אינו יכול להרשות לעצמו), ורק ברירת מחדל לא מצוינת יורדת
אל native, עם שורת יומן שאומרת זאת. הבקאנד בפועל של המושב מדווח
חזרה ללקוח ומסומן בתג, כך שמסוף לעולם אינו יכול להצהיר שהוא מסוגר
בעודו רץ על המארח. מחזור החיים, התמונות והיציאה של ה-VM עצמו
מכוסים במדריך העזר לתחנות.
ב-Windows אין ארגז חול מקורי. NativeSandboxAdapter.probe מחזיר available: false בכל מארח שאינו macOS או Linux/WSL2. לכן שיגור סוכן ב-Windows משתמש ב-none. הבקאנד microvm נפרד: הוא מותנה בבדיקה של סביבת הריצה של microVM וחל על מסופים אינטראקטיביים ועל תחנות, ולא על עטיפת bash במארח.
תוצאות הבדיקה
קטע בשם “תוצאות הבדיקה”הבדיקה היא מה שמשער את האכיפה. היא רצה פעם אחת, באתחול השרת.
| מארח | available |
הערה / רמז |
|---|---|---|
| macOS | true |
sandbox-exec (Seatbelt) — בידוד מרחבי שמות, בלי גבול קרנל |
Linux או WSL2 עם bwrap ו-socat |
true |
bubblewrap — בידוד מרחבי שמות, בלי גבול קרנל |
| Linux או WSL2 שחסר בהם אחד מהכלים | false |
requiresInstall: true, עם רמז התקנה שמציין את החבילות החסרות |
| כל פלטפורמה אחרת | false |
ארגז חול מקורי אינו מוצע בפלטפורמה הזו |
השרת רושם את התוצאה בשורת אתחול אחת: agent sandbox ON בתוספת ההערה, no OS-native agent sandbox on this host בתוספת הרמז, או agent sandbox DISABLED by --sandbox off. GET /healthz אינו נושא שדה של ארגז חול.
--sandbox / CC_SERVER_SANDBOX מקבל on (ברירת מחדל) או off. זהו ביטול מכוון, לא הפעלה: on משמעו “עטוף כשהמארח מציע בקאנד”, ולעולם לא “דרוש אחד”.
הבקאנד המקורי
קטע בשם “הבקאנד המקורי”macOS: Seatbelt
קטע בשם “macOS: Seatbelt”משתמש במנגנון ארגז החול Seatbelt של Apple (אותה מערכת שמשמשת את macOS App Sandbox).
הפרופיל שנוצר הוא מתירני כברירת מחדל ((allow default)) ומגלף ממנו דחיות, משום שפרופיל שדוחה הכול כברירת מחדל הופך מעטפת אינטראקטיבית לבלתי שמישה — יש יותר מדי קריאות dyld, XPC ו-Mach כדי למנות אותן. ההשלכה המעשית היא שסוכן עדיין יכול לקרוא את רוב המארח; הצ׳קאאוטים הרשומים שלכם מוגנים בדחיות כתיבה ושינוי-שם מפורשות, ולא בהיעדר נראות.
- קריאות ממערכת הקבצים: נדחות עבור נתיבי הסודות (
~/.ssh,~/.aws,~/.gnupg,~/.config/gh,~/Library/Keychainsושאר קבוצת דחיית הקריאה) - כתיבה למערכת הקבצים: מאופסת לדחייה, ואז היתרים מפורשים לתת-נתיבים, כשנתיבי הדחייה המחייבת (קובצי rc של המעטפת,
.git/hooks, תצורת Claude, צ׳קאאוטים מוגנים) חסומים גם בתוך שורש שניתן לכתיבה.file-write-unlinkנדחה בכל נתיב נדחה ובאבותיו, כך ששינוי שם אינו יכול לעקוף דחיית כתיבה - תהליכים: דחיות
process-execלקובצי ההרצה המסוכנים תמיד, בתוספת חסימה של הרצת כל דבר מספרייה הניתנת לכתיבה - רשת: מוגבלת לפורטי ה-proxy בתהליך בתוספת DNS — loopback אינו מותר באופן גורף ושקעי Unix אינם מותרים. ה-proxy-ים אוכפים את רשימת ההיתר של הדומיינים לכל מושב (ראו יציאה לרשת)
- תצורה: הפרופילים נוצרים לכל הפעלה מתוך ה-
SandboxSpec
דרישות:
sandbox-exec(/usr/bin/sandbox-exec), חלק מכל התקנת macOS — לא נדרשים כלים נוספים
Linux: bubblewrap
קטע בשם “Linux: bubblewrap”משתמש ב-bubblewrap (bwrap) כדי ליצור מרחבי שמות של עיגון ו-PID.
- מערכת הקבצים: יוצר מרחב שמות של עיגון שבו רק הנתיבים המעוגנים נראים
- רשת: רץ במרחב שמות רשת לא משותף; התעבורה מגיעה ל-proxy-ים של המארח דרך גשרי שקעי Unix של
socat - תהליכים: בידוד מרחב שמות של PID
דרישות:
bubblewrapו-socatמותקנים (sudo apt-get install bubblewrap socatב-Debian/Ubuntu)- תמיכה במרחבי שמות של הקרנל (תקנית ב-Linux מודרני)
Bubblewrap יכול להסתיר נתיב קיים אבל אינו יכול לאסור קובץ .env,
*.key או *.pem חדש בתוך עיגון שניתן לכתיבה. מדיניות השיגור
התקנית דורשת את דחיות תבניות-הגלוב האלה של שמות קבצים, ולכן שיגור סוכן
מקורי נכשל באופן סגור ב-Linux/WSL2 גם כשהבדיקה מוצאת את bubblewrap. הוא
אינו רץ עם מדיניות חלשה יותר בשקט. בקאנד עם כללים לפי שם קובץ בזמן
יצירה נדרש כדי להחזיר את השיגור המקורי ב-Linux. השבתת ארגז החול היא
ביטול מכוון בלי הגבלה, ולא עקיפה שוות-ערך.
בקאנד none
קטע בשם “בקאנד none”בלי ארגז חול. התהליך רץ ישירות על המארח עם הגישה של המארח למערכת הקבצים, לרשת ולתהליכים. ACP וכלי ה-bash של מנגנון ההרצה עדיין מקבלים חיטוי הסביבה ואת מדיניות הפקודות; Claude Code דרך NoSandboxAdapter יורש את סביבת המארח. זה מה שאליו נופל שיגור סוכן במארח שאין בו בקאנד זמין או שיש בו --sandbox off, וזו ברירת המחדל של המסוף כשלקוח אינו מציין דבר.
מסוף מתארח בשרת
קטע בשם “מסוף מתארח בשרת”המסוף עטוף בארגז חול בתנאים שלו עצמו, ולא בידי בדיקת השיגור. defaultBackend של TerminalSessionService הוא none ו-cc_server אינו עוקף אותו, ולכן מושב מסוף מריץ את מעטפת המארח אלא אם הלקוח מבקש native במפורש — פאנל המסוף של שולחן העבודה אינו עושה זאת.
כשמבקשים native, המעטפת נעטפת דרך SandboxManager תחת פרופיל מסוף קבוע: $HOME וספריית העבודה של המושב ניתנים לכתיבה, הרשת פתוחה, והקריאה מ-~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh ו-~/Library/Keychains נדחית. אסימון הקריאה בלבד ושער הדחיפה אינם חלים — זה עניין של שיגור. אם העטיפה אינה נתמכת, המושב נכשל במקום להציג תג מקורי על PTY של מעטפת המארח.
יציאה לרשת
קטע בשם “יציאה לרשת”כשארגז חול מופעל, הגישה היוצאת לרשת נאכפת בידי proxy-ים בתהליך, ולא בכללי חומת אש של הקרנל. במארח שאין בו בקאנד זמין שום דבר מזה אינו חל, ותהליך בן מגיע לרשת בדיוק כפי שמשתמש השרת היה מגיע.
- סביבת הריצה של ארגז החול מריצה proxy של HTTP/HTTPS ו-proxy של SOCKS5 על
127.0.0.1בתוך תהליך ה-cc_server, זוג אחד לכל מושב מוגבל (http_proxy.dart,socks_proxy.dart). הרצות במקביל אינן חולקות זוג. - תהליכים בארגז חול מקבלים משתני סביבה של proxy (
HTTP_PROXY/HTTPS_PROXY→ ה-proxy של HTTP,ALL_PROXY→ ה-proxy של SOCKS;GIT_SSH_COMMANDמנתב git-over-SSH דרך ה-proxy של SOCKS). ב-Linux מרחב השמות של הרשת אינו משותף, ולכן ה-proxy-ים הם הדרך היחידה החוצה; ב-macOS ארגז החול חולק את ה-loopback של המארח ומדבר איתם ישירות. - מארח היעד של כל חיבור נבדק מול רשימת ההיתר של הדומיינים של המושב; כל דבר אחר נדחה. שתי צורות של תווים כלליים, כל אחת עם
*אחד בדיוק:*.example.comמוביל תואם כל תת־דומיין (כוללa.b.example.com) אבל לא את השורש עצמו;bedrock.*.amazonaws.comעם תווית אמצעית תואם תווית אחת בדיוק (bedrock.us-east-1.amazonaws.com, לאbedrock.evil.attacker.amazonaws.com). - רשימת ההיתר נפתרת לכל מושב מתוך קו הבסיס הנבחר (
kBaselineAllowedDomains: ספקי LLM, אחסון Git, מרשמי חבילות), בתוספת דומייני GitHub (kGithubDomains), בתוספתSandboxSpec.egressAllowlist. מסלול השיגור לעולם אינו מעביר רשומות נוספות שלegressAllowlist, ולכן בפועל כל הרצה מקבלת את קו הבסיס בתוספת GitHub. - רשימת דחייה קבועה (
kBaselineDeniedDomains: נקודות קצה של מטא-נתוני ענן, משקעי טלמטריה) גוברת על כל ההיתרים. networkEnabled: falseעדיין מפעיל את ה-proxy-ים של המושב, אבל רשימת ההיתר ריקה ולכן כל חיבור יוצא נדחה. השיגור קובע את הערך הזה בתחילת ההרצה לפי הכלל גישה לרשת: חסום מכבה את הרשת, ואפשר ושאל קודם משאירים אותה דלוקה.
SandboxSpec
קטע בשם “SandboxSpec”המפרט שמועבר אל SandboxPort.launch:
| שדה | סוג | תיאור |
|---|---|---|
sessionId |
String |
מזהה מושב יציב (בדרך כלל מזהה המרחב) |
workspaceId |
String |
מזהה סביבת העבודה הבעלים |
agentId |
String? |
הסוכן המשויך כרגע לארגז החול, אם יש כזה |
bindMounts |
List<SandboxBindMount> |
עיגונים ממארח לאורח; ארגז החול רואה רק את נתיבי המארח הרשומים כאן |
networkEnabled |
bool (ברירת מחדל true) |
נקבע בשיגור לפי כלל התעבורה היוצאת לרשת (כבוי רק כשהוא מוכרע כחסום). כשהוא כבוי, ה-proxy-ים של המושב עדיין עולים אבל רשימת ההיתר ריקה ולכן כל חיבור יוצא נדחה |
egressAllowlist |
List<String> (ברירת מחדל []) |
דומייני יציאה מותרים נוספים; תווים כלליים נתמכים (*.example.com, בתוספת צורה עם תווית אמצעית אחת). השיגור לעולם אינו מאכלס את זה, ולכן הרצה עטופה מקבלת את קו הבסיס הנבחר בתוספת דומייני GitHub |
guestWorkdir |
String? |
ספריית העבודה כברירת מחדל בתוך ארגז החול; קריאות exec בודדות יכולות לעקוף אותה |
mode |
Mode (ברירת מחדל chat) |
מגלף את כללי הכתיבה במערכת הקבצים: chat משאיר את עיגוני ה-bind ניתנים לכתיבה; review, plan ו-orchestrate הם לקריאה בלבד |
protectedPaths |
List<String> (ברירת מחדל []) |
נתיבי מארח שאסור שלעולם יהיו ניתנים לכתיבה בתוך ארגז החול, בכל מצב |
runnerStateDirs |
List<String> (ברירת מחדל []) |
ספריות מארח שהראנר שומר בהן את המצב של עצמו, ניתנות לכתיבה בכל מצב (CLAUDE_CONFIG_DIR בניהול Control Center היא זו שבתוקף) |
execGrantRoots |
List<String> (ברירת מחדל []) |
עצי ספריות שאושרו בידי מפעיל ופותחים מחדש את חסימת ה-exec של ספרייה הניתנת לכתיבה ב-macOS. Linux מתעלם מהם — ל-bwrap אין חסימת exec של $HOME לפתוח מחדש |
protectedPaths מחזיק את הצ׳קאאוטים המקוריים של המאגרים הרשומים, הנפתרים לכל שיגור מתוך המאגרים של סביבת העבודה. סוכנים עובדים אך ורק בעצי עבודה בהעתקה בעת כתיבה לכל שיחה, ולכן המקוריים אסור שלעולם יהיו ניתנים לכתיבה מתוך ארגז החול — ב-macOS, היתר הכתיבה הגורף של Seatbelt ל-$HOME היה אחרת משאיר אותם ניתנים לכתיבה דרך bash. הם מצטרפים לקבוצת דחיית הכתיבה של הסודות בכל מצב, כולל chat.
כל נתיב של דחיית קריאה ושל דחיית כתיבה נפלט גם בצורתו המילולית וגם בצורתו המפוענחת-סימבולית. הקרנל מתאים כלל דחייה לנתיב המפוענח, ולכן כלל שנכתב כנגד נתיב עם קישור סימבולי לעולם אינו פועל — וב-macOS זה המקרה השכיח ולא החריג, משום ש-/tmp נפתר ל-/private/tmp ו-/var/folders/… ל-/private/var/folders/…. רשומות שמכילות * או ? מטופלות כגלובים ונשארות כפי שהן; נתיב שאינו נפתר נשמר כפי שנכתב.
SandboxBindMount
קטע בשם “SandboxBindMount”| שדה | סוג | תיאור |
|---|---|---|
hostPath |
String |
נתיב מוחלט במארח |
guestPath |
String |
נתיב בתוך ארגז החול (בארגז החול המקורי הוא שווה ל-hostPath; נשמר לסימטריה של המתאם) |
readOnly |
bool (ברירת מחדל false) |
עיגון לקריאה בלבד כשהוא true |
SandboxHandle
קטע בשם “SandboxHandle”מוחזר בידי SandboxPort.launch:
| שדה | סוג | תיאור |
|---|---|---|
sessionId |
String |
מזהה מושב |
backend |
SandboxBackend |
איזה בקאנד רץ |
state |
SandboxState |
מצב מחזור החיים |
error |
Object? |
מוגדר כאשר state הוא error |
details |
Map<String, Object?> |
רישום פנימי של המתאם (ספריית עבודה, PID, נתיב פרופיל וכו’) |
SandboxState
קטע בשם “SandboxState”| מצב | תיאור |
|---|---|
created |
המפרט נוצר אבל ה-VM טרם עלה |
warm |
רץ ומוכן להריץ פקודות |
active |
מריץ פקודה כעת |
suspended |
מושהה / נשמר כנקודת ביקורת לדיסק כדי לחסוך בזיכרון |
destroyed |
מפורק; הידית אינה תקפה עוד |
error |
ההפעלה נכשלה — ראו SandboxHandle.error |
אירועי ארגז חול
קטע בשם “אירועי ארגז חול”| סוג אירוע | תיאור |
|---|---|
stdout |
פלט תקני מארגז החול |
stderr |
שגיאה תקנית מארגז החול |
exit |
תהליך ארגז החול הסתיים (נושא exitCode) |
starting |
ארגז החול מתחיל לעלות |
ready |
ארגז החול מוכן לקבל קריאות exec |
killed |
התהליך נהרג בידי המארח (OOM, פסק זמן, עצירה ידנית) |
violation |
מדיניות של ארגז חול הופרה (נושא SandboxViolation) |
SandboxViolation
קטע בשם “SandboxViolation”| שדה | סוג | תיאור |
|---|---|---|
action |
String |
הפועל הנדחה (למשל file-read*, network-outbound) |
target |
String |
נתיב או מארח שהיו היעד של הפעולה הנדחית |
raw |
String? |
שורת יומן גולמית, שימושית לניפוי באגים |
ראו גם
קטע בשם “ראו גם”- ארגז חול ואבטחה
- הגדרת מדיניות ארגז חול
- מעקות בטיחות
- CLI של cc_server: הדגל
--sandbox