mirror of
https://github.com/kevinveenbirkenbach/docker-volume-backup.git
synced 2026-11-05 18:57:42 +00:00
MariaDB dumps and restores read the password from MYSQL_PWD, and docker exec forwards env variables by name only, so no process listing shows a password. baudolo-restore gains --db-password-stdin; --db-password still works but warns. 🎯 Fix: 96 % 💥 Break: 3 % 💸 Cost: – ⏱️ Time: – 🛡️ Security: ~100 % 🏆 Score: 93 🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 % Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
66 lines
2.0 KiB
Python
66 lines
2.0 KiB
Python
import contextlib
|
|
import io
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from baudolo.restore import __main__ as cli
|
|
|
|
BASE = [
|
|
"postgres",
|
|
"app_vol",
|
|
"hash",
|
|
"20260817000000",
|
|
"--repo-name",
|
|
"repo",
|
|
"--container",
|
|
"db",
|
|
"--db-name",
|
|
"app",
|
|
]
|
|
|
|
|
|
class TestRestorePasswordChannel(unittest.TestCase):
|
|
def call(self, extra, stdin=""):
|
|
stderr = io.StringIO()
|
|
with (
|
|
patch.object(cli, "restore_postgres_sql") as restore,
|
|
patch("sys.stdin", io.StringIO(stdin)),
|
|
contextlib.redirect_stderr(stderr),
|
|
):
|
|
code = cli.main([*BASE, *extra])
|
|
return code, restore, stderr.getvalue()
|
|
|
|
def test_stdin_carries_the_password_without_its_newline(self):
|
|
code, restore, stderr = self.call(["--db-password-stdin"], stdin="s3cret\n")
|
|
self.assertEqual(code, 0)
|
|
self.assertEqual(restore.call_args.kwargs["password"], "s3cret")
|
|
self.assertNotIn("WARNING", stderr)
|
|
|
|
def test_the_argument_still_works_but_warns(self):
|
|
code, restore, stderr = self.call(["--db-password", "s3cret"])
|
|
self.assertEqual(code, 0)
|
|
self.assertEqual(restore.call_args.kwargs["password"], "s3cret")
|
|
self.assertIn("visible in the process list", stderr)
|
|
|
|
def test_both_ways_is_a_usage_error(self):
|
|
with self.assertRaises(SystemExit) as caught:
|
|
self.call(["--db-password", "x", "--db-password-stdin"], stdin="y")
|
|
self.assertEqual(caught.exception.code, 2)
|
|
|
|
def test_neither_way_is_a_usage_error(self):
|
|
with self.assertRaises(SystemExit) as caught:
|
|
self.call([])
|
|
self.assertEqual(caught.exception.code, 2)
|
|
|
|
def test_files_needs_no_password(self):
|
|
with patch.object(cli, "restore_volume_files", return_value=0) as restore:
|
|
code = cli.main(
|
|
["files", "app_vol", "hash", "20260817000000", "--repo-name", "repo"]
|
|
)
|
|
self.assertEqual(code, 0)
|
|
restore.assert_called_once()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|