extension_host: Add npm:install
capability (#35144)
This PR adds a new `npm:install` capability for installing npm packges in extensions. Currently all npm packages are allowed. Release Notes: - N/A
This commit is contained in:
parent
2a0170dc3c
commit
89e88c245e
5 changed files with 69 additions and 2 deletions
|
@ -1,7 +1,9 @@
|
||||||
mod download_file_capability;
|
mod download_file_capability;
|
||||||
|
mod npm_install_package_capability;
|
||||||
mod process_exec_capability;
|
mod process_exec_capability;
|
||||||
|
|
||||||
pub use download_file_capability::*;
|
pub use download_file_capability::*;
|
||||||
|
pub use npm_install_package_capability::*;
|
||||||
pub use process_exec_capability::*;
|
pub use process_exec_capability::*;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -13,4 +15,6 @@ pub enum ExtensionCapability {
|
||||||
#[serde(rename = "process:exec")]
|
#[serde(rename = "process:exec")]
|
||||||
ProcessExec(ProcessExecCapability),
|
ProcessExec(ProcessExecCapability),
|
||||||
DownloadFile(DownloadFileCapability),
|
DownloadFile(DownloadFileCapability),
|
||||||
|
#[serde(rename = "npm:install")]
|
||||||
|
NpmInstallPackage(NpmInstallPackageCapability),
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub struct NpmInstallPackageCapability {
|
||||||
|
pub package: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NpmInstallPackageCapability {
|
||||||
|
/// Returns whether the capability allows installing the given NPM package.
|
||||||
|
pub fn allows(&self, package: &str) -> bool {
|
||||||
|
self.package == "*" || self.package == package
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_allows() {
|
||||||
|
let capability = NpmInstallPackageCapability {
|
||||||
|
package: "*".to_string(),
|
||||||
|
};
|
||||||
|
assert_eq!(capability.allows("package"), true);
|
||||||
|
|
||||||
|
let capability = NpmInstallPackageCapability {
|
||||||
|
package: "react".to_string(),
|
||||||
|
};
|
||||||
|
assert_eq!(capability.allows("react"), true);
|
||||||
|
|
||||||
|
let capability = NpmInstallPackageCapability {
|
||||||
|
package: "react".to_string(),
|
||||||
|
};
|
||||||
|
assert_eq!(capability.allows("malicious-package"), false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -63,6 +63,24 @@ impl CapabilityGranter {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn grant_npm_install_package(&self, package_name: &str) -> Result<()> {
|
||||||
|
let is_allowed = self
|
||||||
|
.granted_capabilities
|
||||||
|
.iter()
|
||||||
|
.any(|capability| match capability {
|
||||||
|
ExtensionCapability::NpmInstallPackage(capability) => {
|
||||||
|
capability.allows(package_name)
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if !is_allowed {
|
||||||
|
bail!("capability for npm:install {package_name} is not granted by the extension host",);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -8,8 +8,8 @@ use dap::{DebugRequest, StartDebuggingRequestArgumentsRequest};
|
||||||
use extension::{
|
use extension::{
|
||||||
CodeLabel, Command, Completion, ContextServerConfiguration, DebugAdapterBinary,
|
CodeLabel, Command, Completion, ContextServerConfiguration, DebugAdapterBinary,
|
||||||
DebugTaskDefinition, DownloadFileCapability, ExtensionCapability, ExtensionHostProxy,
|
DebugTaskDefinition, DownloadFileCapability, ExtensionCapability, ExtensionHostProxy,
|
||||||
KeyValueStoreDelegate, ProcessExecCapability, ProjectDelegate, SlashCommand,
|
KeyValueStoreDelegate, NpmInstallPackageCapability, ProcessExecCapability, ProjectDelegate,
|
||||||
SlashCommandArgumentCompletion, SlashCommandOutput, Symbol, WorktreeDelegate,
|
SlashCommand, SlashCommandArgumentCompletion, SlashCommandOutput, Symbol, WorktreeDelegate,
|
||||||
};
|
};
|
||||||
use fs::{Fs, normalize_path};
|
use fs::{Fs, normalize_path};
|
||||||
use futures::future::LocalBoxFuture;
|
use futures::future::LocalBoxFuture;
|
||||||
|
@ -585,6 +585,9 @@ impl WasmHost {
|
||||||
host: "*".to_string(),
|
host: "*".to_string(),
|
||||||
path: vec!["**".to_string()],
|
path: vec!["**".to_string()],
|
||||||
}),
|
}),
|
||||||
|
ExtensionCapability::NpmInstallPackage(NpmInstallPackageCapability {
|
||||||
|
package: "*".to_string(),
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
_main_thread_message_task: task,
|
_main_thread_message_task: task,
|
||||||
main_thread_message_tx: tx,
|
main_thread_message_tx: tx,
|
||||||
|
|
|
@ -745,6 +745,9 @@ impl nodejs::Host for WasmState {
|
||||||
package_name: String,
|
package_name: String,
|
||||||
version: String,
|
version: String,
|
||||||
) -> wasmtime::Result<Result<(), String>> {
|
) -> wasmtime::Result<Result<(), String>> {
|
||||||
|
self.capability_granter
|
||||||
|
.grant_npm_install_package(&package_name)?;
|
||||||
|
|
||||||
self.host
|
self.host
|
||||||
.node_runtime
|
.node_runtime
|
||||||
.npm_install_packages(&self.work_dir(), &[(&package_name, &version)])
|
.npm_install_packages(&self.work_dir(), &[(&package_name, &version)])
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue