@@ -1291,17 +1291,33 @@ impl Project {
cx.subscribe(&worktree_store, Self::on_worktree_store_event)
.detach();
if init_worktree_trust {
- match &connection_options {
- RemoteConnectionOptions::Wsl(..) | RemoteConnectionOptions::Ssh(..) => {
- trusted_worktrees::track_worktree_trust(
- worktree_store.clone(),
- Some(RemoteHostLocation::from(connection_options)),
- None,
- Some((remote_proto.clone(), REMOTE_SERVER_PROJECT_ID)),
- cx,
- );
+ let trust_remote_project = match &connection_options {
+ RemoteConnectionOptions::Ssh(..) | RemoteConnectionOptions::Wsl(..) => false,
+ RemoteConnectionOptions::Docker(..) => true,
+ };
+ let remote_host = RemoteHostLocation::from(connection_options);
+ trusted_worktrees::track_worktree_trust(
+ worktree_store.clone(),
+ Some(remote_host.clone()),
+ None,
+ Some((remote_proto.clone(), REMOTE_SERVER_PROJECT_ID)),
+ cx,
+ );
+ if trust_remote_project {
+ if let Some(trusted_worktres) = TrustedWorktrees::try_get_global(cx) {
+ trusted_worktres.update(cx, |trusted_worktres, cx| {
+ trusted_worktres.trust(
+ worktree_store
+ .read(cx)
+ .worktrees()
+ .map(|worktree| worktree.read(cx).id())
+ .map(PathTrust::Worktree)
+ .collect(),
+ Some(remote_host),
+ cx,
+ );
+ })
}
- RemoteConnectionOptions::Docker(..) => {}
}
}
@@ -337,6 +337,13 @@ impl TrustedWorktreesStore {
if restricted_host != remote_host {
return true;
}
+
+ // When trusting an abs path on the host, we transitively trust all single file worktrees on this host too.
+ if is_file && !new_trusted_abs_paths.is_empty() {
+ trusted_paths.insert(PathTrust::Worktree(*restricted_worktree));
+ return false;
+ }
+
let retain = (!is_file || new_trusted_other_worktrees.is_empty())
&& new_trusted_abs_paths.iter().all(|new_trusted_path| {
!restricted_worktree_path.starts_with(new_trusted_path)
@@ -1045,6 +1052,13 @@ mod tests {
"single-file worktree should be restricted initially"
);
+ let can_trust_directory =
+ trusted_worktrees.update(cx, |store, cx| store.can_trust(dir_worktree_id, cx));
+ assert!(
+ !can_trust_directory,
+ "directory worktree should be restricted initially"
+ );
+
trusted_worktrees.update(cx, |store, cx| {
store.trust(
HashSet::from_iter([PathTrust::Worktree(dir_worktree_id)]),
@@ -1064,6 +1078,78 @@ mod tests {
);
}
+ #[gpui::test]
+ async fn test_parent_path_trust_enables_single_file(cx: &mut TestAppContext) {
+ init_test(cx);
+
+ let fs = FakeFs::new(cx.executor());
+ fs.insert_tree(
+ path!("/"),
+ json!({
+ "project": { "main.rs": "fn main() {}" },
+ "standalone.rs": "fn standalone() {}"
+ }),
+ )
+ .await;
+
+ let project = Project::test(
+ fs,
+ [path!("/project").as_ref(), path!("/standalone.rs").as_ref()],
+ cx,
+ )
+ .await;
+ let worktree_store = project.read_with(cx, |project, _| project.worktree_store());
+ let (dir_worktree_id, file_worktree_id) = worktree_store.read_with(cx, |store, cx| {
+ let worktrees: Vec<_> = store.worktrees().collect();
+ assert_eq!(worktrees.len(), 2);
+ let (dir_worktree, file_worktree) = if worktrees[0].read(cx).is_single_file() {
+ (&worktrees[1], &worktrees[0])
+ } else {
+ (&worktrees[0], &worktrees[1])
+ };
+ assert!(!dir_worktree.read(cx).is_single_file());
+ assert!(file_worktree.read(cx).is_single_file());
+ (dir_worktree.read(cx).id(), file_worktree.read(cx).id())
+ });
+
+ let trusted_worktrees = init_trust_global(worktree_store, cx);
+
+ let can_trust_file =
+ trusted_worktrees.update(cx, |store, cx| store.can_trust(file_worktree_id, cx));
+ assert!(
+ !can_trust_file,
+ "single-file worktree should be restricted initially"
+ );
+
+ let can_trust_directory =
+ trusted_worktrees.update(cx, |store, cx| store.can_trust(dir_worktree_id, cx));
+ assert!(
+ !can_trust_directory,
+ "directory worktree should be restricted initially"
+ );
+
+ trusted_worktrees.update(cx, |store, cx| {
+ store.trust(
+ HashSet::from_iter([PathTrust::AbsPath(PathBuf::from(path!("/project")))]),
+ None,
+ cx,
+ );
+ });
+
+ let can_trust_dir =
+ trusted_worktrees.update(cx, |store, cx| store.can_trust(dir_worktree_id, cx));
+ let can_trust_file_after =
+ trusted_worktrees.update(cx, |store, cx| store.can_trust(file_worktree_id, cx));
+ assert!(
+ can_trust_dir,
+ "directory worktree should be trusted after its parent is trusted"
+ );
+ assert!(
+ can_trust_file_after,
+ "single-file worktree should be trusted after directory worktree trust via its parent directory trust"
+ );
+ }
+
#[gpui::test]
async fn test_abs_path_trust_covers_multiple_worktrees(cx: &mut TestAppContext) {
init_test(cx);