⎇ c22d2480b93b7802be8e8ea5a0075b8175c4fedc
crates/shared/ente-incarnate/src/env.rs
Ñawpa willay
Pi imata llamkarqan
ch'uya
1//! Construcción del entorno del hijo. Sin globals — toma EnvSpec por valor.
2
3use brahman_card::Card;
4use std::path::PathBuf;
5
6/// Var env para el path del bus interno (cuando aplica). Mismo nombre que
7/// usa ente-bus para que clientes existentes (`BusClient::from_env`) sigan
8/// funcionando sin cambios.
9pub const ENV_BUS_SOCK: &str = "ENTE_BUS_SOCK";
10
11/// Var env para el ULID de la Card encarnada.
12pub const ENV_ENTE_ID: &str = "ENTE_ID";
13
14#[derive(Debug, Clone, Default)]
15pub struct EnvSpec {
16 /// Si `Some`, se inyecta como ENTE_BUS_SOCK.
17 pub bus_sock: Option<PathBuf>,
18 /// Si `Some`, se inyecta como NOTIFY_SOCKET (legacy sd_notify).
19 pub notify_socket: Option<PathBuf>,
20 /// Vars adicionales que el caller quiere forzar.
21 pub extra: Vec<(String, String)>,
22}
23
24/// Hereda env del padre, aplica el envp explícito de la Card, y al final
25/// inyecta las vars del fractal según `EnvSpec`.
26pub fn build_env(card: &Card, base_envp: &[(String, String)], spec: &EnvSpec) -> Vec<(String, String)> {
27 let mut env: Vec<(String, String)> = std::env::vars().collect();
28
29 for (k, v) in base_envp {
30 env.retain(|(ek, _)| ek != k);
31 env.push((k.clone(), v.clone()));
32 }
33
34 if let Some(p) = &spec.bus_sock {
35 env.retain(|(k, _)| k != ENV_BUS_SOCK);
36 env.push((ENV_BUS_SOCK.into(), p.to_string_lossy().into_owned()));
37 }
38
39 env.retain(|(k, _)| k != ENV_ENTE_ID);
40 env.push((ENV_ENTE_ID.into(), card.id.to_string()));
41
42 if let Some(p) = &spec.notify_socket {
43 env.retain(|(k, _)| k != "NOTIFY_SOCKET");
44 env.push(("NOTIFY_SOCKET".into(), p.to_string_lossy().into_owned()));
45 }
46
47 for (k, v) in &spec.extra {
48 env.retain(|(ek, _)| ek != k);
49 env.push((k.clone(), v.clone()));
50 }
51
52 env
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58 use brahman_card::Card;
59
60 #[test]
61 fn env_id_and_bus_injected() {
62 let card = Card::new("test");
63 let spec = EnvSpec {
64 bus_sock: Some(PathBuf::from("/tmp/bus.sock")),
65 notify_socket: None,
66 extra: vec![],
67 };
68 let env = build_env(&card, &[], &spec);
69 assert!(env.iter().any(|(k, v)| k == ENV_ENTE_ID && v == &card.id.to_string()));
70 assert!(env.iter().any(|(k, v)| k == ENV_BUS_SOCK && v == "/tmp/bus.sock"));
71 }
72
73 #[test]
74 fn extra_overrides_inherited() {
75 let card = Card::new("test");
76 let spec = EnvSpec {
77 bus_sock: None,
78 notify_socket: None,
79 extra: vec![("PATH".into(), "/sandbox/bin".into())],
80 };
81 let env = build_env(&card, &[], &spec);
82 let path_count = env.iter().filter(|(k, _)| k == "PATH").count();
83 assert_eq!(path_count, 1);
84 assert_eq!(env.iter().find(|(k, _)| k == "PATH").unwrap().1, "/sandbox/bin");
85 }
86
87 #[test]
88 fn notify_socket_only_when_set() {
89 let card = Card::new("test");
90 let spec = EnvSpec::default();
91 let env = build_env(&card, &[], &spec);
92 assert!(!env.iter().any(|(k, _)| k == "NOTIFY_SOCKET"
93 && std::env::var("NOTIFY_SOCKET").is_err()));
94 }
95}