age-vault 0.1.0

A secure vault for managing age-encrypted accounts and data.
Documentation
//! Tests Integration

use age_vault::{Error, Result, Role, Vault};
use std::env;
use std::fs;
use uuid::Uuid;
fn temp_db_path() -> String {
    let mut dir = env::temp_dir();
    let file_name = format!("test_vault_{}.ndbx", Uuid::new_v4());
    dir.push(file_name);
    dir.to_string_lossy().into_owned()
}
struct TestVault {
    vault: Vault,
    path: String,
}
impl TestVault {
    fn new(password: &str) -> Result<Self> {
        let path = temp_db_path();
        let vault = Vault::create(&path, password)?;
        Ok(Self { vault, path })
    }
    fn open(path: &str, password: &str) -> Result<Vault> {
        Vault::open(path, password)
    }
}
impl Drop for TestVault {
    fn drop(&mut self) {
        let _ = fs::remove_file(&self.path);
    }
}
#[test]
fn create_and_open_vault_success() {
    let tv = TestVault::new("strongpassword123").expect("create vault");
    let _vault = TestVault::open(&tv.path, "strongpassword123").expect("open vault");
}
#[test]
fn create_vault_with_short_password_fails() {
    let path = temp_db_path();
    let result = Vault::create(&path, "short");
    assert!(result.is_err());
    let _ = fs::remove_file(&path);
}
#[test]
fn open_nonexistent_vault_fails() {
    let path = temp_db_path();
    let result = Vault::open(&path, "anything");
    assert!(matches!(result, Err(Error::Db(_)) | Err(Error::Io(_))));
}
#[test]
fn open_vault_with_wrong_password_fails() {
    let tv = TestVault::new("correct_password").unwrap();
    let result = Vault::open(&tv.path, "wrong_password");
    assert!(result.is_err());
}
#[test]
fn add_and_list_accounts() {
    let mut tv = TestVault::new("master123").unwrap();
    tv.vault.add_account("alice", Role::User).unwrap();
    tv.vault.add_account("bob", Role::Admin).unwrap();
    let accounts = tv.vault.list_accounts().unwrap();
    assert_eq!(accounts.len(), 2);
    let names: Vec<&str> = accounts.iter().map(|a| a.name.as_str()).collect();
    assert!(names.contains(&"alice"));
    assert!(names.contains(&"bob"));
}
#[test]
fn add_duplicate_account_fails() {
    let mut tv = TestVault::new("master123").unwrap();
    tv.vault.add_account("alice", Role::User).unwrap();
    let result = tv.vault.add_account("alice", Role::Admin);
    assert!(matches!(result, Err(Error::AccountExists(name)) if name == "alice"));
}
#[test]
fn encrypt_and_decrypt_with_account() {
    let mut tv = TestVault::new("master123").unwrap();
    tv.vault.add_account("alice", Role::User).unwrap();
    let plaintext = b"secret data for alice";
    let ciphertext = tv.vault.encrypt_for(&["alice"], plaintext).unwrap();
    let decrypted = tv.vault.decrypt_with("alice", &ciphertext).unwrap();
    assert_eq!(decrypted, plaintext);
}
#[test]
fn encrypt_for_multiple_recipients() {
    let mut tv = TestVault::new("master123").unwrap();
    tv.vault.add_account("alice", Role::User).unwrap();
    tv.vault.add_account("bob", Role::Admin).unwrap();
    let plaintext = b"multi-recipient secret";
    let ciphertext = tv.vault.encrypt_for(&["alice", "bob"], plaintext).unwrap();
    let dec_alice = tv.vault.decrypt_with("alice", &ciphertext).unwrap();
    let dec_bob = tv.vault.decrypt_with("bob", &ciphertext).unwrap();
    assert_eq!(dec_alice, plaintext);
    assert_eq!(dec_bob, plaintext);
}
#[test]
fn decrypt_with_wrong_account_fails() {
    let mut tv = TestVault::new("master123").unwrap();
    tv.vault.add_account("alice", Role::User).unwrap();
    tv.vault.add_account("eve", Role::User).unwrap();
    let ciphertext = tv.vault.encrypt_for(&["alice"], b"only alice").unwrap();
    let result = tv.vault.decrypt_with("eve", &ciphertext);
    assert!(result.is_err());
    assert!(matches!(result, Err(Error::DecryptionFailed(_))));
}
#[test]
fn encrypt_for_nonexistent_account_fails() {
    let tv = TestVault::new("master123").unwrap();
    let result = tv.vault.encrypt_for(&["ghost"], b"data");
    assert!(matches!(result, Err(Error::AccountNotFound(name)) if name == "ghost"));
}
#[test]
fn decrypt_with_nonexistent_account_fails() {
    let tv = TestVault::new("master123").unwrap();
    let ciphertext = vec![0u8; 10];
    let result = tv.vault.decrypt_with("ghost", &ciphertext);
    assert!(matches!(result, Err(Error::AccountNotFound(name)) if name == "ghost"));
}
#[test]
fn remove_account_success() {
    let mut tv = TestVault::new("master123").unwrap();
    tv.vault.add_account("alice", Role::User).unwrap();
    tv.vault.remove_account("alice").unwrap();
    let accounts = tv.vault.list_accounts().unwrap();
    assert!(accounts.is_empty());
    let result = tv.vault.encrypt_for(&["alice"], b"data");
    assert!(result.is_err());
}
#[test]
fn remove_nonexistent_account_fails() {
    let mut tv = TestVault::new("master123").unwrap();
    let result = tv.vault.remove_account("ghost");
    assert!(matches!(result, Err(Error::AccountNotFound(name)) if name == "ghost"));
}
#[test]
fn encrypt_with_empty_recipients_fails() {
    let tv = TestVault::new("master123").unwrap();
    let result = tv.vault.encrypt_for(&[], b"data");
    assert!(result.is_err());
}
#[test]
fn account_has_valid_public_key_format() {
    let mut tv = TestVault::new("master123").unwrap();
    let acc = tv.vault.add_account("alice", Role::User).unwrap();
    assert!(acc.public_key.starts_with("age1"));
    assert!(!acc.public_key.is_empty());
}
#[test]
fn account_secret_key_not_stored_in_plaintext() {
    let mut tv = TestVault::new("master123").unwrap();
    let acc = tv.vault.add_account("alice", Role::User).unwrap();
    assert!(!acc.encrypted_secret_key.is_empty());
    let enc_str = String::from_utf8_lossy(&acc.encrypted_secret_key);
    assert!(!enc_str.contains("AGE-SECRET-KEY-1"));
}