Carry Petri's sandbox plugin variables into workers and test servers

A Petri run executes in the worker process, which resolves the
sandbox-driver plugins itself. The `PETRI_SANDBOX_*` variables (plugin
paths, checksum overrides, dev mode, the Docker host address and the action
host image) now have `EnvVars` names, cross the worker's environment
allowlist with `PATH`, and pass through the test harness's isolation so a
developer's plugin override reaches the servers tests start and the workers
those servers launch.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-09-17 21:20:22 -04:00
parent a621fb72e1
commit 1e2a205ec3
No known key found for this signature in database
3 changed files with 77 additions and 0 deletions

View file

@ -50,6 +50,18 @@ const WORKER_ENV_ALLOWLIST: &[&str] = &[
EnvVars::AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,
EnvVars::AWS_CONTAINER_CREDENTIALS_FULL_URI,
EnvVars::AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE,
// Petri's sandbox-driver plugins are resolved in the worker, where a
// Petri run executes: the plugin path, checksum and dev-mode overrides
// cross with `PATH`, so the worker finds the plugins the server would.
EnvVars::PETRI_SANDBOX_HOST_PLUGIN,
EnvVars::PETRI_SANDBOX_HOST_SHA256,
EnvVars::PETRI_SANDBOX_DOCKER_PLUGIN,
EnvVars::PETRI_SANDBOX_DOCKER_SHA256,
EnvVars::PETRI_SANDBOX_DAYTONA_PLUGIN,
EnvVars::PETRI_SANDBOX_DAYTONA_SHA256,
EnvVars::PETRI_SANDBOX_PLUGIN_DEV,
EnvVars::PETRI_SANDBOX_DOCKER_HOST_ADDRESS,
EnvVars::PETRI_SANDBOX_ACTION_HOST_IMAGE,
];
const RENDER_GRAPH_ENV_ALLOWLIST: &[&str] = &[EnvVars::PATH, EnvVars::HOME, EnvVars::TMPDIR];
@ -144,6 +156,11 @@ mod tests {
("FABRO_DEV_TOKEN".to_string(), "garbage".to_string()),
("FABRO_WORKER_TOKEN".to_string(), "leak".to_string()),
("MY_API_KEY".to_string(), "blocked".to_string()),
(
"PETRI_SANDBOX_HOST_PLUGIN".to_string(),
"/opt/petri/sandbox-driver-host".to_string(),
),
("PETRI_SANDBOX_PLUGIN_DEV".to_string(), "1".to_string()),
]);
let mut cmd = env_command();
apply_allowlist(&mut cmd, WORKER_ENV_ALLOWLIST, &|name| {
@ -178,6 +195,16 @@ mod tests {
Some("xterm-256color")
);
assert_eq!(actual.get("NO_COLOR").map(String::as_str), Some("1"));
// Petri's plugin overrides cross so the worker resolves the same
// sandbox-driver plugins the server would.
assert_eq!(
actual.get("PETRI_SANDBOX_HOST_PLUGIN").map(String::as_str),
Some("/opt/petri/sandbox-driver-host")
);
assert_eq!(
actual.get("PETRI_SANDBOX_PLUGIN_DEV").map(String::as_str),
Some("1")
);
assert_eq!(actual.get("CLICOLOR").map(String::as_str), Some("0"));
assert_eq!(actual.get("CLICOLOR_FORCE").map(String::as_str), Some("1"));
// Bedrock SigV4 chain inputs cross into the worker so it can re-resolve

View file

@ -42,6 +42,34 @@ impl EnvVars {
pub const FABRO_WEB_URL: &'static str = "FABRO_WEB_URL";
pub const FABRO_WORKER_TOKEN: &'static str = "FABRO_WORKER_TOKEN";
// Petri's sandbox-driver plugins: where each provider's plugin executable
// is, its checksum override, dev mode for unpinned plugins, and how a
// remote Docker daemon's containers reach this machine. A run's worker
// resolves the plugins, so these cross into the worker process.
pub const PETRI_SANDBOX_HOST_PLUGIN: &'static str = "PETRI_SANDBOX_HOST_PLUGIN";
pub const PETRI_SANDBOX_HOST_SHA256: &'static str = "PETRI_SANDBOX_HOST_SHA256";
pub const PETRI_SANDBOX_DOCKER_PLUGIN: &'static str = "PETRI_SANDBOX_DOCKER_PLUGIN";
pub const PETRI_SANDBOX_DOCKER_SHA256: &'static str = "PETRI_SANDBOX_DOCKER_SHA256";
pub const PETRI_SANDBOX_DAYTONA_PLUGIN: &'static str = "PETRI_SANDBOX_DAYTONA_PLUGIN";
pub const PETRI_SANDBOX_DAYTONA_SHA256: &'static str = "PETRI_SANDBOX_DAYTONA_SHA256";
pub const PETRI_SANDBOX_PLUGIN_DEV: &'static str = "PETRI_SANDBOX_PLUGIN_DEV";
pub const PETRI_SANDBOX_DOCKER_HOST_ADDRESS: &'static str = "PETRI_SANDBOX_DOCKER_HOST_ADDRESS";
pub const PETRI_SANDBOX_ACTION_HOST_IMAGE: &'static str = "PETRI_SANDBOX_ACTION_HOST_IMAGE";
/// Every Petri plugin variable, in one list for the process boundaries
/// that forward them.
pub const PETRI_SANDBOX_PLUGIN_VARS: &'static [&'static str] = &[
Self::PETRI_SANDBOX_HOST_PLUGIN,
Self::PETRI_SANDBOX_HOST_SHA256,
Self::PETRI_SANDBOX_DOCKER_PLUGIN,
Self::PETRI_SANDBOX_DOCKER_SHA256,
Self::PETRI_SANDBOX_DAYTONA_PLUGIN,
Self::PETRI_SANDBOX_DAYTONA_SHA256,
Self::PETRI_SANDBOX_PLUGIN_DEV,
Self::PETRI_SANDBOX_DOCKER_HOST_ADDRESS,
Self::PETRI_SANDBOX_ACTION_HOST_IMAGE,
];
// LLM providers and tool integrations
pub const ANTHROPIC_API_KEY: &'static str = "ANTHROPIC_API_KEY";
pub const AWS_BEARER_TOKEN_BEDROCK: &'static str = "AWS_BEARER_TOKEN_BEDROCK";
@ -197,6 +225,15 @@ mod tests {
EnvVars::FABRO_VERBOSE,
EnvVars::FABRO_WEB_URL,
EnvVars::FABRO_WORKER_TOKEN,
EnvVars::PETRI_SANDBOX_HOST_PLUGIN,
EnvVars::PETRI_SANDBOX_HOST_SHA256,
EnvVars::PETRI_SANDBOX_DOCKER_PLUGIN,
EnvVars::PETRI_SANDBOX_DOCKER_SHA256,
EnvVars::PETRI_SANDBOX_DAYTONA_PLUGIN,
EnvVars::PETRI_SANDBOX_DAYTONA_SHA256,
EnvVars::PETRI_SANDBOX_PLUGIN_DEV,
EnvVars::PETRI_SANDBOX_DOCKER_HOST_ADDRESS,
EnvVars::PETRI_SANDBOX_ACTION_HOST_IMAGE,
EnvVars::ANTHROPIC_API_KEY,
EnvVars::ANTHROPIC_BASE_URL,
EnvVars::AWS_BEARER_TOKEN_BEDROCK,

View file

@ -177,6 +177,11 @@ pub fn isolated_env(home_dir: &Path) -> HashMap<String, String> {
if let Some(path) = std::env::var_os(EnvVars::PATH).and_then(|value| value.into_string().ok()) {
env.insert(EnvVars::PATH.to_string(), path);
}
for name in EnvVars::PETRI_SANDBOX_PLUGIN_VARS {
if let Some(value) = std::env::var_os(name).and_then(|value| value.into_string().ok()) {
env.insert((*name).to_string(), value);
}
}
env.insert(EnvVars::NO_COLOR.to_string(), "1".to_string());
env.insert(EnvVars::HOME.to_string(), home_dir.display().to_string());
env.insert(
@ -216,6 +221,14 @@ fn apply_test_isolation_with_lookup(
if let Some(path) = lookup(EnvVars::PATH) {
cmd.env(EnvVars::PATH, path);
}
// Petri resolves its sandbox-driver plugins from these, in the server a
// test starts and in the workers that server launches; a developer's
// plugin override reaches them like `PATH` does.
for name in EnvVars::PETRI_SANDBOX_PLUGIN_VARS {
if let Some(value) = lookup(name) {
cmd.env(name, value);
}
}
cmd.env(EnvVars::NO_COLOR, "1");
cmd.env(EnvVars::HOME, home_dir);
cmd.env(EnvVars::FABRO_NO_UPGRADE_CHECK, "true")