extension_host: Add capability for downloading files (#35141)

This PR adds a new capability for downloading files in extensions.

Currently all file downloads are allowed.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2025-07-26 17:33:16 -04:00 committed by GitHub
parent d7b403e981
commit 6a9a539b10
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 165 additions and 12 deletions

View file

@ -2,6 +2,7 @@ use std::sync::Arc;
use anyhow::{Result, bail};
use extension::{ExtensionCapability, ExtensionManifest};
use url::Url;
pub struct CapabilityGranter {
granted_capabilities: Vec<ExtensionCapability>,
@ -33,6 +34,7 @@ impl CapabilityGranter {
ExtensionCapability::ProcessExec(capability) => {
capability.allows(desired_command, desired_args)
}
_ => false,
});
if !is_allowed {
@ -43,6 +45,24 @@ impl CapabilityGranter {
Ok(())
}
pub fn grant_download_file(&self, desired_url: &Url) -> Result<()> {
let is_allowed = self
.granted_capabilities
.iter()
.any(|capability| match capability {
ExtensionCapability::DownloadFile(capability) => capability.allows(desired_url),
_ => false,
});
if !is_allowed {
bail!(
"capability for download_file {desired_url} is not granted by the extension host",
);
}
Ok(())
}
}
#[cfg(test)]

View file

@ -7,9 +7,9 @@ use async_trait::async_trait;
use dap::{DebugRequest, StartDebuggingRequestArgumentsRequest};
use extension::{
CodeLabel, Command, Completion, ContextServerConfiguration, DebugAdapterBinary,
DebugTaskDefinition, ExtensionCapability, ExtensionHostProxy, KeyValueStoreDelegate,
ProcessExecCapability, ProjectDelegate, SlashCommand, SlashCommandArgumentCompletion,
SlashCommandOutput, Symbol, WorktreeDelegate,
DebugTaskDefinition, DownloadFileCapability, ExtensionCapability, ExtensionHostProxy,
KeyValueStoreDelegate, ProcessExecCapability, ProjectDelegate, SlashCommand,
SlashCommandArgumentCompletion, SlashCommandOutput, Symbol, WorktreeDelegate,
};
use fs::{Fs, normalize_path};
use futures::future::LocalBoxFuture;
@ -576,10 +576,16 @@ impl WasmHost {
node_runtime,
proxy,
release_channel: ReleaseChannel::global(cx),
granted_capabilities: vec![ExtensionCapability::ProcessExec(ProcessExecCapability {
command: "*".to_string(),
args: vec!["**".to_string()],
})],
granted_capabilities: vec![
ExtensionCapability::ProcessExec(ProcessExecCapability {
command: "*".to_string(),
args: vec!["**".to_string()],
}),
ExtensionCapability::DownloadFile(DownloadFileCapability {
host: "*".to_string(),
path: vec!["**".to_string()],
}),
],
_main_thread_message_task: task,
main_thread_message_tx: tx,
})

View file

@ -30,6 +30,7 @@ use std::{
sync::{Arc, OnceLock},
};
use task::{SpawnInTerminal, ZedDebugConfig};
use url::Url;
use util::{archive::extract_zip, fs::make_file_executable, maybe};
use wasmtime::component::{Linker, Resource};
@ -1011,6 +1012,9 @@ impl ExtensionImports for WasmState {
file_type: DownloadedFileType,
) -> wasmtime::Result<Result<(), String>> {
maybe!(async {
let parsed_url = Url::parse(&url)?;
self.capability_granter.grant_download_file(&parsed_url)?;
let path = PathBuf::from(path);
let extension_work_dir = self.host.work_dir.join(self.manifest.id.as_ref());