Fix worktree trust handling of multiple projects on the same remote host (#45834) (cherry-pick to preview) (#45839)
Cherry-pick of #45834 to preview ---- Closes https://github.com/zed-industries/zed/issues/45630 Remote host location alone is not enough to distinguish between remote worktrees: different remote projects open in different windows will have the same remote host location and _will_ have the same `WorktreeId`. Thus, require an associated `WorktreeStore` with all `WorktreeId`-related trust questions, and store those IDs based on the store key. Release Notes: - Fixed worktree trust handling of multiple projects on the same remote host Co-authored-by: Kirill Bulatov <kirill@zed.dev>
This commit is contained in:
@@ -855,8 +855,6 @@ async fn test_slow_adapter_startup_retries(
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_ssh_remote_worktree_trust(cx_a: &mut TestAppContext, server_cx: &mut TestAppContext) {
|
||||
use project::trusted_worktrees::RemoteHostLocation;
|
||||
|
||||
cx_a.update(|cx| {
|
||||
release_channel::init(semver::Version::new(0, 0, 0), cx);
|
||||
project::trusted_worktrees::init(HashMap::default(), None, None, cx);
|
||||
@@ -991,23 +989,19 @@ async fn test_ssh_remote_worktree_trust(cx_a: &mut TestAppContext, server_cx: &m
|
||||
});
|
||||
assert_eq!(worktree_ids.len(), 2);
|
||||
|
||||
let remote_host = project_a.read_with(cx_a, |project, cx| {
|
||||
project
|
||||
.remote_connection_options(cx)
|
||||
.map(RemoteHostLocation::from)
|
||||
});
|
||||
|
||||
let trusted_worktrees =
|
||||
cx_a.update(|cx| TrustedWorktrees::try_get_global(cx).expect("trust global should exist"));
|
||||
let worktree_store = project_a.read_with(cx_a, |project, _| project.worktree_store());
|
||||
|
||||
let can_trust_a =
|
||||
trusted_worktrees.update(cx_a, |store, cx| store.can_trust(worktree_ids[0], cx));
|
||||
let can_trust_b =
|
||||
trusted_worktrees.update(cx_a, |store, cx| store.can_trust(worktree_ids[1], cx));
|
||||
let can_trust_a = trusted_worktrees.update(cx_a, |store, cx| {
|
||||
store.can_trust(&worktree_store, worktree_ids[0], cx)
|
||||
});
|
||||
let can_trust_b = trusted_worktrees.update(cx_a, |store, cx| {
|
||||
store.can_trust(&worktree_store, worktree_ids[1], cx)
|
||||
});
|
||||
assert!(!can_trust_a, "project_a should be restricted initially");
|
||||
assert!(!can_trust_b, "project_b should be restricted initially");
|
||||
|
||||
let worktree_store = project_a.read_with(cx_a, |project, _| project.worktree_store());
|
||||
let has_restricted = trusted_worktrees.read_with(cx_a, |store, cx| {
|
||||
store.has_restricted_worktrees(&worktree_store, cx)
|
||||
});
|
||||
@@ -1054,8 +1048,8 @@ async fn test_ssh_remote_worktree_trust(cx_a: &mut TestAppContext, server_cx: &m
|
||||
|
||||
trusted_worktrees.update(cx_a, |store, cx| {
|
||||
store.trust(
|
||||
&worktree_store,
|
||||
HashSet::from_iter([PathTrust::Worktree(worktree_ids[0])]),
|
||||
remote_host.clone(),
|
||||
cx,
|
||||
);
|
||||
});
|
||||
@@ -1080,25 +1074,29 @@ async fn test_ssh_remote_worktree_trust(cx_a: &mut TestAppContext, server_cx: &m
|
||||
"inlay hints should be queried after trust approval"
|
||||
);
|
||||
|
||||
let can_trust_a =
|
||||
trusted_worktrees.update(cx_a, |store, cx| store.can_trust(worktree_ids[0], cx));
|
||||
let can_trust_b =
|
||||
trusted_worktrees.update(cx_a, |store, cx| store.can_trust(worktree_ids[1], cx));
|
||||
let can_trust_a = trusted_worktrees.update(cx_a, |store, cx| {
|
||||
store.can_trust(&worktree_store, worktree_ids[0], cx)
|
||||
});
|
||||
let can_trust_b = trusted_worktrees.update(cx_a, |store, cx| {
|
||||
store.can_trust(&worktree_store, worktree_ids[1], cx)
|
||||
});
|
||||
assert!(can_trust_a, "project_a should be trusted after trust()");
|
||||
assert!(!can_trust_b, "project_b should still be restricted");
|
||||
|
||||
trusted_worktrees.update(cx_a, |store, cx| {
|
||||
store.trust(
|
||||
&worktree_store,
|
||||
HashSet::from_iter([PathTrust::Worktree(worktree_ids[1])]),
|
||||
remote_host.clone(),
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let can_trust_a =
|
||||
trusted_worktrees.update(cx_a, |store, cx| store.can_trust(worktree_ids[0], cx));
|
||||
let can_trust_b =
|
||||
trusted_worktrees.update(cx_a, |store, cx| store.can_trust(worktree_ids[1], cx));
|
||||
let can_trust_a = trusted_worktrees.update(cx_a, |store, cx| {
|
||||
store.can_trust(&worktree_store, worktree_ids[0], cx)
|
||||
});
|
||||
let can_trust_b = trusted_worktrees.update(cx_a, |store, cx| {
|
||||
store.can_trust(&worktree_store, worktree_ids[1], cx)
|
||||
});
|
||||
assert!(can_trust_a, "project_a should remain trusted");
|
||||
assert!(can_trust_b, "project_b should now be trusted");
|
||||
|
||||
|
||||
@@ -29419,11 +29419,14 @@ async fn test_local_worktree_trust(cx: &mut TestAppContext) {
|
||||
.map(|wt| wt.read(cx).id())
|
||||
.expect("should have a worktree")
|
||||
});
|
||||
let worktree_store = project.read_with(cx, |project, _| project.worktree_store());
|
||||
|
||||
let trusted_worktrees =
|
||||
cx.update(|cx| TrustedWorktrees::try_get_global(cx).expect("trust global should exist"));
|
||||
|
||||
let can_trust = trusted_worktrees.update(cx, |store, cx| store.can_trust(worktree_id, cx));
|
||||
let can_trust = trusted_worktrees.update(cx, |store, cx| {
|
||||
store.can_trust(&worktree_store, worktree_id, cx)
|
||||
});
|
||||
assert!(!can_trust, "worktree should be restricted initially");
|
||||
|
||||
let buffer_before_approval = project
|
||||
@@ -29469,8 +29472,8 @@ async fn test_local_worktree_trust(cx: &mut TestAppContext) {
|
||||
|
||||
trusted_worktrees.update(cx, |store, cx| {
|
||||
store.trust(
|
||||
&worktree_store,
|
||||
std::collections::HashSet::from_iter([PathTrust::Worktree(worktree_id)]),
|
||||
None,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
@@ -29497,7 +29500,8 @@ async fn test_local_worktree_trust(cx: &mut TestAppContext) {
|
||||
"inlay hints should be queried after trust approval"
|
||||
);
|
||||
|
||||
let can_trust_after =
|
||||
trusted_worktrees.update(cx, |store, cx| store.can_trust(worktree_id, cx));
|
||||
let can_trust_after = trusted_worktrees.update(cx, |store, cx| {
|
||||
store.can_trust(&worktree_store, worktree_id, cx)
|
||||
});
|
||||
assert!(can_trust_after, "worktree should be trusted after trust()");
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use picker::{Picker, PickerDelegate, PickerEditorPosition};
|
||||
use project::{
|
||||
DirectoryLister,
|
||||
git_store::Repository,
|
||||
trusted_worktrees::{PathTrust, RemoteHostLocation, TrustedWorktrees},
|
||||
trusted_worktrees::{PathTrust, TrustedWorktrees},
|
||||
};
|
||||
use recent_projects::{RemoteConnectionModal, connect};
|
||||
use remote::{RemoteConnectionOptions, remote_client::ConnectionIdentifier};
|
||||
@@ -271,16 +271,18 @@ impl WorktreeListDelegate {
|
||||
if let Some((parent_worktree, _)) =
|
||||
project.read(cx).find_worktree(repo_path, cx)
|
||||
{
|
||||
let worktree_store = project.read(cx).worktree_store();
|
||||
trusted_worktrees.update(cx, |trusted_worktrees, cx| {
|
||||
if trusted_worktrees.can_trust(parent_worktree.read(cx).id(), cx) {
|
||||
if trusted_worktrees.can_trust(
|
||||
&worktree_store,
|
||||
parent_worktree.read(cx).id(),
|
||||
cx,
|
||||
) {
|
||||
trusted_worktrees.trust(
|
||||
&worktree_store,
|
||||
HashSet::from_iter([PathTrust::AbsPath(
|
||||
new_worktree_path.clone(),
|
||||
)]),
|
||||
project
|
||||
.read(cx)
|
||||
.remote_connection_options(cx)
|
||||
.map(RemoteHostLocation::from),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -386,7 +386,7 @@ impl LocalLspStore {
|
||||
let untrusted_worktree_task =
|
||||
TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
|
||||
let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
|
||||
trusted_worktrees.can_trust(worktree_id, cx)
|
||||
trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
|
||||
});
|
||||
if can_trust {
|
||||
self.restricted_worktrees_tasks.remove(&worktree_id);
|
||||
|
||||
@@ -52,7 +52,9 @@ pub use project_search::Search;
|
||||
|
||||
use anyhow::{Context as _, Result, anyhow};
|
||||
use buffer_store::{BufferStore, BufferStoreEvent};
|
||||
use client::{Client, Collaborator, PendingEntitySubscription, TypedEnvelope, UserStore, proto};
|
||||
use client::{
|
||||
Client, Collaborator, PendingEntitySubscription, ProjectId, TypedEnvelope, UserStore, proto,
|
||||
};
|
||||
use clock::ReplicaId;
|
||||
|
||||
use dap::client::DebugAdapterClient;
|
||||
@@ -1295,7 +1297,7 @@ impl Project {
|
||||
worktree_store.clone(),
|
||||
Some(RemoteHostLocation::from(connection_options)),
|
||||
None,
|
||||
Some((remote_proto.clone(), REMOTE_SERVER_PROJECT_ID)),
|
||||
Some((remote_proto.clone(), ProjectId(REMOTE_SERVER_PROJECT_ID))),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
@@ -4814,7 +4816,7 @@ impl Project {
|
||||
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
|
||||
if let Some(trusted_worktrees) = TrustedWorktrees::try_get_global(cx) {
|
||||
trusted_worktrees.update(cx, |trusted_worktrees, cx| {
|
||||
trusted_worktrees.can_trust(worktree_id, cx)
|
||||
trusted_worktrees.can_trust(&project.worktree_store, worktree_id, cx)
|
||||
});
|
||||
}
|
||||
if let Some(worktree) = project.worktree_for_id(worktree_id, cx) {
|
||||
@@ -4853,18 +4855,14 @@ impl Project {
|
||||
.update(|cx| TrustedWorktrees::try_get_global(cx))?
|
||||
.context("missing trusted worktrees")?;
|
||||
trusted_worktrees.update(&mut cx, |trusted_worktrees, cx| {
|
||||
let remote_host = this
|
||||
.read(cx)
|
||||
.remote_connection_options(cx)
|
||||
.map(RemoteHostLocation::from);
|
||||
trusted_worktrees.trust(
|
||||
&this.read(cx).worktree_store(),
|
||||
envelope
|
||||
.payload
|
||||
.trusted_paths
|
||||
.into_iter()
|
||||
.filter_map(|proto_path| PathTrust::from_proto(proto_path))
|
||||
.collect(),
|
||||
remote_host,
|
||||
cx,
|
||||
);
|
||||
})?;
|
||||
@@ -4880,6 +4878,7 @@ impl Project {
|
||||
.update(|cx| TrustedWorktrees::try_get_global(cx))?
|
||||
.context("missing trusted worktrees")?;
|
||||
trusted_worktrees.update(&mut cx, |trusted_worktrees, cx| {
|
||||
let worktree_store = this.read(cx).worktree_store().downgrade();
|
||||
let restricted_paths = envelope
|
||||
.payload
|
||||
.worktree_ids
|
||||
@@ -4887,11 +4886,7 @@ impl Project {
|
||||
.map(WorktreeId::from_proto)
|
||||
.map(PathTrust::Worktree)
|
||||
.collect::<HashSet<_>>();
|
||||
let remote_host = this
|
||||
.read(cx)
|
||||
.remote_connection_options(cx)
|
||||
.map(RemoteHostLocation::from);
|
||||
trusted_worktrees.restrict(restricted_paths, remote_host, cx);
|
||||
trusted_worktrees.restrict(worktree_store, restricted_paths, cx);
|
||||
})?;
|
||||
Ok(proto::Ack {})
|
||||
}
|
||||
|
||||
@@ -1046,7 +1046,7 @@ impl SettingsObserver {
|
||||
if *can_trust_worktree.get_or_init(|| {
|
||||
if let Some(trusted_worktrees) = TrustedWorktrees::try_get_global(cx) {
|
||||
trusted_worktrees.update(cx, |trusted_worktrees, cx| {
|
||||
trusted_worktrees.can_trust(worktree_id, cx)
|
||||
trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
|
||||
})
|
||||
} else {
|
||||
true
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
use anyhow::{Context as _, Result, anyhow};
|
||||
use client::ProjectId;
|
||||
use collections::HashSet;
|
||||
use language::File;
|
||||
use lsp::LanguageServerId;
|
||||
@@ -104,7 +105,7 @@ impl HeadlessProject {
|
||||
project::trusted_worktrees::track_worktree_trust(
|
||||
worktree_store.clone(),
|
||||
None::<RemoteHostLocation>,
|
||||
Some((session.clone(), REMOTE_SERVER_PROJECT_ID)),
|
||||
Some((session.clone(), ProjectId(REMOTE_SERVER_PROJECT_ID))),
|
||||
None,
|
||||
cx,
|
||||
);
|
||||
@@ -611,22 +612,23 @@ impl HeadlessProject {
|
||||
}
|
||||
|
||||
pub async fn handle_trust_worktrees(
|
||||
_: Entity<Self>,
|
||||
this: Entity<Self>,
|
||||
envelope: TypedEnvelope<proto::TrustWorktrees>,
|
||||
mut cx: AsyncApp,
|
||||
) -> Result<proto::Ack> {
|
||||
let trusted_worktrees = cx
|
||||
.update(|cx| TrustedWorktrees::try_get_global(cx))?
|
||||
.context("missing trusted worktrees")?;
|
||||
let worktree_store = this.read_with(&cx, |project, _| project.worktree_store.clone())?;
|
||||
trusted_worktrees.update(&mut cx, |trusted_worktrees, cx| {
|
||||
trusted_worktrees.trust(
|
||||
&worktree_store,
|
||||
envelope
|
||||
.payload
|
||||
.trusted_paths
|
||||
.into_iter()
|
||||
.filter_map(PathTrust::from_proto)
|
||||
.collect(),
|
||||
None,
|
||||
cx,
|
||||
);
|
||||
})?;
|
||||
@@ -634,13 +636,15 @@ impl HeadlessProject {
|
||||
}
|
||||
|
||||
pub async fn handle_restrict_worktrees(
|
||||
_: Entity<Self>,
|
||||
this: Entity<Self>,
|
||||
envelope: TypedEnvelope<proto::RestrictWorktrees>,
|
||||
mut cx: AsyncApp,
|
||||
) -> Result<proto::Ack> {
|
||||
let trusted_worktrees = cx
|
||||
.update(|cx| TrustedWorktrees::try_get_global(cx))?
|
||||
.context("missing trusted worktrees")?;
|
||||
let worktree_store =
|
||||
this.read_with(&cx, |project, _| project.worktree_store.downgrade())?;
|
||||
trusted_worktrees.update(&mut cx, |trusted_worktrees, cx| {
|
||||
let restricted_paths = envelope
|
||||
.payload
|
||||
@@ -649,7 +653,7 @@ impl HeadlessProject {
|
||||
.map(WorktreeId::from_proto)
|
||||
.map(PathTrust::Worktree)
|
||||
.collect::<HashSet<_>>();
|
||||
trusted_worktrees.restrict(restricted_paths, None, cx);
|
||||
trusted_worktrees.restrict(worktree_store, restricted_paths, cx);
|
||||
})?;
|
||||
Ok(proto::Ack {})
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::HeadlessProject;
|
||||
use crate::headless_project::HeadlessAppState;
|
||||
use anyhow::{Context as _, Result, anyhow};
|
||||
use client::ProxySettings;
|
||||
use client::{ProjectId, ProxySettings};
|
||||
use collections::HashMap;
|
||||
use project::trusted_worktrees;
|
||||
use util::ResultExt;
|
||||
@@ -419,7 +419,7 @@ pub fn execute_run(
|
||||
|
||||
log::info!("gpui app started, initializing server");
|
||||
let session = start_server(listeners, log_rx, cx, is_wsl_interop);
|
||||
trusted_worktrees::init(HashMap::default(), Some((session.clone(), REMOTE_SERVER_PROJECT_ID)), None, cx);
|
||||
trusted_worktrees::init(HashMap::default(), Some((session.clone(), ProjectId(REMOTE_SERVER_PROJECT_ID))), None, cx);
|
||||
|
||||
GitHostingProviderRegistry::set_global(git_hosting_provider_registry, cx);
|
||||
git_hosting_providers::init(cx);
|
||||
|
||||
@@ -20,7 +20,7 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AnyProtoClient(Arc<State>);
|
||||
|
||||
type RequestIds = Arc<
|
||||
@@ -45,6 +45,15 @@ struct State {
|
||||
request_ids: RequestIds,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for State {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("State")
|
||||
.field("next_lsp_request_id", &self.next_lsp_request_id)
|
||||
.field("request_ids", &self.request_ids)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ProtoClient: Send + Sync {
|
||||
fn request(
|
||||
&self,
|
||||
|
||||
@@ -15,11 +15,10 @@ use db::{
|
||||
sqlez::{connection::Connection, domain::Domain},
|
||||
sqlez_macros::sql,
|
||||
};
|
||||
use gpui::{Axis, Bounds, Entity, Task, WindowBounds, WindowId, point, size};
|
||||
use gpui::{Axis, Bounds, Task, WindowBounds, WindowId, point, size};
|
||||
use project::{
|
||||
debugger::breakpoint_store::{BreakpointState, SourceBreakpoint},
|
||||
trusted_worktrees::{PathTrust, RemoteHostLocation, find_worktree_in_store},
|
||||
worktree_store::WorktreeStore,
|
||||
trusted_worktrees::{DbTrustedPaths, RemoteHostLocation},
|
||||
};
|
||||
|
||||
use language::{LanguageName, Toolchain, ToolchainScope};
|
||||
@@ -1888,18 +1887,12 @@ VALUES {placeholders};"#
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn fetch_trusted_worktrees(
|
||||
&self,
|
||||
worktree_store: Option<Entity<WorktreeStore>>,
|
||||
host: Option<RemoteHostLocation>,
|
||||
cx: &App,
|
||||
) -> Result<HashMap<Option<RemoteHostLocation>, HashSet<PathTrust>>> {
|
||||
pub fn fetch_trusted_worktrees(&self) -> Result<DbTrustedPaths> {
|
||||
let trusted_worktrees = DB.trusted_worktrees()?;
|
||||
Ok(trusted_worktrees
|
||||
.into_iter()
|
||||
.filter_map(|(abs_path, user_name, host_name)| {
|
||||
let db_host = match (user_name, host_name) {
|
||||
(_, None) => None,
|
||||
(None, Some(host_name)) => Some(RemoteHostLocation {
|
||||
user_name: None,
|
||||
host_identifier: SharedString::new(host_name),
|
||||
@@ -1908,24 +1901,14 @@ VALUES {placeholders};"#
|
||||
user_name: Some(SharedString::new(user_name)),
|
||||
host_identifier: SharedString::new(host_name),
|
||||
}),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let abs_path = abs_path?;
|
||||
Some(if db_host != host {
|
||||
(db_host, PathTrust::AbsPath(abs_path))
|
||||
} else if let Some(worktree_store) = &worktree_store {
|
||||
find_worktree_in_store(worktree_store.read(cx), &abs_path, cx)
|
||||
.map(PathTrust::Worktree)
|
||||
.map(|trusted_worktree| (host.clone(), trusted_worktree))
|
||||
.unwrap_or_else(|| (db_host.clone(), PathTrust::AbsPath(abs_path)))
|
||||
} else {
|
||||
(db_host, PathTrust::AbsPath(abs_path))
|
||||
})
|
||||
Some((db_host, abs_path?))
|
||||
})
|
||||
.fold(HashMap::default(), |mut acc, (remote_host, path_trust)| {
|
||||
.fold(HashMap::default(), |mut acc, (remote_host, abs_path)| {
|
||||
acc.entry(remote_host)
|
||||
.or_insert_with(HashSet::default)
|
||||
.insert(path_trust);
|
||||
.insert(abs_path);
|
||||
acc
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -267,7 +267,9 @@ impl SecurityModal {
|
||||
}
|
||||
|
||||
fn trust_and_dismiss(&mut self, cx: &mut Context<Self>) {
|
||||
if let Some(trusted_worktrees) = TrustedWorktrees::try_get_global(cx) {
|
||||
if let Some((trusted_worktrees, worktree_store)) =
|
||||
TrustedWorktrees::try_get_global(cx).zip(self.worktree_store.upgrade())
|
||||
{
|
||||
trusted_worktrees.update(cx, |trusted_worktrees, cx| {
|
||||
let mut paths_to_trust = self
|
||||
.restricted_paths
|
||||
@@ -288,7 +290,7 @@ impl SecurityModal {
|
||||
},
|
||||
));
|
||||
}
|
||||
trusted_worktrees.trust(paths_to_trust, self.remote_host.clone(), cx);
|
||||
trusted_worktrees.trust(&worktree_store, paths_to_trust, cx);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -305,7 +307,7 @@ impl SecurityModal {
|
||||
if let Some(worktree_store) = self.worktree_store.upgrade() {
|
||||
let new_restricted_worktrees = trusted_worktrees
|
||||
.read(cx)
|
||||
.restricted_worktrees(worktree_store.read(cx), cx)
|
||||
.restricted_worktrees(&worktree_store, cx)
|
||||
.into_iter()
|
||||
.filter_map(|(worktree_id, abs_path)| {
|
||||
let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
|
||||
|
||||
@@ -80,7 +80,7 @@ use project::{
|
||||
debugger::{breakpoint_store::BreakpointStoreEvent, session::ThreadStatus},
|
||||
project_settings::ProjectSettings,
|
||||
toolchain_store::ToolchainStoreEvent,
|
||||
trusted_worktrees::{TrustedWorktrees, TrustedWorktreesEvent},
|
||||
trusted_worktrees::{RemoteHostLocation, TrustedWorktrees, TrustedWorktreesEvent},
|
||||
};
|
||||
use remote::{
|
||||
RemoteClientDelegate, RemoteConnection, RemoteConnectionOptions,
|
||||
@@ -1188,7 +1188,6 @@ pub struct Workspace {
|
||||
_observe_current_user: Task<Result<()>>,
|
||||
_schedule_serialize_workspace: Option<Task<()>>,
|
||||
_schedule_serialize_ssh_paths: Option<Task<()>>,
|
||||
_schedule_serialize_worktree_trust: Task<()>,
|
||||
pane_history_timestamp: Arc<AtomicUsize>,
|
||||
bounds: Bounds<Pixels>,
|
||||
pub centered_layout: bool,
|
||||
@@ -1235,23 +1234,26 @@ impl Workspace {
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
if let Some(trusted_worktrees) = TrustedWorktrees::try_get_global(cx) {
|
||||
cx.subscribe(&trusted_worktrees, |workspace, worktrees_store, e, cx| {
|
||||
cx.subscribe(&trusted_worktrees, |_, worktrees_store, e, cx| {
|
||||
if let TrustedWorktreesEvent::Trusted(..) = e {
|
||||
// Do not persist auto trusted worktrees
|
||||
if !ProjectSettings::get_global(cx).session.trust_all_worktrees {
|
||||
let new_trusted_worktrees =
|
||||
worktrees_store.update(cx, |worktrees_store, cx| {
|
||||
worktrees_store.trusted_paths_for_serialization(cx)
|
||||
});
|
||||
let timeout = cx.background_executor().timer(SERIALIZATION_THROTTLE_TIME);
|
||||
workspace._schedule_serialize_worktree_trust =
|
||||
cx.background_spawn(async move {
|
||||
timeout.await;
|
||||
persistence::DB
|
||||
.save_trusted_worktrees(new_trusted_worktrees)
|
||||
.await
|
||||
.log_err();
|
||||
});
|
||||
worktrees_store.update(cx, |worktrees_store, cx| {
|
||||
worktrees_store.schedule_serialization(
|
||||
cx,
|
||||
|new_trusted_worktrees, cx| {
|
||||
let timeout =
|
||||
cx.background_executor().timer(SERIALIZATION_THROTTLE_TIME);
|
||||
cx.background_spawn(async move {
|
||||
timeout.await;
|
||||
persistence::DB
|
||||
.save_trusted_worktrees(new_trusted_worktrees)
|
||||
.await
|
||||
.log_err();
|
||||
})
|
||||
},
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1282,7 +1284,11 @@ impl Workspace {
|
||||
project::Event::WorktreeUpdatedEntries(worktree_id, _) => {
|
||||
if let Some(trusted_worktrees) = TrustedWorktrees::try_get_global(cx) {
|
||||
trusted_worktrees.update(cx, |trusted_worktrees, cx| {
|
||||
trusted_worktrees.can_trust(*worktree_id, cx);
|
||||
trusted_worktrees.can_trust(
|
||||
&this.project().read(cx).worktree_store(),
|
||||
*worktree_id,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1294,7 +1300,11 @@ impl Workspace {
|
||||
project::Event::WorktreeAdded(worktree_id) => {
|
||||
if let Some(trusted_worktrees) = TrustedWorktrees::try_get_global(cx) {
|
||||
trusted_worktrees.update(cx, |trusted_worktrees, cx| {
|
||||
trusted_worktrees.can_trust(*worktree_id, cx);
|
||||
trusted_worktrees.can_trust(
|
||||
&this.project().read(cx).worktree_store(),
|
||||
*worktree_id,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
}
|
||||
this.update_worktree_data(window, cx);
|
||||
@@ -1583,7 +1593,6 @@ impl Workspace {
|
||||
_apply_leader_updates,
|
||||
_schedule_serialize_workspace: None,
|
||||
_schedule_serialize_ssh_paths: None,
|
||||
_schedule_serialize_worktree_trust: Task::ready(()),
|
||||
leader_updates_tx,
|
||||
_subscriptions: subscriptions,
|
||||
pane_history_timestamp,
|
||||
@@ -6542,7 +6551,9 @@ impl Workspace {
|
||||
.unwrap_or(false);
|
||||
if has_restricted_worktrees {
|
||||
let project = self.project().read(cx);
|
||||
let remote_host = project.remote_connection_options(cx);
|
||||
let remote_host = project
|
||||
.remote_connection_options(cx)
|
||||
.map(RemoteHostLocation::from);
|
||||
let worktree_store = project.worktree_store().downgrade();
|
||||
self.toggle_modal(window, cx, |_, cx| {
|
||||
SecurityModal::new(worktree_store, remote_host, cx)
|
||||
|
||||
@@ -406,14 +406,14 @@ pub fn main() {
|
||||
});
|
||||
|
||||
app.run(move |cx| {
|
||||
let trusted_paths = match workspace::WORKSPACE_DB.fetch_trusted_worktrees(None, None, cx) {
|
||||
let db_trusted_paths = match workspace::WORKSPACE_DB.fetch_trusted_worktrees() {
|
||||
Ok(trusted_paths) => trusted_paths,
|
||||
Err(e) => {
|
||||
log::error!("Failed to do initial trusted worktrees fetch: {e:#}");
|
||||
HashMap::default()
|
||||
}
|
||||
};
|
||||
trusted_worktrees::init(trusted_paths, None, None, cx);
|
||||
trusted_worktrees::init(db_trusted_paths, None, None, cx);
|
||||
menu::init();
|
||||
zed_actions::init();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user