mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-22 00:01:34 +00:00
all
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
BACKEND_PORT=8010
|
||||
FRONTEND_PORT=3010
|
||||
REMOTE=http://localhost:8010
|
||||
Generated
+1
@@ -17462,6 +17462,7 @@ dependencies = [
|
||||
"sha2 0.10.9",
|
||||
"sqlx",
|
||||
"tar",
|
||||
"tempfile",
|
||||
"tiberius",
|
||||
"tokio",
|
||||
"tokio-postgres 0.7.13",
|
||||
|
||||
@@ -33,8 +33,11 @@ pub fn build_sandbox_mounts(setup: &SandboxSetupState) -> String {
|
||||
/// 2. Move the overlay root mount (`dst: "/"`) to be the FIRST mount block.
|
||||
/// nsjail applies mounts in order, so the root bind must come before
|
||||
/// tmpfs/bind mounts that go on top of it.
|
||||
/// 3. Re-add read-only bind mounts for `runtime_bins` paths that fall under
|
||||
/// stripped system dirs (e.g. `/usr/bin/bun`). These are layered on top of
|
||||
/// the overlay so the host runtime binary is available inside the sandbox.
|
||||
/// If no overlay marker is present, returns the config unchanged.
|
||||
pub fn finalize_nsjail_config(config: &str) -> String {
|
||||
pub fn finalize_nsjail_config(config: &str, runtime_bins: &[&str]) -> String {
|
||||
if !config.contains(OVERLAY_MARKER) {
|
||||
return config.to_string();
|
||||
}
|
||||
@@ -87,8 +90,7 @@ pub fn finalize_nsjail_config(config: &str) -> String {
|
||||
if should_remove_block {
|
||||
result_lines.truncate(mount_block_start);
|
||||
} else if is_overlay_root {
|
||||
overlay_root_lines
|
||||
.extend_from_slice(&result_lines[mount_block_start..]);
|
||||
overlay_root_lines.extend_from_slice(&result_lines[mount_block_start..]);
|
||||
overlay_root_lines.push(lines[i]);
|
||||
result_lines.truncate(mount_block_start);
|
||||
} else {
|
||||
@@ -129,7 +131,22 @@ pub fn finalize_nsjail_config(config: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
result_lines.join("\n")
|
||||
// Re-add bind mounts for runtime binaries that fall under stripped system dirs.
|
||||
// These are appended at the end so they layer on top of the overlay root.
|
||||
let runtime_mounts: String = runtime_bins
|
||||
.iter()
|
||||
.filter(|bin| system_dirs.iter().any(|d| bin.starts_with(d)))
|
||||
.map(|bin| {
|
||||
format!("\nmount {{\n src: \"{bin}\"\n dst: \"{bin}\"\n is_bind: true\n}}")
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut result = result_lines.join("\n");
|
||||
if !runtime_mounts.is_empty() {
|
||||
result.push_str(&runtime_mounts);
|
||||
result.push('\n');
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -155,7 +172,10 @@ mod tests {
|
||||
let mut setup = SandboxSetupState::default();
|
||||
setup.volume_mounts.insert(
|
||||
"data".to_string(),
|
||||
(PathBuf::from("/job/volumes/data"), "/workspace/data".to_string()),
|
||||
(
|
||||
PathBuf::from("/job/volumes/data"),
|
||||
"/workspace/data".to_string(),
|
||||
),
|
||||
);
|
||||
let mounts = build_sandbox_mounts(&setup);
|
||||
assert!(mounts.contains("dst: \"/workspace/data\""));
|
||||
@@ -170,11 +190,17 @@ mod tests {
|
||||
let mut setup = SandboxSetupState::default();
|
||||
setup.volume_mounts.insert(
|
||||
"input".to_string(),
|
||||
(PathBuf::from("/job/volumes/input"), "/mnt/input".to_string()),
|
||||
(
|
||||
PathBuf::from("/job/volumes/input"),
|
||||
"/mnt/input".to_string(),
|
||||
),
|
||||
);
|
||||
setup.volume_mounts.insert(
|
||||
"output".to_string(),
|
||||
(PathBuf::from("/job/volumes/output"), "/mnt/output".to_string()),
|
||||
(
|
||||
PathBuf::from("/job/volumes/output"),
|
||||
"/mnt/output".to_string(),
|
||||
),
|
||||
);
|
||||
let mounts = build_sandbox_mounts(&setup);
|
||||
assert!(mounts.contains("/mnt/input"));
|
||||
@@ -212,7 +238,10 @@ mod tests {
|
||||
};
|
||||
setup.volume_mounts.insert(
|
||||
"data".to_string(),
|
||||
(PathBuf::from("/job/volumes/data"), "/workspace/data".to_string()),
|
||||
(
|
||||
PathBuf::from("/job/volumes/data"),
|
||||
"/workspace/data".to_string(),
|
||||
),
|
||||
);
|
||||
let mounts = build_sandbox_mounts(&setup);
|
||||
assert!(mounts.contains(OVERLAY_MARKER));
|
||||
@@ -230,7 +259,7 @@ mod tests {
|
||||
let config = "name: \"test\"\n\
|
||||
mount {\n src: \"/bin\"\n dst: \"/bin\"\n is_bind: true\n}\n\
|
||||
mount {\n dst: \"/tmp\"\n fstype: \"tmpfs\"\n rw: true\n}\n";
|
||||
let result = finalize_nsjail_config(config);
|
||||
let result = finalize_nsjail_config(config, &[]);
|
||||
assert_eq!(result, config);
|
||||
}
|
||||
|
||||
@@ -245,14 +274,17 @@ mod tests {
|
||||
# SANDBOX_OVERLAY_ACTIVE\n\
|
||||
mount {\n src: \"/job/merged\"\n dst: \"/\"\n is_bind: true\n rw: true\n}\n\
|
||||
mount {\n dst: \"/tmp\"\n fstype: \"tmpfs\"\n rw: true\n}\n";
|
||||
let result = finalize_nsjail_config(config);
|
||||
let result = finalize_nsjail_config(config, &[]);
|
||||
for dir in &["/bin", "/lib", "/lib64", "/usr", "/etc"] {
|
||||
assert!(
|
||||
!result.contains(&format!("dst: \"{dir}\"")),
|
||||
"System dir {dir} should be stripped"
|
||||
);
|
||||
}
|
||||
assert!(result.contains("dst: \"/\""), "Overlay root mount preserved");
|
||||
assert!(
|
||||
result.contains("dst: \"/\""),
|
||||
"Overlay root mount preserved"
|
||||
);
|
||||
assert!(result.contains("dst: \"/tmp\""), "tmpfs mount preserved");
|
||||
}
|
||||
|
||||
@@ -265,10 +297,13 @@ mod tests {
|
||||
mount {\n dst: \"/tmp\"\n fstype: \"tmpfs\"\n rw: true\n}\n\
|
||||
# SANDBOX_OVERLAY_ACTIVE\n\
|
||||
mount {\n src: \"/job/merged\"\n dst: \"/\"\n is_bind: true\n rw: true\n}\n";
|
||||
let result = finalize_nsjail_config(config);
|
||||
let result = finalize_nsjail_config(config, &[]);
|
||||
assert!(!result.contains("dst: \"/bin\""), "/bin stripped");
|
||||
assert!(result.contains("dst: \"/dev/null\""), "/dev/null kept");
|
||||
assert!(result.contains("dst: \"/opt/microsoft\""), "/opt/microsoft kept");
|
||||
assert!(
|
||||
result.contains("dst: \"/opt/microsoft\""),
|
||||
"/opt/microsoft kept"
|
||||
);
|
||||
assert!(result.contains("dst: \"/tmp\""), "/tmp tmpfs kept");
|
||||
}
|
||||
|
||||
@@ -277,11 +312,33 @@ mod tests {
|
||||
let config = "name: \"test\"\n\
|
||||
# SANDBOX_OVERLAY_ACTIVE\n\
|
||||
mount {\n src: \"/job/merged\"\n dst: \"/\"\n is_bind: true\n}\n";
|
||||
let result = finalize_nsjail_config(config);
|
||||
let result = finalize_nsjail_config(config, &[]);
|
||||
assert!(!result.contains(OVERLAY_MARKER));
|
||||
assert!(result.contains("dst: \"/\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_finalize_readds_runtime_bins_under_stripped_dirs() {
|
||||
let config = "name: \"test\"\n\
|
||||
mount {\n src: \"/usr\"\n dst: \"/usr\"\n is_bind: true\n}\n\
|
||||
# SANDBOX_OVERLAY_ACTIVE\n\
|
||||
mount {\n src: \"/job/merged\"\n dst: \"/\"\n is_bind: true\n rw: true\n}\n";
|
||||
let result = finalize_nsjail_config(config, &["/usr/bin/bun"]);
|
||||
assert!(!result.contains("dst: \"/usr\""), "/usr stripped");
|
||||
assert!(result.contains("dst: \"/usr/bin/bun\""), "bun re-added");
|
||||
assert!(result.contains("src: \"/usr/bin/bun\""), "bun src set");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_finalize_skips_runtime_bins_not_under_system_dirs() {
|
||||
let config = "name: \"test\"\n\
|
||||
# SANDBOX_OVERLAY_ACTIVE\n\
|
||||
mount {\n src: \"/job/merged\"\n dst: \"/\"\n is_bind: true\n}\n";
|
||||
let result = finalize_nsjail_config(config, &["/tmp/windmill/cache/py_runtime"]);
|
||||
// Should NOT add an extra mount since /tmp is not a stripped system dir
|
||||
assert_eq!(result.matches("mount {").count(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mount_block_syntax() {
|
||||
let setup = SandboxSetupState {
|
||||
|
||||
@@ -143,5 +143,8 @@ hyper-tls = { workspace = true, optional = true }
|
||||
hyper-util = { workspace = true, optional = true }
|
||||
rcgen = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile.workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
libffi-sys = { workspace = true, optional = true }
|
||||
|
||||
@@ -33,9 +33,9 @@ use crate::{
|
||||
read_and_check_result, start_child_process, transform_json, OccupancyMetrics,
|
||||
},
|
||||
handle_child::handle_child,
|
||||
is_sandboxing_enabled,
|
||||
python_executor::{create_dependencies_dir, handle_python_reqs, uv_pip_compile},
|
||||
is_sandboxing_enabled, DISABLE_NUSER, GIT_PATH, HOME_ENV, NSJAIL_PATH, PATH_ENV, PROXY_ENVS,
|
||||
PY_INSTALL_DIR, TZ_ENV,
|
||||
DISABLE_NUSER, GIT_PATH, HOME_ENV, NSJAIL_PATH, PATH_ENV, PROXY_ENVS, PY_INSTALL_DIR, TZ_ENV,
|
||||
};
|
||||
use windmill_common::client::AuthedClient;
|
||||
|
||||
@@ -1192,6 +1192,7 @@ mount {{
|
||||
"{ADDITIONAL_PYTHON_PATHS}",
|
||||
additional_python_paths_folders.as_str(),
|
||||
),
|
||||
&[],
|
||||
);
|
||||
let _ = write_file(job_dir, "run.config.proto", &nsjail_config)?;
|
||||
} else {
|
||||
|
||||
@@ -186,8 +186,8 @@ exit $exit_status
|
||||
|
||||
// Use nsjail if globally enabled, script has #sandbox annotation,
|
||||
// or sandbox mounts are present (snapshot/volume annotations)
|
||||
let nsjail =
|
||||
(is_sandboxing_enabled() || annotation.sandbox || !shared_mount.is_empty()) && is_regular_job;
|
||||
let nsjail = (is_sandboxing_enabled() || annotation.sandbox || !shared_mount.is_empty())
|
||||
&& is_regular_job;
|
||||
let child = if nsjail {
|
||||
let nsjail_config = windmill_sandbox::finalize_nsjail_config(
|
||||
&NSJAIL_CONFIG_RUN_BASH_CONTENT
|
||||
@@ -196,6 +196,7 @@ exit $exit_status
|
||||
.replace("{SHARED_MOUNT}", shared_mount)
|
||||
.replace("{TRACING_PROXY_CA_CERT_PATH}", TRACING_PROXY_CA_CERT_PATH)
|
||||
.replace("#{DEV}", DEV_CONF_NSJAIL),
|
||||
&[],
|
||||
);
|
||||
let _ = write_file(job_dir, "run.config.proto", &nsjail_config)?;
|
||||
let mut cmd_args = vec![
|
||||
|
||||
@@ -47,9 +47,9 @@ use windmill_common::{
|
||||
DB,
|
||||
};
|
||||
|
||||
use crate::global_cache::{exists_in_cache, save_cache};
|
||||
#[cfg(all(feature = "enterprise", feature = "parquet"))]
|
||||
use windmill_object_store::attempt_fetch_bytes;
|
||||
use crate::global_cache::{exists_in_cache, save_cache};
|
||||
|
||||
use windmill_parser::Typ;
|
||||
|
||||
@@ -977,8 +977,7 @@ pub async fn handle_bun_job(
|
||||
}
|
||||
};
|
||||
|
||||
let (cache, logs) =
|
||||
crate::global_cache::load_cache(&local_path, &remote_path, false).await;
|
||||
let (cache, logs) = crate::global_cache::load_cache(&local_path, &remote_path, false).await;
|
||||
(cache, logs, local_path, remote_path)
|
||||
} else {
|
||||
(false, "".to_string(), "".to_string(), "".to_string())
|
||||
@@ -1452,6 +1451,11 @@ try {{
|
||||
|
||||
//do not cache local dependencies
|
||||
let child = if is_sandboxing_enabled() || !shared_mount.is_empty() {
|
||||
let runtime_bin = if annotation.nodejs {
|
||||
&*NODE_BIN_PATH
|
||||
} else {
|
||||
&*BUN_PATH
|
||||
};
|
||||
let nsjail_config = windmill_sandbox::finalize_nsjail_config(
|
||||
&NSJAIL_CONFIG_RUN_BUN_CONTENT
|
||||
.replace("{LANG}", if annotation.nodejs { "nodejs" } else { "bun" })
|
||||
@@ -1470,6 +1474,7 @@ try {{
|
||||
)
|
||||
.replace("{TRACING_PROXY_CA_CERT_PATH}", TRACING_PROXY_CA_CERT_PATH)
|
||||
.replace("#{DEV}", DEV_CONF_NSJAIL),
|
||||
&[runtime_bin],
|
||||
);
|
||||
let _ = write_file(job_dir, "run.config.proto", &nsjail_config)?;
|
||||
|
||||
|
||||
@@ -13,14 +13,11 @@ use itertools::Itertools;
|
||||
#[cfg(feature = "csharp")]
|
||||
use tokio::{fs::File, io::AsyncReadExt, process::Command};
|
||||
#[cfg(feature = "csharp")]
|
||||
use windmill_common::{
|
||||
utils::calculate_hash,
|
||||
worker::write_file,
|
||||
};
|
||||
use windmill_common::{utils::calculate_hash, worker::write_file};
|
||||
|
||||
use windmill_common::error::{self, Error};
|
||||
#[cfg(feature = "csharp")]
|
||||
use crate::global_cache::save_cache;
|
||||
use windmill_common::error::{self, Error};
|
||||
#[cfg(feature = "csharp")]
|
||||
use windmill_queue::append_logs;
|
||||
|
||||
@@ -519,8 +516,7 @@ pub async fn handle_csharp_job(
|
||||
let bin_path = format!("{}/{hash}", CSHARP_CACHE_DIR);
|
||||
let remote_path = format!("{CSHARP_OBJECT_STORE_PREFIX}{hash}");
|
||||
|
||||
let (cache, cache_logs) =
|
||||
crate::global_cache::load_cache(&bin_path, &remote_path, false).await;
|
||||
let (cache, cache_logs) = crate::global_cache::load_cache(&bin_path, &remote_path, false).await;
|
||||
|
||||
let cache_logs = if cache {
|
||||
#[cfg(unix)]
|
||||
@@ -595,6 +591,7 @@ pub async fn handle_csharp_job(
|
||||
.replace("{SHARED_MOUNT}", shared_mount)
|
||||
.replace("{TRACING_PROXY_CA_CERT_PATH}", TRACING_PROXY_CA_CERT_PATH)
|
||||
.replace("#{DEV}", DEV_CONF_NSJAIL),
|
||||
&[],
|
||||
);
|
||||
write_file(job_dir, "run.config.proto", &nsjail_config)?;
|
||||
let mut nsjail_cmd = Command::new(NSJAIL_PATH.as_str());
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::{common::MaybeLock, get_proxy_envs_for_lang};
|
||||
use std::{collections::HashMap, fs::DirBuilder, process::Stdio};
|
||||
use windmill_common::scripts::ScriptLang;
|
||||
|
||||
use crate::global_cache::save_cache;
|
||||
use itertools::Itertools;
|
||||
use serde_json::value::RawValue;
|
||||
use tokio::{
|
||||
@@ -15,7 +16,6 @@ use windmill_common::{
|
||||
utils::calculate_hash,
|
||||
worker::{write_file, Connection, GoAnnotations},
|
||||
};
|
||||
use crate::global_cache::save_cache;
|
||||
use windmill_parser_go::{parse_go_imports, REQUIRE_PARSE};
|
||||
use windmill_queue::{append_logs, CanceledBy, MiniPulledJob};
|
||||
|
||||
@@ -110,8 +110,7 @@ pub async fn handle_go_job(
|
||||
let hash = calculate_hash(&format!("{}{:?}v2", inner_content, &maybe_lock));
|
||||
let bin_path = format!("{}/{hash}", GO_BIN_CACHE_DIR);
|
||||
let remote_path = format!("{GO_OBJECT_STORE_PREFIX}{hash}");
|
||||
let (cache, cache_logs) =
|
||||
crate::global_cache::load_cache(&bin_path, &remote_path, false).await;
|
||||
let (cache, cache_logs) = crate::global_cache::load_cache(&bin_path, &remote_path, false).await;
|
||||
|
||||
let (skip_go_mod, skip_tidy) = if cache {
|
||||
(true, true)
|
||||
@@ -347,6 +346,7 @@ func Run(req Req) (interface{{}}, error){{
|
||||
.replace("{SHARED_MOUNT}", shared_mount)
|
||||
.replace("{TRACING_PROXY_CA_CERT_PATH}", TRACING_PROXY_CA_CERT_PATH)
|
||||
.replace("#{DEV}", DEV_CONF_NSJAIL),
|
||||
&[],
|
||||
);
|
||||
let _ = write_file(job_dir, "run.config.proto", &nsjail_config)?;
|
||||
let mut nsjail_cmd = Command::new(NSJAIL_PATH.as_str());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::{collections::HashMap, path::PathBuf, process::Stdio};
|
||||
|
||||
use crate::global_cache::save_cache;
|
||||
use anyhow::{anyhow, bail};
|
||||
use async_recursion::async_recursion;
|
||||
use itertools::Itertools;
|
||||
@@ -15,7 +16,6 @@ use windmill_common::{
|
||||
utils::calculate_hash,
|
||||
worker::{copy_dir_recursively, write_file, Connection},
|
||||
};
|
||||
use crate::global_cache::save_cache;
|
||||
use windmill_parser::Arg;
|
||||
use windmill_parser_java::parse_java_sig_meta;
|
||||
use windmill_queue::{append_logs, CanceledBy, MiniPulledJob};
|
||||
@@ -605,6 +605,7 @@ async fn run<'a>(
|
||||
.replace("{CACHE_DIR}", JAVA_CACHE_DIR)
|
||||
.replace("{SHARED_MOUNT}", &shared_mount)
|
||||
.replace("{CLONE_NEWUSER}", &(!*DISABLE_NUSER).to_string()),
|
||||
&[],
|
||||
);
|
||||
write_file(job_dir, "run.config.proto", &nsjail_config)?;
|
||||
let mut cmd = Command::new(NSJAIL_PATH.as_str());
|
||||
|
||||
@@ -16,8 +16,8 @@ use crate::{
|
||||
build_command_with_isolation, create_args_and_out_file, get_reserved_variables,
|
||||
read_result, start_child_process, OccupancyMetrics, DEV_CONF_NSJAIL,
|
||||
},
|
||||
get_proxy_envs_for_lang, handle_child, is_sandboxing_enabled, DISABLE_NUSER, NSJAIL_PATH, PATH_ENV,
|
||||
TRACING_PROXY_CA_CERT_PATH,
|
||||
get_proxy_envs_for_lang, handle_child, is_sandboxing_enabled, DISABLE_NUSER, NSJAIL_PATH,
|
||||
PATH_ENV, TRACING_PROXY_CA_CERT_PATH,
|
||||
};
|
||||
use windmill_common::client::AuthedClient;
|
||||
use windmill_common::scripts::ScriptLang;
|
||||
@@ -253,6 +253,7 @@ async fn run<'a>(
|
||||
.replace("{CLONE_NEWUSER}", &(!*DISABLE_NUSER).to_string())
|
||||
.replace("{TRACING_PROXY_CA_CERT_PATH}", TRACING_PROXY_CA_CERT_PATH)
|
||||
.replace("#{DEV}", DEV_CONF_NSJAIL),
|
||||
&[],
|
||||
);
|
||||
write_file(job_dir, "run.config.proto", &nsjail_config)?;
|
||||
let mut nsjail_cmd = Command::new(NSJAIL_PATH.as_str());
|
||||
|
||||
@@ -22,7 +22,7 @@ use crate::{
|
||||
get_reserved_variables, read_result, start_child_process, MaybeLock, OccupancyMetrics,
|
||||
},
|
||||
handle_child::handle_child,
|
||||
COMPOSER_CACHE_DIR, COMPOSER_PATH, is_sandboxing_enabled, DISABLE_NUSER, NSJAIL_PATH, PHP_PATH,
|
||||
is_sandboxing_enabled, COMPOSER_CACHE_DIR, COMPOSER_PATH, DISABLE_NUSER, NSJAIL_PATH, PHP_PATH,
|
||||
};
|
||||
use windmill_common::client::AuthedClient;
|
||||
|
||||
@@ -299,6 +299,7 @@ try {{
|
||||
.replace("{JOB_DIR}", job_dir)
|
||||
.replace("{CLONE_NEWUSER}", &(!*DISABLE_NUSER).to_string())
|
||||
.replace("{SHARED_MOUNT}", shared_mount),
|
||||
&[],
|
||||
);
|
||||
let _ = write_file(job_dir, "run.config.proto", &nsjail_config)?;
|
||||
|
||||
|
||||
@@ -524,6 +524,7 @@ $env:PSModulePath = \"{};$PSModulePathBackup\"",
|
||||
.replace("{CLONE_NEWUSER}", &(!*DISABLE_NUSER).to_string())
|
||||
.replace("{SHARED_MOUNT}", shared_mount)
|
||||
.replace("{CACHE_DIR}", POWERSHELL_CACHE_DIR),
|
||||
&[],
|
||||
);
|
||||
let _ = write_file(job_dir, "run.config.proto", &nsjail_config)?;
|
||||
let cmd_args = vec![
|
||||
|
||||
@@ -784,7 +784,7 @@ except BaseException as e:
|
||||
#[cfg(windows)]
|
||||
let additional_python_paths_folders = additional_python_paths_folders.replace(":", ";");
|
||||
|
||||
if is_sandboxing_enabled() {
|
||||
if is_sandboxing_enabled() || !shared_mount.is_empty() {
|
||||
let shared_deps = additional_python_paths
|
||||
.into_iter()
|
||||
.map(|pp| {
|
||||
@@ -815,6 +815,7 @@ mount {{
|
||||
)
|
||||
.replace("{TRACING_PROXY_CA_CERT_PATH}", TRACING_PROXY_CA_CERT_PATH)
|
||||
.replace("#{DEV}", DEV_CONF_NSJAIL),
|
||||
&[],
|
||||
);
|
||||
let _ = write_file(job_dir, "run.config.proto", &nsjail_config)?;
|
||||
} else {
|
||||
|
||||
@@ -801,6 +801,7 @@ mount {{
|
||||
.replace("{TRACING_PROXY_CA_CERT_PATH}", TRACING_PROXY_CA_CERT_PATH)
|
||||
.replace("#{DEV}", DEV_CONF_NSJAIL)
|
||||
.replace("{CLONE_NEWUSER}", &(!*DISABLE_NUSER).to_string()),
|
||||
&[],
|
||||
);
|
||||
write_file(job_dir, "run.config.proto", &nsjail_config)?;
|
||||
let mut cmd = Command::new(NSJAIL_PATH.as_str());
|
||||
|
||||
@@ -5,6 +5,7 @@ use std::{collections::HashMap, process::Stdio};
|
||||
use uuid::Uuid;
|
||||
use windmill_parser_rust::parse_rust_deps_into_manifest;
|
||||
|
||||
use crate::global_cache::save_cache;
|
||||
use itertools::Itertools;
|
||||
use tokio::{
|
||||
fs::{create_dir_all, File},
|
||||
@@ -16,7 +17,6 @@ use windmill_common::{
|
||||
utils::calculate_hash,
|
||||
worker::{write_file, Connection},
|
||||
};
|
||||
use crate::global_cache::save_cache;
|
||||
use windmill_queue::MiniPulledJob;
|
||||
use windmill_queue::{append_logs, CanceledBy};
|
||||
|
||||
@@ -611,8 +611,7 @@ pub async fn handle_rust_job(
|
||||
let reserved_variables =
|
||||
get_reserved_variables(job, &client.token, conn, parent_runnable_path).await?;
|
||||
|
||||
let (cache, cache_logs) =
|
||||
crate::global_cache::load_cache(&bin_path, &remote_path, false).await;
|
||||
let (cache, cache_logs) = crate::global_cache::load_cache(&bin_path, &remote_path, false).await;
|
||||
|
||||
let cache_logs = if cache {
|
||||
let target = format!("{job_dir}/main");
|
||||
@@ -673,6 +672,7 @@ pub async fn handle_rust_job(
|
||||
.replace("{TRACING_PROXY_CA_CERT_PATH}", TRACING_PROXY_CA_CERT_PATH)
|
||||
.replace("#{DEV}", DEV_CONF_NSJAIL)
|
||||
.replace("{SHARED_MOUNT}", shared_mount),
|
||||
&[],
|
||||
);
|
||||
let _ = write_file(job_dir, "run.config.proto", &nsjail_config)?;
|
||||
let mut nsjail_cmd = Command::new(NSJAIL_PATH.as_str());
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3415,8 +3415,7 @@ pub async fn handle_queued_job(
|
||||
},
|
||||
JobKind::SnapshotBuild => match conn {
|
||||
Connection::Sql(db) => {
|
||||
Box::pin(crate::snapshot_build::handle_snapshot_build(&job, db, conn))
|
||||
.await
|
||||
Box::pin(crate::snapshot_build::handle_snapshot_build(&job, db, conn)).await
|
||||
}
|
||||
Connection::Http(_) => {
|
||||
return Err(Error::internal_err(
|
||||
@@ -4193,18 +4192,19 @@ mount {{
|
||||
|
||||
if let Some(ref snap) = sandbox_config.snapshot {
|
||||
let snapshot_path = windmill_sandbox::ensure_snapshot_cached(
|
||||
&job.workspace_id, &snap.name, &snap.tag, db,
|
||||
&job.workspace_id,
|
||||
&snap.name,
|
||||
&snap.tag,
|
||||
db,
|
||||
)
|
||||
.await?;
|
||||
setup.overlay =
|
||||
Some(windmill_sandbox::mount_overlay(&snapshot_path, job_dir).await?);
|
||||
setup.overlay = Some(windmill_sandbox::mount_overlay(&snapshot_path, job_dir).await?);
|
||||
}
|
||||
|
||||
for (vol_name, mount_path) in &sandbox_config.volumes {
|
||||
let local_dir = format!("{job_dir}/volumes/{vol_name}");
|
||||
std::fs::create_dir_all(&local_dir).map_err(|e| {
|
||||
Error::ExecutionErr(format!("Failed to create volume dir: {e}"))
|
||||
})?;
|
||||
std::fs::create_dir_all(&local_dir)
|
||||
.map_err(|e| Error::ExecutionErr(format!("Failed to create volume dir: {e}")))?;
|
||||
windmill_sandbox::download_volume(
|
||||
&job.workspace_id,
|
||||
vol_name,
|
||||
@@ -4224,6 +4224,17 @@ mount {{
|
||||
None
|
||||
};
|
||||
|
||||
if sandbox_config.snapshot.is_some() || !sandbox_config.volumes.is_empty() {
|
||||
let mut sandbox_logs = "\n--- SANDBOX ---\n".to_string();
|
||||
if let Some(ref snap) = sandbox_config.snapshot {
|
||||
sandbox_logs.push_str(&format!("Snapshot: {}:{}\n", snap.name, snap.tag));
|
||||
}
|
||||
for (vol_name, mount_path) in &sandbox_config.volumes {
|
||||
sandbox_logs.push_str(&format!("Volume: {} -> {}\n", vol_name, mount_path));
|
||||
}
|
||||
append_logs(&job.id, &job.workspace_id, sandbox_logs, conn).await;
|
||||
}
|
||||
|
||||
let envs = build_envs(envs.as_ref())?;
|
||||
|
||||
let Some(language) = language else {
|
||||
@@ -4682,13 +4693,9 @@ mount {{
|
||||
if let Some(ref setup) = sandbox_setup {
|
||||
if let Some(db) = conn.as_sql() {
|
||||
for (vol_name, (local_dir, _)) in &setup.volume_mounts {
|
||||
if let Err(e) = windmill_sandbox::upload_volume(
|
||||
&job.workspace_id,
|
||||
vol_name,
|
||||
local_dir,
|
||||
db,
|
||||
)
|
||||
.await
|
||||
if let Err(e) =
|
||||
windmill_sandbox::upload_volume(&job.workspace_id, vol_name, local_dir, db)
|
||||
.await
|
||||
{
|
||||
tracing::error!("Failed to upload volume {vol_name}: {e}");
|
||||
}
|
||||
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
port_in_use() {
|
||||
lsof -nP -iTCP:"$1" -sTCP:LISTEN &>/dev/null
|
||||
}
|
||||
|
||||
find_port() {
|
||||
local port=$1
|
||||
while port_in_use "$port"; do
|
||||
((port++))
|
||||
done
|
||||
echo "$port"
|
||||
}
|
||||
|
||||
if [[ -z "${WM_SLOT:-}" ]]; then
|
||||
# Auto-assign: find the first slot (1-99) where both ports are free
|
||||
# Slot 0 (8000/3000) is reserved for the main worktree
|
||||
for slot in $(seq 1 99); do
|
||||
bp=$((8000 + slot * 10))
|
||||
fp=$((3000 + slot * 10))
|
||||
if ! port_in_use "$bp" && ! port_in_use "$fp"; then
|
||||
WM_SLOT=$slot
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ -z "${WM_SLOT:-}" ]]; then
|
||||
echo "ERROR: No available slot found (tried 1-99)" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Auto-assigned slot $WM_SLOT"
|
||||
fi
|
||||
|
||||
# Slot-based: predictable ports for SSH forwarding
|
||||
# Slot 0 = 8000/3000, slot 1 = 8010/3010, slot 2 = 8020/3020, etc.
|
||||
backend_port=$((8000 + WM_SLOT * 10))
|
||||
frontend_port=$((3000 + WM_SLOT * 10))
|
||||
|
||||
if port_in_use "$backend_port" || port_in_use "$frontend_port"; then
|
||||
echo "ERROR: Slot $WM_SLOT ports ($backend_port/$frontend_port) already in use" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Generate .env.local with port overrides
|
||||
cat > .env.local <<EOF
|
||||
BACKEND_PORT=$backend_port
|
||||
FRONTEND_PORT=$frontend_port
|
||||
REMOTE=http://localhost:$backend_port
|
||||
EOF
|
||||
|
||||
echo "Created .env.local with ports: backend=$backend_port, frontend=$frontend_port"
|
||||
Reference in New Issue
Block a user