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}