envseal 0.3.11

Write-only secret vault with process-level access control — post-agent secret management
Documentation
//! Runtime guard for the `test-backdoors` cargo feature (audit M21).
//!
//! `MasterKey::from_test_bytes` and `Vault::open_with_key` exist so
//! integration tests in `core/tests/` and `cargo-fuzz` targets can
//! drive the vault without going through the real passphrase / GUI /
//! authenticator stack. They are gated behind the `test-backdoors`
//! cargo feature, which is only enabled via the dev-dependency alias
//! in `core/Cargo.toml`.
//!
//! That feature gate is *not* sufficient on its own: a downstream
//! consumer (or a compromised build script in a transitive
//! dependency) could enable `test-backdoors` and ship a release
//! `envseal-cli` whose `Vault::open_with_key` exposes the entire
//! vault to passphrase-less unlock. The audit's recommendation was to
//! "move test-only constructors into a separate unpublished
//! `envseal-test-helpers` crate, *or* guard with `#[cfg(test)]` only".
//!
//! `#[cfg(test)]` alone does not work — integration tests link
//! against the lib compiled *without* `cfg(test)`, so the symbols
//! would be invisible. Extracting to a separate crate forces every
//! caller through a `pub` API on `envseal` proper, which is exactly
//! the surface we are trying to keep closed.
//!
//! This module is the third option: keep the feature, but **abort
//! the process** if the test-only constructors are reached outside a
//! recognized test / fuzz / bench harness. Cargo sets a number of
//! environment variables when it runs tests, fuzz targets, or
//! benchmarks — none of which are set in a `cargo install`-produced
//! binary that an end user runs. We use that as a "this is not a
//! production binary" signal. A loud `std::process::abort` is the
//! correct response: a malicious actor flipping the feature in their
//! supply chain gets a hard-fail at runtime, not silent unlock.
//!
//! Operators who legitimately need to run a binary built with
//! `--features test-backdoors` outside a Cargo harness (e.g. a
//! property-test runner that drives the compiled binary) can opt in
//! explicitly with `ENVSEAL_TEST_BACKDOORS_OK=1`. That env var is
//! deliberately verbose — anyone who sets it has acknowledged in
//! writing that the binary they are running is a test backdoor build.

#![cfg(any(test, feature = "test-backdoors"))]

use std::sync::atomic::{AtomicBool, Ordering};

/// Cached result of the env-probe so the first call pays the cost
/// and subsequent calls in a hot-path test are free. Reset path
/// not provided — the answer cannot change for a given process.
static SAFETY_DECIDED: AtomicBool = AtomicBool::new(false);
static SAFETY_OK: AtomicBool = AtomicBool::new(false);

/// Aborts the process with a security-focused message if the test
/// backdoors are reached from outside a recognized harness.
///
/// Called from the bodies of [`crate::vault::keychain::MasterKey::from_test_bytes`]
/// and [`crate::vault::Vault::open_with_key`] before any work happens.
pub fn assert_test_backdoor_safe() {
    if SAFETY_DECIDED.load(Ordering::Acquire) {
        if SAFETY_OK.load(Ordering::Acquire) {
            return;
        }
        // Re-fail in case a previous call survived past the abort
        // (shouldn't happen but defense in depth).
        abort_with_message();
    }

    let ok = is_recognized_test_environment();
    SAFETY_OK.store(ok, Ordering::Release);
    SAFETY_DECIDED.store(true, Ordering::Release);
    if !ok {
        abort_with_message();
    }
}

/// Probes the process environment for any signal that we are running
/// under a Cargo test / fuzz / bench harness. None of these env vars
/// are set in a user-installed `envseal` binary.
fn is_recognized_test_environment() -> bool {
    // Explicit operator opt-in. Verbose name so it is hard to set
    // accidentally and easy to grep for in audit logs.
    if std::env::var_os("ENVSEAL_TEST_BACKDOORS_OK").is_some() {
        return true;
    }

    // Cargo sets these for `cargo test` and `cargo bench`. They are
    // set both when integration tests are *running* and inside the
    // unit-test binary `cfg!(test)` body.
    for marker in [
        "CARGO_TARGET_TMPDIR",  // set per-package during cargo test
        "INSTA_WORKSPACE_ROOT", // set by the insta snapshot harness
        "CARGO_MANIFEST_DIR",   // set during build/test of the lib
    ] {
        if std::env::var_os(marker).is_some() {
            return true;
        }
    }

    // cargo-fuzz sets these.
    if std::env::var_os("CARGO_FUZZ_TARGET").is_some() || std::env::var_os("FUZZ_TARGET").is_some()
    {
        return true;
    }

    // Final fallback: if our own binary is named "*-runner" or
    // "*-test-*" we're probably the test harness — be permissive
    // here because false negatives (refuse the test) are worse than
    // false positives (allow a binary that "looks like" a test).
    if let Some(arg0) = std::env::args_os().next() {
        if let Some(s) = arg0.to_str() {
            let lower = s.to_ascii_lowercase();
            if lower.contains("test")
                || lower.contains("bench")
                || lower.contains("fuzz")
                || lower.ends_with("-runner")
            {
                return true;
            }
        }
    }

    false
}

fn abort_with_message() -> ! {
    eprintln!(
        "envseal: SECURITY ABORT — `test-backdoors` feature reached \
         from outside a recognized Cargo test / fuzz / bench harness.\n\
         This binary was compiled with `--features test-backdoors`, which \
         exposes Vault::open_with_key and MasterKey::from_test_bytes — \
         constructors that bypass the passphrase, hardware seal, and \
         FIDO2 layers. They must NEVER be reachable in a production \
         binary.\n\n\
         If you are an operator who genuinely needs this functionality \
         (e.g. for property-based testing of the compiled binary), set \
         ENVSEAL_TEST_BACKDOORS_OK=1 in the environment of the test \
         harness. Otherwise this is a build-supply-chain incident; \
         rebuild from a known-clean source and audit which dependency \
         turned the feature on.\n\n\
         Aborting."
    );
    std::process::abort();
}