diff --git a/mise.toml b/mise.toml index d30f4512..947db429 100644 --- a/mise.toml +++ b/mise.toml @@ -293,13 +293,46 @@ echo mise --env tcp run postgres:setup mise --env tls run postgres:setup +echo +echo '###############################################' +echo '# Test: Prometheus' +echo '###############################################' +echo + +mise --env tcp run proxy:up proxy --extra-args "--detach --wait" +mise --env tcp run test:wait_for_postgres_to_quack --port 6432 --max-retries 20 +mise --env tcp run test:integration:prometheus +mise --env tcp run proxy:down + +echo +echo '###############################################' +echo '# Test: non-TLS' +echo '###############################################' +echo + +mise --env tcp run proxy:up proxy --extra-args "--detach --wait" +mise --env tcp run test:wait_for_postgres_to_quack --port 6432 --max-retries 20 +mise --env tcp run test:integration:psql-tcp +mise --env tcp run proxy:down + +echo +echo '###############################################' +echo '# Test: TLS' +echo '###############################################' +echo + +mise --env tls run proxy:up proxy-tls --extra-args "--detach --wait" +mise --env tls run test:wait_for_postgres_to_quack --port 6432 --max-retries 20 --tls +mise --env tls run test:integration:psql-tls +mise --env tls run proxy:down + + echo echo '###############################################' echo '# Test: Integration' echo '###############################################' echo -mise --env tls e mise --env tls run proxy:up proxy-tls --extra-args "--detach --wait" mise --env tls run test:wait_for_postgres_to_quack --port 6432 --max-retries 20 --tls cargo nextest run --no-fail-fast --nocapture -E 'package(cipherstash-proxy-integration)' diff --git a/packages/cipherstash-proxy-integration/src/common.rs b/packages/cipherstash-proxy-integration/src/common.rs index bfffa3d3..52c38be5 100644 --- a/packages/cipherstash-proxy-integration/src/common.rs +++ b/packages/cipherstash-proxy-integration/src/common.rs @@ -23,6 +23,13 @@ pub fn random_id() -> i64 { rng.random_range(1..=i64::MAX) } +// Limited by valid data range +pub fn random_limited() -> i32 { + use rand::Rng; + let mut rng = rand::rng(); + rng.random_range(1..=31) +} + pub fn random_string() -> String { rand::rng() .sample_iter(&Alphanumeric) @@ -126,6 +133,15 @@ pub async fn query tokio_postgres::types::FromSql<'a> + Send + Sync>( rows.iter().map(|row| row.get(0)).collect::>() } +pub async fn query_by(sql: &str, param: &(dyn ToSql + Sync)) -> Vec +where + T: for<'a> tokio_postgres::types::FromSql<'a> + Send + Sync, +{ + let client = connect_with_tls(PROXY).await; + let rows = client.query(sql, &[param]).await.unwrap(); + rows.iter().map(|row| row.get(0)).collect::>() +} + pub async fn simple_query(sql: &str) -> Vec where ::Err: std::fmt::Debug, diff --git a/packages/cipherstash-proxy-integration/src/insert/insert_with_literal.rs b/packages/cipherstash-proxy-integration/src/insert/insert_with_literal.rs new file mode 100644 index 00000000..079f6ff7 --- /dev/null +++ b/packages/cipherstash-proxy-integration/src/insert/insert_with_literal.rs @@ -0,0 +1,67 @@ +#[cfg(test)] +mod tests { + use crate::common::{clear, insert, query_by, random_id, random_limited, trace}; + use chrono::NaiveDate; + use serde_json::Value; + + macro_rules! test_insert_with_literal { + ($name: ident, $type: ident, $pg_type: ident) => { + #[tokio::test] + pub async fn $name() { + trace(); + + clear().await; + + let id = random_id(); + + let encrypted_col = format!("encrypted_{}", stringify!($pg_type)); + let encrypted_val = crate::value_for_type!($type, random_limited()); + + let sql = format!("INSERT INTO encrypted (id, {encrypted_col}) VALUES ($1, '{encrypted_val}')"); + insert(&sql, &[&id]).await; + + let expected = vec![encrypted_val]; + + let sql = format!("SELECT {encrypted_col} FROM encrypted WHERE id = $1"); + + let actual = query_by::<$type>(&sql, &id).await; + + assert_eq!(expected, actual); + } + }; + } + + test_insert_with_literal!(insert_with_literal_int2, i16, int2); + test_insert_with_literal!(insert_with_literal_int4, i32, int4); + test_insert_with_literal!(insert_with_literal_int8, i64, int8); + test_insert_with_literal!(insert_with_literal_float8, f64, float8); + test_insert_with_literal!(insert_with_literal_bool, bool, bool); + test_insert_with_literal!(insert_with_literal_text, String, text); + test_insert_with_literal!(insert_with_literal_date, NaiveDate, date); + test_insert_with_literal!(insert_with_literal_jsonb, Value, jsonb); + + // ----------------------------------------------------------------- + + /// Sanity check insert of unencrypted literal value + #[tokio::test] + pub async fn insert_with_literal_plaintext() { + trace(); + + clear().await; + + let id = random_id(); + + let encrypted_val = crate::value_for_type!(String, random_limited()); + + let sql = format!("INSERT INTO encrypted (id, plaintext) VALUES ($1, '{encrypted_val}')"); + insert(&sql, &[&id]).await; + + let expected = vec![encrypted_val]; + + let sql = "SELECT plaintext FROM encrypted WHERE id = $1"; + + let actual = query_by::(sql, &id).await; + + assert_eq!(expected, actual); + } +} diff --git a/packages/cipherstash-proxy-integration/src/insert/insert_with_null_literal.rs b/packages/cipherstash-proxy-integration/src/insert/insert_with_null_literal.rs new file mode 100644 index 00000000..55194e9e --- /dev/null +++ b/packages/cipherstash-proxy-integration/src/insert/insert_with_null_literal.rs @@ -0,0 +1,65 @@ +#[cfg(test)] +mod tests { + use crate::common::{clear, insert, query_by, random_id, trace}; + use chrono::NaiveDate; + use serde_json::Value; + + macro_rules! test_insert_with_null_literal { + ($name: ident, $type: ident, $pg_type: ident) => { + #[tokio::test] + pub async fn $name() { + trace(); + + clear().await; + + let id = random_id(); + + let encrypted_col = format!("encrypted_{}", stringify!($pg_type)); + let encrypted_val: Option<$type> = None; + + let sql = format!("INSERT INTO encrypted (id, {encrypted_col}) VALUES ($1, NULL)"); + insert(&sql, &[&id]).await; + + let expected = vec![encrypted_val]; + + let sql = format!("SELECT {encrypted_col} FROM encrypted WHERE id = $1"); + + let actual = query_by::>(&sql, &id).await; + + assert_eq!(expected, actual); + } + }; + } + + test_insert_with_null_literal!(insert_with_null_literal_int2, i16, int2); + test_insert_with_null_literal!(insert_with_null_literal_int4, i32, int4); + test_insert_with_null_literal!(insert_with_null_literal_int8, i64, int8); + test_insert_with_null_literal!(insert_with_null_literal_float8, f64, float8); + test_insert_with_null_literal!(insert_with_null_literal_bool, bool, bool); + test_insert_with_null_literal!(insert_with_null_literal_text, String, text); + test_insert_with_null_literal!(insert_with_null_literal_date, NaiveDate, date); + test_insert_with_null_literal!(insert_with_null_literal_jsonb, Value, jsonb); + + // ----------------------------------------------------------------- + + /// Sanity check insert of unencrypted literal value + #[tokio::test] + pub async fn insert_with_null_literal_plaintext() { + trace(); + + clear().await; + + let id = random_id(); + + let expected: Vec> = vec![None]; + + let sql = "INSERT INTO encrypted (id, plaintext) VALUES ($1, NULL)"; + insert(sql, &[&id]).await; + + let sql = "SELECT plaintext FROM encrypted WHERE id = $1"; + + let actual = query_by::>(sql, &id).await; + + assert_eq!(expected, actual); + } +} diff --git a/packages/cipherstash-proxy-integration/src/insert/insert_with_null_param.rs b/packages/cipherstash-proxy-integration/src/insert/insert_with_null_param.rs new file mode 100644 index 00000000..48b9ded8 --- /dev/null +++ b/packages/cipherstash-proxy-integration/src/insert/insert_with_null_param.rs @@ -0,0 +1,41 @@ +#[cfg(test)] +mod tests { + use crate::common::{clear, insert, query_by, random_id, trace}; + use chrono::NaiveDate; + use serde_json::Value; + + macro_rules! test_insert_with_null_param { + ($name: ident, $type: ident, $pg_type: ident) => { + #[tokio::test] + pub async fn $name() { + trace(); + + clear().await; + + let id = random_id(); + + let encrypted_col = format!("encrypted_{}", stringify!($pg_type)); + let encrypted_val: Option<$type> = None; + + let sql = format!("INSERT INTO encrypted (id, {encrypted_col}) VALUES ($1, $2)"); + insert(&sql, &[&id, &encrypted_val]).await; + + let expected = vec![encrypted_val]; + + let sql = format!("SELECT {encrypted_col} FROM encrypted WHERE id = $1"); + let result = query_by::>(&sql, &id).await; + + assert_eq!(expected, result); + } + }; + } + + test_insert_with_null_param!(insert_with_null_param_int2, i16, int2); + test_insert_with_null_param!(insert_with_null_param_int4, i32, int4); + test_insert_with_null_param!(insert_with_null_param_int8, i64, int8); + test_insert_with_null_param!(insert_with_null_param_float8, f64, float8); + test_insert_with_null_param!(insert_with_null_param_bool, bool, bool); + test_insert_with_null_param!(insert_with_null_param_text_only, String, text); + test_insert_with_null_param!(insert_with_null_param_date, NaiveDate, date); + test_insert_with_null_param!(insert_with_null_param_jsonb, Value, jsonb); +} diff --git a/packages/cipherstash-proxy-integration/src/insert/insert_with_param.rs b/packages/cipherstash-proxy-integration/src/insert/insert_with_param.rs new file mode 100644 index 00000000..fe368eb5 --- /dev/null +++ b/packages/cipherstash-proxy-integration/src/insert/insert_with_param.rs @@ -0,0 +1,67 @@ +#[cfg(test)] +mod tests { + use crate::common::{clear, insert, query_by, random_id, random_limited, trace}; + use chrono::NaiveDate; + use serde_json::Value; + + macro_rules! test_insert_with_param { + ($name: ident, $type: ident, $pg_type: ident) => { + #[tokio::test] + pub async fn $name() { + trace(); + + clear().await; + + let id = random_id(); + + let encrypted_col = format!("encrypted_{}", stringify!($pg_type)); + let encrypted_val = crate::value_for_type!($type, random_limited()); + + let sql = format!("INSERT INTO encrypted (id, {encrypted_col}) VALUES ($1, $2)"); + insert(&sql, &[&id, &encrypted_val]).await; + + let expected = vec![encrypted_val]; + + let sql = format!("SELECT {encrypted_col} FROM encrypted WHERE id = $1"); + + let actual = query_by::<$type>(&sql, &id).await; + + assert_eq!(expected, actual); + } + }; + } + + test_insert_with_param!(insert_with_param_int2, i16, int2); + test_insert_with_param!(insert_with_param_int4, i32, int4); + test_insert_with_param!(insert_with_param_int8, i64, int8); + test_insert_with_param!(insert_with_param_float8, f64, float8); + test_insert_with_param!(insert_with_param_bool, bool, bool); + test_insert_with_param!(insert_with_param_text, String, text); + test_insert_with_param!(insert_with_param_date, NaiveDate, date); + test_insert_with_param!(insert_with_param_jsonb, Value, jsonb); + + // ----------------------------------------------------------------- + + /// Sanity check insert of unencrypted plaintext value + #[tokio::test] + pub async fn insert_with_param_plaintext() { + trace(); + + clear().await; + + let id = random_id(); + + let encrypted_val = crate::value_for_type!(String, random_limited()); + + let sql = "INSERT INTO encrypted (id, plaintext) VALUES ($1, $2)"; + insert(sql, &[&id, &encrypted_val]).await; + + let expected = vec![encrypted_val]; + + let sql = "SELECT plaintext FROM encrypted WHERE id = $1"; + + let actual = query_by::(sql, &id).await; + + assert_eq!(expected, actual); + } +} diff --git a/packages/cipherstash-proxy-integration/src/insert/insert_with_params.rs b/packages/cipherstash-proxy-integration/src/insert/insert_with_params.rs new file mode 100644 index 00000000..170e0e68 --- /dev/null +++ b/packages/cipherstash-proxy-integration/src/insert/insert_with_params.rs @@ -0,0 +1,118 @@ +#[cfg(test)] +mod tests { + use crate::common::{clear, insert, query, random_id, random_limited, trace}; + use chrono::NaiveDate; + use rand::{seq::IndexedRandom, Rng}; + use serde_json::Value; + use tokio_postgres::types::ToSql; + use tracing::info; + + fn value_for_type(t: &str) -> Box { + let mut rng = rand::rng(); + + match t { + "i16" => Box::new(rng.random_range(1..=i16::MAX) as i16), + "i32" => Box::new(rng.random_range(1..=i32::MAX) as i32), + "i64" => Box::new(rng.random_range(1..=i64::MAX) as i64), + "f64" => Box::new(rng.random_range(1.0..=f64::MAX) as f64), + "bool" => Box::new(rand::random_bool(0.5) as bool), + "String" => { + let i = random_limited(); + Box::new(((b'A' + (i - 1) as u8) as char).to_string()) + } + "NaiveDate" => { + let i = random_limited(); + Box::new(NaiveDate::parse_from_str(&format!("2023-01-{}", i), "%Y-%m-%d").unwrap()) + } + "Value" => { + let i = rng.random_range(1..=i32::MAX) as i32; + Box::new(serde_json::json!({"n": i, "s": format!("{}", i) })) + } + + _ => panic!("Unknown type {t}"), + } + } + + /// + /// Generates a random number of columns and values + /// Return as a tuple of two vecs: + /// - first vec contains column names + /// - second vec contains values of the corresponding column type + pub fn generate_columns_with_values() -> (Vec, Vec>) { + let columns = vec![ + ("i16", "int2"), + ("i32", "int4"), + ("i64", "int8"), + ("f64", "float8"), + ("bool", "bool"), + ("String", "text"), + ("NaiveDate", "date"), + ("Value", "jsonb"), + ]; + + let mut rng = rand::rng(); + let n = rng.random_range(1..columns.len()); + + let (mut columns, mut values): (Vec<_>, Vec<_>) = columns + .choose_multiple(&mut rng, n) + .map(|(t, c)| { + let c = format!("encrypted_{c}"); + (c, value_for_type(t)) + }) + .unzip(); + + let id = Box::new(random_id()); + columns.insert(0, "id".to_string()); + values.insert(0, id); + + (columns, values) + } + + pub async fn query tokio_postgres::types::FromSql<'a> + Send + Sync>( + sql: &str, + ) -> Vec { + let client = connect_with_tls(PROXY).await; + let rows = client.query(sql, &[]).await.unwrap(); + rows.iter().map(|row| row.get(0)).collect::>() + } + + #[tokio::test] + pub async fn test_everything_all_at_once() { + trace(); + + clear().await; + + let (columns, values) = generate_columns_with_values(); + + info!("Columns: {:?}", columns.join(",")); + info!("Values: {:?}", values); + + let columns = columns.join(", "); + let params: Vec<&(dyn ToSql + Sync)> = values.iter().map(|v| v.as_ref()).collect(); + + let placeholders = (1..=values.len()) + .map(|i| format!("${}", i)) + .collect::>() + .join(", "); + + let sql = format!("INSERT INTO encrypted ({columns}) VALUES ({placeholders})"); + + info!(sql); + insert(&sql, ¶ms).await; + + let sql = format!("SELECT {columns} FROM encrypted WHERE id = $1"); + + // let actual = query_by::<$type>(&sql, &id).await; + + // assert_eq!(expected, actual); + } + + // test_insert_with_params!(insert_with_params_int2, i16, int2); + // test_insert_with_params!(insert_with_params_int4, i32, int4); + // test_insert_with_params!(insert_with_params_int8, i64, int8); + // test_insert_with_params!(insert_with_params_float8, f64, float8); + // test_insert_with_params!(insert_with_params_bool, bool, bool); + // test_insert_with_params!(insert_with_params_text_only, String, text); + // test_insert_with_params!(insert_with_params_date, NaiveDate, date); + // test_insert_with_params!(insert_with_params_jsonb, Value, jsonb); +} diff --git a/packages/cipherstash-proxy-integration/src/insert/mod.rs b/packages/cipherstash-proxy-integration/src/insert/mod.rs new file mode 100644 index 00000000..f453b68f --- /dev/null +++ b/packages/cipherstash-proxy-integration/src/insert/mod.rs @@ -0,0 +1,4 @@ +mod insert_with_literal; +mod insert_with_null_literal; +mod insert_with_null_param; +mod insert_with_param; diff --git a/packages/cipherstash-proxy-integration/src/lib.rs b/packages/cipherstash-proxy-integration/src/lib.rs index 6f2f6fd2..484ab7a1 100644 --- a/packages/cipherstash-proxy-integration/src/lib.rs +++ b/packages/cipherstash-proxy-integration/src/lib.rs @@ -2,6 +2,7 @@ mod common; mod decrypt; mod empty_result; mod extended_protocol_error_messages; +mod insert; mod map_concat; mod map_literals; mod map_match_index; @@ -16,3 +17,26 @@ mod pipeline; mod schema_change; mod select; mod simple_protocol; + +#[macro_export] +macro_rules! value_for_type { + (String, $i:expr) => { + ((b'A' + ($i - 1) as u8) as char).to_string() + }; + + (NaiveDate, $i:expr) => { + NaiveDate::parse_from_str(&format!("2023-01-{}", $i), "%Y-%m-%d").unwrap() + }; + + (Value, $i:expr) => { + serde_json::json!({"n": $i, "s": format!("{}", $i) }) + }; + + (bool, $i:expr) => { + $i % 2 == 0 + }; + + ($type:ident, $i:expr) => { + $i as $type + }; +} diff --git a/packages/cipherstash-proxy-integration/src/map_params.rs b/packages/cipherstash-proxy-integration/src/map_params.rs index db33e154..d8c84fde 100644 --- a/packages/cipherstash-proxy-integration/src/map_params.rs +++ b/packages/cipherstash-proxy-integration/src/map_params.rs @@ -1,261 +1,6 @@ #[cfg(test)] mod tests { use crate::common::{connect_with_tls, random_id, reset_schema, trace, PROXY}; - use chrono::NaiveDate; - - #[tokio::test] - async fn map_text() { - trace(); - - let client = connect_with_tls(PROXY).await; - - let id = random_id(); - let encrypted_text = "hello@cipherstash.com"; - - let sql = "INSERT INTO encrypted (id, encrypted_text) VALUES ($1, $2)"; - client.query(sql, &[&id, &encrypted_text]).await.unwrap(); - - let sql = "SELECT id, encrypted_text FROM encrypted WHERE id = $1"; - let rows = client.query(sql, &[&id]).await.unwrap(); - - assert_eq!(rows.len(), 1); - - for row in rows { - let result: String = row.get("encrypted_text"); - assert_eq!(encrypted_text, result); - } - } - - #[tokio::test] - async fn map_bool() { - trace(); - - let client = connect_with_tls(PROXY).await; - - let id = random_id(); - let encrypted_bool: bool = true; - - let sql = "INSERT INTO encrypted (id, encrypted_bool) VALUES ($1, $2)"; - client.query(sql, &[&id, &encrypted_bool]).await.unwrap(); - - let sql = "SELECT id, encrypted_bool FROM encrypted WHERE id = $1"; - let rows = client.query(sql, &[&id]).await.unwrap(); - - assert_eq!(rows.len(), 1); - - for row in rows { - let result_id: i64 = row.get("id"); - let result_bool: bool = row.get("encrypted_bool"); - - assert_eq!(id, result_id); - assert_eq!(encrypted_bool, result_bool); - } - } - - #[tokio::test] - async fn map_int2() { - trace(); - - let client = connect_with_tls(PROXY).await; - - let id = random_id(); - let encrypted_int2: i16 = 42; - - let sql = "INSERT INTO encrypted (id, encrypted_int2) VALUES ($1, $2)"; - client.query(sql, &[&id, &encrypted_int2]).await.unwrap(); - - let sql = "SELECT id, encrypted_int2 FROM encrypted WHERE id = $1"; - let rows = client.query(sql, &[&id]).await.unwrap(); - - assert_eq!(rows.len(), 1); - - for row in rows { - let result_id: i64 = row.get("id"); - let result_int: i16 = row.get("encrypted_int2"); - - assert_eq!(id, result_id); - assert_eq!(encrypted_int2, result_int); - } - } - - #[tokio::test] - async fn map_int4() { - trace(); - - let client = connect_with_tls(PROXY).await; - - let id = random_id(); - let encrypted_int4: i32 = 42; - - let sql = "INSERT INTO encrypted (id, encrypted_int4) VALUES ($1, $2)"; - client.query(sql, &[&id, &encrypted_int4]).await.unwrap(); - - let sql = "SELECT id, encrypted_int4 FROM encrypted WHERE id = $1"; - let rows = client.query(sql, &[&id]).await.unwrap(); - - assert_eq!(rows.len(), 1); - - for row in rows { - let result_id: i64 = row.get("id"); - let result_int: i32 = row.get("encrypted_int4"); - - assert_eq!(id, result_id); - assert_eq!(encrypted_int4, result_int); - } - } - - #[tokio::test] - async fn map_int8() { - trace(); - - let client = connect_with_tls(PROXY).await; - - let id = random_id(); - let encrypted_int8: i64 = 42; - - let sql = "INSERT INTO encrypted (id, encrypted_int8) VALUES ($1, $2)"; - client.query(sql, &[&id, &encrypted_int8]).await.unwrap(); - - let sql = "SELECT id, encrypted_int8 FROM encrypted WHERE id = $1"; - let rows = client.query(sql, &[&id]).await.unwrap(); - - assert_eq!(rows.len(), 1); - - for row in rows { - let result_id: i64 = row.get("id"); - let result_int: i64 = row.get("encrypted_int8"); - - assert_eq!(id, result_id); - assert_eq!(encrypted_int8, result_int); - } - } - - #[tokio::test] - async fn map_float8() { - trace(); - - let client = connect_with_tls(PROXY).await; - - let id = random_id(); - let encrypted_float8: f64 = 42.00; - - let sql = "INSERT INTO encrypted (id, encrypted_float8) VALUES ($1, $2)"; - client.query(sql, &[&id, &encrypted_float8]).await.unwrap(); - - let sql = "SELECT id, encrypted_float8 FROM encrypted WHERE id = $1"; - let rows = client.query(sql, &[&id]).await.unwrap(); - - assert_eq!(rows.len(), 1); - - for row in rows { - let result_id: i64 = row.get("id"); - let result: f64 = row.get("encrypted_float8"); - - assert_eq!(id, result_id); - assert_eq!(encrypted_float8, result); - } - } - - #[tokio::test] - async fn map_date() { - trace(); - - let client = connect_with_tls(PROXY).await; - - let id = random_id(); - let encrypted_date = NaiveDate::parse_from_str("2025-01-01", "%Y-%m-%d").unwrap(); - - let sql = "INSERT INTO encrypted (id, encrypted_date) VALUES ($1, $2)"; - client.query(sql, &[&id, &encrypted_date]).await.unwrap(); - - let sql = "SELECT id, encrypted_date FROM encrypted WHERE id = $1"; - let rows = client.query(sql, &[&id]).await.unwrap(); - - assert_eq!(rows.len(), 1); - - for row in rows { - let result_id: i64 = row.get("id"); - let result: NaiveDate = row.get("encrypted_date"); - - assert_eq!(id, result_id); - assert_eq!(encrypted_date, result); - } - } - - #[tokio::test] - async fn map_jsonb() { - trace(); - - let client = connect_with_tls(PROXY).await; - - let id = random_id(); - let encrypted_jsonb = serde_json::json!({"key": "value"}); - - let sql = "INSERT INTO encrypted (id, encrypted_jsonb) VALUES ($1, $2)"; - client.query(sql, &[&id, &encrypted_jsonb]).await.unwrap(); - - let sql = "SELECT id, encrypted_jsonb FROM encrypted WHERE id = $1"; - let rows = client.query(sql, &[&id]).await.unwrap(); - - assert_eq!(rows.len(), 1); - - for row in rows { - let result_id: i64 = row.get("id"); - let result: serde_json::Value = row.get("encrypted_jsonb"); - - assert_eq!(id, result_id); - assert_eq!(encrypted_jsonb, result); - } - } - - #[tokio::test] - async fn map_jsonb_with_number() { - trace(); - - let client = connect_with_tls(PROXY).await; - - let id = random_id(); - let encrypted_jsonb = serde_json::json!({"key": 42}); - - let sql = "INSERT INTO encrypted (id, encrypted_jsonb) VALUES ($1, $2)"; - client.query(sql, &[&id, &encrypted_jsonb]).await.unwrap(); - - let sql = "SELECT id, encrypted_jsonb FROM encrypted WHERE id = $1"; - let rows = client.query(sql, &[&id]).await.unwrap(); - - assert_eq!(rows.len(), 1); - - for row in rows { - let result_id: i64 = row.get("id"); - let result: serde_json::Value = row.get("encrypted_jsonb"); - - assert_eq!(id, result_id); - assert_eq!(encrypted_jsonb, result); - } - } - - #[tokio::test] - async fn map_plaintext() { - trace(); - - let client = connect_with_tls(PROXY).await; - - let id = random_id(); - let plaintext = "hello@cipherstash.com"; - - let sql = "INSERT INTO encrypted (id, plaintext) VALUES ($1, $2)"; - client.query(sql, &[&id, &plaintext]).await.unwrap(); - - let sql = "SELECT id, plaintext FROM encrypted WHERE id = $1"; - let rows = client.query(sql, &[&id]).await.unwrap(); - - assert_eq!(rows.len(), 1); - - for row in rows { - let result: String = row.get("plaintext"); - assert_eq!(plaintext, result); - } - } #[tokio::test] async fn map_all_with_wildcard() { diff --git a/packages/cipherstash-proxy-integration/src/select/group_by.rs b/packages/cipherstash-proxy-integration/src/select/group_by.rs index 87bd3fea..ad3d7596 100644 --- a/packages/cipherstash-proxy-integration/src/select/group_by.rs +++ b/packages/cipherstash-proxy-integration/src/select/group_by.rs @@ -16,7 +16,7 @@ mod tests { for i in 1..=10 { let encrypted_val = crate::value_for_type!($type, i); - // Create two records with the same encrypted_int4 value + // Create two records with the same value for _ in 1..=2 { let id = random_id(); let sql = @@ -52,4 +52,7 @@ mod tests { test_group_by!(group_by_float8, f64, float8); test_group_by!(group_by_text, String, text); test_group_by!(group_by_date, NaiveDate, date); + + // Bool breaks the macro logic, will come to figure it out + // test_group_by!(group_by_bool, bool, bool); } diff --git a/packages/cipherstash-proxy-integration/src/select/mod.rs b/packages/cipherstash-proxy-integration/src/select/mod.rs index d50dc665..7fe1bf97 100644 --- a/packages/cipherstash-proxy-integration/src/select/mod.rs +++ b/packages/cipherstash-proxy-integration/src/select/mod.rs @@ -1,18 +1,3 @@ mod group_by; mod order_by; mod order_by_with_null; - -#[macro_export] -macro_rules! value_for_type { - (String, $i:expr) => { - ((b'A' + ($i - 1) as u8) as char).to_string() - }; - - (NaiveDate, $i:expr) => { - NaiveDate::parse_from_str(&format!("2023-01-{}", $i), "%Y-%m-%d").unwrap() - }; - - ($type:ident, $i:expr) => { - $i as $type - }; -} diff --git a/packages/cipherstash-proxy-integration/src/select/order_by.rs b/packages/cipherstash-proxy-integration/src/select/order_by.rs index f6b498ab..df1a7992 100644 --- a/packages/cipherstash-proxy-integration/src/select/order_by.rs +++ b/packages/cipherstash-proxy-integration/src/select/order_by.rs @@ -28,6 +28,7 @@ mod tests { format!("SELECT {encrypted_col} FROM encrypted ORDER BY {encrypted_col} ASC"); let actual = query::<$type>(&sql).await; + assert_eq!(expected, actual); let actual = simple_query::<$type>(&sql).await; @@ -53,4 +54,7 @@ mod tests { test_order_by!(order_by_float8, f64, float8); test_order_by!(order_by_text, String, text); test_order_by!(order_by_date, NaiveDate, date); + + // Bool breaks the macro logic, will come to figure it out + // test_order_by!(order_by_bool, bool, bool); } diff --git a/tests/tasks/test/integration/psql-tcp.sh b/tests/tasks/test/integration/psql-tcp.sh index 061b3fbd..f04fa00c 100755 --- a/tests/tasks/test/integration/psql-tcp.sh +++ b/tests/tasks/test/integration/psql-tcp.sh @@ -9,7 +9,7 @@ set -x source "$(dirname "${BASH_SOURCE[0]}")/url_encode.sh" encoded_password=$(urlencode "${CS_DATABASE__PASSWORD}") - +echo "Encoded password: ${encoded_password}" # sanity check direct connections docker exec -i postgres${CONTAINER_SUFFIX} psql postgresql://${CS_DATABASE__USERNAME}:${encoded_password}@${CS_DATABASE__HOST}:${CS_DATABASE__PORT}/cipherstash <<-EOF @@ -22,13 +22,13 @@ SELECT 1; EOF # Connect to the proxy -docker exec -i postgres psql 'postgresql://cipherstash:${encoded_password}@proxy:6432/cipherstash' <<-EOF +docker exec -i postgres psql postgresql://cipherstash:${encoded_password}@proxy:6432/cipherstash <<-EOF SELECT 1; EOF # Attempt with TLS set +e -docker exec -i postgres psql 'postgresql://cipherstash:${encoded_password}@proxy:6432/cipherstash?sslmode=require' <<-EOF +docker exec -i postgres psql postgresql://cipherstash:${encoded_password}@proxy:6432/cipherstash?sslmode=require <<-EOF SELECT 1; EOF if [ $? -eq 0 ]; then diff --git a/tests/tasks/test/integration/psql-tls.sh b/tests/tasks/test/integration/psql-tls.sh index 563a2054..d8f0e7da 100755 --- a/tests/tasks/test/integration/psql-tls.sh +++ b/tests/tasks/test/integration/psql-tls.sh @@ -21,13 +21,13 @@ SELECT 1; EOF # Connect to the proxy forcing TLS -docker exec -i postgres${CONTAINER_SUFFIX} psql 'postgresql://cipherstash:${encoded_password}@proxy:6432/cipherstash?sslmode=require' <<-EOF +docker exec -i postgres${CONTAINER_SUFFIX} psql postgresql://cipherstash:${encoded_password}@proxy:6432/cipherstash?sslmode=require <<-EOF SELECT 1; EOF # Connect without TLS set +e -OUTPUT="$(docker exec -i postgres${CONTAINER_SUFFIX} psql 'postgresql://cipherstash:${encoded_password}@proxy:6432/cipherstash?sslmode=disable' --command 'SELECT 1' 2>&1)" +OUTPUT="$(docker exec -i postgres${CONTAINER_SUFFIX} psql postgresql://cipherstash:${encoded_password}@proxy:6432/cipherstash?sslmode=disable --command 'SELECT 1' 2>&1)" retval=$? if echo ${OUTPUT} | grep -v 'Transport Layer Security (TLS) connection is required'; then echo "error: did not see string in output: \"Transport Layer Security (TLS) connection is required\""