from __future__ import annotations import importlib def test_redaction_removes_nested_secret_fields_and_canaries() -> None: redaction = importlib.import_module("backup_tool.security.redaction") canary = "canary-a96f" value = { "username": "operator", "password": canary, "nested": {"token": canary, "safe": "visible"}, "items": [{"secret": canary}, canary], } result = redaction.redact(value, canaries=(canary,)) rendered = repr(result) assert canary not in rendered assert result["username"] == "operator" assert result["nested"]["safe"] == "visible" assert result["password"] == "[REDACTED]" def test_envelope_cipher_round_trips_with_purpose_binding(tmp_path) -> None: secrets = importlib.import_module("backup_tool.security.secrets") key_path = tmp_path / "master.key" key_path.write_bytes(b"x" * 32) cipher = secrets.EnvelopeCipher.from_file(key_path) ciphertext, key_id = cipher.encrypt("sensitive", purpose="ssh", version=1) assert b"sensitive" not in ciphertext assert cipher.decrypt(ciphertext, purpose="ssh", version=1) == "sensitive" assert key_id try: cipher.decrypt(ciphertext, purpose="database", version=1) except Exception as error: assert error.__class__.__name__ == "InvalidTag" else: # pragma: no cover - required safety assertion raise AssertionError("ciphertext accepted under a different purpose")