Skip to main content

secret_manager/
no_op_encryptor.rs

1use crate::encryptor::{Encrypted, EncryptorError, KeyEncryptor};
2use async_trait::async_trait;
3
4/// A passthrough [`KeyEncryptor`] that stores key bytes as-is (no encryption).
5///
6/// Intended for development, testing, or deployments where at-rest encryption
7/// is handled by the storage layer itself.
8#[derive(Clone)]
9pub struct NoOpEncryptor;
10
11#[async_trait]
12impl KeyEncryptor for NoOpEncryptor {
13    async fn encrypt(&self, plaintext: &[u8]) -> Result<Encrypted, EncryptorError> {
14        Ok(Encrypted {
15            ciphertext: plaintext.to_vec(),
16            nonce: None,
17            key_version: 0, // 0 = plaintext / no-op
18        })
19    }
20
21    async fn decrypt(&self, encrypted: &Encrypted) -> Result<Vec<u8>, EncryptorError> {
22        if encrypted.key_version != 0 {
23            return Err(EncryptorError::WrongKeyVersion(encrypted.key_version));
24        }
25        Ok(encrypted.ciphertext.clone())
26    }
27}
28
29#[cfg(test)]
30mod tests {
31    use super::*;
32
33    #[tokio::test]
34    async fn test_noop_encrypt_decrypt() {
35        let encryptor = NoOpEncryptor;
36        let plaintext = b"secret-key-material";
37
38        let encrypted = encryptor.encrypt(plaintext).await.unwrap();
39        assert_eq!(encrypted.ciphertext, plaintext);
40        assert!(encrypted.nonce.is_none());
41        assert_eq!(encrypted.key_version, 0);
42
43        let decrypted = encryptor.decrypt(&encrypted).await.unwrap();
44        assert_eq!(decrypted, plaintext);
45    }
46
47    #[tokio::test]
48    async fn test_noop_invalid_version() {
49        let encryptor = NoOpEncryptor;
50        let encrypted = Encrypted {
51            ciphertext: b"some data".to_vec(),
52            nonce: None,
53            key_version: 1,
54        };
55
56        let result = encryptor.decrypt(&encrypted).await;
57        assert!(result.is_err());
58        assert!(result.unwrap_err().to_string().contains("wrong key version"));
59    }
60}