Skip to main content

evault_core/traits/
process_runner.rs

1//! [`ProcessRunner`] — execute a child process with a custom environment.
2
3use std::collections::BTreeMap;
4use std::path::Path;
5
6use crate::error::RunnerError;
7
8/// Result of running a child process.
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct ProcessOutcome {
11    /// Exit status reported by the OS. `None` if the process was terminated
12    /// by a signal (Unix).
13    pub exit_code: Option<i32>,
14}
15
16impl ProcessOutcome {
17    /// Returns `true` when the process exited normally with code `0`.
18    #[must_use]
19    pub const fn is_success(&self) -> bool {
20        matches!(self.exit_code, Some(0))
21    }
22}
23
24/// Spawn a child process with an injected environment.
25///
26/// The intent is `evault run --project X -- npm start`: the runner takes the
27/// resolved environment, spawns `npm start`, waits for it to exit, and
28/// propagates the exit code. The environment is **not** materialized to disk.
29pub trait ProcessRunner: Send + Sync {
30    /// Run `program` with the given `args`, working directory `cwd`, and an
31    /// extra environment overlay `env`.
32    ///
33    /// The overlay is **added to** (not replacing) the parent process's
34    /// environment so that `PATH` and similar variables remain available to
35    /// the child. Keys in `env` override identically-named keys from the
36    /// parent.
37    ///
38    /// **Implementors MUST** strip variables matching the `EVAULT_*` prefix
39    /// from the parent environment before applying the overlay, so that
40    /// internal runtime configuration (master key paths, telemetry knobs)
41    /// does not leak into untrusted child processes.
42    ///
43    /// **Implementors MUST** validate every supplied key (same shape as a
44    /// variable name) and reject values containing a NUL byte before
45    /// touching `std::process::Command` — a NUL would terminate the OS
46    /// environment block early and is non-recoverable.
47    ///
48    /// # Errors
49    /// Returns [`RunnerError::Invalid`] when the env overlay contains a
50    /// malformed key or a value with a NUL byte;
51    /// [`RunnerError::Spawn`] if the process could not start;
52    /// [`RunnerError::Io`] for IO failure during execution.
53    fn run(
54        &self,
55        program: &str,
56        args: &[String],
57        cwd: &Path,
58        env: &BTreeMap<String, String>,
59    ) -> Result<ProcessOutcome, RunnerError>;
60}