1
0
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:
2026-05-24 22:02:31 +00:00
committed by Rafeed M. Bhuiyan
parent 05ddf62399
commit cfc0c52010
4 changed files with 157 additions and 11 deletions

View File

@ -1,5 +1,5 @@
when:
- event: push
- event: [push, manual]
branch: main
steps:

View File

@ -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]

View File

@ -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()

View File

@ -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());
}
}