test: add coverage for wallet creation in non-writable directory
What changed, and why it matters
This commit only adds a new automated test that checks Bitcoin Core correctly refuses to create a wallet in a directory without write permission. It does not change the wallet-creation logic itself, so it does not fix or introduce a security issue in the software.
No action required; treat as routine test-coverage improvement.
Security signals we found
test-only change
no production code modified
asserts expected error on non-writable directory
Evidence from the diff
The diff adds a helper is_dir_writable() and a functional test test_bad_dir_permissions() that creates a read-only wallet directory, verifies createwallet fails with the expected SQLite error, and restores permissions. The production code path is unchanged; this is purely regression-test coverage for an existing error-handling behavior.
Changed components
test/functional/wallet_createwallet.pytest/functional/test_framework/util.pyInspect captured patch +31 / −0
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 8e1e3c71..3e7e6dd9 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 8edbbcf4..bb7918a9 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.",
Why this scored 14/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.