Rename the crate from alknet-vault to alkvault across source and docs: - Cargo.toml: package name and lib name (alknet_vault -> alkvault) - src/ doc comments and doc-test use statements - tests/ use statements and one string literal Convert references to non-vault alknet ADRs (003, 005, 008, 010, 014, 064) that were broken local links into @alkdev/alknet: cross-repo references, matching the alktype sibling pattern. Local ADR/OQ references are now proper links. Rewrote monorepo path references (crates/alknet-vault/src/...) to the flat layout (src/...). Fixed sdd_process.md package name (@alkdev/storage -> @alkdev/alkvault). ADR/OQ renumbering is deferred to a subsequent pass per the alknet- origin numbering convention. Generic prose 'vault' and type names (VaultServiceHandle, VaultServiceError, etc.) are unchanged. Build, 108 tests, and clippy all pass clean.
99 lines
2.8 KiB
Rust
99 lines
2.8 KiB
Rust
//! Integration tests for the VaultService lifecycle.
|
|
//!
|
|
//! These tests verify the unlock/lock lifecycle, error conditions,
|
|
//! and that the vault correctly manages state transitions.
|
|
|
|
use alkvault::derivation::PATHS;
|
|
use alkvault::service::{VaultServiceError, VaultServiceHandle};
|
|
|
|
#[test]
|
|
fn test_full_lifecycle() {
|
|
let service = VaultServiceHandle::new();
|
|
|
|
// Starts locked
|
|
assert!(!service.is_unlocked());
|
|
|
|
// Can't derive while locked
|
|
let result = service.derive_ed25519(PATHS::IDENTITY);
|
|
assert!(matches!(result, Err(VaultServiceError::VaultLocked)));
|
|
|
|
// Unlock
|
|
let phrase = service.unlock_new(24).unwrap();
|
|
assert!(service.is_unlocked());
|
|
assert!(!phrase.is_empty());
|
|
|
|
// Can derive while unlocked
|
|
let key = service.derive_ed25519(PATHS::IDENTITY).unwrap();
|
|
assert!(!key.private_key.is_empty());
|
|
|
|
// Lock
|
|
service.lock();
|
|
assert!(!service.is_unlocked());
|
|
|
|
// Can't derive again
|
|
let result = service.derive_ed25519(PATHS::IDENTITY);
|
|
assert!(matches!(result, Err(VaultServiceError::VaultLocked)));
|
|
}
|
|
|
|
#[test]
|
|
fn test_unlock_with_known_phrase() {
|
|
let service = VaultServiceHandle::new();
|
|
|
|
// Generate a phrase
|
|
let phrase = service.unlock_new(24).unwrap();
|
|
service.lock();
|
|
|
|
// Re-unlock with the same phrase
|
|
service.unlock(&phrase, None).unwrap();
|
|
assert!(service.is_unlocked());
|
|
|
|
// Different passphrase produces different seed
|
|
// (tested by deriving keys with different passphrases)
|
|
}
|
|
|
|
#[test]
|
|
fn test_double_unlock_fails() {
|
|
let service = VaultServiceHandle::new();
|
|
service.unlock_new(24).unwrap();
|
|
|
|
let result = service.unlock_new(12);
|
|
assert!(matches!(result, Err(VaultServiceError::AlreadyUnlocked)));
|
|
}
|
|
|
|
#[test]
|
|
fn test_lock_when_already_locked_is_noop() {
|
|
let service = VaultServiceHandle::new();
|
|
assert!(!service.is_unlocked());
|
|
|
|
// Lock on already-locked service is a no-op
|
|
service.lock();
|
|
assert!(!service.is_unlocked());
|
|
}
|
|
|
|
#[test]
|
|
fn test_encrypt_decrypt_lifecycle() {
|
|
let service = VaultServiceHandle::new();
|
|
service.unlock_new(24).unwrap();
|
|
|
|
let plaintext = "my-api-key-12345";
|
|
let encrypted = service.encrypt(plaintext, 2).unwrap();
|
|
let decrypted = service.decrypt(&encrypted).unwrap();
|
|
assert_eq!(decrypted, plaintext);
|
|
|
|
// After lock, can't decrypt
|
|
service.lock();
|
|
let result = service.decrypt(&encrypted);
|
|
assert!(matches!(result, Err(VaultServiceError::VaultLocked)));
|
|
}
|
|
|
|
#[test]
|
|
fn test_multiple_derive_paths_succeed() {
|
|
let service = VaultServiceHandle::new();
|
|
service.unlock_new(24).unwrap();
|
|
|
|
// All standard paths should work
|
|
let _identity = service.derive_ed25519(PATHS::IDENTITY).unwrap();
|
|
let _ssh = service.derive_ed25519(PATHS::SSH_HOST).unwrap();
|
|
let _enc = service.derive_encryption_key(PATHS::ENCRYPTION).unwrap();
|
|
}
|