chatbot1-12 Exercise 2: A Restore Drill ========================================== ex2.py (save in the project root): # Exercise 2: a backup and restore drill. A backup you have never restored is a hope, not a backup. import os, pathlib, sqlite3, tempfile from bot.backup import backup_database from bot.crypto import ContentCipher, generate_key from bot.store import Store d = tempfile.mkdtemp() live, key = os.path.join(d, "chatbot.db"), generate_key() s = Store(live, cipher=ContentCipher([key])) for i in range(5): s.add_exchange(f"s{i}", f"question {i}", f"answer {i}") s.close() backup = backup_database(live, os.path.join(d, "backups")) print("backup made:", backup.name) os.remove(live) # the disaster print("live database exists:", os.path.exists(live)) pathlib.Path(live).write_bytes(backup.read_bytes()) # the restore (service stopped first, in real life) con = sqlite3.connect(live) print("integrity_check:", con.execute("PRAGMA integrity_check").fetchone()[0], "| messages:", con.execute("SELECT COUNT(*) FROM messages").fetchone()[0]) con.close() restored = Store(live, cipher=ContentCipher([key])) print("readable with the key:", restored.messages("s3")[0][1]["content"]) restored.close() try: wrong = Store(live, cipher=ContentCipher([generate_key()])); wrong.messages("s3") except Exception as e: print("with a different key:", type(e).__name__) Run with: py ex2.py Output: backup made: chatbot-20261010-162949.db live database exists: False integrity_check: ok | messages: 10 readable with the key: question 3 with a different key: WrongKey Notes: - In a real restore, stop the service first, copy the backup into place, then start it; do not overwrite a database that a running process has open. - The restored file is readable only with the same content key. A backup without its key is unreadable by design, so the drill is not finished until you have confirmed you can find the key. - The restore replaced the live database with the backup, so anything written after the backup was made is gone. That is the recovery point, and it is why the backup interval matters. WHY THIS WORKS AS AN ANSWER --------------------------- It performs each step you would perform in a real incident, in order, and checks each: the backup exists, the live file is gone, the restored file passes PRAGMA integrity_check, the row count is right, a message decrypts with the right key, and the wrong key fails loudly instead of returning garbage.