Skip to main content

capsec_std/
env.rs

1//! Capability-gated environment variable access.
2//!
3//! Drop-in replacements for `std::env` functions that require a capability token.
4
5use capsec_core::cap::Cap;
6use capsec_core::cap_provider::CapProvider;
7use capsec_core::error::CapSecError;
8use capsec_core::permission::{EnvRead, EnvWrite};
9
10/// Reads an environment variable.
11/// Requires [`EnvRead`] permission.
12pub fn var(key: &str, cap: &impl CapProvider<EnvRead>) -> Result<String, CapSecError> {
13    let _proof: Cap<EnvRead> = cap.provide_cap(key)?;
14    Ok(std::env::var(key)?)
15}
16
17/// Returns an iterator of all environment variables.
18/// Requires [`EnvRead`] permission.
19pub fn vars(cap: &impl CapProvider<EnvRead>) -> Result<std::env::Vars, CapSecError> {
20    let _proof: Cap<EnvRead> = cap.provide_cap("*")?;
21    Ok(std::env::vars())
22}
23
24/// Sets an environment variable.
25/// Requires [`EnvWrite`] permission.
26///
27/// # Safety note
28///
29/// In Rust edition 2024, `std::env::set_var` is `unsafe` because it's not
30/// thread-safe. This wrapper encapsulates that unsafety.
31///
32/// # Thread safety
33///
34/// `std::env::set_var` is not thread-safe. Even though `Cap<EnvWrite>` can be
35/// cloned and transferred across threads via `make_send()`, calling this
36/// function concurrently from multiple threads is undefined behavior. The
37/// capability system tracks *permission*, not *exclusivity* — synchronization
38/// is the caller's responsibility.
39///
40/// # Errors
41///
42/// The underlying `std::env::set_var` is infallible (panics on failure).
43/// The `Err` path only triggers from `CapProvider` scope checks.
44pub fn set_var(
45    key: impl AsRef<std::ffi::OsStr>,
46    value: impl AsRef<std::ffi::OsStr>,
47    cap: &impl CapProvider<EnvWrite>,
48) -> Result<(), CapSecError> {
49    let _proof: Cap<EnvWrite> = cap.provide_cap(&key.as_ref().to_string_lossy())?;
50    unsafe {
51        std::env::set_var(key, value);
52    }
53    Ok(())
54}