refactor(sandbox): home the runtime directory under the system tmp dir

Use /tmp/fabro/runtime for both Docker and Daytona instead of
provider-specific roots. A writable /tmp inside the sandbox is already
a dependency (commit-message files, exec stop-files), it needs no
root-level mkdir for non-root container users, and it makes the two
providers uniform.

The trailing runtime path component stays load-bearing: materialized
blobs at runtime/blobs/{hash}.json are recognized as managed blob
references and normalized back to blob:// in durable context.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Kmn5jyrdpyCdvcfvmEDvA
This commit is contained in:
Bryan Helmkamp 2026-08-25 07:21:24 -04:00
parent b4fd7ae00b
commit f322025b3d
No known key found for this signature in database
5 changed files with 24 additions and 14 deletions

View file

@ -61,7 +61,11 @@ const DAYTONA_BASH_SESSION_REMEDIATION: &str = "Daytona ran the direct command t
pub(crate) const WORKING_DIRECTORY: &str = "/home/daytona/workspace";
pub(crate) const REPOS_ROOT: &str = "/home/daytona/repos";
pub(crate) const RUNTIME_DIRECTORY: &str = "/home/daytona/fabro/runtime";
// Beneath the system tmp dir so any sandbox user can create it; the
// trailing `runtime` component is load-bearing — materialized blobs at
// `runtime/blobs/{hash}.json` are recognized as managed blob references and
// normalized back to `blob://` in durable context.
pub(crate) const RUNTIME_DIRECTORY: &str = "/tmp/fabro/runtime";
const DEFAULT_SNAPSHOT: &str = "daytona-medium";
pub const DEFAULT_DAYTONA_API_URL: &str = "https://app.daytona.io/api";
pub(crate) const DAYTONA_DASHBOARD_SANDBOXES_URL: &str =

View file

@ -49,7 +49,11 @@ const DOCKER_BASH_REQUIREMENT: &str = "Docker sandboxes require /bin/bash for ev
pub(crate) const WORKING_DIRECTORY: &str = "/workspace";
pub(crate) const REPOS_ROOT: &str = "/repos";
pub(crate) const RUNTIME_DIRECTORY: &str = "/fabro/runtime";
// Beneath the system tmp dir so any container user can create it; the
// trailing `runtime` component is load-bearing — materialized blobs at
// `runtime/blobs/{hash}.json` are recognized as managed blob references and
// normalized back to `blob://` in durable context.
pub(crate) const RUNTIME_DIRECTORY: &str = "/tmp/fabro/runtime";
const DEFAULT_GIT_CLONE_DEPTH: usize = RunCloneSettings::DEFAULT_DEPTH.unsigned_abs() as usize;
const GIT_CLONE_TIMEOUT: Duration = Duration::from_mins(5);
#[cfg(test)]

View file

@ -1543,12 +1543,13 @@ mod tests {
async fn demote_materializes_remote_values_under_sandbox_runtime_directory() {
let run_store: RunStoreHandle = make_run_store("prompt-demote-remote").await.into();
let run_dir = tempfile::tempdir().unwrap();
let env = TestSyncEnv::new(false, "/workspace").with_runtime_directory("/fabro/runtime");
let env =
TestSyncEnv::new(false, "/workspace").with_runtime_directory("/tmp/fabro/runtime");
let oversized = serde_json::json!("x".repeat(PROMPT_INLINE_VALUE_MAX + 1));
let expected_bytes = serde_json::to_vec(&oversized).unwrap();
let expected_path = format!(
"/fabro/runtime/blobs/{}.json",
"/tmp/fabro/runtime/blobs/{}.json",
BlobHash::new(&expected_bytes)
);
let mut values = HashMap::from([("dataset".to_string(), oversized)]);
@ -1605,7 +1606,8 @@ mod tests {
let blob_hash = run_store.write_blob(&report_bytes).await.unwrap();
let context = Context::new();
context.set("report", fabro_types::format_blob_ref(&blob_hash).into());
let env = TestSyncEnv::new(false, "/workspace").with_runtime_directory("/fabro/runtime");
let env =
TestSyncEnv::new(false, "/workspace").with_runtime_directory("/tmp/fabro/runtime");
let run_dir = tempfile::tempdir().unwrap();
let resolved =
@ -1613,7 +1615,7 @@ mod tests {
.await
.unwrap();
let expected_path = format!("/fabro/runtime/blobs/{blob_hash}.json");
let expected_path = format!("/tmp/fabro/runtime/blobs/{blob_hash}.json");
assert_eq!(
resolved["report"],
serde_json::json!(format!("file://{expected_path}"))

View file

@ -788,7 +788,7 @@ mod tests {
"security_findings",
large_prompt_value(
1_843_279,
"/fabro/runtime/blobs/findings.json",
"/tmp/fabro/runtime/blobs/findings.json",
"{\"findings\":[\n{\"severity\":\"high\"}",
),
);
@ -798,7 +798,7 @@ mod tests {
keys::COMMAND_OUTPUT.to_string(),
large_prompt_value(
12 * 1024,
"/fabro/runtime/blobs/output.json",
"/tmp/fabro/runtime/blobs/output.json",
"first result\nsecond result",
),
);
@ -819,12 +819,12 @@ mod tests {
"\n## Completed stages\n",
"- **scan**: succeeded\n",
" - Script: `scan --json`\n",
" - Output (12.0 KB; full value: `/fabro/runtime/blobs/output.json`)\n",
" - Output (12.0 KB; full value: `/tmp/fabro/runtime/blobs/output.json`)\n",
" Preview: first result\n",
" second result…\n",
"\n## Context\n",
"- security_findings (1.8 MB; full value: ",
"`/fabro/runtime/blobs/findings.json`)\n",
"`/tmp/fabro/runtime/blobs/findings.json`)\n",
" Preview: {\"findings\":[\n",
" {\"severity\":\"high\"}…\n",
)
@ -1703,7 +1703,7 @@ mod tests {
"security_findings",
large_prompt_value(
1_843_279,
"/fabro/runtime/blobs/findings.json",
"/tmp/fabro/runtime/blobs/findings.json",
"{\"findings\": [\n{\"message\": \"a | b\"}]}",
),
);
@ -1718,7 +1718,7 @@ mod tests {
assert!(preamble.contains(concat!(
"| security_findings | 1.8 MB; full value: ",
"`/fabro/runtime/blobs/findings.json`; Preview: ",
"`/tmp/fabro/runtime/blobs/findings.json`; Preview: ",
"{\"findings\": [ {\"message\": \"a \\| b\"}]}… |",
)));
assert!(!preamble.contains("fabroLargeValue"));

View file

@ -10137,7 +10137,7 @@ impl fabro_agent::Sandbox for RemoteMockEnv {
}
fn runtime_directory(&self) -> Option<&str> {
Some("/fabro/runtime")
Some("/tmp/fabro/runtime")
}
async fn list_directory(
@ -10445,7 +10445,7 @@ async fn downstream_remote_execution_resolves_response_blob_refs_as_text() {
assert!(
written
.iter()
.all(|(path, _)| path.starts_with("/fabro/runtime/blobs/")),
.all(|(path, _)| path.starts_with("/tmp/fabro/runtime/blobs/")),
"nothing is written outside the sandbox runtime blob directory"
);
assert!(