diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml
index 7fd37064..ac24e7de 100644
--- a/.github/workflows/benchmark.yml
+++ b/.github/workflows/benchmark.yml
@@ -34,6 +34,7 @@ jobs:
CS_DEFAULT_KEYSET_ID: ${{ secrets.CS_DEFAULT_KEYSET_ID }}
CS_CLIENT_ID: ${{ secrets.CS_CLIENT_ID }}
CS_CLIENT_KEY: ${{ secrets.CS_CLIENT_KEY }}
+ CS_REGION: "ap-southeast-2.aws"
RUST_BACKTRACE: "1"
run: mise run benchmark:continuous
# Download previous benchmark result from cache (if exists)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 64c17a0c..e1f8b028 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -21,11 +21,14 @@ jobs:
- run: |
mise run postgres:up --extra-args "--detach --wait"
- env:
+ # REMEMBER TO ADD ENVIRONMENT VARIABLES TO tests/docker-compose.yml
+ # The tests/docker-compose.yml config passes the ENV vars into the container
CS_WORKSPACE_ID: ${{ secrets.CS_WORKSPACE_ID }}
CS_CLIENT_ACCESS_KEY: ${{ secrets.CS_CLIENT_ACCESS_KEY }}
CS_DEFAULT_KEYSET_ID: ${{ secrets.CS_DEFAULT_KEYSET_ID }}
CS_CLIENT_ID: ${{ secrets.CS_CLIENT_ID }}
CS_CLIENT_KEY: ${{ secrets.CS_CLIENT_KEY }}
+ CS_REGION: "ap-southeast-2.aws"
RUST_BACKTRACE: "1"
run: |
diff --git a/.gitignore b/.gitignore
index a5b17a57..05413b30 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,8 +4,6 @@
/cipherstash-proxy.local.toml
mise.local.toml
tests/pg/data**
-tests/sql/cipherstash-encrypt.sql
-tests/sql/cipherstash-encrypt-uninstall.sql
.vscode
rust-toolchain.toml
@@ -13,8 +11,9 @@ rust-toolchain.toml
# release artifacts
/cipherstash-proxy
-/cipherstash-eql.sql
/packages/cipherstash-proxy/eql-version-at-build-time.txt
+/cipherstash-encrypt.sql
+/cipherstash-encrypt-uninstall.sql
# credentials for local dev
.env.proxy.docker
diff --git a/Cargo.lock b/Cargo.lock
index 70247c27..de9237ca 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -181,6 +181,7 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
dependencies = [
+ "serde",
"zeroize",
]
@@ -193,7 +194,7 @@ dependencies = [
"asn1-rs-derive",
"asn1-rs-impl",
"displaydoc",
- "nom",
+ "nom 7.1.3",
"num-traits",
"rusticata-macros",
"thiserror 2.0.12",
@@ -287,6 +288,61 @@ dependencies = [
"fs_extra",
]
+[[package]]
+name = "axum"
+version = "0.7.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
+dependencies = [
+ "async-trait",
+ "axum-core",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "itoa",
+ "matchit",
+ "memchr",
+ "mime",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustversion",
+ "serde",
+ "serde_json",
+ "serde_path_to_error",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "tokio",
+ "tower",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "axum-core"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
+dependencies = [
+ "async-trait",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "mime",
+ "pin-project-lite",
+ "rustversion",
+ "sync_wrapper",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
[[package]]
name = "backtrace"
version = "0.3.74"
@@ -317,6 +373,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
+[[package]]
+name = "base32"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "022dfe9eb35f19ebbcb51e0b40a5ab759f46ad60cadf7297e0bd085afb50e076"
+
[[package]]
name = "base64"
version = "0.22.1"
@@ -537,7 +599,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
- "nom",
+ "nom 7.1.3",
]
[[package]]
@@ -588,9 +650,9 @@ dependencies = [
[[package]]
name = "cipherstash-client"
-version = "0.18.0"
+version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f099b1db6cf37b0ca36e9c8e0c2dade20f2035804e225f52475d44e750dd5dd5"
+checksum = "0f85784b109d3cacec64a735ca5ac791ef4e9c4d1d451156dd3bb513c9b4ddf0"
dependencies = [
"aes-gcm-siv",
"anyhow",
@@ -605,6 +667,7 @@ dependencies = [
"cipherstash-config",
"cipherstash-core",
"cllw-ore",
+ "cts-common",
"derive_more",
"dirs",
"futures",
@@ -679,7 +742,6 @@ dependencies = [
"bytes",
"chrono",
"cipherstash-client",
- "cipherstash-config",
"clap",
"config",
"eql-mapper",
@@ -724,9 +786,12 @@ name = "cipherstash-proxy-integration"
version = "0.1.0"
dependencies = [
"chrono",
+ "cipherstash-client",
+ "cipherstash-config",
"cipherstash-proxy",
"clap",
"fake 4.2.0",
+ "hex",
"rand 0.9.0",
"recipher",
"rustls",
@@ -739,6 +804,7 @@ dependencies = [
"tokio-rustls",
"tracing",
"tracing-subscriber",
+ "uuid",
"webpki-roots",
]
@@ -953,6 +1019,28 @@ dependencies = [
"cipher 0.4.4",
]
+[[package]]
+name = "cts-common"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "058540fce9a147af37cab4f55a5f9d8ae7f35f66efeec58c08cce6beb173d9c3"
+dependencies = [
+ "arrayvec",
+ "axum",
+ "base32",
+ "diesel",
+ "fake 3.1.0",
+ "http",
+ "miette",
+ "nom 8.0.0",
+ "rand 0.8.5",
+ "regex",
+ "serde",
+ "thiserror 1.0.69",
+ "url",
+ "vitaminc",
+]
+
[[package]]
name = "darling"
version = "0.20.10"
@@ -973,6 +1061,7 @@ dependencies = [
"ident_case",
"proc-macro2",
"quote",
+ "strsim",
"syn 2.0.100",
]
@@ -1022,7 +1111,7 @@ checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6"
dependencies = [
"asn1-rs",
"displaydoc",
- "nom",
+ "nom 7.1.3",
"num-bigint",
"num-traits",
"rusticata-macros",
@@ -1075,6 +1164,39 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc55fe0d1f6c107595572ec8b107c0999bb1a2e0b75e37429a4fb0d6474a0e7d"
+[[package]]
+name = "diesel"
+version = "2.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff3e1edb1f37b4953dd5176916347289ed43d7119cc2e6c7c3f7849ff44ea506"
+dependencies = [
+ "chrono",
+ "diesel_derives",
+ "uuid",
+]
+
+[[package]]
+name = "diesel_derives"
+version = "2.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68d4216021b3ea446fd2047f5c8f8fe6e98af34508a254a01e4d6bc1e844f84d"
+dependencies = [
+ "diesel_table_macro_syntax",
+ "dsl_auto_type",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "diesel_table_macro_syntax"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25"
+dependencies = [
+ "syn 2.0.100",
+]
+
[[package]]
name = "diff"
version = "0.1.13"
@@ -1123,6 +1245,20 @@ dependencies = [
"syn 2.0.100",
]
+[[package]]
+name = "dsl_auto_type"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "139ae9aca7527f85f26dd76483eb38533fd84bd571065da1739656ef71c5ff5b"
+dependencies = [
+ "darling",
+ "either",
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
[[package]]
name = "dummy"
version = "0.8.0"
@@ -1135,6 +1271,18 @@ dependencies = [
"syn 2.0.100",
]
+[[package]]
+name = "dummy"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abcba80bdf851db5616e27ff869399468e2d339d7c6480f5887681e6bdfc2186"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
[[package]]
name = "dummy"
version = "0.11.0"
@@ -1172,6 +1320,7 @@ dependencies = [
"thiserror 2.0.12",
"tracing",
"tracing-subscriber",
+ "vec1",
]
[[package]]
@@ -1223,12 +1372,24 @@ dependencies = [
"uuid",
]
+[[package]]
+name = "fake"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aef603df4ba9adbca6a332db7da6f614f21eafefbaf8e087844e452fdec152d0"
+dependencies = [
+ "deunicode",
+ "dummy 0.9.2",
+ "rand 0.8.5",
+]
+
[[package]]
name = "fake"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b591050272097cc85b2f3c1cc4817ba4560057d10fcae6f7339f1cf622da0a0f"
dependencies = [
+ "chrono",
"deunicode",
"dummy 0.11.0",
"rand 0.9.0",
@@ -2034,6 +2195,12 @@ dependencies = [
"regex-automata 0.1.10",
]
+[[package]]
+name = "matchit"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
+
[[package]]
name = "md-5"
version = "0.10.6"
@@ -2187,6 +2354,15 @@ dependencies = [
"minimal-lexical",
]
+[[package]]
+name = "nom"
+version = "8.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
@@ -3089,7 +3265,7 @@ version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
dependencies = [
- "nom",
+ "nom 7.1.3",
]
[[package]]
@@ -3328,6 +3504,16 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serde_path_to_error"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a"
+dependencies = [
+ "itoa",
+ "serde",
+]
+
[[package]]
name = "serde_spanned"
version = "0.6.8"
@@ -3905,6 +4091,7 @@ dependencies = [
"tokio",
"tower-layer",
"tower-service",
+ "tracing",
]
[[package]]
@@ -4134,6 +4321,12 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+[[package]]
+name = "vec1"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eab68b56840f69efb0fefbe3ab6661499217ffdc58e2eef7c3f6f69835386322"
+
[[package]]
name = "version_check"
version = "0.9.5"
@@ -4325,9 +4518,9 @@ dependencies = [
[[package]]
name = "webpki-roots"
-version = "0.26.8"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9"
+checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb"
dependencies = [
"rustls-pki-types",
]
@@ -4727,7 +4920,7 @@ dependencies = [
"data-encoding",
"der-parser",
"lazy_static",
- "nom",
+ "nom 7.1.3",
"oid-registry",
"rusticata-macros",
"thiserror 2.0.12",
diff --git a/docs/errors.md b/docs/errors.md
index 7e5faceb..3ea90ec6 100644
--- a/docs/errors.md
+++ b/docs/errors.md
@@ -21,6 +21,10 @@
- [Unknown column](#encrypt-unknown-column)
- [Unknown table](#encrypt-unknown-table)
- [Unknown index term](#encrypt-unknown-index-term)
+ - [Column configuration mismatch](#encrypt-column-config-mismatch)
+
+- Decrypt errors:
+ - [Column could not be deserialised](#encrypt-column-could-not-be-deserialised)
- Configuration errors:
- [Missing or invalid TLS configuration](#config-missing-or-invalid-tls)
@@ -263,9 +267,9 @@ The most likely cause is network access to the ZeroKMS service.
### How to Fix
1. Check that CipherStash ZeroKMS is available at [the status page](https://status.cipherstash.com/).
-1. Check that CipherStash Proxy has network access to ZeroKMS in the appropriate region.
+2. Check that CipherStash Proxy has network access to ZeroKMS in the appropriate region.
-1. Check that the encrypted configuration `cast` matches the expected type.
+3. Check that the encrypted configuration `cast` matches the expected type.
@@ -307,14 +311,14 @@ For example:
### How to fix
1. Check the encrypted configuration has the correct type.
-1. Check that the configuration has not changed.
-1. Check [EQL](https://github.com/cipherstash/encrypt-query-language).
+2. Check that the configuration has not changed.
+3. Check [EQL](https://github.com/cipherstash/encrypt-query-language).
## Unknown Column
-The column has an encrypted type (PostgreSQL `cs_encrypted_v1` type ) with no encryption configuration.
+The column has an encrypted type (PostgreSQL `eql_v2_encrypted` type ) with no encryption configuration.
Without the configuration, Cipherstash Proxy does not know how to encrypt the column.
Any data is unprotected and unencrypted.
@@ -331,7 +335,7 @@ Column 'column_name' in table 'table_name' has no Encrypt configuration
1. Define the encrypted configuration using [EQL](https://github.com/cipherstash/encrypt-query-language).
-1. Add `users.email` as an encrypted column:
+2. Add `users.email` as an encrypted column:
```sql
SELECT cs_add_column_v1('users', 'email');
```
@@ -341,7 +345,7 @@ Column 'column_name' in table 'table_name' has no Encrypt configuration
## Unknown Table
-The table has one or more encrypted columns (PostgreSQL `cs_encrypted_v1` type ) with no encryption configuration.
+The table has one or more encrypted columns (PostgreSQL `eql_v2_encrypted` type ) with no encryption configuration.
Without the configuration, Cipherstash Proxy does not know how to encrypt the column.
Any data is unprotected and unencrypted.
@@ -357,7 +361,7 @@ Table 'table_name' has no Encrypt configuration
1. Define the encrypted configuration using [EQL](https://github.com/cipherstash/encrypt-query-language).
-1. Add `users.email` as an encrypted column:
+2. Add `users.email` as an encrypted column:
```sql
SELECT cs_add_column_v1('users', 'email');
```
@@ -385,13 +389,83 @@ Unknown Index Term for column '{column_name}' in table '{table_name}'.
### How to fix
1. Check the Encrypt configuration for the column.
-1. Define the encrypted configuration using [EQL](https://github.com/cipherstash/encrypt-query-language).
+2. Define the encrypted configuration using [EQL](https://github.com/cipherstash/encrypt-query-language).
+
+
+
+
+
+
+## Column configuration mismatch
+
+A returned encrypted column does not match the column configuration.
+
+### Error message
+
+```
+Column configuration for column '{column_name}' in table '{table_name}' does not match the encrypted column.
+```
+
+### Notes
+
+CipherStash Proxy validates that encrypted columns match the configuration before decrypting any data.
+If the table and column are not the same, this error is returned.
+The check is there to help prevent "confused deputy" issues and the error should *never* appear during normal operation.
+
+If the error persists, please contact CipherStash [support](https://cipherstash.com/support).
+
+
+### Further reading
+
+[AWS: The confused deputy problem](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html)
+[Wikipedia: Confused deputy problem](https://en.wikipedia.org/wiki/Confused_deputy_problem)
+
+
+
+
+
+
+
+
+
+# Decrypt errors
+
+
+## Column could not be deserialised
+
+The column could not be deserialised for decryption.
+
+
+### Error message
+
+```
+Column 'column_name' in table 'table_name' could not be deserialised.
+```
+
+### Notes
+
+CipherStash Proxy stores encrypted data and search terms as `jsonb`. The structure is defined as part of EQL.
+
+The error indicates an internal issue has occurred deserialising and extracting the ciphertext data for decryption.
+It may be caused if the the encrypted data has been altered by another process or application.
+
+If the error persists, please contact CipherStash [support](https://cipherstash.com/support).
+
+
+### How to Fix
+
+1. Check that the data in the encrypted column is in correct format [EQL](https://github.com/cipherstash/encrypt-query-language).
+
+
+
+
+
# Configuration errors
diff --git a/docs/getting-started/schema-example.sql b/docs/getting-started/schema-example.sql
index 29e3e743..e1627419 100644
--- a/docs/getting-started/schema-example.sql
+++ b/docs/getting-started/schema-example.sql
@@ -1,12 +1,12 @@
-TRUNCATE TABLE cs_configuration_v1;
+TRUNCATE TABLE public.eql_v2_configuration;
-- Exciting cipherstash table
DROP TABLE IF EXISTS users;
CREATE TABLE users (
id SERIAL PRIMARY KEY,
- encrypted_email cs_encrypted_v1,
- encrypted_dob cs_encrypted_v1,
- encrypted_salary cs_encrypted_v1
+ encrypted_email eql_v2_encrypted,
+ encrypted_dob eql_v2_encrypted,
+ encrypted_salary eql_v2_encrypted
);
SELECT cs_add_index_v1(
diff --git a/docs/how-to.md b/docs/how-to.md
index a38f80cb..0f8954e5 100644
--- a/docs/how-to.md
+++ b/docs/how-to.md
@@ -153,7 +153,7 @@ You can also install EQL by running [the installation script](https://github.com
Once you have installed EQL, you can see what version is installed by querying the database:
```sql
-SELECT cs_eql_version();
+SELECT eql_v2.version();
```
This will output the version of EQL installed.
@@ -162,22 +162,22 @@ This will output the version of EQL installed.
In your existing PostgreSQL database, you store your data in tables and columns.
Those columns have types like `integer`, `text`, `timestamp`, and `boolean`.
-When storing encrypted data in PostgreSQL with Proxy, you use a special column type called `cs_encrypted_v1`, which is [provided by EQL](#setting-up-the-database-schema).
-`cs_encrypted_v1` is a container column type that can be used for any type of encrypted data you want to store or search, whether they are numbers (`int`, `small_int`, `big_int`), text (`text`), dates and times (`date`), or booleans (`boolean`).
+When storing encrypted data in PostgreSQL with Proxy, you use a special column type called `eql_v2_encrypted`, which is [provided by EQL](#setting-up-the-database-schema).
+`eql_v2_encrypted` is a container column type that can be used for any type of encrypted data you want to store or search, whether they are numbers (`int`, `small_int`, `big_int`), text (`text`), dates and times (`date`. `timestamp`), or booleans (`boolean`).
Create a table with an encrypted column for `email`:
```sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
- email cs_encrypted_v1
+ email eql_v2_encrypted
)
```
This creates a `users` table with two columns:
- `id`, an autoincrementing integer column that is the primary key for the record
- - `email`, a `cs_encrypted_v1` column
+ - `email`, a `eql_v2_encrypted` column
There are important differences between the plaintext columns you've traditionally used in PostgreSQL and encrypted columns with CipherStash Proxy:
diff --git a/mise.toml b/mise.toml
index 9cf04e2a..cd840193 100644
--- a/mise.toml
+++ b/mise.toml
@@ -22,8 +22,9 @@ CS_DATABASE__PORT = "5532"
# Default configuration for dev cipherstash-proxy run using 'mise run proxy:up'
CS_PROXY__HOST = "proxy"
# Misc
-DOCKER_CLI_HINTS = "false" # Please don't show us What's Next.
-CS_EQL_VERSION = "eql-1.0.1"
+DOCKER_CLI_HINTS = "false" # Please don't show us What's Next.
+
+CS_EQL_VERSION = "eql-2.0.0"
[tools]
"cargo:cargo-binstall" = "latest"
@@ -409,27 +410,28 @@ fi
"""
[tasks."postgres:setup"]
+depends = ["postgres:eql:teardown"]
alias = 's'
description = "Installs EQL and applies schema to database"
run = """
#!/bin/bash
cd tests
mise run postgres:fail_if_not_running
-mise run postgres:eql:download
-cat sql/cipherstash-encrypt.sql | docker exec -i postgres${CONTAINER_SUFFIX} psql postgresql://${CS_DATABASE__USERNAME}:${CS_DATABASE__PASSWORD}@${CS_DATABASE__HOST}:${CS_DATABASE__PORT}/${CS_DATABASE__NAME} -f-
+cat sql/schema-uninstall.sql | docker exec -i postgres${CONTAINER_SUFFIX} psql postgresql://${CS_DATABASE__USERNAME}:${CS_DATABASE__PASSWORD}@${CS_DATABASE__HOST}:${CS_DATABASE__PORT}/${CS_DATABASE__NAME} -f-
+cat ../cipherstash-encrypt-uninstall.sql | docker exec -i postgres${CONTAINER_SUFFIX} psql postgresql://${CS_DATABASE__USERNAME}:${CS_DATABASE__PASSWORD}@${CS_DATABASE__HOST}:${CS_DATABASE__PORT}/${CS_DATABASE__NAME} -f-
+cat ../cipherstash-encrypt.sql | docker exec -i postgres${CONTAINER_SUFFIX} psql postgresql://${CS_DATABASE__USERNAME}:${CS_DATABASE__PASSWORD}@${CS_DATABASE__HOST}:${CS_DATABASE__PORT}/${CS_DATABASE__NAME} -f-
cat sql/schema.sql | docker exec -i postgres${CONTAINER_SUFFIX} psql postgresql://${CS_DATABASE__USERNAME}:${CS_DATABASE__PASSWORD}@${CS_DATABASE__HOST}:${CS_DATABASE__PORT}/${CS_DATABASE__NAME} -f-
"""
[tasks."postgres:eql:teardown"]
-alias = 's'
+depends = ["eql:download"]
description = "Uninstalls EQL and removes schema from database"
run = """
#!/bin/bash
cd tests
mise run postgres:fail_if_not_running
-mise run postgres:eql:download
cat sql/schema-uninstall.sql | docker exec -i postgres${CONTAINER_SUFFIX} psql postgresql://${CS_DATABASE__USERNAME}:${CS_DATABASE__PASSWORD}@${CS_DATABASE__HOST}:${CS_DATABASE__PORT}/${CS_DATABASE__NAME} -f-
-cat sql/cipherstash-encrypt-uninstall.sql | docker exec -i postgres${CONTAINER_SUFFIX} psql postgresql://${CS_DATABASE__USERNAME}:${CS_DATABASE__PASSWORD}@${CS_DATABASE__HOST}:${CS_DATABASE__PORT}/${CS_DATABASE__NAME} -f-
+cat ../cipherstash-encrypt-uninstall.sql | docker exec -i postgres${CONTAINER_SUFFIX} psql postgresql://${CS_DATABASE__USERNAME}:${CS_DATABASE__PASSWORD}@${CS_DATABASE__HOST}:${CS_DATABASE__PORT}/${CS_DATABASE__NAME} -f-
"""
[tasks."postgres:up"]
@@ -490,34 +492,34 @@ for d in tests/pg/data-*; do
done
"""
-
-[tasks."postgres:eql:download"]
+[tasks."eql:download"]
alias = 'e'
-description = "Download latest EQL release"
+description = "Download latest EQL release or use local copy"
dir = "{{config_root}}/tests"
outputs = [
- "{{config_root}}/tests/sql/cipherstash-encrypt.sql",
- "{{config_root}}/tests/sql/cipherstash-encrypt-uninstall.sql",
+ "{{config_root}}/cipherstash-encrypt.sql",
+ "{{config_root}}/cipherstash-encrypt-uninstall.sql",
]
run = """
# install script
if [ -z "$CS_EQL_PATH" ]; then
- curl -sLo sql/cipherstash-encrypt.sql https://github.com/cipherstash/encrypt-query-language/releases/download/${CS_EQL_VERSION}/cipherstash-encrypt.sql
+ echo "Downloading ${CS_EQL_VERSION} install"
+ curl -sLo "{{config_root}}/cipherstash-encrypt.sql" https://github.com/cipherstash/encrypt-query-language/releases/download/${CS_EQL_VERSION}/cipherstash-encrypt.sql
else
- echo "Using EQL: ${CS_EQL_PATH}"
- cp "$CS_EQL_PATH" sql/cipherstash-encrypt.sql
+ echo "Using EQL: ${CS_EQL_PATH}/cipherstash-encrypt.sql"
+ cp "$CS_EQL_PATH/cipherstash-encrypt.sql" "{{config_root}}/cipherstash-encrypt.sql"
fi
# uninstall script
-if [ -z "$CS_EQL_UNINSTALL_PATH" ]; then
- curl -sLo sql/cipherstash-encrypt-uninstall.sql https://github.com/cipherstash/encrypt-query-language/releases/download/${CS_EQL_VERSION}/cipherstash-encrypt-uninstall.sql
+if [ -z "$CS_EQL_PATH" ]; then
+ echo "Downloading ${CS_EQL_VERSION} uninstall"
+ curl -sLo "{{config_root}}/cipherstash-encrypt-uninstall.sql" https://github.com/cipherstash/encrypt-query-language/releases/download/${CS_EQL_VERSION}/cipherstash-encrypt-uninstall.sql
else
- echo "Using EQL: ${CS_EQL_PATH}"
- cp "$CS_EQL_UNINSTALL_PATH" sql/cipherstash-encrypt-uninstall.sql
+ echo "Using EQL: ${CS_EQL_PATH}/cipherstash-encrypt-uninstall.sql"
+ cp "$CS_EQL_PATH/cipherstash-encrypt-uninstall.sql" "{{config_root}}/cipherstash-encrypt-uninstall.sql"
fi
"""
-
[tasks."python:test"]
dir = "{{config_root}}/tests"
description = "Runs python tests"
@@ -567,7 +569,7 @@ cp -v {{config_root}}/target/{{ target }}/release/cipherstash-proxy {{config_roo
"""
[tasks."build:docker"]
-depends = ["build:docker:fetch_eql"]
+depends = ["eql:download"]
description = "Build a Docker image for cipherstash-proxy"
run = """
{% set default_platform = "linux/" ~ arch() | replace(from="x86_64", to="amd64") %}
diff --git a/packages/cipherstash-proxy-integration/Cargo.toml b/packages/cipherstash-proxy-integration/Cargo.toml
index 546e1ff8..90162eb9 100644
--- a/packages/cipherstash-proxy-integration/Cargo.toml
+++ b/packages/cipherstash-proxy-integration/Cargo.toml
@@ -21,8 +21,12 @@ tokio-postgres-rustls = "0.13.0"
tokio-rustls = "0.26.0"
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
-webpki-roots = "0.26.7"
+webpki-roots = "1.0"
[dev-dependencies]
+cipherstash-client = { version = "0.22.0", features = ["tokio"] }
+cipherstash-config = "0.2.3"
clap = "4.5.32"
-fake = { version = "4", features = ["derive"] }
+fake = { version = "4", features = ["chrono", "derive"] }
+hex = "0.4.3"
+uuid = { version = "1.11.0", features = ["serde", "v4"] }
diff --git a/packages/cipherstash-proxy-integration/src/extended_protocol_error_messages.rs b/packages/cipherstash-proxy-integration/src/extended_protocol_error_messages.rs
index c45ec4af..ae868aea 100644
--- a/packages/cipherstash-proxy-integration/src/extended_protocol_error_messages.rs
+++ b/packages/cipherstash-proxy-integration/src/extended_protocol_error_messages.rs
@@ -66,11 +66,7 @@ mod tests {
if let Err(err) = result {
let msg = err.to_string();
- // This is similar to below. The error message comes from tokio-postgres when Proxy
- // returns cs_encrypted_v1 and the client cannot convert to a string.
- // If mapping errors are enabled (enable_mapping_errors or CS_DEVELOPMENT__ENABLE_MAPPING_ERRORS),
- // then Proxy will return an error that says "Column X in table Y has no Encrypt configuration"
- assert_eq!(msg, "error serializing parameter 1: cannot convert between the Rust type `&str` and the Postgres type `cs_encrypted_v1`");
+ assert_eq!(msg, "db error: ERROR: Column 'encrypted_unconfigured' in table 'unconfigured' has no Encrypt configuration. For help visit https://github.com/cipherstash/proxy/blob/main/docs/errors.md#encrypt-unknown-column");
} else {
unreachable!();
}
diff --git a/packages/cipherstash-proxy-integration/src/generate.rs b/packages/cipherstash-proxy-integration/src/generate.rs
new file mode 100644
index 00000000..13d11820
--- /dev/null
+++ b/packages/cipherstash-proxy-integration/src/generate.rs
@@ -0,0 +1,259 @@
+#[cfg(test)]
+mod tests {
+ use crate::common::trace;
+ use cipherstash_client::config::EnvSource;
+ use cipherstash_client::credentials::auto_refresh::AutoRefresh;
+ use cipherstash_client::encryption::{
+ Encrypted, EncryptedSteVecTerm, JsonIndexer, JsonIndexerOptions, OreTerm, Plaintext,
+ PlaintextTarget, ReferencedPendingPipeline,
+ };
+ use cipherstash_client::{encryption::ScopedCipher, zerokms::EncryptedRecord};
+ use cipherstash_client::{ConsoleConfig, CtsConfig, ZeroKMSConfig};
+ use cipherstash_config::column::{Index, IndexType};
+ use cipherstash_config::{ColumnConfig, ColumnType};
+ use cipherstash_proxy::Identifier;
+ use serde::{Deserialize, Serialize};
+ use std::sync::Arc;
+ use tracing::info;
+ use uuid::Uuid;
+
+ pub mod option_mp_base85 {
+ use cipherstash_client::zerokms::encrypted_record::formats::mp_base85;
+ use cipherstash_client::zerokms::EncryptedRecord;
+ use serde::{Deserialize, Deserializer, Serializer};
+
+ pub fn serialize(
+ value: &Option,
+ serializer: S,
+ ) -> Result
+ where
+ S: Serializer,
+ {
+ match value {
+ Some(record) => mp_base85::serialize(record, serializer),
+ None => serializer.serialize_none(),
+ }
+ }
+
+ pub fn deserialize<'de, D>(deserializer: D) -> Result