From 0218966c0dceb8b9c25a26c92eb6902faa56fbd9 Mon Sep 17 00:00:00 2001 From: furszy Date: Mon, 29 Dec 2025 14:34:09 -0500 Subject: [PATCH] test: add coverage for wallet creation in non-writable directory --- test/functional/test_framework/util.py | 10 ++++++++++ test/functional/wallet_createwallet.py | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 8e1e3c716f6..3e7e6dd97a9 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -749,3 +749,13 @@ def wallet_importprivkey(wallet_rpc, privkey, timestamp, *, label=""): }] import_res = wallet_rpc.importdescriptors(req) assert_equal(import_res[0]["success"], True) + +def is_dir_writable(dir_path: pathlib.Path) -> bool: + """Return True if we can create a file in the directory, False otherwise""" + try: + tmp = dir_path / f".tmp_{random.randrange(1 << 32)}" + tmp.touch() + tmp.unlink() + return True + except OSError: + return False diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py index 8edbbcf4b3f..bb7918a9a44 100755 --- a/test/functional/wallet_createwallet.py +++ b/test/functional/wallet_createwallet.py @@ -4,12 +4,15 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test createwallet arguments. """ +import os +import stat from test_framework.descriptors import descsum_create from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises_rpc_error, + is_dir_writable, wallet_importprivkey, ) from test_framework.wallet_util import generate_keypair, WalletUnlock @@ -25,9 +28,27 @@ class CreateWalletTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() + def test_bad_dir_permissions(self, node): + self.log.info("Test wallet creation failure due to non-writable directory") + wallet_name = "bad_permissions" + dir_path = node.wallets_path / wallet_name + dir_path.mkdir(parents=True) + original_dir_perms = dir_path.stat().st_mode + os.chmod(dir_path, original_dir_perms & ~(stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH)) + if is_dir_writable(dir_path): + self.log.warning("Skipping non-writable directory test: unable to enforce read-only permissions") + else: + # Run actual test + assert_raises_rpc_error(-4, f"SQLiteDatabase: Failed to open database in directory '{str(dir_path)}': directory is not writable", node.createwallet, wallet_name=wallet_name) + # Reset directory permissions for cleanup + dir_path.chmod(original_dir_perms) + + def run_test(self): node = self.nodes[0] + self.test_bad_dir_permissions(node) + self.log.info("Run createwallet with invalid parameters.") # Run createwallet with invalid parameters. This must not prevent a new wallet with the same name from being created with the correct parameters. assert_raises_rpc_error(-4, "Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.",