forked from wrenn/wrenn
v2.0.0 updated (#54)
Co-authored-by: Tasnim Kabir Sadik <tksadik@omukk.dev> Reviewed-on: wrenn/wrenn#54 Co-authored-by: pptx704 <rafeed@omukk.dev> Co-committed-by: pptx704 <rafeed@omukk.dev>
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
when:
|
||||
- event: push
|
||||
- event: [push, manual]
|
||||
branch: main
|
||||
|
||||
steps:
|
||||
|
||||
@ -4,7 +4,7 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
use nix::unistd::{Gid, Uid};
|
||||
|
||||
fn expand_tilde(path: &str, home_dir: &str) -> Result<String, String> {
|
||||
pub(crate) fn expand_tilde(path: &str, home_dir: &str) -> Result<String, String> {
|
||||
if path.is_empty() || !path.starts_with('~') {
|
||||
return Ok(path.to_string());
|
||||
}
|
||||
@ -112,6 +112,34 @@ mod tests {
|
||||
assert_eq!(expand_tilde("relative/path", "/home/u").unwrap(), "relative/path");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tilde_cmd_like() {
|
||||
assert_eq!(expand_tilde("~/bin/myapp", "/home/user").unwrap(), "/home/user/bin/myapp");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tilde_bare_path_arg() {
|
||||
assert_eq!(expand_tilde("~", "/home/user").unwrap(), "/home/user");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tilde_slash_only() {
|
||||
assert_eq!(expand_tilde("~/", "/home/u").unwrap(), "/home/u/");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tilde_embedded_not_expanded() {
|
||||
assert_eq!(expand_tilde("/a/~/b", "/home/u").unwrap(), "/a/~/b");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tilde_long_home_dir() {
|
||||
assert_eq!(
|
||||
expand_tilde("~/code/project", "/very/long/home/directory/path").unwrap(),
|
||||
"/very/long/home/directory/path/code/project"
|
||||
);
|
||||
}
|
||||
|
||||
// expand_and_resolve
|
||||
|
||||
#[test]
|
||||
|
||||
@ -177,13 +177,22 @@ pub fn spawn_process(
|
||||
// commands run as a non-root user. Writing 100 to the process's own
|
||||
// oom_score_adj is always permitted (raising the score).
|
||||
let nice_delta = 0 - current_nice();
|
||||
let profile_source = r#"test -f /etc/profile && . /etc/profile
|
||||
test -f "${HOME}/.bashrc" && . "${HOME}/.bashrc""#;
|
||||
let oom_script = if nice_delta > 0 {
|
||||
format!(
|
||||
r#"echo 100 > /proc/$$/oom_score_adj && exec /usr/bin/nice -n {} "${{@}}""#,
|
||||
nice_delta
|
||||
r#"echo 100 > /proc/$$/oom_score_adj
|
||||
{}
|
||||
exec /usr/bin/nice -n {} "${{@}}""#,
|
||||
profile_source, nice_delta,
|
||||
)
|
||||
} else {
|
||||
r#"echo 100 > /proc/$$/oom_score_adj && exec "$@""#.to_string()
|
||||
format!(
|
||||
r#"echo 100 > /proc/$$/oom_score_adj
|
||||
{}
|
||||
exec "$@""#,
|
||||
profile_source
|
||||
)
|
||||
};
|
||||
let mut wrapper_args = vec![
|
||||
"-c".to_string(),
|
||||
@ -222,7 +231,7 @@ pub fn spawn_process(
|
||||
let master_fd = pty_result.master;
|
||||
let slave_fd = pty_result.slave;
|
||||
|
||||
let mut command = std::process::Command::new("/bin/sh");
|
||||
let mut command = std::process::Command::new("/bin/bash");
|
||||
command
|
||||
.args(&wrapper_args)
|
||||
.env_clear()
|
||||
@ -322,7 +331,7 @@ pub fn spawn_process(
|
||||
tracing::info!(pid, cmd = cmd_str, "process started (pty)");
|
||||
Ok(SpawnedProcess { handle, data_rx, end_rx })
|
||||
} else {
|
||||
let mut command = std::process::Command::new("/bin/sh");
|
||||
let mut command = std::process::Command::new("/bin/bash");
|
||||
command
|
||||
.args(&wrapper_args)
|
||||
.env_clear()
|
||||
|
||||
@ -6,7 +6,7 @@ use connectrpc::{ConnectError, Context, ErrorCode};
|
||||
use dashmap::DashMap;
|
||||
use futures::Stream;
|
||||
|
||||
use crate::permissions::path::expand_and_resolve;
|
||||
use crate::permissions::path::{expand_and_resolve, expand_tilde};
|
||||
use crate::permissions::user::lookup_user;
|
||||
use crate::rpc::pb::process::*;
|
||||
use crate::rpc::process_handler::{self, DataEvent, ProcessHandle};
|
||||
@ -75,8 +75,8 @@ impl ProcessServiceImpl {
|
||||
let user =
|
||||
lookup_user(&username).map_err(|e| ConnectError::new(ErrorCode::Internal, e))?;
|
||||
|
||||
let cmd: &str = proc_config.cmd;
|
||||
let args: Vec<String> = proc_config.args.iter().map(|s| s.to_string()).collect();
|
||||
let cmd_raw: &str = proc_config.cmd;
|
||||
let args_raw: Vec<String> = proc_config.args.iter().map(|s| s.to_string()).collect();
|
||||
let envs: HashMap<String, String> = proc_config
|
||||
.envs
|
||||
.iter()
|
||||
@ -84,6 +84,13 @@ impl ProcessServiceImpl {
|
||||
.collect();
|
||||
|
||||
let home_dir = user.dir.to_string_lossy().to_string();
|
||||
|
||||
let cmd = expand_tilde(cmd_raw, &home_dir)
|
||||
.map_err(|e| ConnectError::new(ErrorCode::InvalidArgument, e))?;
|
||||
let args: Vec<String> = args_raw.into_iter()
|
||||
.map(|a| expand_tilde(&a, &home_dir).unwrap_or(a))
|
||||
.collect();
|
||||
|
||||
let cwd_str: &str = proc_config.cwd.unwrap_or("");
|
||||
let default_workdir = self.state.defaults.workdir();
|
||||
let cwd = expand_and_resolve(cwd_str, &home_dir, default_workdir.as_deref())
|
||||
@ -118,7 +125,7 @@ impl ProcessServiceImpl {
|
||||
);
|
||||
|
||||
let spawned = process_handler::spawn_process(
|
||||
cmd,
|
||||
&cmd,
|
||||
&args,
|
||||
&envs,
|
||||
effective_cwd,
|
||||
@ -525,3 +532,105 @@ fn make_end_start_response(end: process_handler::EndEvent) -> StartResponse {
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn cmd_expands_tilde_slash() {
|
||||
let home_dir = "/home/testuser";
|
||||
let result = expand_tilde("~/bin/mytool", home_dir).unwrap();
|
||||
assert_eq!(result, "/home/testuser/bin/mytool");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmd_expands_bare_tilde() {
|
||||
let home_dir = "/home/testuser";
|
||||
let result = expand_tilde("~", home_dir).unwrap();
|
||||
assert_eq!(result, "/home/testuser");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmd_passthrough_absolute() {
|
||||
let home_dir = "/home/testuser";
|
||||
let result = expand_tilde("/usr/bin/env", home_dir).unwrap();
|
||||
assert_eq!(result, "/usr/bin/env");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmd_passthrough_relative_no_tilde() {
|
||||
let home_dir = "/home/testuser";
|
||||
let result = expand_tilde("bin/tool", home_dir).unwrap();
|
||||
assert_eq!(result, "bin/tool");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmd_errors_on_other_user() {
|
||||
let home_dir = "/home/testuser";
|
||||
assert!(expand_tilde("~other/bin/tool", home_dir).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn args_expands_tilde_slash() {
|
||||
let home_dir = "/home/testuser";
|
||||
let result = expand_tilde("~/hi", home_dir).unwrap();
|
||||
assert_eq!(result, "/home/testuser/hi");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn args_expands_bare_tilde() {
|
||||
let home_dir = "/home/testuser";
|
||||
let result = expand_tilde("~", home_dir).unwrap();
|
||||
assert_eq!(result, "/home/testuser");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn args_other_user_left_literal() {
|
||||
let home_dir = "/home/testuser";
|
||||
let args_raw = vec!["~other".to_string(), "~other/path".to_string()];
|
||||
let args: Vec<String> = args_raw.into_iter()
|
||||
.map(|a| expand_tilde(&a, home_dir).unwrap_or(a))
|
||||
.collect();
|
||||
assert_eq!(args, vec!["~other", "~other/path"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn args_passthrough_absolute() {
|
||||
let home_dir = "/home/testuser";
|
||||
let result = expand_tilde("/tmp/file", home_dir).unwrap();
|
||||
assert_eq!(result, "/tmp/file");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn args_passthrough_relative_no_tilde() {
|
||||
let home_dir = "/home/testuser";
|
||||
let result = expand_tilde("relative/path", home_dir).unwrap();
|
||||
assert_eq!(result, "relative/path");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn args_mixed_expands_tilde_keeps_rest() {
|
||||
let home_dir = "/home/testuser";
|
||||
let args_raw = vec![
|
||||
"-p".to_string(),
|
||||
"~/data".to_string(),
|
||||
"/tmp/out".to_string(),
|
||||
"~other".to_string(),
|
||||
];
|
||||
let args: Vec<String> = args_raw.into_iter()
|
||||
.map(|a| expand_tilde(&a, home_dir).unwrap_or(a))
|
||||
.collect();
|
||||
assert_eq!(args, vec!["-p", "/home/testuser/data", "/tmp/out", "~other"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn args_empty_passthrough() {
|
||||
let home_dir = "/home/testuser";
|
||||
let args_raw: Vec<String> = vec![];
|
||||
let args: Vec<String> = args_raw.into_iter()
|
||||
.map(|a| expand_tilde(&a, home_dir).unwrap_or(a))
|
||||
.collect();
|
||||
assert!(args.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user