import pytest from cryptography.fernet import Fernet from infrasynth.shared.crypto import decrypt, encrypt, generate_key, rotate_keys class TestEncryptDecrypt: def test_roundtrip(self): token = encrypt("hello-world") assert decrypt(token) == "hello-world" def test_different_plaintexts(self): for text in ["a", "hello", "data with spaces", "12345", ""]: assert decrypt(encrypt(text)) == text def test_encrypted_values_differ(self): t1 = encrypt("same") t2 = encrypt("same") assert t1 != t2 def test_decrypt_invalid_token(self): with pytest.raises(ValueError, match="Invalid Fernet token"): decrypt("invalid-token-here") def test_decrypt_garbage(self): with pytest.raises(ValueError, match="Invalid Fernet token"): decrypt("AAAA") def test_decrypt_empty_string(self): with pytest.raises(ValueError, match="Invalid Fernet token"): decrypt("") class TestGenerateKey: def test_generates_string(self): key = generate_key() assert isinstance(key, str) assert len(key) > 0 def test_keys_are_unique(self): keys = {generate_key() for _ in range(10)} assert len(keys) == 10 def test_key_is_valid_fernet_key(self): key = generate_key() Fernet(key.encode()) class TestRotateKeys: def _encrypt_with_key(self, key: str, value: str) -> str: f = Fernet(key.encode()) return f.encrypt(value.encode()).decode() def test_rotate_single_token(self): old_key = generate_key() new_key = generate_key() token = self._encrypt_with_key(old_key, "secret-value") rotated = rotate_keys(old_key, new_key, [token]) assert len(rotated) == 1 assert rotated[0] != token f = Fernet(new_key.encode()) assert f.decrypt(rotated[0].encode()).decode() == "secret-value" def test_rotate_multiple_tokens(self): old_key = generate_key() new_key = generate_key() values = [f"value-{i}" for i in range(5)] tokens = [self._encrypt_with_key(old_key, v) for v in values] rotated = rotate_keys(old_key, new_key, tokens) assert len(rotated) == 5 f = Fernet(new_key.encode()) for plaintext, cipher in zip(values, rotated): assert f.decrypt(cipher.encode()).decode() == plaintext def test_rotate_with_same_key(self): key = generate_key() token = self._encrypt_with_key(key, "persistent") rotated = rotate_keys(key, key, [token]) assert len(rotated) == 1 assert rotated[0] != token f = Fernet(key.encode()) assert f.decrypt(rotated[0].encode()).decode() == "persistent" def test_rotate_preserves_all_values(self): old_key = generate_key() new_key = generate_key() values = ["keep-me-safe", "another-value", "123"] tokens = [self._encrypt_with_key(old_key, v) for v in values] rotated = rotate_keys(old_key, new_key, tokens) f = Fernet(new_key.encode()) for original, cipher in zip(values, rotated): assert f.decrypt(cipher.encode()).decode() == original