Sandbox Docker
Obiettivo: eseguire comandi nella sandbox Docker e aprire solo la rete che un progetto richiede.
Prerequisiti
- Docker, raggiungibile dalla macchina che esegue il worker.
- Un manifesto
Projectconsandbox.imageimpostato.
Passi
-
Esegui i comandi da un agente
deepconexecute: true, o da un nodoscript. Entrambi usano il container che apre il pluginafe-docker(sandboxes/docker). -
Fai elencare a un agente
acpi nomi delle variabili d'ambiente che gli servono. L'adapter Docker passa ognuna come-e NAME. Il valore si legge dall'ambiente del clientdocker, e non compare mai in un argv. Token della forge e chiavi del motore non entrano mai in una sandbox. -
Esegui un nodo con
run: <Script name>. Esegue ilcommanddello Script nella sandbox del progetto, in/workspace. L'artefatto nominato dawritessi riempie daok,exit_codeeoutput, e dalle chiavi di un oggetto JSON sullo stdout. Un'uscita diversa da zero è un esito, non un fallimento. -
Usa
run: builtin:merge_and_ciper committare il worktree di ogni lane, fondere i branch delle lane in quello di integrazione ed eseguireci.scriptnella sandbox di integrazione. L'artefatto portamerged,conflicts,ci_passedeci_output. Un conflitto di merge o una CI rossa è un esito su cui il flow instrada conwhen. -
Quando un progetto richiede la rete, dichiara
sandbox.egress:sandbox:image: afe-sandbox-acp:testegress: ["openrouter.ai"]Il motore crea una rete interna, e avvia un proxy
squiddadocker/egress-proxycon l'allowlist inAFE_EGRESS_HOSTS. Lo collega alla bridge di default, e mette la sandbox sulla rete interna conHTTP_PROXY/HTTPS_PROXYche puntano al proxy. Escono solo gli host in lista. Ogni altro host è rifiutato, e così una connessione diretta che ignora il proxy.
Il container
Di default una sandbox non ha rete (--network none). Il container è:
- un container per ticket e scope, con un nome fisso e l'etichetta
afe.ticket=<id>. Viene ritrovato dopo un riavvio. - per un workspace
git, un volume con nome per ticket (afe-<key>-ws) e un solo container per ticket (afe-<key>), condiviso da tutti gli scope (V7b, R14). Per un workspacefolderresta il mount della cartella sull'host. - niente rete di default, tutte le capability tolte,
no-new-privileges. CPU, memoria e processi sono limitati, e gira come utente non-root. - montato solo su
/workspace. Il socket Docker non è mai montato. - limitato alle variabili d'ambiente che un agente
acpdichiara per nome. Mai un token della forge, mai una chiave del motore.
Un comando oltre il suo timeout viene ucciso e riportato come scaduto. Sandbox, proxy, rete e
volume del workspace portano tutti l'etichetta afe.ticket. Spariscono con il ticket, alla fine
(done, failed, cancelled) o su richiesta. Un ticket in pausa tiene il suo container, e così
lo ritrova.
Un comando o uno script in volo quando un worker muore viene rieseguito dopo il recupero. I comandi si assumono ripetibili.
Risoluzione dei problemi
Un comando script o deep si blocca e poi fallisce per timeout
Il comando ha superato sandbox.timeoutS (o il timeout del nodo). La sandbox lo uccide e riporta
l'esito come scaduto. Non lo riprova da sola. Alza il timeout, o dividi il comando in passi più
piccoli.
Una chiamata di rete dalla sandbox fallisce o va in timeout
L'host non è in sandbox.egress. Squid nega ogni host che non permette, e una connessione diretta
che aggira il proxy non ha una via d'uscita. Aggiungi l'host a egress.
La sandbox è sparita dopo un riavvio, ma il ticket aspetta ancora Il container viene rimosso quando il ticket finisce, non mentre è in pausa. Se la sandbox manca per un ticket che aspetta ancora, controlla il log del worker per una sandbox persa. Il motore rimuove la sandbox e il suo volume, poi rimette in coda il ticket. Un ripristino da checkpoint a quel punto scarta il turno salvato del nodo interrotto.