From 85d25458922c2341400bb3704df1cf3b981a23a4 Mon Sep 17 00:00:00 2001 From: Anish Pallati Date: Mon, 4 May 2026 03:24:28 -0400 Subject: [PATCH 1/2] feat: add devenv.preFlight for pre-init env injection --- devenv/src/devenv/mod.rs | 2 + devenv/src/devenv/preflight.rs | 70 ++++++++++++++++++++++++++++++++++ src/modules/top-level.nix | 27 +++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 devenv/src/devenv/preflight.rs diff --git a/devenv/src/devenv/mod.rs b/devenv/src/devenv/mod.rs index e99a4e503..43a145890 100644 --- a/devenv/src/devenv/mod.rs +++ b/devenv/src/devenv/mod.rs @@ -1,6 +1,7 @@ mod cachix; mod container; mod gc; +mod preflight; mod search; use super::{processes, tasks, util}; @@ -663,6 +664,7 @@ impl Devenv { let Some(cnix) = self.cnix() else { return Ok(None); }; + preflight::run(cnix).await?; cachix::CachixIntegration::init( cnix, &self.cachix_manager, diff --git a/devenv/src/devenv/preflight.rs b/devenv/src/devenv/preflight.rs new file mode 100644 index 000000000..8e1e62b7f --- /dev/null +++ b/devenv/src/devenv/preflight.rs @@ -0,0 +1,70 @@ +//! Pre-flight commands. +//! +//! Runs user-defined commands during devenv startup, before subsystems +//! that read `env::var()` (cachix, substituter netrc, …) initialize. +//! Stdout in `KEY=value` form is merged into the process environment. + +use std::collections::BTreeMap; + +use devenv_activity::{Activity, ActivityLevel, start}; +use devenv_nix_backend::NixCBackend; +use miette::{IntoDiagnostic, Result, WrapErr}; +use tracing::{debug, warn}; + +#[derive(serde::Deserialize)] +struct PreFlight { + command: String, +} + +pub async fn run(cnix: &NixCBackend) -> Result<()> { + let activity = + start!(Activity::evaluate("Reading config.devenv.preFlight").level(ActivityLevel::Debug)); + let json = match cnix.eval_attr("config.devenv.preFlight", &activity).await { + Ok(j) => j, + Err(_) => return Ok(()), + }; + let entries: BTreeMap = serde_json::from_str(&json) + .into_diagnostic() + .wrap_err("Failed to deserialize config.devenv.preFlight")?; + + if entries.is_empty() { + return Ok(()); + } + + for (name, pf) in &entries { + debug!(name = %name, "running preFlight command"); + let output = tokio::process::Command::new("sh") + .arg("-c") + .arg(&pf.command) + .output() + .await + .into_diagnostic() + .wrap_err_with(|| format!("preFlight `{name}` failed to spawn"))?; + + if !output.status.success() { + warn!( + name = %name, + status = %output.status, + stderr = %String::from_utf8_lossy(&output.stderr).trim(), + "preFlight command failed", + ); + continue; + } + + for line in String::from_utf8_lossy(&output.stdout).lines() { + let Some((key, val)) = line.split_once('=') else { + continue; + }; + let key = key.trim(); + let val = val.trim(); + if key.is_empty() { + continue; + } + // SAFETY: pre-flight runs before subsystems that read env::var(). + // The point of this hook is to mutate process env. + unsafe { std::env::set_var(key, val) }; + } + } + + Ok(()) +} diff --git a/src/modules/top-level.nix b/src/modules/top-level.nix index 0faacf8f1..7e0de365c 100644 --- a/src/modules/top-level.nix +++ b/src/modules/top-level.nix @@ -225,6 +225,33 @@ in }; devenv = { + preFlight = lib.mkOption { + type = types.attrsOf (types.submodule { + options.command = lib.mkOption { + type = types.str; + description = '' + Shell command run during devenv startup, before its internal + subsystems (cachix, substituter netrc, etc.) initialize. + Lines of `KEY=value` written to stdout are merged into + devenv's process environment and become visible to those + subsystems. + ''; + }; + }); + default = { }; + description = '' + Pre-flight commands run during devenv startup, before its + internal subsystems initialize. Useful for fetching tokens or + other values that devenv-core itself reads from the environment + early. Commands run in dependency-key alphabetical order. + ''; + example = lib.literalExpression '' + { + cachix-auth.command = "echo CACHIX_AUTH_TOKEN=$(get-token-somehow)"; + } + ''; + }; + root = lib.mkOption { type = types.str; internal = true; From 1492bdcda50aad9e814dd98b000dd69366885c08 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 07:26:59 +0000 Subject: [PATCH 2/2] Auto generate docs/src/reference/options.md --- docs/src/reference/options.md | 66 ++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/docs/src/reference/options.md b/docs/src/reference/options.md index 73837561d..b2eb260c1 100644 --- a/docs/src/reference/options.md +++ b/docs/src/reference/options.md @@ -3585,6 +3585,64 @@ string +## devenv.preFlight + + + +Pre-flight commands run during devenv startup, before its +internal subsystems initialize. Useful for fetching tokens or +other values that devenv-core itself reads from the environment +early. Commands run in dependency-key alphabetical order. + + + +*Type:* +attribute set of (submodule) + + + +*Default:* + +```nix +{ } +``` + + + +*Example:* + +```nix +{ + cachix-auth.command = "echo CACHIX_AUTH_TOKEN=$(get-token-somehow)"; +} + +``` + +*Declared by:* + - [https://github.com/cachix/devenv/blob/main/src/modules/top-level.nix](https://github.com/cachix/devenv/blob/main/src/modules/top-level.nix) + + + +## devenv.preFlight.\.command + + + +Shell command run during devenv startup, before its internal +subsystems (cachix, substituter netrc, etc.) initialize. +Lines of ` KEY=value ` written to stdout are merged into +devenv’s process environment and become visible to those +subsystems. + + + +*Type:* +string + +*Declared by:* + - [https://github.com/cachix/devenv/blob/main/src/modules/top-level.nix](https://github.com/cachix/devenv/blob/main/src/modules/top-level.nix) + + + ## devenv.warnOnNewVersion @@ -5971,8 +6029,6 @@ submodule ## git-hooks.hooks.biome.enable - - Whether to enable this pre-commit hook. @@ -6031,6 +6087,8 @@ null or string or absolute path ## git-hooks.hooks.biome.settings.configPath + + Path to the configuration JSON file @@ -8244,8 +8302,6 @@ false ## git-hooks.hooks.isort.settings.flags - - Flags passed to isort. See all available [here](https://pycqa.github.io/isort/docs/configuration/options.html). @@ -8292,6 +8348,8 @@ one of “”, “black”, “django”, “pycharm”, “google”, “open_s ## git-hooks.hooks.lacheck + + lacheck hook