notiziephp.it

BashBox: un interprete Bash in sandbox per agenti AI in PHP

Traduzione da Laravel News
11 Ottobre 2026 Tempo di lettura: 5 minuti
BashBox: un interprete Bash in sandbox per agenti AI in PHP

BashBox è un interprete bash scritto in puro PHP da Pushpak Chhajed, che ha anche creato il pacchetto Grant roles and permissions. Esegue gli script generati dagli agenti AI senza chiamare proc_open, exec o shell_exec. Ogni comando è una classe PHP che opera su un filesystem virtuale, e ogni esecuzione avviene entro limiti configurabili.

Eseguire gli script

Create un'istanza di Bash e passate uno script a exec(). Il risultato contiene l'output dello script e il codice di uscita:

use BashBox\Bash;

$bash = new Bash;

$result = $bash->exec('
NAME="BashBox"
echo "Hello, $NAME" | tr a-z A-Z
');

$result->stdout;   // "HELLO, BASHBOX\n"
$result->exitCode; // 0

L'interprete supporta pipe, redirezioni di fd come 2>&1, here-doc, process substitution, array, funzioni, control flow, parameter expansion e le opzioni set/shopt. Include 58 comandi, tra cui grep, sed, sort, find, xargs e sha256sum, oltre a builtin come cd, export, source, read e trap. Non c'è alcun binario sh o bash da richiamare. Uno script che non viene interpretato correttamente restituisce il codice di uscita 2 con l'errore di sintassi di bash su stderr invece di lanciare un'eccezione.

Potete pre-popolare la sandbox con file e variabili d'ambiente al momento della creazione:

use BashBox\Bash;
use BashBox\BashOptions;

$bash = new Bash(new BashOptions(
initialFiles: [
'/home/user/app.log' => "INFO boot\nERROR db timeout\nINFO ready\n",
],
env: ['APP_ENV' => 'production'],
));

$bash->exec('grep ERROR app.log')->stdout; // "ERROR db timeout\n"

Per una singola chiamata, ExecOptions passa stdin, variabili d'ambiente aggiuntive o limiti diversi a exec().

Backend del filesystem

Il backend predefinito InMemoryFs non tocca mai il disco. Altri tre backend danno a uno script accesso a file reali:

  • OverlayFs legge da una directory reale e mantiene le scritture in un layer copy-on-write in memoria
  • ReadWriteFs legge e scrive su disco, confinato a una directory root
  • MountableFs monta backend diversi su percorsi diversi
use BashBox\Filesystem\InMemoryFs;
use BashBox\Filesystem\MountableFs;
use BashBox\Filesystem\OverlayFs;
use BashBox\Filesystem\ReadWriteFs;

// Read a real project, keep all writes in memory
$bash = new Bash(new BashOptions(
fs: new OverlayFs('/path/to/project'),
));

// Keep everything in memory except a writable /data mount
$mount = new MountableFs(new InMemoryFs);
$mount->mount('/data', new ReadWriteFs('/real/data'));
$bash = new Bash(new BashOptions(fs: $mount));

Ogni backend ha per impostazione predefinita una quota disco di 64 MB e 10.000 voci. Una scrittura che supera la quota fallisce con No space left on device, come accadrebbe su un disco pieno. BashBox blocca anche il path traversal e l'injection di null byte, e OverlayFs nega i symlink per impostazione predefinita quando legge da una directory reale.

Limiti di esecuzione

La classe Limits ha 18 impostazioni, dal numero di comandi e iterazioni dei loop alla dimensione degli here-doc e alla profondità dell'albero di parsing. Superarne una lancia BashBox\Exceptions\ExecutionLimitException:

use BashBox\Limits;

$bash = new Bash(new BashOptions(
limits: new Limits(
maxCommandCount: 100,
maxLoopIterations: 500,
maxOutputSize: 1024 * 1024, // 1MB
maxCallDepth: 10,
),
));

I valori predefiniti consentono 10.000 comandi per script, 10.000 iterazioni per loop, 10 MB di output, una profondità di chiamata delle funzioni pari a 100 e 1 MB di testo dello script. ExecOptions può sovrascrivere i limiti per una singola chiamata a exec(), a eccezione della quota del filesystem, che viene impostata quando create l'istanza di Bash.

Accesso alla rete

L'accesso alla rete è disattivato per impostazione predefinita, e il comando curl non esiste finché non passate una NetworkConfig:

use BashBox\Network\NetworkConfig;

$bash = new Bash(new BashOptions(
network: new NetworkConfig(
allowedUrlPrefixes: ['https://api.example.com/'],
allowedMethods: ['GET', 'POST'],
denyPrivateRanges: true,
maxResponseSize: 5 * 1024 * 1024, // 5MB
timeout: 10,
),
));

Gli script possono quindi chiamare curl su qualsiasi URL sotto un prefisso consentito. L'opzione denyPrivateRanges è attiva per impostazione predefinita. Rifiuta indirizzi loopback, privati, link-local e altri indirizzi IPv4 e IPv6 non pubblici, e verifica sia l'host dell'URL sia l'indirizzo a cui curl si connette. Come il vero curl, il curl di BashBox segue i redirect solo con -L. Verifica ogni destinazione di redirect rispetto alla allow-list e rimuove gli header Authorization e Cookie sui redirect cross-origin. Una lista allowedUrlPrefixes vuota nega ogni URL. Per consentire qualsiasi URL, impostate dangerouslyAllowFullInternetAccess: true.

Comandi personalizzati

Per aggiungere un comando che BashBox non include, estendete AbstractCommand e registratelo sull'istanza di Bash:

use BashBox\Commands\AbstractCommand;
use BashBox\Commands\CommandContext;
use BashBox\ExecResult;

class MyCommand extends AbstractCommand
{
public function getName(): string
{
return 'mycommand';
}

public function execute(array $args, CommandContext $ctx): ExecResult
{
return $this->success('Hello from my command!');
}
}

$bash->registerCommand(new MyCommand);

$bash->exec('mycommand')->stdout; // "Hello from my command!"

Installazione

BashBox richiede PHP 8.4 o versione successiva e non ha altre dipendenze Composer. Potete richiamarlo da uno strumento nel Laravel AI SDK o da qualsiasi altra libreria per agenti, e restituire l'output al modello. Con l'estensione opzionale ffi, BashBox usa il motore regex RE2. Senza di essa, BashBox usa PCRE con limiti rigidi.

composer require shipfastlabs/bashbox

BashBox è distribuito con licenza MIT e l'ultima release è la v0.0.3. Potete trovare il codice sorgente e la documentazione completa nel repository BashBox su GitHub.

Condividi su: LinkedIn

Altri articoli recenti

01
02
03