diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index c3becd317..12073def9 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -38,6 +38,8 @@ jobs: python-version: "3.10" - name: Build run: cargo build --verbose + - name: Test Encryption + run: cargo test --features encryption --color=always --test integration_tests query_processing::encryption - name: Test env: RUST_LOG: ${{ runner.debug && 'turso_core::storage=trace' || '' }} diff --git a/tests/Cargo.toml b/tests/Cargo.toml index f2936a014..b26ca9b5f 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -32,3 +32,6 @@ zerocopy = "0.8.26" test-log = { version = "0.2.17", features = ["trace"] } tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } tracing = "0.1.41" + +[features] +encryption = ["turso_core/encryption"] \ No newline at end of file diff --git a/tests/integration/query_processing/encryption.rs b/tests/integration/query_processing/encryption.rs new file mode 100644 index 000000000..c286bde7c --- /dev/null +++ b/tests/integration/query_processing/encryption.rs @@ -0,0 +1,70 @@ +use crate::common::{do_flush, TempDatabase}; +use crate::query_processing::test_write_path::{run_query, run_query_on_row}; +use rand::{rng, RngCore}; +use std::panic; +use turso_core::Row; + +#[test] +fn test_per_page_encryption() -> anyhow::Result<()> { + let _ = env_logger::try_init(); + let db_name = format!("test-{}.db", rng().next_u32()); + let tmp_db = TempDatabase::new(&db_name, false); + let db_path = tmp_db.path.clone(); + + { + let conn = tmp_db.connect_limbo(); + run_query( + &tmp_db, + &conn, + "PRAGMA key = 'super secret key for encryption';", + )?; + run_query( + &tmp_db, + &conn, + "CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT);", + )?; + run_query( + &tmp_db, + &conn, + "INSERT INTO test (value) VALUES ('Hello, World!')", + )?; + let mut row_count = 0; + run_query_on_row(&tmp_db, &conn, "SELECT * FROM test", |row: &Row| { + assert_eq!(row.get::(0).unwrap(), 1); + assert_eq!(row.get::(1).unwrap(), "Hello, World!"); + row_count += 1; + })?; + assert_eq!(row_count, 1); + do_flush(&conn, &tmp_db)?; + } + + { + // this should panik because we should not be able to access the encrypted database + // without the key + let conn = tmp_db.connect_limbo(); + let should_panic = panic::catch_unwind(panic::AssertUnwindSafe(|| { + run_query_on_row(&tmp_db, &conn, "SELECT * FROM test", |_: &Row| {}).unwrap(); + })); + assert!( + should_panic.is_err(), + "should panic when accessing encrypted DB without key" + ); + } + + { + // let's test the existing db with the key + let existing_db = TempDatabase::new_with_existent(&db_path, false); + let conn = existing_db.connect_limbo(); + run_query( + &existing_db, + &conn, + "PRAGMA key = 'super secret key for encryption';", + )?; + run_query_on_row(&existing_db, &conn, "SELECT * FROM test", |row: &Row| { + assert_eq!(row.get::(0).unwrap(), 1); + assert_eq!(row.get::(1).unwrap(), "Hello, World!"); + })?; + } + + Ok(()) +} diff --git a/tests/integration/query_processing/mod.rs b/tests/integration/query_processing/mod.rs index c77608718..742cdf52c 100644 --- a/tests/integration/query_processing/mod.rs +++ b/tests/integration/query_processing/mod.rs @@ -4,3 +4,6 @@ mod test_write_path; mod test_multi_thread; mod test_transactions; + +#[cfg(feature = "encryption")] +mod encryption;