fix(database): add parent directory validation before database creation (#1161)

- Add work directory creation check in cdk-cli main
- Add parent directory existence validation in cdk-redb wallet database
- Add parent directory check in cdk-sqlite connection manager
- Add IO error variant to cdk-redb error types for better error handling
This commit is contained in:
tsk
2025-10-07 15:19:14 +02:00
committed by GitHub
parent c30a078a12
commit 6fe65553a3
4 changed files with 37 additions and 0 deletions

View File

@@ -131,6 +131,11 @@ async fn main() -> Result<()> {
}
};
// Create work directory if it doesn't exist
if !work_dir.exists() {
fs::create_dir_all(&work_dir)?;
}
let localstore: Arc<dyn WalletDatabase<Err = cdk_database::Error> + Send + Sync> =
match args.engine.as_str() {
"sqlite" => {

View File

@@ -43,6 +43,9 @@ pub enum Error {
/// CDK Error
#[error(transparent)]
CDK(#[from] cdk_common::error::Error),
/// IO Error
#[error(transparent)]
Io(#[from] std::io::Error),
/// NUT00 Error
#[error(transparent)]
CDKNUT00(#[from] cdk_common::nuts::nut00::Error),

View File

@@ -58,6 +58,16 @@ impl WalletRedbDatabase {
/// Create new [`WalletRedbDatabase`]
pub fn new(path: &Path) -> Result<Self, Error> {
{
// Check if parent directory exists before attempting to create database
if let Some(parent) = path.parent() {
if !parent.exists() {
return Err(Error::Io(std::io::Error::new(
std::io::ErrorKind::NotFound,
format!("Parent directory does not exist: {:?}", parent),
)));
}
}
let db = Arc::new(Database::create(path)?);
let db_version: Option<String>;
@@ -156,6 +166,16 @@ impl WalletRedbDatabase {
drop(db);
}
// Check parent directory again for final database creation
if let Some(parent) = path.parent() {
if !parent.exists() {
return Err(Error::Io(std::io::Error::new(
std::io::ErrorKind::NotFound,
format!("Parent directory does not exist: {:?}", parent),
)));
}
}
let mut db = Database::create(path)?;
db.upgrade()?;

View File

@@ -47,6 +47,15 @@ impl DatabasePool for SqliteConnectionManager {
_timeout: Duration,
) -> Result<Self::Connection, pool::Error<Self::Error>> {
let conn = if let Some(path) = config.path.as_ref() {
// Check if parent directory exists before attempting to open database
let path_buf = PathBuf::from(path);
if let Some(parent) = path_buf.parent() {
if !parent.exists() {
return Err(pool::Error::Resource(rusqlite::Error::InvalidPath(
path_buf.clone(),
)));
}
}
Connection::open(path)?
} else {
Connection::open_in_memory()?