Hub Python Library documentation

Sandbox di balik layar

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Sandbox di balik layar

Panduan ini menjelaskan cara kerja Sandboxes secara internal, mengapa mereka dibangun dengan cara tersebut, dan apa saja keterbatasannya. Jika Anda hanya ingin menggunakan sandboxes, panduan Sandboxes sudah cukup; lanjutkan membaca jika Anda ingin memahami mekanismenya, mengevaluasi model kepercayaannya, atau melakukan debug pada sesuatu.

API Sandbox bersifat eksperimental. API dan perilakunya dapat berubah tanpa pemberitahuan.

Tidak ada “sandbox service”

Hal pertama yang perlu dipahami adalah tidak ada backend sandbox khusus. Sandbox hanyalah HF Job (VM) yang menjalankan satu binari statis kecil sbx-server yang berkomunikasi melalui HTTP. Klien berbicara dengan server tersebut melalui proxy Jobs (URL *.hf.jobs yang diekspos oleh Job). Segala hal lainnya — autentikasi, penemuan, pengemasan banyak sandbox ke dalam satu Job — dibangun dari primitif Jobs yang sudah ada: label, variabel lingkungan, dan rahasia.

Desain “tanpa infrastruktur baru” ini adalah alasan mengapa sandbox dapat berjalan di image Docker mana pun dan secara otomatis mewarisi penagihan, varian hardware, serta izin namespace dari Jobs.

Membuat server

Saat startup job, perintah Job adalah skrip /bin/sh -c kecil yang mengambil biner sbx-server, membuatnya dapat dieksekusi, dan melakukan exec padanya. Biner ini adalah build statis musl berukuran ~640KB dengan nol dependensi runtime, sehingga dapat berjalan di image Linux x86_64 apa pun.

Beberapa keputusan yang perlu dicatat:

  • Unduh, dengan fallback mount. Jalur cepat mengunduh biner dari CDN HF dengan wget atau curl (setiap base image umum menyertakan salah satunya), yang cepat dan gratis. Sebagai jaring pengaman, repo Hub server juga di-mount sebagai volume di setiap job: jika image tidak memiliki wget maupun curl, skrip akan menyalin biner dari mount tersebut. Mount bersifat transparan — tidak menimbulkan biaya kecuali benar-benar dibaca — tetapi membacanya menambah ~2-3 detik pada cold start, sehingga bukan menjadi default. Satu-satunya persyaratan keras pada image adalah /bin/sh.
  • Server HTTP/1.1 buatan manual, tanpa framework. Streaming output langsung memerlukan flush setiap chunk saat chunk tersebut dihasilkan. Server HTTP Rust minimal yang umum (misalnya tiny_http) men-buffer respons chunked hingga respons selesai, yang merusak streaming. Oleh karena itu, server ini mengimplementasikan HTTP/1.1 secara manual: stream event NDJSON untuk exec, body mentah untuk file, dan flush eksplisit per chunk.
  • Port 49983. Server mendengarkan pada port yang sengaja dipilih agar tidak umum, sehingga port pengembangan yang umum (3000, 8000, 8080, …) tetap tersedia untuk kode Anda sendiri.

Server ini open source di github.com/huggingface/sandbox-server.

Autentikasi bersifat stateless

Dua lapisan independen melindungi sandbox:

  1. Gerbang proxy. Proxy Jobs hanya meneruskan permintaan yang membawa token HF dengan akses baca ke namespace pekerjaan tersebut. Anggota internet yang acak tidak dapat mencapai URL tersebut.
  2. Gerbang aplikasi. sbx-server juga memeriksa header X-Sandbox-Token pada setiap permintaan kecuali /health. Ini adalah pertahanan berlapis: anggota namespace read-only yang dapat mencapai proxy tetap tidak dapat mengeksekusi perintah.

Token sandbox diturunkan, bukan disimpan:

nonce  = random 128-bit hex                       # stored in the job label "hf-sandbox-nonce"
token  = HMAC-SHA256(key=your_hf_token, msg="hf-sandbox:" + nonce)

Nonce bersifat publik dan kunci HMAC adalah token HF Anda, sehingga mesin mana pun yang memegang token tersebut dapat menghitung ulang token sandbox — itulah yang membuat rekoneksi bersifat stateless. Hal ini juga berarti token tersebut adalah capability yang diturunkan dari kredensial Anda, bukan pemeriksaan identitas pada pemanggil: server memverifikasi bahwa pemanggil mengetahui token tersebut, bukan siapa mereka.

Setiap tugas sandbox juga membawa dua label stabil untuk penemuan — hf-sandbox=1 (pada semua tugas) dan hf-sandbox-mode=dedicated atau hf-sandbox-mode=pool — sehingga Anda dapat mendaftar atau memfilternya di sisi server, misalnya hf jobs ps --label hf-sandbox=1.

Token dikirim ke server melalui Job secret. Klien menurunkannya kembali sesuai permintaan dari nonce publik di label. Hal ini memiliki beberapa konsekuensi yang menguntungkan:

  • Koneksi ulang tanpa state. Sandbox.connect(id) dapat dijalankan dari mesin mana pun yang memegang token HF yang sama — baca nonce dari label, hitung ulang token. Tidak ada file lokal, tidak ada state yang perlu disalin.
  • Token HF tidak diteruskan ke sandbox sebagai variabel lingkungan atau rahasia job (kecuali Anda memilih untuk mengaktifkannya dengan forward_hf_token=True). Ini bukan jaminan mutlak bahwa kredensial Anda tetap tidak dapat diakses: proses yang mendengarkan pada port sandbox adalah apa pun yang dimulai pertama kali oleh image, sehingga image yang tidak tepercaya mungkin dapat mengamati permintaan yang dikirim oleh klien — termasuk header Authorization mereka. Perlakukan kredensial yang dapat dijangkau dari sandbox sebagai berpotensi terekspos kepadanya.

Cakupan token

Satu nonce dicetak per Job, sehingga token yang diturunkan merupakan kredensial job. Dalam mode khusus, job adalah sandbox, sehingga keduanya sama. Dalam mode pool, job adalah host, dan satu host menampung banyak sandbox — sehingga sandbox dalam pool mendapatkan kredensial kedua yang lebih sempit miliknya sendiri:

kredensialditurunkan bagaimanamengotorisasi
token sandbox khususHMAC(hf_token, nonce) dari label jobsandbox tersebut (yang merupakan seluruh tugasnya)
token host poolHMAC(hf_token, nonce) dari label host jobmanajemen pool: membuat, mendaftar, dan menghapus sandbox di host tersebut, serta memulihkan token mereka
token sandbox yang digabungkan256 bit acak, dibuat oleh server host per sandboxsandbox itu satu — bukan saudara, bukan pool

Klien menggunakan yang sempit secara otomatis: pool.create() menerimanya dalam respons pembuatan, Sandbox.connect("<host>.<id>") memulihkannya dengan token host, dan proxy_headers memberikan token sandbox alih-alih token host (menyelesaikan bearer HF pada saat Anda membacanya, sehingga handle berumur panjang tidak memberikan yang kedaluwarsa) — header tersebut biasanya berakhir di browser atau klien WebSocket, jadi seharusnya hanya memberikan akses ke satu sandbox dan tidak lebih.

Artinya bagi kebocoran: token sandbox yang dipoolkan yang bocor akan mengompromikan sandbox tersebut. Token host yang bocor akan mengompromikan host — semua sandbox di atasnya, baik yang ada saat ini maupun yang akan datang, beserta rute pengelolaannya — sehingga perlakukan token ini sebagai kredensial admin pool. Anggota namespace Anda memegang token HF yang berbeda dan tidak dapat menurunkan token Anda, namun lihat Batasan yang diketahui untuk bagaimana sebuah token dapat dikirimkan ke tempat yang salah.

Klien memerlukan token berlingkup sandbox yang tidak kosong untuk operasi pooled dan menolak host yang tidak menyediakannya. Klien tidak pernah mengganti kredensial manajemen host. Tingkatkan klien dan daur ulang host pool yang lebih lama sebelum menggunakan API ini.

Sandbox khusus ( Sandbox.create )

Model yang sederhana: satu Job per sandbox. Job adalah VM sungguhan, sehingga memberikan isolasi terkuat (level VM), mendukung berbagai jenis perangkat keras termasuk GPU, dan merupakan pilihan yang tepat untuk kode yang saling tidak tepercaya. Rute API-nya berada di /v1/* dan jalur file bersifat absolut pada sistem berkas kontainer. kill() hanya membatalkan Job.

Batas yang diberikan oleh sandbox khusus adalah antara Job dan segala sesuatu di luarnya. Di dalam VM, kode Anda dan sbx-server keduanya berjalan sebagai root di dalam container yang sama: sbx-server tidak melakukan sandboxing terhadap perintah yang dijalankan untuk Anda, melainkan hanya mengeksposnya melalui HTTP. Jadi, begitu kode yang tidak Anda percaya telah dieksekusi di dalam sandbox khusus, perlakukan VM tersebut — termasuk control plane-nya — sebagai milik kode itu: kode tersebut dapat mematikan atau mengganti server, dan apa pun yang Anda lakukan di dalam sandbox itu selanjutnya akan berjalan di bawah kendalinya. Gunakan satu sandbox khusus untuk setiap workload yang tidak tepercaya dan kill() saat selesai, alih-alih menggunakan ulang satu sandbox yang sama melintasi batas kepercayaan.

Biayanya terlihat jelas pada diagram: setiap sandbox membayar biaya cold start VM penuh sekitar 6 detik dan menagihkan satu mesin utuh. Untuk satu sandbox atau beban kerja GPU, itu memang yang Anda inginkan. Untuk 100–1000 tugas CPU singkat, hal itu menjadi pemborosan — dan itulah tujuan dari pool.

Pools: banyak sandbox dalam satu Job ( SandboxPool )

Pools ditujukan untuk workload di dalam satu trust boundary. Pooled sandbox adalah uid + ruleset Landlock di dalam VM bersama, bukan VM tersendiri, dan host-nya menjalankan control plane berprivilese yang menjadi titik komunikasi bagi semua sandbox di dalamnya. Gunakan pools untuk mendistribusikan kode Anda sendiri secara hemat biaya. Untuk workload yang saling tidak mempercayai — apa pun yang tidak Anda izinkan membaca file sandbox Anda yang lain — gunakan Sandbox.create(), yang memberikan setiap workload VM-nya sendiri. Lihat Batasan yang diketahui untuk detail celah spesifiknya.

Rollout RL atau sandbox eksekusi tool yang tipikal membutuhkan beberapa MB RAM dan satu core selama beberapa detik. Membayar VM 2-vCPU dan cold start 6 detik untuk masing-masing — serta memicu burst penjadwalan 1000-VM — adalah trade-off yang salah. Jadi, SandboxPool menjalankan satu Job sebagai host dan memultipleks banyak sandbox di dalamnya.

Sandbox yang dipoolkan bukanlah VM atau container bersarang. Ini adalah primitif multi-user Unix klasik:

  • a uid khusus (≥ 20000),
  • a rumah 0700 privat yang dimiliki oleh uid tersebut,
  • perintah exec yang dijalankan sebagai uid tersebut dengan lingkungan yang dibersihkan (env_clear, sehingga rahasia host tidak pernah bocor), NO_NEW_PRIVS, rlimits per proses, dan Landlock ruleset per sandbox.

Membuat sandbox pada dasarnya adalah mkdir + chown + build ruleset ≈ 1ms di sisi server — tanpa boot VM kedua. Latensi yang terlihat oleh klien hanyalah round-trip proxy.

ID publik dari sandbox yang dipool adalah <host_job_id>.<local_id>, sehingga connect/exec/kill bekerja secara stateless persis seperti sandbox khusus. kill() pada sandbox yang dipool mengirim DELETE ke host-nya (membebaskan slot); host tetap berjalan.

Isolasi dalam pool: uid + Landlock

Ini adalah inti dari desain pool, sehingga penting untuk menjelaskan secara tepat apa yang dan apa yang tidak terisolasi.

Job standar berjalan sebagai root di dalam namespace pengguna yang hanya memetakan uid 0..65535, dengan filter seccomp aktif dan tanpa CAP_SYS_ADMIN / CAP_NET_ADMIN / CAP_NET_RAW. Hal ini menyingkirkan alat isolasi berat yang umum: tidak ada namespace bersarang, tidak ada mount baru, dan tidak ada delegasi cgroup (unshare, mount, penulisan ke /sys/fs/cgroup/... semuanya gagal). Yang ditawarkan kernel adalah Landlock (ABI 6), sebuah Linux Security Module yang memungkinkan proses non-privilese mana pun membatasi dirinya dan anak-anaknya — tepat batasan per-sandbox yang kita butuhkan. Untuk setiap sandbox, server membangun ruleset; anak exec turun ke uid/gid sandbox dan menerapkan NO_NEW_PRIVS, landlock_restrict_self, serta rlimits sebelum menjalankan perintah.

Menggabungkan uid yang berbeda (kontrol akses diskresioner) dengan Landlock dirancang dan diuji untuk menyediakan:

  • ✅ A tidak dapat membaca environ dari proses lain, sehingga mencegah akses langsung ke token HF dan sandbox antar sandbox.
  • ✅ A tidak dapat SIGKILL / ptrace / membaca memori proses B, setuid menjadi B, atau membaca home B dengan 0700.
  • ✅ Akses ke /tmp dan /dev/shm ditolak — setiap sandbox dibatasi oleh Landlock ke home-nya sendiri (TMPDIR menunjuk ke dalam $HOME).
  • ✅ A tidak dapat bind port TCP, sehingga tidak ada layanan localhost antar-sandbox (outbound connect tetap diizinkan, sehingga internet berfungsi).
  • ✅ Sockets unix abstrak lintas-sandbox diblokir (LANDLOCK_SCOPED_ABSTRACT_UNIX_SOCKET; isolasi uid saja tidak memblokir ini).

Kontrol ini membatasi beban kerja. Kontrol root plane tetap menjadi batas kepercayaan yang terpisah: operasi file mode host-nya menolak symlink, proxy socket-nya mengunci inode socket dan memeriksa uid peer, serta rute khusus tidak tersedia dalam mode host. Kanal bersama yang tersisa dijelaskan dalam Batasan yang diketahui.

Mengapa ini bukan pengganti VM. Landlock dan isolasi uid ditujukan untuk workload dalam batas kepercayaan yang sama. Karena sandbox yang dipool berbagi kernel, VM, dan control plane, perlindungan dari setiap serangan lintas-sandbox tidak dijamin; sumber daya dan beberapa metadata daftar proses juga tetap dibagikan. Untuk kode yang saling tidak dipercaya, atau untuk GPU, gunakan Sandbox.create(), yang memberikan setiap sandbox VM-nya sendiri.

File model dalam pool

Karena satu-satunya area yang dapat ditulis pada sandbox yang dipool adalah home yang dibatasi Landlock (yang juga merupakan direktori kerja default-nya), API file membatasi semua path pada home tersebut: files.write("data/in.txt", ...) menulis ke $HOME/data/in.txt, awalan / dianggap relatif terhadap home, dan .. tidak dapat keluar darinya. File yang ditulis melalui API di-chown ke uid sandbox agar kode sandbox itu sendiri dapat membacanya. Hal ini memberikan model “filesystem yang berakar pada sandbox” yang bersih dan persis sesuai dengan apa yang dapat disentuh oleh kode di dalam sandbox — dan berbeda dari sandbox khusus, di mana path bersifat absolut pada filesystem container.

Path dinormalisasi secara leksikal, kemudian diselesaikan relatif terhadap deskriptor direktori home yang terbuka dengan penolakan symlink pada setiap komponen. API file tidak mengikuti symlink, termasuk tautan di dalam home yang sama; kode sandbox masih dapat menggunakannya di bawah aturan Landlock-nya.

Pools tidak memiliki state lokal yang otoritatif

Pool secara sengaja bukan file konfigurasi lokal. Pool adalah kumpulan host Job yang sedang berjalan, semuanya berbagi label hf-sandbox-pool=<id>. Hal ini menjaga konsistensi pool dengan bagian lain dari API sandbox (semuanya dapat ditemukan dari label dan dapat dilampirkan ulang dari mesin mana pun), dan berarti pool akan berhenti ada begitu host terakhirnya hilang.

  • Sebuah host membawa konfigurasi pool (image, flavor, sandboxes_per_host, idle timeout) dalam variabel env job-nya — label hanya digunakan untuk filtering. Ketika klien harus memulai host duplikat, ia membaca kembali konfigurasi tersebut dari host yang sedang berjalan (inspect_job), sehingga semua host dalam satu pool tetap konsisten tanpa catatan terpusat.
  • Env dan secrets bersifat per-sandbox, diberikan saat pembuatan — bukan pada level pool. Lingkungan dari sandbox yang di-pool disimpan di memori server host selama masa hidup sandbox tersebut (diterapkan ulang ke setiap perintah yang Anda jalankan); tidak pernah ditulis ke disk dan tidak pernah muncul di metadata Job mana pun. Tidak ada kanal secrets terenkripsi untuk sandbox yang di-pool — gunakan env dan perlakukan nilai-nilai tersebut sebagai “tidak disimpan di disk, tetapi juga tidak terenkripsi”. Untuk nilai yang memerlukan penyimpanan terenkripsi, gunakan secrets dari sandbox khusus.
  • Kapasitas bersifat otoritatif di sisi server. Host menolak pembuatan yang melebihi sandboxes_per_host (dengan balasan {"rejected": N}); klien memindahkan kelebihan ke host lain atau memulai duplikat. Hal ini menjaga pengemasan tetap tepat meskipun beberapa proses membuat ke pool yang sama secara bersamaan.
  • Evicting idle resources bersifat dua tingkat. Setiap sandbox dievict setelah melewati idle_timeout inaktivitasnya masing-masing (kecuali jika masih ada proses yang berjalan); begitu sebuah host tidak memiliki sandbox selama host idle timeout, host tersebut akan mematikan dirinya sendiri — sebagai pengaman penagihan bahkan jika semua klien menghilang.

Cache best-effort menjaga agar create --pool tetap cepat

Tidak adanya state lokal yang otoritatif memang bagus untuk keakuratan, tetapi berbiaya latensi. Sebuah hf sandbox create --pool <id> yang dingin (proses CLI baru) seharusnya harus menemukan ulang semuanya melalui jaringan sebelum dapat membuat sandbox: list_jobs untuk memindai namespace → inspect_job setiap host untuk membangun ulang URL dan noncenya → GET /v1/sandboxes untuk melihat seberapa penuh masing-masing → akhirnya POST untuk membuat. Beberapa round-trip yang murni overhead, pada setiap panggilan.

Cache best-effort di $HF_HOME/sandbox/pools/<context>/<pool-id>.json menghilangkan hal tersebut. Setelah setiap create/warm, sebuah proses mencatat konfigurasi pool serta, per host, URL proxy, auth nonce, dan slot kosong terakhir yang terlihat. Proses berikutnya membangun ulang transport host langsung dari file (tanpa HTTP) dan langsung menuju ke POST.

<context> adalah ringkasan dari endpoint, kredensial, dan namespace tempat entri tersebut ditulis — kredensial sebagai sidik jari; token Anda sendiri tidak pernah ditulis ke cache. Baik nama direktori maupun file memuatnya, dan pembacaan yang tidak cocok pada ketiga hal tersebut adalah cache miss biasa, sehingga pengguna lain dari mesin, endpoint lain, atau connect(pool, namespace="other-org") akan mendapatkan jalur dingin alih-alih host yang di-cache untuk sesuatu yang lain. File dibuat dengan 0600, direktori dengan 0700.

Apa yang dapat dan tidak dapat dipercaya dari cache:

  • Tidak berwenang terkait kapasitas. Server dalam-kerja tetap berwenang, sehingga jumlah live yang kedaluwarsa hanya akan menyebabkan permintaan yang terbuang, bukan host yang dikemas dengan salah.
  • Tidak dapat dipercaya untuk menentukan lokasi host. URL yang di-cache hanya digunakan jika URL tersebut adalah URL jobs-proxy HTTPS dari job yang namanya sama dengan entri tersebut, sehingga file cache tidak dapat memilih tujuan di mana token bearer HF dan token sandbox Anda dikirim; entri yang menyebutkan hal lain akan dihapus dari file. Setelah 15 menit, entri juga tidak lagi dianggap valid secara mandiri: inspect_job harus mengonfirmasi bahwa job masih berjalan, masih diberi label untuk pool ini, dan masih berada di URL tersebut sebelum transport dibangun.
  • Tidak dapat dipercaya berdasarkan bentuknya. Tipe dan rentang diperiksa saat dibaca, sehingga file yang diedit manual, terpotong, atau bertipe string akan menjadi cache miss, bukan error di tengah proses create().
  • Self-healing. Host yang di-cache tetapi sudah tidak ada akan dihapus pada permintaan pertama yang gagal dan dipangkas dari file; operasi create secara transparan beralih ke penemuan label.
  • Aman terhadap konkurensi. Penulisan digabungkan di bawah kunci file (berdasarkan job_id) dan dikomit secara atomik, sehingga proses create paralel tidak saling menimpa dan pembaca tidak pernah melihat file yang ditulis setengah.
  • Sekali pakai. Hapus dan Anda akan mengalami cache miss: jalur dingin berjalan dan semuanya tetap berfungsi. Tidak pernah dibagikan antar mesin.

Ada dua hal yang perlu diperhatikan. Perlakukan $HF_HOME sebagai data sensitif: sebuah entri tetap berupa URL host yang dapat digunakan kembali beserta nonce publik yang menjadi dasar turunan tokennya, dan meskipun file yang ditulis di bawah kredensial lain akan diabaikan, file yang ditulis di bawah kredensial Anda akan dihitung untuk jendela 15 menit di atas. Dan karena namespace merupakan bagian dari kunci, pool yang di-cache di bawah namespace= eksplisit hanya akan ditemukan kembali ketika namespace= yang sama dilewatkan — hf sandbox create --pool <id> membutuhkan --namespace yang sama dengan yang digunakan saat pool dibuat, atau ia akan mengambil jalur dingin dan mencari di namespace Anda sendiri.

Batasan yang diketahui

Pools digunakan untuk workload dalam satu trust boundary. Gunakan sandbox khusus untuk kode yang tidak Anda percaya. Pengecekan di bawah mengurangi risiko tertentu; mereka tidak mengubah sandbox yang di-pool menjadi VM terpisah.

Model ancaman sekilas

ActorDedikatifPool
Pengguna internet anonimProxy Jobs memerlukan token HF dengan akses baca namespace.Sama.
Anggota namespace dengan akses bacaDapat mencapai proxy dan pemeriksaan kesehatan publik, tetapi memerlukan token sandbox untuk operasi API.Sama.
Anggota namespace yang dapat membuat JobsTidak dapat menurunkan token pengguna lain dari noncenya.Dapat menyalin label pool, tetapi adopsi default memeriksa initiator dari API Jobs. adopt_hosts="namespace" memilih untuk mempercayai pembuat lain.
Kode yang berjalan di dalam sandboxBerbagi root dengan server di dalam VM; jangan gunakan ulang VM tersebut di antara batas kepercayaan.Dibatasi oleh uid dan Landlock, tetapi berbagi kernel, VM, dan control plane yang memiliki privilese.
Klien AndaMenyimpan kredensial HF dan sandbox khusus.Menyimpan kredensial manajemen host dan kemampuan per-sandbox yang terpisah.

Isolasi dan kekurangan sumber daya

  • Penemuan host bukan atestasi. Nilai default adopt_hosts="own" memeriksa inisiator, image, flavor, perintah, dan URL yang diekspos. Nilai ini tidak mengatestasi binari yang sedang berjalan atau membuat image yang dapat diubah menjadi dapat dipercaya. Gunakan adopt_hosts="namespace" hanya dengan anggota namespace yang Anda percaya.
  • Kredensial host tetap memiliki kekuatan penuh. Kredensial ini mengelola pool dan memulihkan token untuk setiap sandbox. Kredensial ini tidak pernah menggantikan token scoped yang hilang oleh klien ini. Host yang di-boot oleh versi ini menjalankan sbx-server 0.7.0, yang menolak kredensial tersebut pada rute scoped; host yang dimulai oleh klien versi lama tetap mempertahankan servernya (dan kompatibilitas token hostnya) hingga mereka didaur ulang.
  • Kanal bersama tetap ada. TCP keluar, akses loopback ke server kontrol, UDP, IPC kernel, dan metadata daftar proses yang dapat dibaca tidak terisolasi. Direktori sistem dan node perangkat tertentu tetap dapat diakses. Isolasi pool GPU belum diuji; gunakan mode khusus untuk GPU.
  • Batas bukan kuota agregat. rlimits per proses dan antrean output yang dibatasi mengurangi amplifikasi sumber daya. Mereka tidak mempartisi bagian CPU, total memori, ruang disk, inode, atau kapasitas jaringan antar sandbox. Paginasi direktori membatasi respons tetapi masih mematerialkan direktori di server. Penulisan file API bukan kuota disk, dan penulisan mode khusus ke file khusus dapat memblokir.
  • Pembatasan dapat dilemahkan secara eksplisit. Mode host secara default membutuhkan Landlock ABI 6 dan menolak ruleset yang gagal. Menurunkan SBX_MIN_LANDLOCK_ABI atau menggunakan flag pengembangan --allow-unconfined dari server menerima jaminan yang lebih sedikit; periksa /health yang terautentikasi untuk ABI dan fitur yang berlaku.
  • Koneksi proxy hanya diotentikasi sekali. Setelah permintaan pertama, proxy menyalin byte ke backend tersebut hingga EOF. Permintaan HTTP berikutnya pada koneksi itu tidak diotentikasi atau di-rutekan secara independen. Kompatibilitas WebSocket/SSE tidak menjamin keamanan terhadap penggunaan ulang koneksi upstream.

Siklus hidup dan kredensial

  • Descendant yang terputus dapat bertahan setelah proses berakhir atau timeout. Keduanya mengirim sinyal ke grup proses; descendant yang memanggil setsid() keluar dari grup tersebut. Hapus sandbox yang dipool atau akhiri Job khusus untuk mengakhiri seluruh workload.
  • max_hosts bersifat best-effort. Klien yang terpisah dapat menghitung host yang sama dan keduanya memprovision lebih banyak. Penerimaan backend atau idempotensi diperlukan untuk batas bersama yang ketat.
  • Teardown dapat gagal. Pembatalan host yang gagal akan memicu dan mempertahankan catatan cache. close() membatasi waktu tunggu untuk pembuatan yang sedang berjalan; pembuatan yang melebihi waktu tunggu tersebut dapat meninggalkan Job yang dapat ditagih. Gunakan Jobs API atau CLI untuk menyelaraskan sumber daya yang sedang berjalan.
  • Rotasi Bearer tidak memutar kemampuan sandbox. Autentikasi proxy menyelesaikan token HF saat ini per permintaan, tetapi reconnect stateless menurunkan token host dari nilai bearer asli yang persis. Memutar nilai tersebut dapat mencegah reconnect ke host yang sudah ada.
  • Kache lokal tetap menjadi input yang tepercaya selama 15 menit. URL dan konteks keamanannya diperiksa, tetapi tidak memiliki MAC integritas; lindungi $HF_HOME dari penulisan oleh kode yang tidak tepercaya.
  • Pin digest bukan provenance yang ditandatangani. Klien memverifikasi satu biner server tertentu. Publikasi dan pembaruan pin tersebut tetap menjadi langkah rilis; manifest dari alur kerja bukanlah atestasi kriptografis. Pintu keluar eksplisit SBX_ALLOW_UNVERIFIED_SERVER=1 hanya melewati verifikasi ketika kedua alat hash tidak ada.

/health tanpa autentikasi hanya mengekspos liveness dan protokol. Metadata terperinci memerlukan kredensial host. ID sandbox dan token memerlukan sumber acak kernel; penggunaan ulang UID mengikuti pembersihan proses dan home yang telah diverifikasi.

Kinerja

Semua angka diukur terhadap HF Jobs nyata di cpu-basic, dengan klien di laptop dan semua lalu lintas mengalir melalui proxy Jobs.

Sandbox khusus:

metrikvalue
mulai dingin (create() mengembalikan, server menjawab)~5,8s median
round-trip run()p50 ~110ms (batas bawah RTT proxy adalah ~105ms; overhead klien ≈ 0)
transfer file (paralel berjangkauan, >8 MiB)~340 MiB/s turun, ~441 MiB/s naik

Pool (mode bersama/host):

N sandboxhost (50/host)provision + buat semuaexec di semuakill alltotal
10026.1s1.5s0.6s8.2s
1000207.4s4.2s4.2s15.8s

1000 sandbox dibuat, dieksekusi, dan dihentikan dalam ~16 detik, dengan biaya yang kira-kira setara dengan satu cold start host (~6 detik) yang diamortisasi di seluruhnya — total sekitar $0,0009 (20 × cpu-basic), dibandingkan dengan ~$0,06 dan burst penjadwalan 1000-VM untuk satu Job per sandbox. Operasi create/exec/delete di sisi server masing-masing ~1 ms; anggaran waktu sepenuhnya berasal dari round-trip jaringan.

Keputusan desain, ringkasan

keputusanmengapa
Bangun di atas Jobs, tanpa layanan barumewarisi penagihan, perangkat keras, izin; berfungsi di setiap image
Binari Rust statis, diunduh saat startuptanpa Python/pip; ~6s cold start vs 30–90s untuk bootstrap berbasis pip
HTTP/1.1 buatan sendiriframework minimal menyangga respons chunked dan merusak streaming langsung (terverifikasi)
Autentikasi HMAC tanpa statusmenyambung ulang dari mana saja; token turunan alih-alih token HF itu sendiri (dibatasi per tugas — lihat Cakupan token)
run() akan melempar error jika exit code bukan nol (check=False untuk menonaktifkan)DX terbaik untuk loop “jalankan kode, lihat error” (gaya E2B)
idle_timeout watchdog alih-alih pembersihan di sisi kliensandbox yang persisten adalah fitur; yang bocor tetap akan mati
Pools = uid + Landlock, kapasitas yang bersifat otoritatif di server, tanpa status lokalfan-out pengguna yang sama cepat; benar di bawah konkurensi; dapat dilampirkan ulang di mana saja
Update on GitHub