Langkau ke kandungan

Guardrail — satu polisi untuk setiap tindakan yang mengubah keadaan

Ejen dalam Control Center boleh memadam fail, push cawangan, menerbitkan pull request dan memanggil API luaran. Setiap satu daripadanya ialah jenis risiko yang berbeza, dan untuk masa yang lama hanya satu daripadanya — perintah shell — mempunyai polisi. Guardrail wujud untuk menjawab satu soalan secara seragam, bagi setiap tindakan yang mengubah keadaan yang boleh dilakukan oleh ejen, tanpa mengira runtime atau alat yang mencadangkannya: adakah ini dibenarkan, adakah ia memerlukan kelulusan, atau adakah ia ditolak?

Terdapat tepat satu enjin polisi. Ia dirujuk pada setiap titik tempat sesuatu tindakan boleh keluar daripada sistem: daftar alat harness terbina, pintu penghantar MCP di sisi pelayan dan mutasi operasi repo. Peraturan yang ditulis sekali oleh itu terpakai kepada runtime terbina dan CLI ejen luaran sama rata — tiada laluan kedua yang lebih senyap untuk mengelilinginya. Polisi perintah lama yang hanya untuk bash masih berfungsi: peraturan boleh memadankan awalan perintah dan bukan kelas tindakan, dan kedua-dua bentuk itu wujud bersama dalam stor yang sama.

Namun, enjin ini bukan pengganti kotak pasir OS, dan kotak pasir bukan penggantinya. Kedua-duanya menjawab soalan yang berbeza: guardrail menentukan sama ada panggilan yang dapat dilihat oleh Control Center dibenarkan berlaku sama sekali, manakala kotak pasir mengehadkan ke mana proses yang terhasil boleh menjangkau. cc_server menerapkan kotak pasir di tempat hos menawarkan backend — tetapi Windows tidak menawarkannya dan Linux memerlukan bwrap dan socat. Pada hos seperti itu, guardrail ialah lapisan penguatkuasaan paling luar dan bukan polisi yang berdiri di atas lantai, dan itu wajar diketahui apabila anda memutuskan sejauh mana kebebasan yang ingin diberikan.

Setiap alat yang mengubah keadaan mengisytiharkan ActionClasses mana yang menjadi miliknya, daripada himpunan tertutup yang mengandungi tiga belas kelas kesan. Lima daripadanya bertanya dahulu secara lalai; yang selebihnya membenarkan, dan peraturanlah yang mengubahnya.

Kelas Lalai terbina Apa yang dicakup
fileDelete Tanya dahulu Memadam fail (tulisan berbentuk padam, rm)
gitPush Tanya dahulu Push ke remote git
prCreate Tanya dahulu Membuka pull request
prPublish Tanya dahulu Menerbitkan semakan, mencantumkan PR
vendorSyncWrite Tanya dahulu Menulis ke penjejak tiket luaran (Linear, Jira, penyegerakan GitHub)
fileWriteOutsideWorktree benarkan Menulis fail di luar worktree terasing
gitCommit benarkan Mencipta commit git
networkEgress benarkan Keluaran rangkaian (pengambilan web, HTTP sewenang-wenangnya)
secretAccess benarkan Membaca rahsia atau kelayakan
packageInstall benarkan Memasang pakej (npm, pip, pub, brew)
processSpawn benarkan Menjalankan proses (shell dan apa-apa yang memanggil shell)
workspaceMutation benarkan Mengubah struktur ruang kerja (repo, ruang, ejen)
enclosureControl benarkan Mengawal persekitaran terasing (stesen): menghidupkan VM, menghantar input kepadanya

Lapan kelas yang membenarkan secara lalai dipilih dengan andaian bahawa lantai kotak pasir terpakai di bawahnya. Ia terpakai di tempat hos menawarkan backend, dan tidak terpakai pada Windows atau pada mesin Linux yang tiada bwrap dan socat — jadi jika anda mahu fileWriteOutsideWorktree atau packageInstall dikawal di situ, itulah peraturan yang perlu anda tulis sendiri.

Himpunan ini ditutup dengan sengaja. Alat pengubah baharu yang tidak mengisytiharkan sebarang kelas akan gagal dalam ujian ratchet, jadi taksonomi hanya boleh berkembang melalui keputusan yang eksplisit dan berhujah — “kekacauan taksonomi ialah kematian ciri ini.” Tiga belas kelas cukup untuk menyatakan polisi yang benar-benar ditulis orang (jangan sekali-kali push tanpa bertanya, jangan sekali-kali memadam di luar worktree, sentiasa benarkan bacaan) dan cukup sedikit sehingga UI tetapan kekal mudah difahami.

Peraturan memetakan (scope, ActionClass | command prefix) → allow | prompt | deny. Skop bersarang daripada yang paling khusus kepada yang paling umum:

ruang > ejen > ruang kerja > praset modus > lalai terbina

Penyelesaian mengutamakan kekhususan dahulu: skop pertama yang mempunyai peraturan yang sepadan akan memutuskan dan penyelesaian berhenti di situ. Paling ketat hanyalah pemecah seri — antara dua peraturan yang sama khusus dalam satu skop dan apabila menggabungkan beberapa kelas yang diisytiharkan oleh satu tindakan. Dalam sesuatu skop, peraturan perintah dipadankan pada awalan perintah yang terpanjang. Benarkan tidak mengalahkan tolak di mana-mana.

Dua keputusan membawa jaminan keras:

  • Tanya dahulu yang tertutup apabila gagal. prompt tanpa pelulus yang bersambung diselesaikan sebagai ditolak. Soalan yang tidak dijawab tidak pernah menjadi ya.
  • Gabungan paling ketat. Tindakan yang merentasi beberapa kelas digabungkan secara paling ketat; apabila beberapa kelas bertanya dahulu, satu pengesahan menyenaraikan kesemuanya.

Tiada selak bagi setiap giliran, dan itu memang disengajakan. Setiap panggilan alat menyelesaikan semula polisi dari awal, jadi permintaan berulang untuk tindakan yang sama dihadkan oleh “ingat keputusan ini” milik pengendali sendiri, bukan oleh apa-apa yang berskop giliran.

Peraturan boleh mengekang ARGUMEN sesuatu tindakan, bukan hanya kata kerjanya. “Boleh push” dan “boleh push ke feature/*” ialah dakwaan yang berbeza, dan hanya dakwaan kedua yang merupakan kawalan — pintu keupayaan yang hanya membenarkan kata kerjanya ialah bentuk di sebalik kebanyakan insiden ejen yang dilaporkan secara terbuka.

Kekangan boleh menamakan:

  • laluan — corak glob (repos/**, !**/.env)
  • ref — ref git, dengan penafian ! (['**', '!main'] dibaca sebagai “mana-mana cawangan kecuali main”)
  • hos — destinasi rangkaian, dengan kad bebas subdomain (*.internal)
  • perintah — awalan perintah, dipadankan pada sempadan perkataan
  • siling — maxCount / maxCents, jadi “padam sehingga 50 fail” boleh dinyatakan

Tiga sifat terhasil daripada mengekalkan tatabahasa yang tertutup dan tanpa gelung, dan ketiga-tiganya itulah tujuannya: setiap peraturan dipaparkan sebagai ayat yang boleh anda baca semula, setiap penolakan boleh menamakan kekangan yang padan, dan keseluruhan polisi boleh disenaraikan — anda boleh melihat apa yang boleh dilakukan oleh ejen sebelum ia berjalan.

Tiga peraturan yang penting:

  • Peraturan yang dikekang lebih khusus daripada peraturan tanpa kekangan pada skop yang sama, jadi “tolak push ke main” mengalahkan “benarkan push” tanpa sesiapa perlu memikirkan susunan.
  • Peraturan ketat (tolak / tanya dahulu) terpakai apabila permintaan menyentuh mana-mana nilai yang dinamakannya; peraturan permisif (benarkan) hanya terpakai apabila permintaan sepenuhnya berada di dalamnya. Membaca kedua-duanya dengan cara yang sama akan membolehkan ejen menyeludupkan laluan terlarang dengan menyelitkan laluan yang tidak bersalah di sebelahnya.
  • Peraturan yang menamakan faset yang tidak disebut langsung oleh permintaan tidak diterapkan dan juga tidak dilangkau: ia dinaikkan kepada kelulusan. Melangkaunya secara senyap akan menjadikan setiap peraturan cawangan terlindung tidak berkesan terhadap alat yang tidak melaporkan refnya; menolak secara senyap akan menolak setiap push yang tidak dapat dihuraikan oleh pengekstrak. Dengan tiada pelulus bersambung, peraturan sedia ada yang tertutup apabila gagal menukar peningkatan itu kepada penolakan.

Apa yang boleh dan tidak boleh ditangkap oleh peraturan perintah

Bahagian bertajuk “Apa yang boleh dan tidak boleh ditangkap oleh peraturan perintah”

Peraturan commandPrefix dipadankan pada sempadan perkataan: git push merangkumi git push origin main dan bukan git pushx. Ia tidak menormalkan shell. git push (dua ruang), cd sub && git push dan GIT_DIR=… git push semuanya rentetan yang berbeza dan tiada satu pun daripadanya sepadan dengan peraturan tentang git push.

Itu had yang nyata dan ia dinyatakan dan bukan ditutup-tutupi: peraturan perintah ialah kemudahan bagi pengendali untuk membentuk tingkah laku ejen biasa, bukan sempadan terhadap ejen yang bermusuhan. Sempadannya ialah kelas kesan (yang diisytiharkan oleh sesuatu alat dan tidak boleh dieja semula), jaring perintah modus di bawah stor polisi, dan kotak pasir OS di bawah kedua-duanya. Peraturan perintah yang diselesaikan kepada allow tidak pernah melonggarkan mana-mana satu daripadanya — jaring modus berjalan selepasnya dan deny daripadanya adalah muktamad.

Menjawab permintaan kelulusan dengan “ingat ini” menulis peraturan polisi yang sebenar: berskop (ruang / ejen / ruang kerja), dikekang oleh argumen (meluluskan push ke feature/login memberikan feature/**, bukan main) dan membatalkan dirinya sendiri pada TTL yang eksplisit. Berkata ya untuk beberapa jam berikutnya tidak sama dengan menulis semula polisi kekal anda secara senyap, dan peraturan yang ditulisnya masuk ke dalam stor yang sama dengan asal usul remembered dan tarikh luput, jadi ia boleh dibatalkan lebih awal.

Setiap peraturan membawa satu tahap:

  • advisory — benarkan, tetapi rekod bahawa peraturan itu padan. Inilah laluan penerimaan: lancarkan peraturan ketat dalam modus advisory, baca jejak audit selama seminggu untuk melihat dengan tepat apa yang akan disekatnya, kemudian naikkan tarafnya. Tanpa tahap ini, polisi ketat tidak akan pernah dihidupkan.
  • soft — tolak, boleh diatasi oleh seseorang yang memegang kebenaran mengatasi, dengan justifikasi yang direkodkan. Pengatasan itu sendiri ialah peristiwa yang diaudit.
  • hard (lalai) — tolak. Tiada apa yang boleh mengatasinya.

Pengendali pemasangan boleh memaku polisi yang tidak boleh dilonggarkan oleh mana-mana pentadbir ruang kerja. Peraturan terurus berada di sisi pelayan dan digabungkan secara paling ketat dengan rantaian setiap ruang kerja sendiri — ia bukan skop di kepala rantaian itu, kerana allow terurus di kepala rantaian akan membolehkan pemasangan mengatasi penolakan sesuatu ruang kerja, iaitu bertentangan dengan tujuan sebuah pengapit. Oleh itu, peraturan terurus hanya boleh mengetatkan.

Menyetel CC_SERVER_MANAGED_POLICY kepada fail JSON mengatasi peraturan tersimpan sepenuhnya; itulah yang membolehkan pengendali memaku pendirian yang tidak boleh dibalikkan oleh mana-mana UI pentadbir — jawapan kepada “bolehkah saya menghalang pembangun saya daripada mematikan kawalan keselamatan?”.

Dail autonomi setiap ruang ialah profil bernama di atas stor polisi yang sama ini, bukan mekanisme kedua. Ketiga-tiga tetapannya disimpan dan dihantar sebagai proposeOnly, actWithApproval dan actFreely (bentuk bersempang hanyalah prosa UI dan autonomy.setForSpace menolak apa-apa yang lain). Membiarkannya tidak ditetapkan berkelakuan seperti actWithApproval.

Apa yang dilakukan oleh setiap satu terhadap keputusan yang telah diselesaikan:

  • proposeOnly menolak terus setiap alat yang melalui pintu polisi. Ejen masih boleh menaakul dan membalas; cuma ia tidak boleh bertindak dan mesejnya menyatakan sebabnya.
  • actWithApproval (dan tidak ditetapkan) ialah pintu kelulusan tertutup apabila gagal yang diterangkan di atas.
  • actFreely meluluskan terlebih dahulu apa-apa yang tidak diselesaikan kepada deny yang keras.

Yang terakhir itu wajar dinyatakan secara terus terang dan bukan dilembutkan: di bawah actFreely, keputusan prompt tidak dinaikkan kepada pelulus — ia dibenarkan dan tiada sesiapa ditanya. Hanya peraturan deny yang eksplisit bertahan melalui dail ini. Jadi actFreely ialah pemberian autonomi yang disengajakan, bukan tetapan keselesaan, dan peraturan tertutup apabila gagal melindungi tepat kes yang penting (actWithApproval, lalai).

Perwakilan antara ejen dikawal pada titik penyempitan delegate_task oleh kesemua empat pengawal: had kedalaman (lalai 3), pengesanan kitaran, siling autonomi (ejen yang diwakilkan tidak boleh bertindak dengan autonomi melebihi ejen yang mewakilkannya — keistimewaan tidak boleh diseludupkan dengan menyerahkan kerja kepada ejen yang lebih bebas) dan sampul belanjawan (perwakilan mengebilkan baki belanjawan ejen yang mewakilkan dan tidak boleh mencetak lebih banyak). Setiap satu ditolak secara lantang, dengan sebab pengawal itu dikembalikan kepada ejen kata demi kata.

Tidak setiap runtime membenarkan Control Center memintas setiap tindakan. CLI ejen luaran menjalankan sesetengah alat secara natif, in-process, di tempat yang tiada pintu boleh berada. Daripada berpura-pura sebaliknya, setiap penyesuai membawa matriks kejujuran: bagi setiap penyesuai, sama ada Control Center menapis permukaan alat, memintas panggilan alat, memerhati kontrak penyelesaian, boleh melihat alat natif pelari dan sama ada alat in-process diliputi oleh profil kotak pasir.

Dua entri wajar dibaca sebelum anda mempercayai sesuatu konfigurasi. Harness terbina mengisytiharkan bahawa alat fail in-processnya tidak diletakkan di dalam kotak pasir — permukaan alat dan enjin polisi ini ialah satu-satunya sempadan sistem fail yang dimilikinya. Claude Code mengisytiharkan bahawa panggilan alatnya sendiri tidak boleh dipintas, kerana ia dilancarkan dengan --dangerously-skip-permissions; Control Center melihat panggilan mcp__*nya dan, melalui hook, baris perintah Bash-nya, manakala alat baca, tulis dan edit miliknya sendiri berjalan tanpa dilihat.

Layar tetapan memaparkan matriks ini, kerana satu-satunya kegagalan yang tidak boleh dimaafkan bagi sistem guardrail ialah menuntut liputan yang tidak wujud.

Guardrail berada di Tetapan → Ruang kerja → Kebenaran ejen (/workspaces/<id>/settings/workspace/permissions). Layar ini mempunyai matriks polisi tempat peraturan ditulis, templat polisi, ujian “Bagaimana jika?”, jejak audit kebenaran dan matriks kejujuran penyesuai.

Ujian itu menerima kelas tindakan (atau perintah) dan sesuatu skop lalu menunjukkan peraturan mana yang memutuskan dan mengapa. Kerana penyelesaiannya tulen dan deterministik — tindakan yang sama, skop yang sama, keputusan yang sama — jawapan ujian itu ialah jawapan yang akan diterima oleh ejen.