You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

67 lines
2.9 KiB

//! Test-only environment bootstrap.
//!
//! The main crate forbids `unsafe`, and `std::env::set_var` is `unsafe` on
//! edition 2024, so the mutation lives here. The `#[ctor]` constructor runs
//! before `main` and before any test thread exists, which is the only point
//! where the process environment can be changed race-free and the only point
//! early enough to beat the first deref of Vaultwarden's process-global
//! `CONFIG` (a `LazyLock` that reads the environment).
//!
//! Linkage is intentional: this crate only takes effect in test binaries that
//! reference it (`use test_support as _;`). Feature combos that do not compile
//! those test modules never link it and keep upstream behaviour.
/// Points every config-relevant environment variable at a per-process
/// temporary directory and enables the flags the SCIM test suite needs.
///
/// `DATABASE_URL` is deliberately left unset: Vaultwarden derives it as
/// `sqlite://{DATA_FOLDER}/db.sqlite3`, which lands inside the hermetic
/// directory, and hardcoding a sqlite URL here would poison config validation
/// for mysql/postgresql-only feature combos.
pub fn init_hermetic_env() {
let base = std::env::temp_dir().join(format!("vaultwarden-test-{}", std::process::id()));
let data = base.join("data");
std::fs::create_dir_all(&data).expect("creating hermetic test data dir");
// An empty env file: a configured-but-missing ENV_FILE makes Vaultwarden
// exit at config load, and an unset one falls back to the repo's dev .env.
let env_file = base.join("test.env");
std::fs::write(&env_file, "").expect("creating hermetic test env file");
let vars: &[(&str, String)] = &[
("ENV_FILE", env_file.to_string_lossy().into_owned()),
("DATA_FOLDER", data.to_string_lossy().into_owned()),
("DOMAIN", String::from("http://localhost:8000")),
("WEB_VAULT_ENABLED", String::from("false")),
("SIGNUPS_ALLOWED", String::from("true")),
("INVITATIONS_ALLOWED", String::from("true")),
("ORG_GROUPS_ENABLED", String::from("true")),
("SCIM_ENABLED", String::from("true")),
("SCIM_RATELIMIT_SECONDS", String::from("1")),
// High burst so the shared per-IP limiter never trips ordinary tests;
// the 429 path is exercised against a distinct synthetic IP.
("SCIM_RATELIMIT_MAX_BURST", String::from("10000")),
];
for (key, value) in vars {
// SAFETY: runs pre-main via #[ctor]; the process is single-threaded,
// so mutating the environment cannot race with any reader.
unsafe {
std::env::set_var(key, value);
}
}
// Make sure a developer shell exporting SMTP settings cannot leak mail
// sending into tests.
for key in ["SMTP_HOST", "SMTP_FROM", "USE_SENDMAIL"] {
// SAFETY: as above.
unsafe {
std::env::remove_var(key);
}
}
}
#[ctor::ctor(unsafe)]
fn hermetic_env() {
init_hermetic_env();
}