mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-06 02:48:25 +00:00
Fix Daytona sandbox clone failing on unpushed worktree branch
When `arc run` uses a Daytona sandbox, `initialize()` re-detects the
branch from cwd — but by that point the worktree has switched HEAD to
`arc/run/{run_id}`, which was never pushed, causing the clone to fail
with HTTP 400. Pass the already-known base branch (e.g. `main`) from
the caller instead of re-detecting it inside the sandbox.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ecb585d2a4
commit
9245a9987b
3 changed files with 47 additions and 6 deletions
|
|
@ -737,6 +737,7 @@ pub async fn run_command(
|
|||
config,
|
||||
github_app.clone(),
|
||||
Some(run_id.clone()),
|
||||
detected_base_branch.clone(),
|
||||
);
|
||||
let emitter_cb = Arc::clone(&emitter);
|
||||
env.set_event_callback(Arc::new(move |event| {
|
||||
|
|
@ -1923,6 +1924,7 @@ async fn run_preflight(
|
|||
config,
|
||||
github_app,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
Ok(Arc::new(env) as Arc<dyn Sandbox>)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,6 +160,10 @@ pub struct DaytonaSandbox {
|
|||
/// HTTPS origin URL stored after clone so we can refresh push credentials later.
|
||||
origin_url: tokio::sync::OnceCell<String>,
|
||||
run_id: Option<String>,
|
||||
/// Explicit branch to clone. When set, overrides the branch detected by
|
||||
/// `detect_repo_info` — avoids cloning a local-only worktree branch
|
||||
/// (e.g. `arc/run/...`) that was never pushed to origin.
|
||||
clone_branch: Option<String>,
|
||||
}
|
||||
|
||||
impl DaytonaSandbox {
|
||||
|
|
@ -169,6 +173,7 @@ impl DaytonaSandbox {
|
|||
config: DaytonaConfig,
|
||||
github_app: Option<GitHubAppCredentials>,
|
||||
run_id: Option<String>,
|
||||
clone_branch: Option<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
config,
|
||||
|
|
@ -179,6 +184,7 @@ impl DaytonaSandbox {
|
|||
event_callback: None,
|
||||
origin_url: tokio::sync::OnceCell::new(),
|
||||
run_id,
|
||||
clone_branch,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -197,6 +203,7 @@ impl DaytonaSandbox {
|
|||
event_callback: None,
|
||||
origin_url: tokio::sync::OnceCell::new(),
|
||||
run_id: None,
|
||||
clone_branch: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -562,7 +569,10 @@ impl Sandbox for DaytonaSandbox {
|
|||
|
||||
// Clone the repo into the sandbox
|
||||
match detect_repo_info(&cwd) {
|
||||
Ok((detected_url, branch)) => {
|
||||
Ok((detected_url, detected_branch)) => {
|
||||
// Use explicit clone_branch if provided (avoids cloning a local-only
|
||||
// worktree branch like arc/run/... that hasn't been pushed).
|
||||
let branch = self.clone_branch.clone().or(detected_branch);
|
||||
// Daytona clones over HTTPS with token auth, so rewrite SSH URLs.
|
||||
let url = ssh_url_to_https(&detected_url);
|
||||
self.emit(SandboxEvent::GitCloneStarted {
|
||||
|
|
@ -1369,4 +1379,33 @@ mod tests {
|
|||
"unexpected error: {msg}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn detect_repo_info_returns_worktree_branch() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let repo = git2::Repository::init(dir.path()).unwrap();
|
||||
|
||||
// Create an initial commit so HEAD exists
|
||||
let sig = git2::Signature::now("Test", "test@test.com").unwrap();
|
||||
let tree_id = repo.index().unwrap().write_tree().unwrap();
|
||||
let tree = repo.find_tree(tree_id).unwrap();
|
||||
let commit = repo
|
||||
.commit(Some("HEAD"), &sig, &sig, "init", &tree, &[])
|
||||
.unwrap();
|
||||
|
||||
repo.remote("origin", "https://github.com/org/repo.git")
|
||||
.unwrap();
|
||||
|
||||
// Create and check out an arc/run/... branch (simulating worktree setup)
|
||||
let commit_obj = repo.find_commit(commit).unwrap();
|
||||
repo.branch("arc/run/ABC", &commit_obj, false).unwrap();
|
||||
repo.set_head("refs/heads/arc/run/ABC").unwrap();
|
||||
|
||||
let (_, branch) = detect_repo_info(dir.path()).unwrap();
|
||||
// Documents the current behavior: detect_repo_info returns whatever HEAD points to
|
||||
assert_eq!(branch, Some("arc/run/ABC".into()));
|
||||
}
|
||||
|
||||
// The `clone_branch` field on `DaytonaSandbox::new()` is verified at compile time —
|
||||
// all call sites (run.rs, integration tests) must pass the new parameter.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ async fn create_env_with_github_app(
|
|||
let client = daytona_sdk::Client::new()
|
||||
.await
|
||||
.expect("Failed to create Daytona client — is DAYTONA_API_KEY set?");
|
||||
DaytonaSandbox::new(client, DaytonaConfig::default(), github_app, None)
|
||||
DaytonaSandbox::new(client, DaytonaConfig::default(), github_app, None, None)
|
||||
}
|
||||
|
||||
fn load_github_app_credentials() -> arc_github::GitHubAppCredentials {
|
||||
|
|
@ -253,7 +253,7 @@ async fn daytona_snapshot_sandbox() {
|
|||
};
|
||||
|
||||
let creds = load_github_app_credentials();
|
||||
let env = DaytonaSandbox::new(client, config, Some(creds), None);
|
||||
let env = DaytonaSandbox::new(client, config, Some(creds), None, None);
|
||||
env.initialize().await.unwrap();
|
||||
|
||||
// Verify rg is available (installed by snapshot)
|
||||
|
|
@ -929,7 +929,7 @@ async fn run_daytona_cli_test(provider: Provider, model: &str, install_command:
|
|||
}),
|
||||
..DaytonaConfig::default()
|
||||
};
|
||||
let env = DaytonaSandbox::new(client, config, Some(creds), None);
|
||||
let env = DaytonaSandbox::new(client, config, Some(creds), None, None);
|
||||
env.initialize().await.unwrap();
|
||||
let env: Arc<dyn Sandbox> = Arc::new(env);
|
||||
|
||||
|
|
@ -1875,7 +1875,7 @@ async fn daytona_computer_use_browser_screenshot() {
|
|||
}),
|
||||
..DaytonaConfig::default()
|
||||
};
|
||||
let env = DaytonaSandbox::new(client, config, None, None);
|
||||
let env = DaytonaSandbox::new(client, config, None, None, None);
|
||||
env.initialize().await.unwrap();
|
||||
|
||||
// 1. Start the computer use desktop environment (Xvfb, xfce4, etc.)
|
||||
|
|
@ -2036,7 +2036,7 @@ async fn daytona_playwright_mcp_sandbox_transport() {
|
|||
}),
|
||||
..DaytonaConfig::default()
|
||||
};
|
||||
let sandbox = DaytonaSandbox::new(client, config, None, None);
|
||||
let sandbox = DaytonaSandbox::new(client, config, None, None, None);
|
||||
sandbox.initialize().await.unwrap();
|
||||
|
||||
// 1. Install Playwright MCP server and its browser
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue