mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-21 00:02:30 +00:00
feat: add trustedDependencies escape hatch for bun (#2364)
* trustedDeps * fix frontend * trustedDeps * fix frontend
This commit is contained in:
@@ -14,7 +14,7 @@ if (!bo.success) {
|
||||
process.exit(1);
|
||||
} else {
|
||||
let content = await fs.readFile("./out/main.js", { encoding: "utf8" });
|
||||
const imports = new Bun.Transpiler().scanImports(content);
|
||||
const imports = new Bun.Transpiler().scanImports(content.replaceAll("__require", "require"));
|
||||
|
||||
const { intersect } = require("semver-intersect");
|
||||
const dependencies: Record<string, string[]> = {};
|
||||
|
||||
@@ -8,6 +8,7 @@ use anyhow::Context;
|
||||
|
||||
use base64::Engine;
|
||||
use itertools::Itertools;
|
||||
use regex::Regex;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
@@ -42,7 +43,7 @@ use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use windmill_common::variables;
|
||||
|
||||
use windmill_common::{
|
||||
error::{self, Result},
|
||||
error::{self, to_anyhow, Result},
|
||||
jobs::QueuedJob,
|
||||
};
|
||||
use windmill_parser::Typ;
|
||||
@@ -56,6 +57,10 @@ const NSJAIL_CONFIG_RUN_BUN_CONTENT: &str = include_str!("../nsjail/run.bun.conf
|
||||
pub const BUN_LOCKB_SPLIT: &str = "\n//bun.lockb\n";
|
||||
pub const EMPTY_FILE: &str = "<empty>";
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref TRUSTED_DEP: Regex = Regex::new(r"//\s?trustedDependencies:(.*)\n").unwrap();
|
||||
}
|
||||
|
||||
pub async fn gen_lockfile(
|
||||
logs: &mut String,
|
||||
job_id: &Uuid,
|
||||
@@ -67,6 +72,7 @@ pub async fn gen_lockfile(
|
||||
base_internal_url: &str,
|
||||
worker_name: &str,
|
||||
export_pkg: bool,
|
||||
trusted_deps: Vec<String>,
|
||||
) -> Result<Option<String>> {
|
||||
let _ = write_file(
|
||||
&job_dir,
|
||||
@@ -112,6 +118,37 @@ pub async fn gen_lockfile(
|
||||
)
|
||||
.await?;
|
||||
|
||||
if trusted_deps.len() > 0 {
|
||||
logs.push_str(&format!(
|
||||
"\ndetected trustedDependencies: {}\n",
|
||||
trusted_deps.join(", ")
|
||||
));
|
||||
let mut content = "".to_string();
|
||||
{
|
||||
let mut file = File::open(format!("{job_dir}/package.json")).await?;
|
||||
file.read_to_string(&mut content).await?;
|
||||
}
|
||||
let mut value =
|
||||
serde_json::from_str::<serde_json::Map<String, serde_json::Value>>(&content)
|
||||
.map_err(to_anyhow)?;
|
||||
value.insert(
|
||||
"trustedDependencies".to_string(),
|
||||
serde_json::json!(trusted_deps),
|
||||
);
|
||||
write_file(
|
||||
job_dir,
|
||||
"package.json",
|
||||
&serde_json::to_string(&value).map_err(to_anyhow)?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut content = "".to_string();
|
||||
{
|
||||
let mut file = File::open(format!("{job_dir}/package.json")).await?;
|
||||
file.read_to_string(&mut content).await?;
|
||||
}
|
||||
}
|
||||
|
||||
install_lockfile(
|
||||
logs,
|
||||
job_id,
|
||||
@@ -181,6 +218,23 @@ pub async fn install_lockfile(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_trusted_deps(code: &str) -> Vec<String> {
|
||||
// postinstall not allowed with nsjail
|
||||
if !*DISABLE_NSJAIL {
|
||||
return vec![];
|
||||
}
|
||||
TRUSTED_DEP
|
||||
.captures(code)
|
||||
.map(|x| {
|
||||
x[1].to_string()
|
||||
.trim()
|
||||
.split(',')
|
||||
.map(|y| y.trim().to_string())
|
||||
.collect_vec()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all)]
|
||||
pub async fn handle_bun_job(
|
||||
requirements_o: Option<String>,
|
||||
@@ -196,6 +250,7 @@ pub async fn handle_bun_job(
|
||||
shared_mount: &str,
|
||||
) -> error::Result<serde_json::Value> {
|
||||
let _ = write_file(job_dir, "main.ts", inner_content).await?;
|
||||
|
||||
let common_bun_proc_envs: HashMap<String, String> =
|
||||
get_common_bun_proc_envs(&base_internal_url);
|
||||
|
||||
@@ -209,16 +264,20 @@ pub async fn handle_bun_job(
|
||||
let _ = write_file(job_dir, "package.json", &splitted[0]).await?;
|
||||
let lockb = splitted[1];
|
||||
if lockb != EMPTY_FILE {
|
||||
let _ = write_file_binary(
|
||||
job_dir,
|
||||
"bun.lockb",
|
||||
&base64::engine::general_purpose::STANDARD
|
||||
.decode(&splitted[1])
|
||||
.map_err(|_| {
|
||||
error::Error::InternalErr("Could not decode bun.lockb".to_string())
|
||||
})?,
|
||||
)
|
||||
.await?;
|
||||
let has_trusted_deps = &splitted[0].contains("trustedDependencies");
|
||||
|
||||
if !has_trusted_deps {
|
||||
let _ = write_file_binary(
|
||||
job_dir,
|
||||
"bun.lockb",
|
||||
&base64::engine::general_purpose::STANDARD
|
||||
.decode(&splitted[1])
|
||||
.map_err(|_| {
|
||||
error::Error::InternalErr("Could not decode bun.lockb".to_string())
|
||||
})?,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
install_lockfile(
|
||||
logs,
|
||||
@@ -230,25 +289,40 @@ pub async fn handle_bun_job(
|
||||
common_bun_proc_envs.clone(),
|
||||
)
|
||||
.await?;
|
||||
remove_dir_all(format!("{}/node_modules", job_dir)).await?;
|
||||
if !has_trusted_deps {
|
||||
remove_dir_all(format!("{}/node_modules", job_dir)).await?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO: remove once bun implement a reasonable set of trusted deps
|
||||
let trusted_deps = get_trusted_deps(inner_content);
|
||||
let empty_trusted_deps = trusted_deps.len() == 0;
|
||||
if !*DISABLE_NSJAIL || !empty_trusted_deps {
|
||||
logs.push_str("\n\n--- BUN INSTALL ---\n");
|
||||
set_logs(&logs, &job.id, &db).await;
|
||||
let _ = gen_lockfile(
|
||||
logs,
|
||||
&job.id,
|
||||
&job.workspace_id,
|
||||
db,
|
||||
&client.get_token().await,
|
||||
&job.script_path(),
|
||||
job_dir,
|
||||
base_internal_url,
|
||||
worker_name,
|
||||
false,
|
||||
trusted_deps,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if empty_trusted_deps {
|
||||
let node_modules_path = format!("{}/node_modules", job_dir);
|
||||
let node_modules_exists = tokio::fs::metadata(&node_modules_path).await.is_ok();
|
||||
if node_modules_exists {
|
||||
remove_dir_all(&node_modules_path).await?;
|
||||
}
|
||||
}
|
||||
} else if !*DISABLE_NSJAIL {
|
||||
logs.push_str("\n\n--- BUN INSTALL ---\n");
|
||||
set_logs(&logs, &job.id, &db).await;
|
||||
let _ = gen_lockfile(
|
||||
logs,
|
||||
&job.id,
|
||||
&job.workspace_id,
|
||||
db,
|
||||
&client.get_token().await,
|
||||
&job.script_path(),
|
||||
job_dir,
|
||||
base_internal_url,
|
||||
worker_name,
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
remove_dir_all(format!("{}/node_modules", job_dir)).await?;
|
||||
}
|
||||
|
||||
logs.push_str("\n\n--- BUN CODE EXECUTION ---\n");
|
||||
|
||||
@@ -68,7 +68,7 @@ use windmill_queue::{add_completed_job, add_completed_job_error};
|
||||
|
||||
use crate::{
|
||||
bash_executor::{handle_bash_job, handle_powershell_job, ANSI_ESCAPE_RE},
|
||||
bun_executor::{gen_lockfile, handle_bun_job},
|
||||
bun_executor::{gen_lockfile, get_trusted_deps, handle_bun_job},
|
||||
common::{hash_args, read_result, save_in_cache, transform_json_value, write_file},
|
||||
deno_executor::{generate_deno_lock, handle_deno_job},
|
||||
go_executor::{handle_go_job, install_go_dependencies},
|
||||
@@ -2671,6 +2671,8 @@ async fn capture_dependency_job(
|
||||
}
|
||||
ScriptLang::Bun => {
|
||||
let _ = write_file(job_dir, "main.ts", job_raw_code).await?;
|
||||
//TODO: remove once bun provides sane default fot it
|
||||
let trusted_deps = get_trusted_deps(job_raw_code);
|
||||
let req = gen_lockfile(
|
||||
logs,
|
||||
job_id,
|
||||
@@ -2682,6 +2684,7 @@ async fn capture_dependency_job(
|
||||
base_internal_url,
|
||||
worker_name,
|
||||
true,
|
||||
trusted_deps,
|
||||
)
|
||||
.await?;
|
||||
Ok(req.unwrap_or_else(String::new))
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
ScriptService,
|
||||
UserService
|
||||
} from '$lib/gen'
|
||||
import { classNames, sendUserToast } from '$lib/utils'
|
||||
import { classNames } from '$lib/utils'
|
||||
|
||||
import WorkspaceMenu from '$lib/components/sidebar/WorkspaceMenu.svelte'
|
||||
import SidebarContent from '$lib/components/sidebar/SidebarContent.svelte'
|
||||
@@ -20,7 +20,6 @@
|
||||
enterpriseLicense,
|
||||
starStore,
|
||||
superadmin,
|
||||
tutorialsToDo,
|
||||
usageStore,
|
||||
userStore,
|
||||
workspaceStore
|
||||
@@ -35,7 +34,7 @@
|
||||
import { SUPERADMIN_SETTINGS_HASH, USER_SETTINGS_HASH } from '$lib/components/sidebar/settings'
|
||||
import { isCloudHosted } from '$lib/cloud'
|
||||
import MultiplayerMenu from '$lib/components/sidebar/MultiplayerMenu.svelte'
|
||||
import { syncTutorialsTodos, updateProgress } from '$lib/tutorialUtils'
|
||||
import { syncTutorialsTodos } from '$lib/tutorialUtils'
|
||||
|
||||
OpenAPI.WITH_CREDENTIALS = true
|
||||
let menuOpen = false
|
||||
|
||||
Reference in New Issue
Block a user