Bỏ qua để đến nội dung

Backend sandbox

Backend Giá trị Nền tảng Khả dụng
VM khép kín microvm macOS, Linux, Windows (hypervisor microVM) Được đặt cổng theo bước dò trên runtime microVM; áp dụng cho terminal tương tác — shell chạy bên trong một rig, không phải trên máy chủ
Gốc native macOS (Seatbelt), Linux và WSL2 (bubblewrap) Được dò lúc khởi động; Linux từ chối một lượt chạy cần các lệnh từ chối ghi theo mẫu tên tệp mà bubblewrap không thể thực thi
Không cô lập none Tất cả Giá trị mặc định khi phân tích, mặc định của terminal và phương án dự phòng khi không có backend nào khả dụng hoặc --sandbox off được đặt

SandboxBackend.fromName trả về none khi giá trị được lưu là null hoặc không nhận ra. Giá trị "docker" được lưu sẽ ánh xạ thành native.

microvm là backend duy nhất có ranh giới kernel — khối lượng công việc thực sự không chạy trên máy chủ. Nó không bao giờ là phương án dự phòng âm thầm theo cả hai hướng: yêu cầu nó một cách tường minh trên một máy chủ không thể khởi động VM sẽ thất bại ồn ào (“tôi xin một VM mà lại nhận được laptop của mình” là kiểu suy giảm duy nhất mà môi trường khép kín không thể cho phép), và chỉ một mặc định không được chỉ định mới hạ xuống native, kèm một dòng log nói rõ điều đó. Backend thực tế của phiên được báo về máy khách và gắn nhãn, nên một terminal không bao giờ có thể tự nhận là khép kín trong khi đang chạy trên máy chủ. Vòng đời, image và egress cho chính VM được trình bày trong tham chiếu rigs.

Windows không có sandbox gốc. NativeSandboxAdapter.probe trả về available: false trên mọi máy chủ không phải macOS hay Linux/WSL2. Do đó việc điều phối agent trên Windows dùng none. Backend microvm là riêng biệt: nó được đặt cổng theo bước dò trên runtime microVM và áp dụng cho terminal tương tác cùng rig, không áp dụng cho việc bọc bash trên máy chủ.

Bước dò chính là thứ đặt cổng cho việc thực thi. Nó chạy một lần, lúc máy chủ khởi động.

Máy chủ available Ghi chú / gợi ý
macOS true sandbox-exec (Seatbelt) — cô lập namespace, không có ranh giới kernel
Linux hoặc WSL2 có bwrap và socat true bubblewrap — cô lập namespace, không có ranh giới kernel
Linux hoặc WSL2 thiếu một trong hai công cụ false requiresInstall: true, kèm một gợi ý cài đặt nêu tên các gói còn thiếu
Mọi nền tảng khác false Sandbox gốc không được cung cấp trên nền tảng này

Máy chủ ghi kết quả vào một dòng khởi động duy nhất: agent sandbox ON kèm ghi chú, no OS-native agent sandbox on this host kèm gợi ý, hoặc agent sandbox DISABLED by --sandbox off. GET /healthz không mang trường sandbox nào.

--sandbox / CC_SERVER_SANDBOX chấp nhận on (mặc định) hoặc off. Đây là cơ chế chủ động tắt, không phải bật: on nghĩa là “bọc khi máy chủ cung cấp một backend”, không bao giờ là “bắt buộc phải có một backend”.

Dùng cơ chế sandbox Seatbelt của Apple (cùng hệ thống mà macOS App Sandbox dùng).

Profile được sinh ra mặc định là dễ dãi ((allow default)) và khoét ra các lệnh từ chối, bởi một profile từ chối-hoàn-toàn-theo-mặc-định sẽ khiến một shell tương tác không dùng được — có quá nhiều lệnh gọi dyld, XPC và Mach để liệt kê hết. Hệ quả thực tế là agent vẫn có thể đọc phần lớn máy chủ; những bản checkout đã đăng ký của bạn được bảo vệ bằng các lệnh từ chối ghi và rename tường minh, chứ không phải bằng sự vô hình.

  • Đọc hệ thống tệp: bị từ chối với các đường dẫn bí mật (~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh, ~/Library/Keychains và phần còn lại của nhóm từ chối đọc)
  • Ghi hệ thống tệp: được đặt lại thành từ chối, rồi các lệnh cho phép tường minh cho từng đường dẫn con, với những đường dẫn bắt buộc từ chối (tệp rc của shell, .git/hooks, cấu hình Claude, các bản checkout được bảo vệ) bị chặn ngay cả bên trong một gốc có thể ghi. file-write-unlink bị từ chối trên mọi đường dẫn bị từ chối và các tổ tiên của nó, nên một lệnh rename không thể lách qua một lệnh từ chối ghi
  • Tiến trình: process-exec từ chối các tệp nhị phân luôn nguy hiểm, cộng thêm việc chặn thực thi bất cứ thứ gì từ một thư mục có thể ghi
  • Mạng: bị giới hạn ở các cổng proxy in-process cùng DNS — loopback không được cho phép toàn bộ và socket Unix không được phép. Các proxy thực thi danh sách cho phép theo tên miền của từng phiên (xem Egress mạng)
  • Cấu hình: profile được sinh theo từng lần khởi chạy từ SandboxSpec

Yêu cầu:

  • sandbox-exec (/usr/bin/sandbox-exec), có trong mọi bản cài macOS — không cần công cụ bổ sung

Dùng bubblewrap (bwrap) để tạo các namespace mount và PID.

  • Hệ thống tệp: tạo một namespace mount chỉ nhìn thấy những đường dẫn đã được gắn
  • Mạng: chạy trong một namespace mạng không chia sẻ; lưu lượng tới được các proxy của máy chủ qua những cầu socket Unix bằng socat
  • Tiến trình: cô lập namespace PID

Yêu cầu:

  • Đã cài bubblewrap và socat (sudo apt-get install bubblewrap socat trên Debian/Ubuntu)
  • Kernel hỗ trợ namespace (tiêu chuẩn trên Linux hiện đại)

Bubblewrap có thể che khuất một đường dẫn đã tồn tại nhưng không thể cấm một tệp .env, *.key hay *.pem mới nằm trong một bind có thể ghi. Chính sách điều phối tiêu chuẩn yêu cầu những lệnh từ chối theo mẫu tên tệp này, nên việc điều phối agent bằng backend gốc hiện đóng-khi-lỗi trên Linux/WSL2 ngay cả khi bước dò tìm thấy bubblewrap. Nó không chạy với một chính sách âm thầm yếu hơn. Cần một backend có quy tắc tên tệp tại thời điểm tạo để khôi phục việc điều phối gốc trên Linux. Tắt sandboxing là một lựa chọn chủ động từ bỏ mọi ràng buộc, không phải một cách lách tương đương.

Không có sandbox. Tiến trình chạy trực tiếp trên máy chủ với quyền truy cập hệ thống tệp, mạng và tiến trình của máy chủ. ACP và công cụ bash của harness vẫn được làm sạch môi trường và áp chính sách lệnh; Claude Code qua NoSandboxAdapter kế thừa môi trường của máy chủ. Đây là thứ việc điều phối agent quay về trên một máy chủ không có backend khả dụng hoặc có --sandbox off, và cũng là mặc định của terminal khi máy khách không nêu backend nào.

Terminal được sandbox theo những quy tắc riêng của nó, không theo bước dò của đường điều phối. defaultBackend của TerminalSessionService là none và cc_server không ghi đè nó, nên một phiên terminal chạy shell của máy chủ trừ khi máy khách yêu cầu native một cách tường minh — còn bảng terminal của ứng dụng desktop thì không.

Khi native được yêu cầu, shell được bọc qua SandboxManager dưới một profile terminal cố định: $HOME và thư mục làm việc của phiên có thể ghi, mạng mở và ~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh cùng ~/Library/Keychains bị từ chối đọc. Token forge chỉ đọc và cổng push không áp dụng ở đây — đó là chuyện của đường điều phối. Nếu việc bọc không được hỗ trợ, phiên sẽ thất bại thay vì hiển thị một nhãn native trên một PTY là shell của máy chủ.

Khi một sandbox được khởi chạy, quyền truy cập mạng ra ngoài được thực thi bởi các proxy in-process, không phải bởi các quy tắc tường lửa của kernel. Trên một máy chủ không có backend khả dụng, không điều nào ở đây áp dụng và một tiến trình được spawn tiếp cận mạng đúng như người dùng máy chủ sẽ làm.

  • Runtime sandbox chạy một proxy HTTP/HTTPS và một proxy SOCKS5 trên 127.0.0.1 bên trong tiến trình cc_server, một cặp cho mỗi phiên bị giới hạn (http_proxy.dart, socks_proxy.dart). Các lượt chạy đồng thời không dùng chung một cặp.
  • Các tiến trình được sandbox nhận các biến môi trường proxy (HTTP_PROXY/HTTPS_PROXY → proxy HTTP, ALL_PROXY → proxy SOCKS; GIT_SSH_COMMAND định tuyến git-qua-SSH qua proxy SOCKS). Trên Linux, namespace mạng không được chia sẻ, nên các proxy là lối ra duy nhất; trên macOS, sandbox dùng chung loopback của máy chủ và nói chuyện trực tiếp với chúng.
  • Máy chủ đích của mỗi kết nối được đối chiếu với danh sách cho phép tên miền của phiên; mọi thứ khác đều bị từ chối. Có hai dạng ký tự đại diện, mỗi dạng có đúng một dấu *: dạng đứng đầu *.example.com khớp với mọi tên miền con (kể cả a.b.example.com) nhưng không khớp với chính tên miền gốc; dạng ở nhãn giữa bedrock.*.amazonaws.com khớp với đúng một nhãn (bedrock.us-east-1.amazonaws.com, không khớp bedrock.evil.attacker.amazonaws.com).
  • Danh sách cho phép được phân giải theo từng phiên từ đường cơ sở được tuyển chọn (kBaselineAllowedDomains: các nhà cung cấp LLM, nơi lưu trữ Git, các registry gói), cộng với các tên miền GitHub (kGithubDomains), cộng với SandboxSpec.egressAllowlist. Đường điều phối không bao giờ truyền các mục egressAllowlist bổ sung, nên trên thực tế mọi lượt chạy đều nhận đường cơ sở cộng với GitHub.
  • Một danh sách từ chối cố định (kBaselineDeniedDomains: các endpoint metadata của cloud, các điểm thu thập telemetry) có quyền ưu tiên hơn mọi lệnh cho phép.
  • networkEnabled: false vẫn khởi động các proxy theo phiên, nhưng danh sách cho phép rỗng nên mọi kết nối ra ngoài đều bị từ chối. Đường điều phối đặt giá trị này khi lượt chạy bắt đầu, dựa trên quy tắc Truy cập mạng: từ chối sẽ tắt mạng, cho phép và hỏi trước giữ mạng bật.

Đặc tả được truyền cho SandboxPort.launch:

Trường Kiểu Mô tả
sessionId String Mã định danh phiên ổn định (thường là id của space)
workspaceId String Id của không gian làm việc sở hữu
agentId String? Agent hiện đang được gắn với sandbox, nếu có
bindMounts List<SandboxBindMount> Các mount máy chủ→khách; sandbox chỉ nhìn thấy những đường dẫn máy chủ được liệt kê ở đây
networkEnabled bool (mặc định true) Được đặt lúc điều phối từ quy tắc egress mạng (chỉ tắt khi quy tắc phân giải thành từ chối). Khi tắt, các proxy theo phiên vẫn khởi động nhưng danh sách cho phép rỗng nên mọi kết nối ra ngoài đều bị từ chối
egressAllowlist List<String> (mặc định []) Các tên miền egress được phép bổ sung; hỗ trợ ký tự đại diện (*.example.com, cùng dạng một nhãn ở giữa). Đường điều phối không bao giờ điền vào trường này, nên một lượt chạy được bọc sẽ nhận đường cơ sở được tuyển chọn cộng với các tên miền GitHub
guestWorkdir String? Thư mục làm việc mặc định bên trong sandbox; từng lệnh gọi exec riêng lẻ có thể ghi đè nó
mode Mode (mặc định chat) Khoét ra các quy tắc ghi vào hệ thống tệp: chat giữ các bind mount ở chế độ có thể ghi; review, plan và orchestrate chỉ đọc
protectedPaths List<String> (mặc định []) Các đường dẫn máy chủ không bao giờ được phép ghi bên trong sandbox, ở bất kỳ chế độ nào
runnerStateDirs List<String> (mặc định []) Các thư mục máy chủ mà runner lưu trạng thái riêng của nó, có thể ghi ở mọi chế độ (hiện tại là một CLAUDE_CONFIG_DIR do Control Center quản lý)
execGrantRoots List<String> (mặc định []) Các cây thư mục được người vận hành phê duyệt, mở lại lệnh chặn exec trong thư mục có thể ghi trên macOS. Linux bỏ qua chúng — bwrap không có lệnh chặn exec $HOME nào để mở lại

protectedPaths chứa các bản checkout repo đã đăng ký gốc, được phân giải theo từng lần điều phối từ các repo của không gian làm việc. Agent chỉ làm việc trong các cây làm việc copy-on-write theo từng cuộc hội thoại, nên các bản gốc không bao giờ được phép ghi từ bên trong sandbox — nếu không, trên macOS, lệnh cho phép ghi $HOME toàn diện của Seatbelt sẽ để chúng có thể ghi được qua bash. Chúng gia nhập nhóm từ chối ghi các thông tin bí mật ở mọi chế độ, kể cả chat.

Mọi đường dẫn từ chối đọc và từ chối ghi đều được phát ra theo cả cách viết nguyên văn lẫn cách viết đã phân giải symlink. Kernel so khớp một quy tắc từ chối với đường dẫn đã phân giải, nên một quy tắc viết theo một đường dẫn có symlink sẽ không bao giờ kích hoạt — và trên macOS đó là trường hợp phổ biến chứ không phải ngoại lệ, vì /tmp phân giải thành /private/tmp và /var/folders/… thành /private/var/folders/…. Các mục chứa * hoặc ? được coi là glob và để nguyên; một đường dẫn không phân giải được thì được giữ nguyên như đã viết.

Trường Kiểu Mô tả
hostPath String Đường dẫn tuyệt đối trên máy chủ
guestPath String Đường dẫn bên trong sandbox (với sandbox gốc thì bằng hostPath; được giữ lại để các adapter đối xứng nhau)
readOnly bool (mặc định false) Gắn ở chế độ chỉ đọc khi là true

Được trả về bởi SandboxPort.launch:

Trường Kiểu Mô tả
sessionId String Mã định danh phiên
backend SandboxBackend Backend nào đang chạy
state SandboxState Trạng thái vòng đời
error Object? Được đặt khi state là error
details Map<String, Object?> Thông tin ghi chép riêng của adapter (thư mục làm việc, PID, đường dẫn profile, v.v.)
Trạng thái Mô tả
created Đặc tả đã được tạo nhưng VM chưa khởi động
warm Đang chạy và sẵn sàng thực thi lệnh
active Đang thực thi một lệnh
suspended Tạm dừng / được checkpoint xuống đĩa để tiết kiệm RAM
destroyed Đã bị hủy; handle không còn hợp lệ
error Khởi chạy thất bại — xem SandboxHandle.error
Loại sự kiện Mô tả
stdout Đầu ra chuẩn từ sandbox
stderr Đầu ra lỗi chuẩn từ sandbox
exit Tiến trình sandbox đã thoát (mang theo exitCode)
starting Sandbox đang khởi động
ready Sandbox sẵn sàng nhận các lệnh gọi exec
killed Tiến trình bị máy chủ kill (OOM, hết thời gian chờ, dừng thủ công)
violation Một chính sách sandbox đã bị vi phạm (mang theo một SandboxViolation)
Trường Kiểu Mô tả
action String Động từ bị từ chối (ví dụ file-read*, network-outbound)
target String Đường dẫn hoặc máy chủ là đích của thao tác bị từ chối
raw String? Dòng log thô, hữu ích khi gỡ lỗi