envseal 0.3.5

Write-only secret vault with process-level access control — post-agent secret management
Documentation
//! Shared test helpers for envseal.
#![allow(dead_code)]

use envseal::vault::Vault;
use std::path::Path;
#[cfg(unix)]
use std::path::PathBuf;

/// Temporary directory usable as a vault root (not under `/tmp`).
///
/// [`Vault::open`] and [`Vault::open_with_passphrase`] reject world-writable and
/// `/tmp`-family paths on Unix; tests must use a user-owned directory.
///
/// On Unix we put the tempdir under `~/.cache/envseal-core-tests/`. On
/// Windows the OS-default `tempfile::tempdir()` (`%LOCALAPPDATA%\Temp`)
/// is already user-owned and not blocked, so we use it directly — using
/// a single shared base directory under `~/.cache/` produced flaky
/// `NotFound` errors on Windows when many tempdirs were being created
/// and dropped concurrently in the same parent.
pub fn vault_tempdir() -> tempfile::TempDir {
    #[cfg(unix)]
    {
        let home = std::env::var_os("HOME")
            .expect("tests require HOME to be set (vault-safe temp directories)");
        let base = PathBuf::from(home)
            .join(".cache")
            .join("envseal-core-tests");
        std::fs::create_dir_all(&base).expect("create ~/.cache/envseal-core-tests");
        tempfile::tempdir_in(&base).expect("tempdir_in vault-safe base")
    }
    #[cfg(not(unix))]
    {
        tempfile::tempdir().expect("create OS-provided tempdir")
    }
}

/// Standard deterministic passphrase used across tests.
pub fn test_passphrase() -> zeroize::Zeroizing<String> {
    zeroize::Zeroizing::new("envseal-integration-test-passphrase".to_string())
}

/// Alternative deterministic passphrase for cross-vault / cross-key tests.
pub fn test_passphrase_alt() -> zeroize::Zeroizing<String> {
    zeroize::Zeroizing::new("envseal-integration-test-passphrase-alt".to_string())
}

/// Fixed 32-byte key material for policy HMAC tests.
pub const TEST_KEY_BYTES: [u8; 32] = [
    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
    0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
];

/// Alternative fixed 32-byte key material.
pub const TEST_KEY_BYTES_ALT: [u8; 32] = [0xFF; 32];

/// Create a temporary vault with a deterministic passphrase (no GUI).
/// Returns the temp dir handle (must be kept alive) and the vault.
pub fn temp_vault() -> (tempfile::TempDir, Vault) {
    let dir = vault_tempdir();
    let passphrase = test_passphrase();
    let vault = Vault::open_with_passphrase(dir.path(), &passphrase).unwrap();
    (dir, vault)
}

/// Write a temporary file with the given content and return the temp file
/// handle and its path.
pub fn temp_file(content: &str) -> (tempfile::NamedTempFile, std::path::PathBuf) {
    use std::io::Write;
    let mut file = tempfile::NamedTempFile::new().unwrap();
    file.write_all(content.as_bytes()).unwrap();
    let path = file.path().to_path_buf();
    (file, path)
}

/// Get the path to a secret file on disk for direct manipulation in tests.
pub fn secret_file_path(vault_root: &Path, name: &str) -> std::path::PathBuf {
    vault_root.join("vault").join(format!("{name}.seal"))
}

/// Construct a deterministic [`MasterKey`] for tests that need one
/// without going through the passphrase / Argon2 path. Backed by
/// [`TEST_KEY_BYTES`].
pub fn test_key() -> envseal::keychain::MasterKey {
    envseal::keychain::MasterKey::from_test_bytes(TEST_KEY_BYTES)
}

/// Alternative deterministic [`MasterKey`] for cross-vault tests.
/// Backed by [`TEST_KEY_BYTES_ALT`].
pub fn test_key_alt() -> envseal::keychain::MasterKey {
    envseal::keychain::MasterKey::from_test_bytes(TEST_KEY_BYTES_ALT)
}