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::has::Has;
7use capsec_core::permission::{EnvRead, EnvWrite};
8
9/// Reads an environment variable.
10/// Requires [`EnvRead`] permission.
11pub fn var(key: &str, cap: &impl Has<EnvRead>) -> Result<String, std::env::VarError> {
12    let _proof: Cap<EnvRead> = cap.cap_ref();
13    std::env::var(key)
14}
15
16/// Returns an iterator of all environment variables.
17/// Requires [`EnvRead`] permission.
18pub fn vars(cap: &impl Has<EnvRead>) -> std::env::Vars {
19    let _proof: Cap<EnvRead> = cap.cap_ref();
20    std::env::vars()
21}
22
23/// Sets an environment variable.
24/// Requires [`EnvWrite`] permission.
25///
26/// # Safety note
27///
28/// In Rust edition 2024, `std::env::set_var` is `unsafe` because it's not
29/// thread-safe. This wrapper encapsulates that unsafety.
30///
31/// # Thread safety
32///
33/// `std::env::set_var` is not thread-safe. Even though `Cap<EnvWrite>` can be
34/// cloned and transferred across threads via `make_send()`, calling this
35/// function concurrently from multiple threads is undefined behavior. The
36/// capability system tracks *permission*, not *exclusivity* — synchronization
37/// is the caller's responsibility.
38pub fn set_var(
39    key: impl AsRef<std::ffi::OsStr>,
40    value: impl AsRef<std::ffi::OsStr>,
41    cap: &impl Has<EnvWrite>,
42) {
43    let _proof: Cap<EnvWrite> = cap.cap_ref();
44    unsafe {
45        std::env::set_var(key, value);
46    }
47}