fusabi_stdlib_ext/
env.rs

1//! Environment module.
2//!
3//! Provides functions for environment variable access with safety controls.
4
5use std::sync::Arc;
6
7use fusabi_host::ExecutionContext;
8use fusabi_host::Value;
9
10use crate::safety::SafetyConfig;
11
12/// Get an environment variable.
13pub fn get(
14    safety: &Arc<SafetyConfig>,
15    args: &[Value],
16    _ctx: &ExecutionContext,
17) -> fusabi_host::Result<Value> {
18    let name = args
19        .first()
20        .and_then(|v| v.as_str())
21        .ok_or_else(|| fusabi_host::Error::host_function("env.get: missing name argument"))?;
22
23    // Check safety
24    safety.check_env(name).map_err(|e| {
25        fusabi_host::Error::host_function(e.to_string())
26    })?;
27
28    match std::env::var(name) {
29        Ok(value) => Ok(Value::String(value)),
30        Err(_) => Ok(Value::Null),
31    }
32}
33
34/// Set an environment variable.
35pub fn set(
36    safety: &Arc<SafetyConfig>,
37    args: &[Value],
38    _ctx: &ExecutionContext,
39) -> fusabi_host::Result<Value> {
40    let name = args
41        .first()
42        .and_then(|v| v.as_str())
43        .ok_or_else(|| fusabi_host::Error::host_function("env.set: missing name argument"))?;
44
45    let value = args
46        .get(1)
47        .and_then(|v| v.as_str())
48        .ok_or_else(|| fusabi_host::Error::host_function("env.set: missing value argument"))?;
49
50    // Check safety
51    safety.check_env(name).map_err(|e| {
52        fusabi_host::Error::host_function(e.to_string())
53    })?;
54
55    std::env::set_var(name, value);
56    Ok(Value::Null)
57}
58
59/// Get the current working directory.
60pub fn cwd(
61    _args: &[Value],
62    _ctx: &ExecutionContext,
63) -> fusabi_host::Result<Value> {
64    match std::env::current_dir() {
65        Ok(path) => Ok(Value::String(path.to_string_lossy().into_owned())),
66        Err(e) => Err(fusabi_host::Error::host_function(format!("env.cwd: {}", e))),
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73    use fusabi_host::Capabilities;
74    use fusabi_host::{Sandbox, SandboxConfig};
75    use fusabi_host::Limits;
76
77    fn create_test_ctx() -> ExecutionContext {
78        let sandbox = Sandbox::new(SandboxConfig::default()).unwrap();
79        ExecutionContext::new(1, Capabilities::none(), Limits::default(), sandbox)
80    }
81
82    #[test]
83    fn test_get_safety_check() {
84        let safety = Arc::new(SafetyConfig::strict());
85        let ctx = create_test_ctx();
86
87        let result = get(&safety, &[Value::String("PATH".into())], &ctx);
88        assert!(result.is_err()); // Should fail - env not allowed
89    }
90
91    #[test]
92    fn test_get_with_permission() {
93        let safety = Arc::new(SafetyConfig::new().with_env_vars(["PATH"]));
94        let ctx = create_test_ctx();
95
96        let result = get(&safety, &[Value::String("PATH".into())], &ctx);
97        assert!(result.is_ok());
98    }
99
100    #[test]
101    fn test_cwd() {
102        let ctx = create_test_ctx();
103        let result = cwd(&[], &ctx);
104        assert!(result.is_ok());
105        assert!(result.unwrap().as_str().is_some());
106    }
107}