From e02f62f961f2b9ea5919cc93ed144b3822ea43a8 Mon Sep 17 00:00:00 2001 From: adlee-was-taken Date: Mon, 27 Apr 2026 22:42:44 -0400 Subject: [PATCH] test(core): backup error paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Covers bad magic, unsupported version, wrong passphrase, truncation, and tampered ciphertext. The wrong-passphrase / tampered-tag pair both collapse to RelicarioError::Decrypt — same opaque-failure contract as the live vault. --- crates/relicario-core/tests/backup.rs | 57 ++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/crates/relicario-core/tests/backup.rs b/crates/relicario-core/tests/backup.rs index 449d127..1ca3ec6 100644 --- a/crates/relicario-core/tests/backup.rs +++ b/crates/relicario-core/tests/backup.rs @@ -1,6 +1,6 @@ //! Backup container round-trip + error-path coverage. -use relicario_core::backup::{pack_backup, unpack_backup, BackupInput, BackupOutput}; +use relicario_core::backup::{pack_backup, unpack_backup, BackupInput}; fn empty_input() -> BackupInput<'static> { BackupInput { @@ -131,3 +131,58 @@ fn no_history_produces_strict_subset() { with.len(), without.len() ); } + +use relicario_core::RelicarioError; + +#[test] +fn bad_magic_rejected() { + let mut bytes = pack_backup(empty_input(), "p").unwrap(); + bytes[0] = b'X'; + match unpack_backup(&bytes, "p") { + Err(RelicarioError::BackupBadMagic) => {} + other => panic!("expected BackupBadMagic, got {other:?}"), + } +} + +#[test] +fn unsupported_version_rejected() { + let mut bytes = pack_backup(empty_input(), "p").unwrap(); + bytes[4] = 0xFF; + match unpack_backup(&bytes, "p") { + Err(RelicarioError::BackupUnsupportedVersion { found, expected }) => { + assert_eq!(found, 0xFF); + assert_eq!(expected, 0x01); + } + other => panic!("expected BackupUnsupportedVersion, got {other:?}"), + } +} + +#[test] +fn wrong_passphrase_rejected_as_decrypt_error() { + let bytes = pack_backup(empty_input(), "right-passphrase").unwrap(); + match unpack_backup(&bytes, "wrong-passphrase") { + Err(RelicarioError::Decrypt) => {} + other => panic!("expected Decrypt (opaque), got {other:?}"), + } +} + +#[test] +fn truncated_file_rejected() { + let bytes = pack_backup(empty_input(), "p").unwrap(); + let truncated = &bytes[..bytes.len().min(60)]; // shorter than HEADER_LEN + TAG_LEN + match unpack_backup(truncated, "p") { + Err(RelicarioError::Format(_)) => {} + other => panic!("expected Format(truncated), got {other:?}"), + } +} + +#[test] +fn tampered_ciphertext_rejected_as_decrypt_error() { + let mut bytes = pack_backup(empty_input(), "p").unwrap(); + let last = bytes.len() - 1; + bytes[last] ^= 0xFF; // flip a byte in the auth-tag region + match unpack_backup(&bytes, "p") { + Err(RelicarioError::Decrypt) => {} + other => panic!("expected Decrypt for tampered tag, got {other:?}"), + } +}