systemprompt_models/subprocess/
mod.rs1pub const SUBPROCESS_MARKER_ENV: &str = "SYSTEMPROMPT_SUBPROCESS";
20pub const AGENT_NAME_ENV: &str = "AGENT_NAME";
21pub const MCP_SERVICE_ID_ENV: &str = "MCP_SERVICE_ID";
22
23pub const DEPLOYMENT_HOST_ENV: &str = "SYSTEMPROMPT_DEPLOYMENT_HOST";
24
25const FLY_HOST_ENV: &str = "FLY_APP_NAME";
27
28pub fn deployment_host(lookup: impl Fn(&str) -> Option<String>) -> Option<String> {
29 [DEPLOYMENT_HOST_ENV, FLY_HOST_ENV].iter().find_map(|name| {
30 lookup(name)
31 .map(|value| value.trim().to_owned())
32 .filter(|value| !value.is_empty())
33 })
34}
35
36pub fn is_deployment_host(lookup: impl Fn(&str) -> Option<String>) -> bool {
37 deployment_host(lookup).is_some()
38}
39
40pub fn inherited_parent_env(lookup: impl Fn(&str) -> Option<String>) -> Vec<(String, String)> {
41 let mut env: Vec<(String, String)> = [
42 DEPLOYMENT_HOST_ENV,
43 FLY_HOST_ENV,
44 "HOSTNAME",
45 "PATH",
46 "HOME",
47 ]
48 .iter()
49 .filter_map(|name| lookup(name).map(|value| ((*name).to_owned(), value)))
50 .collect();
51
52 if let Some(entry) = crate::net::trusted_hosts_env_entry(&lookup) {
53 env.push(entry);
54 }
55
56 env
57}
58
59#[must_use]
60pub const fn identity_verification_supported() -> bool {
61 cfg!(any(target_os = "linux", target_os = "macos"))
62}
63
64#[must_use]
65pub fn signalable_pid(pid: u32) -> Option<i32> {
66 if pid == 0 {
67 return None;
68 }
69 i32::try_from(pid).ok()
70}
71#[must_use]
72pub fn environ_identifies_child(environ: &[u8], name_key: &str, service_name: &str) -> bool {
73 let marker = format!("{SUBPROCESS_MARKER_ENV}=1");
74 let expected_name = format!("{name_key}={service_name}");
75
76 let mut has_marker = false;
77 let mut has_name = false;
78 for entry in environ.split(|&b| b == 0) {
79 if entry == marker.as_bytes() {
80 has_marker = true;
81 } else if entry == expected_name.as_bytes() {
82 has_name = true;
83 }
84 }
85
86 has_marker && has_name
87}
88
89#[must_use]
93pub fn environ_from_procargs2(blob: &[u8]) -> Option<&[u8]> {
94 const ARGC_LEN: usize = size_of::<i32>();
95
96 let argc_bytes: [u8; ARGC_LEN] = blob.get(..ARGC_LEN)?.try_into().ok()?;
97 let argc = usize::try_from(i32::from_ne_bytes(argc_bytes)).ok()?;
98
99 let mut rest = blob.get(ARGC_LEN..)?;
100 let exec_path_end = rest.iter().position(|&b| b == 0)?;
101 rest = rest.get(exec_path_end + 1..)?;
102
103 let argv_start = rest.iter().position(|&b| b != 0)?;
104 rest = rest.get(argv_start..)?;
105
106 for _ in 0..argc {
107 let entry_end = rest.iter().position(|&b| b == 0)?;
108 rest = rest.get(entry_end + 1..)?;
109 }
110
111 Some(rest)
112}