diff --git a/.changeset/eql-text-equality-transcoding.md b/.changeset/eql-text-equality-transcoding.md new file mode 100644 index 000000000..969aa9653 --- /dev/null +++ b/.changeset/eql-text-equality-transcoding.md @@ -0,0 +1,5 @@ +--- +'@cipherstash/eql': minor +--- + +**Rust `TextEq` and `TextEqQuery` support Stack Encrypt's target-directed API behind the `stack-encrypt` feature.** The stored table and column identifier supplies the encryption context; native ciphertext and equality terms are transcoded into EQL payloads while Vitamin C owns plaintext encoding. This is a new producer profile with exact string equality, independent of existing cipherstash-client ciphertext and terms. Query operands carry no recoverable ciphertext. diff --git a/.github/workflows/test-eql.yml b/.github/workflows/test-eql.yml index 5cbaa6608..6153bdc29 100644 --- a/.github/workflows/test-eql.yml +++ b/.github/workflows/test-eql.yml @@ -520,6 +520,18 @@ jobs: github.event_name != 'pull_request' || needs.changes.outputs.relevant == 'true' runs-on: blacksmith-16vcpu-ubuntu-2204 + services: + encryption-postgres: + image: postgres:17 + env: + POSTGRES_PASSWORD: postgres + ports: + - 7433:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: @@ -549,6 +561,26 @@ jobs: rustup component add --toolchain "${active_rust_toolchain}" rustfmt clippy mise run test:crates + # Registry builds require the unpublished Stack Encrypt crates from + # cipherstash-suite#2215 to be published before this change merges. + - name: Test Rust text equality with PostgreSQL + env: + PGPASSWORD: postgres + EQL_TEST_DATABASE_URL: "host=localhost port=7433 user=postgres password=postgres dbname=postgres" + run: | + set -euo pipefail + cargo test --locked -p eql-bindings --features stack-encrypt + cargo test --locked -p eql-encryption-tests + cargo clippy --locked -p eql-bindings -p eql-encryption-tests --all-features --all-targets -- -D warnings + psql -h localhost -p 7433 -U postgres -d postgres -v ON_ERROR_STOP=1 -f crates/eql-bindings/sql/cipherstash-encrypt.sql + cargo test --locked -p eql-encryption-tests --test text_eq -- --ignored + + - name: Compile Rust text equality for WASI without HTTP + run: | + set -euo pipefail + rustup target add wasm32-wasip1 + cargo check --locked -p eql-bindings --features stack-encrypt --target wasm32-wasip1 + # Freshness gate for the eql-types codegen output: regenerate the # TypeScript bindings and JSON Schemas and fail if the checked-in # copies differ. Reuses the toolchain from the step above. diff --git a/AGENTS.md b/AGENTS.md index 239450d94..dfc7759d6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -83,7 +83,7 @@ If these variables are missing, tests that require live encryption will fail or - `packages/utils`: Shared config (`utils/config`) and logger (`utils/logger`) - `packages/bench`: Performance / index-engagement benchmarks (private, not published) - `packages/protect-ffi`: Native FFI bindings to the CipherStash Client SDK (`@cipherstash/protect-ffi`) — the Rust core that `packages/stack` encrypts and decrypts through, absorbed from `cipherstash/protectjs-ffi`. Contains a **nested Cargo workspace** (`crates/`) and six per-platform binary packages under `platforms/*`, each published as `@cipherstash/protect-ffi-` and linked here via `workspace:*`. Also holds the repo's live FFI integration suite at `integration-tests/` — a private workspace member (`@cipherstash/ffi-integration-tests`) enrolled by its own literal entry in `pnpm-workspace.yaml`, needing Docker and credentials, and deliberately carrying **no `test` script** so `pnpm test` cannot reach it. See the "Working on protect-ffi" notes below before touching it — its default `test` and `build` are deliberately Rust-free. -- `packages/eql`: The Encrypt Query Language subtree — the SQL bundle that stores and queries encrypted payloads — absorbed from `cipherstash/encrypt-query-language`. **The directory is the subtree root, not the package.** It was imported at a *verbatim prefix* so its repo-root-relative paths (mise tasks, `Doxyfile`, `sync-generated.mjs`) keep resolving, which puts the npm package `@cipherstash/eql` two levels down at `packages/eql/packages/eql` — the same shape as `packages/protect-ffi/platforms/*`, and enrolled the same way, by an explicit `packages/eql/packages/*` glob in `pnpm-workspace.yaml`. The subtree root deliberately carries no `package.json`. Also contains a **nested Cargo workspace** at `packages/eql/crates/` (`eql-bindings`, published in lockstep with the npm package, plus `eql-domains` / `eql-codegen` / `eql-tests-macros`, which are not), a SQLx test crate at `packages/eql/tests/sqlx`, an ~900-line `mise.toml` task surface, its own `AGENTS.md`, and `docs/`. See the "Working on EQL" notes below before touching it. +- `packages/eql`: The Encrypt Query Language subtree — the SQL bundle that stores and queries encrypted payloads — absorbed from `cipherstash/encrypt-query-language`. **The directory is the subtree root, not the package.** It was imported at a *verbatim prefix* so its repo-root-relative paths (mise tasks, `Doxyfile`, `sync-generated.mjs`) keep resolving, which puts the npm package `@cipherstash/eql` two levels down at `packages/eql/packages/eql` — the same shape as `packages/protect-ffi/platforms/*`, and enrolled the same way, by an explicit `packages/eql/packages/*` glob in `pnpm-workspace.yaml`. The subtree root deliberately carries no `package.json`. Also contains a **nested Cargo workspace** at `packages/eql/crates/` (`eql-bindings`, published in lockstep with the npm package, plus `eql-domains` / `eql-codegen` / `eql-tests-macros`, which are not), a SQLx test crate at `packages/eql/tests/sqlx`, an unpublished encryption test crate at `packages/eql/tests/encryption` (real encryption with a fake key source, the executable Rustdoc example at `packages/eql/crates/eql-bindings/src/encryption/example.rs`, plus optional PostgreSQL coverage), an ~900-line `mise.toml` task surface, its own `AGENTS.md`, and `docs/`. See the "Working on EQL" notes below before touching it. **Repository ownership:** EQL now lives in `cipherstash/stack`. File and update EQL issues in this repository, never in the historical `cipherstash/encrypt-query-language` repository. Old upstream issue and PR diff --git a/SECURITY.md b/SECURITY.md index eab646082..6249f4ba2 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -26,6 +26,12 @@ This repository also carries the source of the **`eql-bindings`** Rust crate lockstep with `@cipherstash/eql`. It is in scope for security reports on the same terms as the npm packages above. +The `eql-encryption-tests` Rust crate (`packages/eql/tests/encryption`) is +an unpublished test harness for these bindings. It uses real encryption with +a fake key source, executes the Rustdoc text encryption example, and provides +optional disposable PostgreSQL coverage. It adds no published package or +production service. + > **Note on publishing.** `@cipherstash/eql` and the `eql-bindings` crate are > developed here but are *published* from `cipherstash/encrypt-query-language` > until the Phase 5 cutover in diff --git a/packages/eql/Cargo.lock b/packages/eql/Cargo.lock index 8e6f936bb..5c2389ddb 100644 --- a/packages/eql/Cargo.lock +++ b/packages/eql/Cargo.lock @@ -345,6 +345,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" dependencies = [ "hybrid-array", + "zeroize", ] [[package]] @@ -565,15 +566,15 @@ dependencies = [ "base85", "blake3", "chrono", - "cipherstash-config", + "cipherstash-config 0.42.2", "cipherstash-core", - "cllw-ore", - "cts-common", + "cllw-ore 0.4.2", + "cts-common 0.42.2", "derive_more 1.0.0", "dirs", "futures", "hex", - "hmac", + "hmac 0.12.1", "itertools 0.12.1", "lazy_static", "log", @@ -583,7 +584,7 @@ dependencies = [ "ore-rs", "percent-encoding", "rand 0.8.6", - "recipher", + "recipher 0.2.3", "reqwest", "rmp-serde", "rust-stemmers", @@ -593,9 +594,9 @@ dependencies = [ "serde_cbor", "serde_json", "serdect", - "sha2", - "stack-auth", - "stack-profile", + "sha2 0.10.9", + "stack-auth 0.42.2", + "stack-profile 0.42.2", "static_assertions", "thiserror 1.0.69", "tokio", @@ -603,11 +604,11 @@ dependencies = [ "tracing", "url", "uuid", - "vitaminc", - "vitaminc-protected", + "vitaminc 0.2.0-pre", + "vitaminc-protected 0.2.0-pre", "winnow 0.6.26", "zeroize", - "zerokms-protocol", + "zerokms-protocol 0.12.28", ] [[package]] @@ -622,6 +623,16 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "cipherstash-config" +version = "0.42.3" +dependencies = [ + "bitflags", + "serde", + "serde_json", + "thiserror 1.0.69", +] + [[package]] name = "cipherstash-core" version = "0.42.0" @@ -629,12 +640,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1946988e0b7f9de259d85b10c9c1fd7e1327751103b808c2c6e930b9a87c25c9" dependencies = [ "getrandom 0.2.16", - "hmac", + "hmac 0.12.1", "lazy_static", "num-bigint", "rand 0.8.6", "regex", - "sha2", + "sha2 0.10.9", "thiserror 1.0.69", ] @@ -654,6 +665,18 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "cllw-ore" +version = "0.4.3" +dependencies = [ + "blake3", + "hex", + "subtle", + "thiserror 1.0.69", + "unicode-normalization", + "zeroize", +] + [[package]] name = "cmac" version = "0.7.2" @@ -674,6 +697,12 @@ dependencies = [ "cc", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + [[package]] name = "combine" version = "4.6.7" @@ -729,6 +758,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "constant_time_eq" version = "0.4.2" @@ -893,7 +928,40 @@ dependencies = [ "url", "utoipa", "uuid", - "vitaminc", + "vitaminc 0.2.0-pre", +] + +[[package]] +name = "cts-common" +version = "0.42.3" +dependencies = [ + "arrayvec", + "base32", + "cached", + "chrono", + "derive_more 2.1.1", + "either", + "getrandom 0.4.2", + "miette", + "nom", + "regex", + "serde", + "serde_json", + "thiserror 1.0.69", + "tracing", + "url", + "utoipa", + "uuid", + "vitaminc 0.4.0", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", ] [[package]] @@ -952,7 +1020,7 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid", + "const-oid 0.9.6", "pem-rfc7468", "zeroize", ] @@ -1023,7 +1091,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", - "const-oid", + "const-oid 0.9.6", "crypto-common 0.1.6", "subtle", ] @@ -1035,7 +1103,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ "block-buffer 0.12.0", + "const-oid 0.10.2", "crypto-common 0.2.2", + "ctutils", + "zeroize", ] [[package]] @@ -1133,11 +1204,15 @@ dependencies = [ name = "eql-bindings" version = "3.0.5" dependencies = [ + "base64", "eql-domains", + "hex", "schemars", "serde", "serde_json", + "stack-encrypt", "ts-rs", + "vitaminc-prf", ] [[package]] @@ -1162,6 +1237,20 @@ dependencies = [ "proptest", ] +[[package]] +name = "eql-encryption-tests" +version = "0.1.0" +dependencies = [ + "eql-bindings", + "postgres", + "serde", + "serde_json", + "stack-encrypt", + "stack-kms", + "tokio", + "uuid", +] + [[package]] name = "eql-tests-macros" version = "0.1.0" @@ -1249,6 +1338,12 @@ dependencies = [ "uuid", ] +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + [[package]] name = "fancy-regex" version = "0.18.0" @@ -1482,7 +1577,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", "wasm-bindgen", ] @@ -1655,7 +1750,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "hmac", + "hmac 0.12.1", ] [[package]] @@ -1667,6 +1762,15 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", +] + [[package]] name = "home" version = "0.5.11" @@ -2181,13 +2285,14 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" -version = "0.1.10" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +checksum = "6480ccc157a1389bb2e4891b24751b0f798ba640d22386f23143fbcc89da195a" dependencies = [ "bitflags", "libc", - "redox_syscall", + "plain", + "redox_syscall 0.9.4", ] [[package]] @@ -2249,6 +2354,16 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "md-5" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" +dependencies = [ + "cfg-if", + "digest 0.11.3", +] + [[package]] name = "memchr" version = "2.7.6" @@ -2316,7 +2431,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", "windows-sys 0.61.2", ] @@ -2337,6 +2452,12 @@ dependencies = [ "uuid", ] +[[package]] +name = "mutants" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ac067452ff1aca8c5002111bd6b1c895baee6e45fcbc44e0193aea17be56" + [[package]] name = "nom" version = "8.0.0" @@ -2448,6 +2569,24 @@ dependencies = [ "libm", ] +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags", +] + +[[package]] +name = "objc2-system-configuration" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396" +dependencies = [ + "objc2-core-foundation", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -2543,7 +2682,7 @@ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.18", "smallvec", "windows-link", ] @@ -2585,6 +2724,25 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_shared", + "serde", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -2624,6 +2782,12 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "polyval" version = "0.6.2" @@ -2642,6 +2806,49 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +[[package]] +name = "postgres" +version = "0.19.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ad20e0aa0b24f5a394eab4f78c781d248982b22b25cecc7e3aa46a681605bd" +dependencies = [ + "bytes", + "fallible-iterator", + "futures-util", + "log", + "tokio", + "tokio-postgres", +] + +[[package]] +name = "postgres-protocol" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08808e3c483c46e999108051c78334f473d5adb59d78bb80a1268c7e6aa6c514" +dependencies = [ + "base64", + "byteorder", + "bytes", + "fallible-iterator", + "hmac 0.13.0", + "md-5 0.11.0", + "memchr", + "rand 0.10.1", + "sha2 0.11.0", + "stringprep", +] + +[[package]] +name = "postgres-types" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "851ca9db4932932d69f3ea811b1abe63087a0f740a47692619dd40d4899b68be" +dependencies = [ + "bytes", + "fallible-iterator", + "postgres-protocol", +] + [[package]] name = "potential_utf" version = "0.1.3" @@ -2955,7 +3162,26 @@ dependencies = [ "rand_chacha 0.3.1", "serde", "serde_cbor", - "sha2", + "sha2 0.10.9", + "thiserror 1.0.69", + "zeroize", +] + +[[package]] +name = "recipher" +version = "0.3.0" +dependencies = [ + "aes", + "cmac", + "getrandom 0.2.16", + "hex", + "hex-literal", + "opaque-debug", + "rand 0.8.6", + "rand_chacha 0.3.1", + "serde", + "serde_cbor", + "sha2 0.10.9", "thiserror 1.0.69", "zeroize", ] @@ -2969,6 +3195,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "737970939a87c6fa31e7acad13307bccbb017a073b695b6089a2c484f929e20e" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.4.6" @@ -3172,7 +3407,7 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ - "const-oid", + "const-oid 0.9.6", "digest 0.10.7", "num-bigint-dig", "num-integer", @@ -3571,6 +3806,17 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", +] + [[package]] name = "shlex" version = "1.3.0" @@ -3630,6 +3876,12 @@ dependencies = [ "time", ] +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + [[package]] name = "slab" version = "0.4.11" @@ -3714,7 +3966,7 @@ dependencies = [ "rust_decimal", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "thiserror 2.0.20", "tokio", @@ -3751,7 +4003,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "sqlx-core", "sqlx-mysql", "sqlx-postgres", @@ -3784,10 +4036,10 @@ dependencies = [ "generic-array", "hex", "hkdf", - "hmac", + "hmac 0.12.1", "itoa", "log", - "md-5", + "md-5 0.10.6", "memchr", "once_cell", "percent-encoding", @@ -3796,13 +4048,13 @@ dependencies = [ "rust_decimal", "serde", "sha1", - "sha2", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", "thiserror 2.0.20", "tracing", - "whoami", + "whoami 1.6.1", ] [[package]] @@ -3824,24 +4076,24 @@ dependencies = [ "futures-util", "hex", "hkdf", - "hmac", + "hmac 0.12.1", "home", "itoa", "log", - "md-5", + "md-5 0.10.6", "memchr", "once_cell", "rand 0.8.6", "rust_decimal", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", "thiserror 2.0.20", "tracing", - "whoami", + "whoami 1.6.1", ] [[package]] @@ -3883,24 +4135,105 @@ checksum = "f1a9ac43060af7605899754daa3de2e26302c2ab4d9249a8bc16157bc53dad65" dependencies = [ "aquamarine", "base64", - "cts-common", + "cts-common 0.42.2", "jsonwebtoken", "miette", "open", "reqwest", "serde", "serde_json", - "stack-profile", + "stack-profile 0.42.2", + "thiserror 1.0.69", + "tokio", + "tracing", + "url", + "uuid", + "vitaminc 0.2.0-pre", + "vitaminc-protected 0.2.0-pre", + "web-time", + "zeroize", + "zerokms-protocol 0.12.28", +] + +[[package]] +name = "stack-auth" +version = "0.42.3" +dependencies = [ + "aquamarine", + "base64", + "cts-common 0.42.3", + "jsonwebtoken", + "miette", + "open", + "serde", + "serde_json", + "stack-profile 0.42.3", "thiserror 1.0.69", "tokio", "tracing", "url", "uuid", - "vitaminc", - "vitaminc-protected", + "vitaminc 0.4.0", + "vitaminc-protected 0.4.0", "web-time", "zeroize", - "zerokms-protocol", + "zerokms-protocol 0.12.30", +] + +[[package]] +name = "stack-encrypt" +version = "0.1.0" +dependencies = [ + "base64ct", + "cllw-ore 0.4.3", + "serde", + "stack-encrypt-derive", + "stack-kms", + "thiserror 1.0.69", + "uuid", + "vitaminc-aead 0.4.0", + "vitaminc-encrypt 0.4.0", + "vitaminc-hmac", + "vitaminc-prf", + "vitaminc-protected 0.4.0", + "zeroize", +] + +[[package]] +name = "stack-encrypt-derive" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "stack-kms" +version = "0.1.0" +dependencies = [ + "base16ct", + "base64ct", + "blake3", + "futures", + "miette", + "opaque-debug", + "recipher 0.3.0", + "serde", + "serde_cbor", + "serde_json", + "serdect", + "sha2 0.10.9", + "stack-auth 0.42.3", + "stack-profile 0.42.3", + "thiserror 1.0.69", + "tracing", + "url", + "uuid", + "vitaminc 0.4.0", + "vitaminc-protected 0.4.0", + "zeroize", + "zerokms-protocol 0.12.30", ] [[package]] @@ -3917,6 +4250,18 @@ dependencies = [ "uuid", ] +[[package]] +name = "stack-profile" +version = "0.42.3" +dependencies = [ + "dirs", + "gethostname", + "serde", + "serde_json", + "thiserror 1.0.69", + "uuid", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -4163,6 +4508,32 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "tokio-postgres" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a528f7d280f6d5b9cd149635c8705b0dd049754bc67d81d31fa25169a93809d3" +dependencies = [ + "async-trait", + "byteorder", + "bytes", + "fallible-iterator", + "futures-channel", + "futures-util", + "log", + "parking_lot", + "percent-encoding", + "phf", + "pin-project-lite", + "postgres-protocol", + "postgres-types", + "rand 0.10.1", + "socket2", + "tokio", + "tokio-util", + "whoami 2.1.3", +] + [[package]] name = "tokio-rustls" version = "0.26.4" @@ -4516,7 +4887,7 @@ dependencies = [ "atomic", "getrandom 0.4.2", "js-sys", - "md-5", + "md-5 0.10.6", "serde_core", "sha1_smol", "wasm-bindgen", @@ -4580,11 +4951,24 @@ version = "0.2.0-pre" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec9807fc6a29a9ab4a9cd24f103573661d7e04d48651ce8c752d32e73a686446" dependencies = [ - "vitaminc-aead", - "vitaminc-encrypt", - "vitaminc-protected", - "vitaminc-random", - "vitaminc-traits", + "vitaminc-aead 0.2.0-pre", + "vitaminc-encrypt 0.2.0-pre", + "vitaminc-protected 0.2.0-pre", + "vitaminc-random 0.2.0-pre", + "vitaminc-traits 0.2.0-pre", +] + +[[package]] +name = "vitaminc" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b26ab159600161f73a1a519a31562ec4732257991acc6cba180db826c7765035" +dependencies = [ + "vitaminc-aead 0.4.0", + "vitaminc-encrypt 0.4.0", + "vitaminc-protected 0.4.0", + "vitaminc-random 0.4.0", + "vitaminc-traits 0.4.0", ] [[package]] @@ -4595,11 +4979,37 @@ checksum = "3933759550ab4841536e8d019fc73cd77ec2e43dcdaefa3218936534eefabb8d" dependencies = [ "bytes", "serde", - "vitaminc-protected", - "vitaminc-random", + "vitaminc-protected 0.2.0-pre", + "vitaminc-random 0.2.0-pre", + "zeroize", +] + +[[package]] +name = "vitaminc-aead" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52b4b439efcb59c4fb2b56aa59934d5907d6907172feb45b45df1eb9311f357e" +dependencies = [ + "bytes", + "serde", + "vitaminc-aead-derive", + "vitaminc-prf", + "vitaminc-protected 0.4.0", + "vitaminc-random 0.4.0", "zeroize", ] +[[package]] +name = "vitaminc-aead-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fa56c62afe5cc393173876b83ee361246e341e855f7d45a334e1edd30c0018e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + [[package]] name = "vitaminc-encrypt" version = "0.2.0-pre" @@ -4608,12 +5018,50 @@ checksum = "2bdbcfd5e9054ce2a3f0cfac67c3e3164d65f38f3a6d593bc4d5d943e53aaf44" dependencies = [ "aes-gcm", "aws-lc-rs", - "vitaminc-aead", - "vitaminc-protected", - "vitaminc-random", + "vitaminc-aead 0.2.0-pre", + "vitaminc-protected 0.2.0-pre", + "vitaminc-random 0.2.0-pre", + "zeroize", +] + +[[package]] +name = "vitaminc-encrypt" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb81b908b8747fd74ffc198591849ccab8e0be52049d41b3d5d7bb8aed5342b" +dependencies = [ + "aes-gcm", + "aws-lc-rs", + "vitaminc-aead 0.4.0", + "vitaminc-protected 0.4.0", + "vitaminc-random 0.4.0", + "zeroize", +] + +[[package]] +name = "vitaminc-hmac" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d9de7991de2c5e4526d9fc81ab2c153ba5c0af7b50bdc9f1bd19eddb10b8307" +dependencies = [ + "hmac 0.13.0", + "sha2 0.11.0", + "vitaminc-prf", + "vitaminc-protected 0.4.0", "zeroize", ] +[[package]] +name = "vitaminc-prf" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d8978944fc2fba04255b776b384ff71b9ed5abc4d5bce859a11cc5d6841cba9" +dependencies = [ + "mutants", + "thiserror 2.0.20", + "vitaminc-protected 0.4.0", +] + [[package]] name = "vitaminc-protected" version = "0.2.0-pre" @@ -4625,7 +5073,23 @@ dependencies = [ "serde", "serde_bytes", "subtle", - "vitaminc-protected-derive", + "vitaminc-protected-derive 0.2.0-pre", + "zeroize", +] + +[[package]] +name = "vitaminc-protected" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31efcddf3193efbe1801959922159ffe60a1e1388bc993927d3d7242f144c7" +dependencies = [ + "bitvec", + "digest 0.11.3", + "serde", + "serde_bytes", + "subtle", + "thiserror 2.0.20", + "vitaminc-protected-derive 0.4.0", "zeroize", ] @@ -4640,6 +5104,17 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "vitaminc-protected-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17fe15916386e0404b17c468e8c5a255ffc037e930512b5aa494802c8bba22d8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + [[package]] name = "vitaminc-random" version = "0.2.0-pre" @@ -4649,8 +5124,22 @@ dependencies = [ "getrandom 0.4.2", "rand 0.10.1", "thiserror 2.0.20", - "vitaminc-protected", - "vitaminc-random-derives", + "vitaminc-protected 0.2.0-pre", + "vitaminc-random-derives 0.2.0-pre", + "zeroize", +] + +[[package]] +name = "vitaminc-random" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f8f9bc3db765f757068db06bd60f5e6fbfa8d546ed6da82246c33b6321fe45f" +dependencies = [ + "getrandom 0.4.2", + "rand 0.10.1", + "thiserror 2.0.20", + "vitaminc-protected 0.4.0", + "vitaminc-random-derives 0.4.0", "zeroize", ] @@ -4665,6 +5154,17 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "vitaminc-random-derives" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0931f7e84808c1072d77b30bab7f4e254334e038fc28929fbf7d647796b856cd" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + [[package]] name = "vitaminc-traits" version = "0.2.0-pre" @@ -4676,8 +5176,24 @@ dependencies = [ "rmp-serde", "serde", "thiserror 2.0.20", - "vitaminc-protected", - "vitaminc-random", + "vitaminc-protected 0.2.0-pre", + "vitaminc-random 0.2.0-pre", + "zeroize", +] + +[[package]] +name = "vitaminc-traits" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c806b05905d3a51c5440c64eb087bfe4b2a02e06dd4792ba9c53e005d42aeb5" +dependencies = [ + "anyhow", + "bytes", + "rmp-serde", + "serde", + "thiserror 2.0.20", + "vitaminc-protected 0.4.0", + "vitaminc-random 0.4.0", "zeroize", ] @@ -4721,6 +5237,15 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + [[package]] name = "wasip2" version = "1.0.3+wasi-0.2.9" @@ -4745,6 +5270,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" +[[package]] +name = "wasite" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fe902b4a6b8028a753d5424909b764ccf79b7a209eac9bf97e59cda9f71a42" +dependencies = [ + "wasi 0.14.7+wasi-0.2.4", +] + [[package]] name = "wasm-bindgen" version = "0.2.121" @@ -4884,7 +5418,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" dependencies = [ "libredox", - "wasite", + "wasite 0.1.0", +] + +[[package]] +name = "whoami" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626c4bac6755d76ffc12cb01b2eac751db1996b9e0041de9aa02c8c211ddc82c" +dependencies = [ + "libc", + "libredox", + "objc2-system-configuration", + "wasite 1.0.2", + "web-sys", ] [[package]] @@ -5453,9 +6000,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29486723fdd2bdb0c234174dc242051a46ac0c82935ccaa39e9781dbf7bcc6d2" dependencies = [ "base64", - "cipherstash-config", + "cipherstash-config 0.42.2", + "const-hex", + "cts-common 0.42.2", + "fake", + "getrandom 0.2.16", + "opaque-debug", + "rand 0.8.6", + "serde", + "static_assertions", + "thiserror 1.0.69", + "utoipa", + "uuid", + "validator", + "zeroize", +] + +[[package]] +name = "zerokms-protocol" +version = "0.12.30" +dependencies = [ + "base64", + "cipherstash-config 0.42.3", "const-hex", - "cts-common", + "cts-common 0.42.3", "fake", "getrandom 0.2.16", "opaque-debug", diff --git a/packages/eql/Cargo.toml b/packages/eql/Cargo.toml index 0c8086b8f..ab1492558 100644 --- a/packages/eql/Cargo.toml +++ b/packages/eql/Cargo.toml @@ -26,6 +26,7 @@ members = [ "crates/eql-tests-macros", "crates/eql-bindings", "tests/sqlx", + "tests/encryption", ] default-members = ["tests/sqlx"] diff --git a/packages/eql/crates/eql-bindings/Cargo.toml b/packages/eql/crates/eql-bindings/Cargo.toml index 5c443d5cc..1724f7e41 100644 --- a/packages/eql/crates/eql-bindings/Cargo.toml +++ b/packages/eql/crates/eql-bindings/Cargo.toml @@ -33,6 +33,19 @@ serde_json = "1" # caught by the `types:check` gate on the committed TS/JSON output. ts-rs = { version = "10", features = ["no-serde-warnings"] } schemars = "1" +# Unpublished until cipherstash-suite#2215 lands. Local development uses +# tasks/dev/with-stack-encrypt.sh; release/CI use the registry versions. +stack-encrypt = { version = "0.1.0", optional = true, default-features = false } +vitaminc-prf = { version = "0.4.0", optional = true } +base64 = { version = "0.22", optional = true } +hex = { version = "0.4", optional = true } + +[features] +default = [] +stack-encrypt = ["dep:stack-encrypt", "dep:vitaminc-prf", "dep:base64", "dep:hex"] + +[package.metadata.docs.rs] +features = ["stack-encrypt"] [dev-dependencies] # Parity oracle: tests/catalog_parity.rs asserts the v3 domain inventory diff --git a/packages/eql/crates/eql-bindings/README.md b/packages/eql/crates/eql-bindings/README.md index 4812c331e..58e84301a 100644 --- a/packages/eql/crates/eql-bindings/README.md +++ b/packages/eql/crates/eql-bindings/README.md @@ -98,3 +98,76 @@ evolution plan. [`ts-rs`]: https://github.com/Aleph-Alpha/ts-rs [`schemars`]: https://graham.cool/schemars/ + +## Rust text equality with Stack Encrypt + +The optional `stack-encrypt` feature enables `EncryptFrom` for `TextEq` +and `TextEqQuery`, and `DecryptInto` for `TextEq`. Other domains do not +yet expose these conversions. The derives are emitted by `eql-codegen`. + +The generated API docs include a complete, executable example in the +`eql_bindings::encryption` module, from cipher setup through decryption. Its +[source](src/encryption/example.rs) is also run by the encryption test crate: + +```bash +# From packages/eql, using the unpublished suite checkout: +bash tasks/dev/with-stack-encrypt.sh /path/to/cipherstash-suite \ + test -p eql-encryption-tests --test text_eq_example +``` + +With an initialized cipher, the essential calls are: + +```rust,ignore +use eql_bindings::{Identifier, v3::text::{TextEq, TextEqQuery}}; + +let column = Identifier::for_column("users", "email")?; +let keyset = cipher.default_keyset(); +let email = "alice@example.com".to_owned(); +let stored: TextEq = keyset.encrypt_as(&email, column.clone()).await?; +let query: TextEqQuery = keyset.encrypt_as(&email, column.clone()).await?; +let opened: String = cipher.decrypt_as(stored, column.into()).await?; +``` + +Both identifier components must be nonempty. Encryption stores the identifier +in `i`; its table and column supply the ciphertext AAD, term context, and ZeroKMS +descriptor. The storage field names `c` and `hm` add no further context. +Decryption validates `i` before retrieving keys. Passing an expected identifier, +as above, also checks the destination. `Default::default()` uses the stored +identifier alone, so moving a complete payload with its original `i` still opens. + +Ciphertext uses Vitamin C's native string encoding. Equality uses its exact +string PRF input, with no normalization or case folding: `café` and +`cafe\u{301}`, or `Alice` and `alice`, produce different terms. A query contains +only `v`, `i`, and `hm` and requests no data keys. Neither EQL type implements +the plaintext-side `Encrypt` or `Decrypt` traits. + +This is a **new producer profile**, independent of existing cipherstash-client +ciphertext and terms. `c` is `stack-encrypt:1:` followed by padded standard base64 of Stack +Encrypt's native `SealedValue` bytes; `hm` is the native 32-byte equality term +encoded as hex. Serde handles the final EQL JSON envelope only. SQL consumes +these payloads through the existing `public.eql_v3_text_eq` and +`eql_v3.query_text_eq` domains and their equality extractor index. Writers and +query producers for these values must use this same profile. + +### Developing against the unpublished crates + +Stack Encrypt and its runtime prerequisites must be published before the normal +registry-based build, CI, and `eql-bindings` publication can succeed. Regenerate +`Cargo.lock` without local overrides once they are published, before merging. +During development, use a checkout containing +[cipherstash-suite#2215](https://github.com/cipherstash/cipherstash-suite/pull/2215) +(tested with commit `cbb3e000009b5974e90ec7da98d015b4b19a7270`): + +```bash +# From packages/eql. Generates a temporary Cargo patch; no local paths are committed. +bash tasks/dev/with-stack-encrypt.sh /path/to/cipherstash-suite \ + test -p eql-encryption-tests +bash tasks/dev/with-stack-encrypt.sh /path/to/cipherstash-suite \ + test -p eql-bindings --features stack-encrypt + +# Against a disposable PostgreSQL database, using fresh encryption and a fake KMS: +psql "$EQL_TEST_DATABASE_URL" -v ON_ERROR_STOP=1 \ + -f crates/eql-bindings/sql/cipherstash-encrypt.sql +bash tasks/dev/with-stack-encrypt.sh /path/to/cipherstash-suite \ + test -p eql-encryption-tests --test text_eq -- --ignored +``` diff --git a/packages/eql/crates/eql-bindings/bindings/v3/Ciphertext.ts b/packages/eql/crates/eql-bindings/bindings/v3/Ciphertext.ts index 7beff648e..01c400762 100644 --- a/packages/eql/crates/eql-bindings/bindings/v3/Ciphertext.ts +++ b/packages/eql/crates/eql-bindings/bindings/v3/Ciphertext.ts @@ -1,7 +1,7 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. /** - * mp_base85 source ciphertext — the `c` envelope key. + * Producer-encoded source ciphertext — the `c` envelope key. * * Required by every v3 domain CHECK; present on every payload. */ diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint.json index dcf39ca1d..f2d22fb58 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_eq.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_eq.json index 376e97e59..895726c7e 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_eq.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_ord.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_ord.json index 4dd53489d..4087631d9 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_ord.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_ord_ope.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_ord_ope.json index c9b7f2155..b48b3b984 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_ord_ope.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_ord_ore.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_ord_ore.json index ec0620b71..643631c7e 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_ord_ore.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_bigint_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_boolean.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_boolean.json index feee8688d..d8a5ad205 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_boolean.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_boolean.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date.json index 7265731c5..a0eedd9e6 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_eq.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_eq.json index 87c588b18..659840e85 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_eq.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_ord.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_ord.json index e7a1898bd..39485b088 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_ord.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_ord_ope.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_ord_ope.json index 67d2daa5b..8f4cf8216 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_ord_ope.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_ord_ore.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_ord_ore.json index 010869e58..63caa1ed2 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_ord_ore.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_date_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double.json index 2b2dc709f..bbad0b189 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_eq.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_eq.json index fea7dbc50..6338de607 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_eq.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_ord.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_ord.json index d636c06d7..da2e629f3 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_ord.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_ord_ope.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_ord_ope.json index 6a1ddba44..b27cdb37c 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_ord_ope.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_ord_ore.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_ord_ore.json index ebc8a6ded..e95ad4033 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_ord_ore.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_double_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer.json index 92d36fa97..15ba554eb 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_eq.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_eq.json index 7a07dc8dc..7d83e20ea 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_eq.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_ord.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_ord.json index 096415e90..40684c7df 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_ord.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_ord_ope.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_ord_ope.json index 7a9173d07..bec37060d 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_ord_ope.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_ord_ore.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_ord_ore.json index b270f38f9..3cdd5a4f9 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_ord_ore.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_integer_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_json.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_json.json index 5a206f9d9..67a7488ba 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_json.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_json.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric.json index 8d2d08a06..fb76317a5 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_eq.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_eq.json index 741c95904..de4c798bc 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_eq.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_ord.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_ord.json index ae0074cf0..de1e85247 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_ord.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_ord_ope.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_ord_ope.json index 2ffee02ff..09886d191 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_ord_ope.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_ord_ore.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_ord_ore.json index 9db393f7a..e3ad24415 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_ord_ore.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_numeric_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real.json index 52da42ac2..7e12f7197 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_eq.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_eq.json index ce0f03141..a0d474ca5 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_eq.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_ord.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_ord.json index 69aeb260e..08ab922bb 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_ord.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_ord_ope.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_ord_ope.json index 548832cd3..d6bc7fdec 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_ord_ope.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_ord_ore.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_ord_ore.json index c6b5ca349..bc8fdd5d8 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_ord_ore.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_real_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint.json index f04378a6f..7d3e346b4 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_eq.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_eq.json index a793597d4..342927953 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_eq.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_ord.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_ord.json index 5e95b20ac..806ef68d3 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_ord.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_ord_ope.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_ord_ope.json index 63f1b3dd2..627c73238 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_ord_ope.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_ord_ore.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_ord_ore.json index 8b84af97c..395c2a733 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_ord_ore.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_smallint_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text.json index 60a7fdafd..e50fcb359 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_eq.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_eq.json index b7d94f830..89be47f98 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_eq.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_match.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_match.json index e7f9f34cf..df5e41012 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_match.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_match.json @@ -11,7 +11,7 @@ "type": "array" }, "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_ord.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_ord.json index 7ef5a1242..efd68d5b7 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_ord.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_ord_ope.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_ord_ope.json index 0d6a0ab29..10151de25 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_ord_ope.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_ord_ore.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_ord_ore.json index 5f97ccc7d..ccd48ea8b 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_ord_ore.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_search.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_search.json index ee05c7bfc..bd942a291 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_search.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_search.json @@ -11,7 +11,7 @@ "type": "array" }, "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_search_ore.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_search_ore.json index 17121f697..3567eac0d 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_search_ore.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_text_search_ore.json @@ -11,7 +11,7 @@ "type": "array" }, "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp.json index 16e97bd9d..853050330 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_eq.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_eq.json index c76a60ade..97e064b29 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_eq.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_ord.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_ord.json index e0a74f83a..4462017f6 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_ord.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_ord_ope.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_ord_ope.json index cdf411d46..da2ae0deb 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_ord_ope.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_ord_ore.json b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_ord_ore.json index 0a286d1c1..e5c5eefcc 100644 --- a/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_ord_ore.json +++ b/packages/eql/crates/eql-bindings/schema/v3/eql_v3_timestamp_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/crates/eql-bindings/src/encryption.rs b/packages/eql/crates/eql-bindings/src/encryption.rs new file mode 100644 index 000000000..553796c4e --- /dev/null +++ b/packages/eql/crates/eql-bindings/src/encryption.rs @@ -0,0 +1,225 @@ +//! Opt-in Stack Encrypt support for [`TextEq`] and [`TextEqQuery`]. +//! +//! The target declares its operations; Stack Encrypt invokes Vitamin C's +//! plaintext implementations. These adapters only encode encrypted outputs. +//! Equality uses Vitamin C's exact string semantics: no normalization or case +//! folding. The stored identifier supplies context for ciphertext and terms. +//! +//! This is a new producer profile, independent of existing cipherstash-client +//! ciphertext and terms. The EQL envelope and SQL domains remain unchanged. +//! +//! [`TextEq`]: crate::v3::text::TextEq +//! [`TextEqQuery`]: crate::v3::text::TextEqQuery +//! +//! # Example +//! +//! Enable the `stack-encrypt` feature on `eql-bindings`. Both targets accept +//! a [`String`] as plaintext and a [`NonEmpty`] as context. +//! [`Identifier::for_column`] validates the table and column; the returned +//! identifier is passed directly to `encrypt_as` and stored in the output's `i`. +//! The output type selects the encryption operations: [`TextEq`] includes +//! ciphertext and an equality term, while [`TextEqQuery`] contains only the term. +//! +//! This complete example runs locally without credentials. It uses real +//! encryption with `stack_kms::FakeDataKeySource`, whose keys exist only for +//! this process. Add `stack-encrypt`, `stack-kms` (with `default-features = false` +//! and `features = ["test-support"]`), and `tokio` (with `features = ["rt", "macros"]`) +//! to your example's dependencies. Stack Encrypt is currently unpublished; +//! use the local development helper described in the crate README. +//! +//! The code below is executed by `cargo test -p eql-encryption-tests --test +//! text_eq_example`. It is excluded from this crate's doctests so its optional +//! test key source and runtime remain in the separate encryption test crate. +#![doc = concat!("```rust,ignore\n", include_str!("encryption/example.rs"), "\n```")] +//! +//! For ZeroKMS, enable Stack Encrypt's `http` feature and replace the fake-key +//! builder with `StackCipher::new().await?`, using your configured CipherStash +//! credentials. The encryption and decryption calls are identical. +//! +//! Use the same table and column identifier for writes and queries. Passing +//! `column.into()` on decryption also checks that the stored identifier matches +//! the expected destination before retrieving keys. `Default::default()` instead +//! uses the stored identifier alone. +//! +//! # Unsupported conversions +//! +//! Query terms cannot recover plaintext: +//! ```compile_fail +//! use eql_bindings::v3::text::TextEqQuery; +//! fn require>() {} +//! require::(); +//! ``` +//! An encrypted EQL record is not a plaintext value: +//! ```compile_fail +//! use eql_bindings::v3::text::TextEq; +//! fn require() {} +//! require::(); +//! ``` +//! The text domain accepts text, and requires a concrete column identifier: +//! ```compile_fail +//! use eql_bindings::v3::text::TextEq; +//! fn require>() {} +//! require::(); +//! ``` +//! ```compile_fail +//! use eql_bindings::v3::text::TextEq; +//! fn require>() {} +//! require::(); +//! ``` + +use base64::{engine::general_purpose::STANDARD, Engine as _}; +use stack_encrypt::sem::EqualityTerm; +use stack_encrypt::target::transcode::{Reader, Transcode, Visitor}; +use stack_encrypt::target::{self, AeadContext, CallerContext}; +use stack_encrypt::{ + Aad, AadPiece, CipherText, Decrypt, DecryptField, DecryptInto, Decryptable, Decryption, + Encrypt, EncryptFrom, Encryption, Error, IntoAad, IntoPrfContext, MaybeEmpty, NonEmpty, + PrfContext, SealedValue, StackCipherText, +}; +use vitaminc_prf::PrfValue; + +use crate::{ + v3::terms::{Ciphertext, Hmac256}, + Identifier, +}; + +// An explicit producer/version marker prevents a legacy EQL ciphertext from +// being interpreted as a native Stack Encrypt leaf. The body is base64 of the +// cipher's own SealedValue encoding, never a serialization of the plaintext. +const CIPHERTEXT_PREFIX: &str = "stack-encrypt:1:"; + +fn codec(error: impl std::error::Error + Send + Sync + 'static) -> Error { + Error::Other(Box::new(error)) +} + +impl Identifier { + /// Validate the table and column used for writes and equality probes. + pub fn for_column( + table: impl Into, + column: impl Into, + ) -> Result, stack_encrypt::EmptyError> { + NonEmpty::new(Self { + t: table.into(), + c: column.into(), + }) + } +} + +impl MaybeEmpty for Identifier { + fn is_empty(&self) -> bool { + self.t.is_empty() || self.c.is_empty() + } +} +impl<'a> IntoAad<'a> for Identifier { + fn into_aad(self) -> Aad<'a> { + (self.t, self.c).into_aad() + } + fn into_aad_piece(self) -> AadPiece<'a> { + (self.t, self.c).into_aad_piece() + } +} +impl<'a> IntoPrfContext<'a> for Identifier { + fn into_prf_context(self) -> PrfContext<'a> { + (self.t, self.c).into_prf_context() + } +} + +/// Builds the final EQL ciphertext string from a native sealed leaf. +#[doc(hidden)] +pub struct CiphertextVisitor; +impl Visitor for CiphertextVisitor { + type Value = Ciphertext; + fn sealed(self, leaf: SealedValue) -> Result { + let mut encoded = String::from(CIPHERTEXT_PREFIX); + STANDARD.encode_string(leaf.to_bytes(), &mut encoded); + Ok(Ciphertext(encoded)) + } +} +impl Transcode for Ciphertext { + type Visitor = CiphertextVisitor; + fn visitor() -> Self::Visitor { + CiphertextVisitor + } +} +impl Reader for Ciphertext { + fn read(self, visitor: V) -> Result { + let body = self + .0 + .strip_prefix(CIPHERTEXT_PREFIX) + .ok_or_else(|| Error::Other("unsupported EQL ciphertext producer or version".into()))?; + let bytes = STANDARD.decode(body).map_err(codec)?; + visitor.sealed(SealedValue::from_bytes(&bytes).map_err(codec)?) + } +} + +impl EncryptFrom for Ciphertext { + type Context = AeadContext; + fn encryption<'s, K: 'static>(context: Self::Context) -> Encryption<'s, S, Self, K> + where + S: 's, + { + target::ciphertext(context).transcode() + } +} + +struct NativeCiphertextVisitor; +impl Visitor for NativeCiphertextVisitor { + type Value = StackCipherText; + fn sealed(self, leaf: SealedValue) -> Result { + Ok(CipherText::Single(leaf)) + } +} +impl + 'static> DecryptInto

for Ciphertext { + type Context = AeadContext; + fn decryption(self, context: Self::Context) -> Decryption { + match self.read(NativeCiphertextVisitor) { + Ok(native) => target::open(native, context), + Err(error) => Decryption::failed(error), + } + } +} +impl Decryptable for Ciphertext { + const DECRYPTABLE: bool = true; +} +impl DecryptField for Ciphertext +where + Self: DecryptInto

, + Ctx: Into<>::Context>, +{ + fn decryption_field(self, context: Ctx) -> Option> { + Some(self.decryption(context.into())) + } +} + +/// Builds EQL's hex equality term from the native HMAC output. +#[doc(hidden)] +pub struct EqualityVisitor; +impl Visitor for EqualityVisitor { + type Value = Hmac256; + fn equality(self, term: EqualityTerm) -> Result { + Ok(Hmac256(hex::encode(term.as_bytes()))) + } +} +impl Transcode for Hmac256 { + type Visitor = EqualityVisitor; + fn visitor() -> Self::Visitor { + EqualityVisitor + } +} +impl EncryptFrom for Hmac256 { + type Context = CallerContext; + fn encryption<'s, K: 'static>(context: Self::Context) -> Encryption<'s, S, Self, K> + where + S: 's, + { + target::equality(context).transcode() + } +} +impl Decryptable for Hmac256 { + const DECRYPTABLE: bool = false; +} +impl DecryptField for Hmac256 { + fn decryption_field(self, _: Ctx) -> Option> { + None + } +} diff --git a/packages/eql/crates/eql-bindings/src/encryption/example.rs b/packages/eql/crates/eql-bindings/src/encryption/example.rs new file mode 100644 index 000000000..58a482b94 --- /dev/null +++ b/packages/eql/crates/eql-bindings/src/encryption/example.rs @@ -0,0 +1,32 @@ +use eql_bindings::{ + v3::text::{TextEq, TextEqQuery}, + Identifier, +}; +use stack_encrypt::StackCipher; +use stack_kms::FakeDataKeySource; + +#[tokio::main(flavor = "current_thread")] +async fn main() -> Result<(), Box> { + // Local example only: these keys are held in memory, not in ZeroKMS. + let cipher = StackCipher::builder() + .kms(FakeDataKeySource::new()) + .init() + .await?; + let keyset = cipher.default_keyset(); + let column = Identifier::for_column("users", "email")?; + let email = String::from("alice@example.com"); + + // The output type selects ciphertext plus the equality term. + let stored: TextEq = keyset.encrypt_as(&email, column.clone()).await?; + assert_eq!(stored.i.t, "users"); + assert_eq!(stored.i.c, "email"); + + // Use the same identifier to produce an equality query for this column. + let query: TextEqQuery = keyset.encrypt_as(&email, column.clone()).await?; + assert_eq!(stored.hm, query.hm); + + // Decrypt to String, also checking the expected table and column. + let opened: String = cipher.decrypt_as(stored, column.into()).await?; + assert_eq!(opened, email); + Ok(()) +} diff --git a/packages/eql/crates/eql-bindings/src/lib.rs b/packages/eql/crates/eql-bindings/src/lib.rs index 7846e5807..b88f65b61 100644 --- a/packages/eql/crates/eql-bindings/src/lib.rs +++ b/packages/eql/crates/eql-bindings/src/lib.rs @@ -25,6 +25,13 @@ //! //! Wire rule: **field names ARE wire names** — no `#[serde(rename)]` //! anywhere. The struct definition reads exactly like the JSON payload. +//! +//! Enable the `stack-encrypt` feature to encrypt Rust strings into `TextEq` +//! storage values and `TextEqQuery` search values. +#![cfg_attr( + feature = "stack-encrypt", + doc = "See the [complete encryption example](encryption#example), including cipher setup, table/column identifiers, and decryption." +)] use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -34,6 +41,9 @@ pub mod from_v2; pub mod sql; pub mod v3; +#[cfg(feature = "stack-encrypt")] +pub mod encryption; + /// EQL wire-format version. Hard-coded to `3` for every payload in the /// [`v3`] tier, whose generated domain CHECKs assert `VALUE->>'v' = '3'`. /// (The legacy `eql_v2` wire stays `v: 2` — see diff --git a/packages/eql/crates/eql-bindings/src/v3/bigint.rs b/packages/eql/crates/eql-bindings/src/v3/bigint.rs index 62ae38ffe..cf9b64b1b 100644 --- a/packages/eql/crates/eql-bindings/src/v3/bigint.rs +++ b/packages/eql/crates/eql-bindings/src/v3/bigint.rs @@ -9,6 +9,11 @@ use ts_rs::TS; /// `public.eql_v3_bigint` — storage-only domain. /// /// Operators: none. Required keys: `v` `i` `c`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL bigint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -40,6 +45,11 @@ impl DomainType for Bigint { /// `public.eql_v3_bigint_eq` — equality domain. /// /// Operators: `=` `<>`. Required keys: `v` `i` `c` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL bigint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -72,6 +82,11 @@ impl DomainType for BigintEq { /// `public.eql_v3_bigint_ord_ore` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL bigint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -104,6 +119,11 @@ impl DomainType for BigintOrdOre { /// `public.eql_v3_bigint_ord` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL bigint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -136,6 +156,11 @@ impl DomainType for BigintOrd { /// `public.eql_v3_bigint_ord_ope` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL bigint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -168,6 +193,11 @@ impl DomainType for BigintOrdOpe { /// `eql_v3.query_bigint_eq` — equality domain query operand. /// /// Operators: `=` `<>`. Required keys: `v` `i` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL bigint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -199,6 +229,11 @@ impl DomainType for BigintEqQuery { /// `eql_v3.query_bigint_ord_ore` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL bigint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -230,6 +265,11 @@ impl DomainType for BigintOrdOreQuery { /// `eql_v3.query_bigint_ord` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL bigint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -261,6 +301,11 @@ impl DomainType for BigintOrdQuery { /// `eql_v3.query_bigint_ord_ope` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL bigint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] diff --git a/packages/eql/crates/eql-bindings/src/v3/boolean.rs b/packages/eql/crates/eql-bindings/src/v3/boolean.rs index 2a64a6046..98eb74eb9 100644 --- a/packages/eql/crates/eql-bindings/src/v3/boolean.rs +++ b/packages/eql/crates/eql-bindings/src/v3/boolean.rs @@ -9,6 +9,11 @@ use ts_rs::TS; /// `public.eql_v3_boolean` — storage-only domain. /// /// Operators: none. Required keys: `v` `i` `c`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL boolean reference](https://cipherstash.com/docs/reference/eql/booleans) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] diff --git a/packages/eql/crates/eql-bindings/src/v3/date.rs b/packages/eql/crates/eql-bindings/src/v3/date.rs index c85bedc34..1c112e073 100644 --- a/packages/eql/crates/eql-bindings/src/v3/date.rs +++ b/packages/eql/crates/eql-bindings/src/v3/date.rs @@ -9,6 +9,11 @@ use ts_rs::TS; /// `public.eql_v3_date` — storage-only domain. /// /// Operators: none. Required keys: `v` `i` `c`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL date reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -40,6 +45,11 @@ impl DomainType for Date { /// `public.eql_v3_date_eq` — equality domain. /// /// Operators: `=` `<>`. Required keys: `v` `i` `c` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL date reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -72,6 +82,11 @@ impl DomainType for DateEq { /// `public.eql_v3_date_ord_ore` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL date reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -104,6 +119,11 @@ impl DomainType for DateOrdOre { /// `public.eql_v3_date_ord` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL date reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -136,6 +156,11 @@ impl DomainType for DateOrd { /// `public.eql_v3_date_ord_ope` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL date reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -168,6 +193,11 @@ impl DomainType for DateOrdOpe { /// `eql_v3.query_date_eq` — equality domain query operand. /// /// Operators: `=` `<>`. Required keys: `v` `i` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL date reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -199,6 +229,11 @@ impl DomainType for DateEqQuery { /// `eql_v3.query_date_ord_ore` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL date reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -230,6 +265,11 @@ impl DomainType for DateOrdOreQuery { /// `eql_v3.query_date_ord` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL date reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -261,6 +301,11 @@ impl DomainType for DateOrdQuery { /// `eql_v3.query_date_ord_ope` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL date reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] diff --git a/packages/eql/crates/eql-bindings/src/v3/double.rs b/packages/eql/crates/eql-bindings/src/v3/double.rs index 7564d5614..d45cf48a4 100644 --- a/packages/eql/crates/eql-bindings/src/v3/double.rs +++ b/packages/eql/crates/eql-bindings/src/v3/double.rs @@ -9,6 +9,11 @@ use ts_rs::TS; /// `public.eql_v3_double` — storage-only domain. /// /// Operators: none. Required keys: `v` `i` `c`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL double reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -40,6 +45,11 @@ impl DomainType for Double { /// `public.eql_v3_double_eq` — equality domain. /// /// Operators: `=` `<>`. Required keys: `v` `i` `c` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL double reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -72,6 +82,11 @@ impl DomainType for DoubleEq { /// `public.eql_v3_double_ord_ore` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL double reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -104,6 +119,11 @@ impl DomainType for DoubleOrdOre { /// `public.eql_v3_double_ord` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL double reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -136,6 +156,11 @@ impl DomainType for DoubleOrd { /// `public.eql_v3_double_ord_ope` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL double reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -168,6 +193,11 @@ impl DomainType for DoubleOrdOpe { /// `eql_v3.query_double_eq` — equality domain query operand. /// /// Operators: `=` `<>`. Required keys: `v` `i` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL double reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -199,6 +229,11 @@ impl DomainType for DoubleEqQuery { /// `eql_v3.query_double_ord_ore` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL double reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -230,6 +265,11 @@ impl DomainType for DoubleOrdOreQuery { /// `eql_v3.query_double_ord` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL double reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -261,6 +301,11 @@ impl DomainType for DoubleOrdQuery { /// `eql_v3.query_double_ord_ope` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL double reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] diff --git a/packages/eql/crates/eql-bindings/src/v3/integer.rs b/packages/eql/crates/eql-bindings/src/v3/integer.rs index 12db55037..19ad4516e 100644 --- a/packages/eql/crates/eql-bindings/src/v3/integer.rs +++ b/packages/eql/crates/eql-bindings/src/v3/integer.rs @@ -9,6 +9,11 @@ use ts_rs::TS; /// `public.eql_v3_integer` — storage-only domain. /// /// Operators: none. Required keys: `v` `i` `c`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL integer reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -40,6 +45,11 @@ impl DomainType for Integer { /// `public.eql_v3_integer_eq` — equality domain. /// /// Operators: `=` `<>`. Required keys: `v` `i` `c` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL integer reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -72,6 +82,11 @@ impl DomainType for IntegerEq { /// `public.eql_v3_integer_ord_ore` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL integer reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -104,6 +119,11 @@ impl DomainType for IntegerOrdOre { /// `public.eql_v3_integer_ord` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL integer reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -136,6 +156,11 @@ impl DomainType for IntegerOrd { /// `public.eql_v3_integer_ord_ope` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL integer reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -168,6 +193,11 @@ impl DomainType for IntegerOrdOpe { /// `eql_v3.query_integer_eq` — equality domain query operand. /// /// Operators: `=` `<>`. Required keys: `v` `i` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL integer reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -199,6 +229,11 @@ impl DomainType for IntegerEqQuery { /// `eql_v3.query_integer_ord_ore` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL integer reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -230,6 +265,11 @@ impl DomainType for IntegerOrdOreQuery { /// `eql_v3.query_integer_ord` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL integer reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -261,6 +301,11 @@ impl DomainType for IntegerOrdQuery { /// `eql_v3.query_integer_ord_ope` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL integer reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] diff --git a/packages/eql/crates/eql-bindings/src/v3/json.rs b/packages/eql/crates/eql-bindings/src/v3/json.rs index c53f2348d..3ae7642ff 100644 --- a/packages/eql/crates/eql-bindings/src/v3/json.rs +++ b/packages/eql/crates/eql-bindings/src/v3/json.rs @@ -86,6 +86,11 @@ impl JsonSchema for SteVecForm { /// stored once for the whole document (every entry encrypts under the /// document's single data key, with per-entry nonces derived from the /// entries' selectors). +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = "See the [EQL JSON reference](https://cipherstash.com/docs/reference/eql/json) for document storage and containment queries." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -107,6 +112,11 @@ pub struct SteVecDocument { /// presence, so no per-entry equality term exists (`hm` is retired). The /// optional `i`/`v`/`h` fields model metadata grafted onto an entry returned by /// `->`; naming them explicitly keeps unknown keys rejectable. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = "See the [EQL JSON reference](https://cipherstash.com/docs/reference/eql/json) for encrypted field access." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -136,6 +146,11 @@ pub struct SteVecEntry { } /// `eql_v3.query_json` — a containment needle (`{sv:[query-entry]}`). Strict. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = "See the [EQL JSON reference](https://cipherstash.com/docs/reference/eql/json) for containment queries." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -148,6 +163,11 @@ pub struct SteVecQuery { /// entries are selector-only (matched on presence), and (per the SQL CHECK) /// no element carries a ciphertext. Unknown fields are rejected so the Rust /// parser and published JSON Schema enforce the same boundary as PostgreSQL. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = "See the [EQL JSON reference](https://cipherstash.com/docs/reference/eql/json) for containment query entries." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] diff --git a/packages/eql/crates/eql-bindings/src/v3/json_storage.rs b/packages/eql/crates/eql-bindings/src/v3/json_storage.rs index 4a969edb5..a9934edd9 100644 --- a/packages/eql/crates/eql-bindings/src/v3/json_storage.rs +++ b/packages/eql/crates/eql-bindings/src/v3/json_storage.rs @@ -9,6 +9,11 @@ use ts_rs::TS; /// `public.eql_v3_json` — storage-only domain. /// /// Operators: none. Required keys: `v` `i` `c`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL json reference](https://cipherstash.com/docs/reference/eql/json) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] diff --git a/packages/eql/crates/eql-bindings/src/v3/numeric.rs b/packages/eql/crates/eql-bindings/src/v3/numeric.rs index b55989fd7..835b322cf 100644 --- a/packages/eql/crates/eql-bindings/src/v3/numeric.rs +++ b/packages/eql/crates/eql-bindings/src/v3/numeric.rs @@ -9,6 +9,11 @@ use ts_rs::TS; /// `public.eql_v3_numeric` — storage-only domain. /// /// Operators: none. Required keys: `v` `i` `c`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL numeric reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -40,6 +45,11 @@ impl DomainType for Numeric { /// `public.eql_v3_numeric_eq` — equality domain. /// /// Operators: `=` `<>`. Required keys: `v` `i` `c` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL numeric reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -72,6 +82,11 @@ impl DomainType for NumericEq { /// `public.eql_v3_numeric_ord_ore` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL numeric reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -104,6 +119,11 @@ impl DomainType for NumericOrdOre { /// `public.eql_v3_numeric_ord` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL numeric reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -136,6 +156,11 @@ impl DomainType for NumericOrd { /// `public.eql_v3_numeric_ord_ope` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL numeric reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -168,6 +193,11 @@ impl DomainType for NumericOrdOpe { /// `eql_v3.query_numeric_eq` — equality domain query operand. /// /// Operators: `=` `<>`. Required keys: `v` `i` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL numeric reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -199,6 +229,11 @@ impl DomainType for NumericEqQuery { /// `eql_v3.query_numeric_ord_ore` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL numeric reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -230,6 +265,11 @@ impl DomainType for NumericOrdOreQuery { /// `eql_v3.query_numeric_ord` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL numeric reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -261,6 +301,11 @@ impl DomainType for NumericOrdQuery { /// `eql_v3.query_numeric_ord_ope` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL numeric reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] diff --git a/packages/eql/crates/eql-bindings/src/v3/real.rs b/packages/eql/crates/eql-bindings/src/v3/real.rs index 186d98699..a118fdff9 100644 --- a/packages/eql/crates/eql-bindings/src/v3/real.rs +++ b/packages/eql/crates/eql-bindings/src/v3/real.rs @@ -9,6 +9,11 @@ use ts_rs::TS; /// `public.eql_v3_real` — storage-only domain. /// /// Operators: none. Required keys: `v` `i` `c`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL real reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -40,6 +45,11 @@ impl DomainType for Real { /// `public.eql_v3_real_eq` — equality domain. /// /// Operators: `=` `<>`. Required keys: `v` `i` `c` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL real reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -72,6 +82,11 @@ impl DomainType for RealEq { /// `public.eql_v3_real_ord_ore` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL real reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -104,6 +119,11 @@ impl DomainType for RealOrdOre { /// `public.eql_v3_real_ord` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL real reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -136,6 +156,11 @@ impl DomainType for RealOrd { /// `public.eql_v3_real_ord_ope` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL real reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -168,6 +193,11 @@ impl DomainType for RealOrdOpe { /// `eql_v3.query_real_eq` — equality domain query operand. /// /// Operators: `=` `<>`. Required keys: `v` `i` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL real reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -199,6 +229,11 @@ impl DomainType for RealEqQuery { /// `eql_v3.query_real_ord_ore` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL real reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -230,6 +265,11 @@ impl DomainType for RealOrdOreQuery { /// `eql_v3.query_real_ord` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL real reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -261,6 +301,11 @@ impl DomainType for RealOrdQuery { /// `eql_v3.query_real_ord_ope` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL real reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] diff --git a/packages/eql/crates/eql-bindings/src/v3/smallint.rs b/packages/eql/crates/eql-bindings/src/v3/smallint.rs index e6ca7dec8..fe69cfaec 100644 --- a/packages/eql/crates/eql-bindings/src/v3/smallint.rs +++ b/packages/eql/crates/eql-bindings/src/v3/smallint.rs @@ -9,6 +9,11 @@ use ts_rs::TS; /// `public.eql_v3_smallint` — storage-only domain. /// /// Operators: none. Required keys: `v` `i` `c`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL smallint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -40,6 +45,11 @@ impl DomainType for Smallint { /// `public.eql_v3_smallint_eq` — equality domain. /// /// Operators: `=` `<>`. Required keys: `v` `i` `c` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL smallint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -72,6 +82,11 @@ impl DomainType for SmallintEq { /// `public.eql_v3_smallint_ord_ore` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL smallint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -104,6 +119,11 @@ impl DomainType for SmallintOrdOre { /// `public.eql_v3_smallint_ord` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL smallint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -136,6 +156,11 @@ impl DomainType for SmallintOrd { /// `public.eql_v3_smallint_ord_ope` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL smallint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -168,6 +193,11 @@ impl DomainType for SmallintOrdOpe { /// `eql_v3.query_smallint_eq` — equality domain query operand. /// /// Operators: `=` `<>`. Required keys: `v` `i` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL smallint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -199,6 +229,11 @@ impl DomainType for SmallintEqQuery { /// `eql_v3.query_smallint_ord_ore` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL smallint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -230,6 +265,11 @@ impl DomainType for SmallintOrdOreQuery { /// `eql_v3.query_smallint_ord` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL smallint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -261,6 +301,11 @@ impl DomainType for SmallintOrdQuery { /// `eql_v3.query_smallint_ord_ope` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL smallint reference](https://cipherstash.com/docs/reference/eql/numbers) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] diff --git a/packages/eql/crates/eql-bindings/src/v3/terms.rs b/packages/eql/crates/eql-bindings/src/v3/terms.rs index e2300f302..1e9d97de7 100644 --- a/packages/eql/crates/eql-bindings/src/v3/terms.rs +++ b/packages/eql/crates/eql-bindings/src/v3/terms.rs @@ -15,7 +15,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use ts_rs::TS; -/// mp_base85 source ciphertext — the `c` envelope key. +/// Producer-encoded source ciphertext — the `c` envelope key. /// /// Required by every v3 domain CHECK; present on every payload. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, TS, JsonSchema)] diff --git a/packages/eql/crates/eql-bindings/src/v3/text.rs b/packages/eql/crates/eql-bindings/src/v3/text.rs index de7ce7b2c..504fc4646 100644 --- a/packages/eql/crates/eql-bindings/src/v3/text.rs +++ b/packages/eql/crates/eql-bindings/src/v3/text.rs @@ -9,6 +9,11 @@ use ts_rs::TS; /// `public.eql_v3_text` — storage-only domain. /// /// Operators: none. Required keys: `v` `i` `c`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL text reference](https://cipherstash.com/docs/reference/eql/text) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -40,11 +45,34 @@ impl DomainType for Text { /// `public.eql_v3_text_eq` — equality domain. /// /// Operators: `=` `<>`. Required keys: `v` `i` `c` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL text reference](https://cipherstash.com/docs/reference/eql/text) for SQL domain variants, operators, and query examples." +)] +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " Plaintext input and decrypted output: [`String`]. With the `stack-encrypt` feature, implements `EncryptFrom` and `DecryptInto`." +)] +#[cfg_attr( + doc, + doc = " Encryption context: `NonEmpty`, constructed with `Identifier::for_column(table, column)` and stored in `i`." +)] +#[cfg_attr( + all(doc, feature = "stack-encrypt"), + doc = " See the [complete encryption example](crate::encryption#example)." +)] +#[cfg_attr(feature = "stack-encrypt", derive(stack_encrypt::EncryptFrom))] +#[cfg_attr(feature = "stack-encrypt", derive(stack_encrypt::DecryptInto))] +#[cfg_attr(feature = "stack-encrypt", stash(plaintext = String))] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] pub struct TextEq { + #[cfg_attr(feature = "stack-encrypt", stash(default))] pub v: SchemaVersion, + #[cfg_attr(feature = "stack-encrypt", stash(context_field))] pub i: Identifier, pub c: Ciphertext, pub hm: Hmac256, @@ -72,6 +100,11 @@ impl DomainType for TextEq { /// `public.eql_v3_text_match` — match domain. /// /// Operators: `@@`. Required keys: `v` `i` `c` `bf`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL text reference](https://cipherstash.com/docs/reference/eql/text) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -104,6 +137,11 @@ impl DomainType for TextMatch { /// `public.eql_v3_text_ord_ore` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `hm` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL text reference](https://cipherstash.com/docs/reference/eql/text) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -137,6 +175,11 @@ impl DomainType for TextOrdOre { /// `public.eql_v3_text_ord` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `hm` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL text reference](https://cipherstash.com/docs/reference/eql/text) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -170,6 +213,11 @@ impl DomainType for TextOrd { /// `public.eql_v3_text_ord_ope` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `hm` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL text reference](https://cipherstash.com/docs/reference/eql/text) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -203,6 +251,11 @@ impl DomainType for TextOrdOpe { /// `public.eql_v3_text_search_ore` — search domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=` `@@`. Required keys: `v` `i` `c` `hm` `ob` `bf`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL text reference](https://cipherstash.com/docs/reference/eql/text) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -237,6 +290,11 @@ impl DomainType for TextSearchOre { /// `public.eql_v3_text_search` — search domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=` `@@`. Required keys: `v` `i` `c` `hm` `op` `bf`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL text reference](https://cipherstash.com/docs/reference/eql/text) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -271,11 +329,33 @@ impl DomainType for TextSearch { /// `eql_v3.query_text_eq` — equality domain query operand. /// /// Operators: `=` `<>`. Required keys: `v` `i` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL text reference](https://cipherstash.com/docs/reference/eql/text) for SQL domain variants, operators, and query examples." +)] +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " Plaintext input: [`String`]. With the `stack-encrypt` feature, implements `EncryptFrom` to build equality query terms. Query operands do not decrypt." +)] +#[cfg_attr( + doc, + doc = " Encryption context: `NonEmpty`, constructed with `Identifier::for_column(table, column)` and stored in `i`." +)] +#[cfg_attr( + all(doc, feature = "stack-encrypt"), + doc = " See the [complete encryption example](crate::encryption#example)." +)] +#[cfg_attr(feature = "stack-encrypt", derive(stack_encrypt::EncryptFrom))] +#[cfg_attr(feature = "stack-encrypt", stash(plaintext = String))] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] pub struct TextEqQuery { + #[cfg_attr(feature = "stack-encrypt", stash(default))] pub v: SchemaVersion, + #[cfg_attr(feature = "stack-encrypt", stash(context_field))] pub i: Identifier, pub hm: Hmac256, } @@ -302,6 +382,11 @@ impl DomainType for TextEqQuery { /// `eql_v3.query_text_match` — match domain query operand. /// /// Operators: `@@`. Required keys: `v` `i` `bf`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL text reference](https://cipherstash.com/docs/reference/eql/text) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -333,6 +418,11 @@ impl DomainType for TextMatchQuery { /// `eql_v3.query_text_ord_ore` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `hm` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL text reference](https://cipherstash.com/docs/reference/eql/text) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -365,6 +455,11 @@ impl DomainType for TextOrdOreQuery { /// `eql_v3.query_text_ord` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `hm` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL text reference](https://cipherstash.com/docs/reference/eql/text) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -397,6 +492,11 @@ impl DomainType for TextOrdQuery { /// `eql_v3.query_text_ord_ope` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `hm` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL text reference](https://cipherstash.com/docs/reference/eql/text) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -429,6 +529,11 @@ impl DomainType for TextOrdOpeQuery { /// `eql_v3.query_text_search_ore` — search domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=` `@@`. Required keys: `v` `i` `hm` `ob` `bf`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL text reference](https://cipherstash.com/docs/reference/eql/text) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -462,6 +567,11 @@ impl DomainType for TextSearchOreQuery { /// `eql_v3.query_text_search` — search domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=` `@@`. Required keys: `v` `i` `hm` `op` `bf`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL text reference](https://cipherstash.com/docs/reference/eql/text) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] diff --git a/packages/eql/crates/eql-bindings/src/v3/timestamp.rs b/packages/eql/crates/eql-bindings/src/v3/timestamp.rs index 33284a5c3..de022873d 100644 --- a/packages/eql/crates/eql-bindings/src/v3/timestamp.rs +++ b/packages/eql/crates/eql-bindings/src/v3/timestamp.rs @@ -9,6 +9,11 @@ use ts_rs::TS; /// `public.eql_v3_timestamp` — storage-only domain. /// /// Operators: none. Required keys: `v` `i` `c`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL timestamp reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -40,6 +45,11 @@ impl DomainType for Timestamp { /// `public.eql_v3_timestamp_eq` — equality domain. /// /// Operators: `=` `<>`. Required keys: `v` `i` `c` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL timestamp reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -72,6 +82,11 @@ impl DomainType for TimestampEq { /// `public.eql_v3_timestamp_ord_ore` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL timestamp reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -104,6 +119,11 @@ impl DomainType for TimestampOrdOre { /// `public.eql_v3_timestamp_ord` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL timestamp reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -136,6 +156,11 @@ impl DomainType for TimestampOrd { /// `public.eql_v3_timestamp_ord_ope` — ordering domain. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `c` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL timestamp reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -168,6 +193,11 @@ impl DomainType for TimestampOrdOpe { /// `eql_v3.query_timestamp_eq` — equality domain query operand. /// /// Operators: `=` `<>`. Required keys: `v` `i` `hm`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL timestamp reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -199,6 +229,11 @@ impl DomainType for TimestampEqQuery { /// `eql_v3.query_timestamp_ord_ore` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `ob`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL timestamp reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -230,6 +265,11 @@ impl DomainType for TimestampOrdOreQuery { /// `eql_v3.query_timestamp_ord` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL timestamp reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -261,6 +301,11 @@ impl DomainType for TimestampOrdQuery { /// `eql_v3.query_timestamp_ord_ope` — ordering domain query operand. /// /// Operators: `=` `<>` `<` `<=` `>` `>=`. Required keys: `v` `i` `op`. +#[cfg_attr(doc, doc = "")] +#[cfg_attr( + doc, + doc = " See the [EQL timestamp reference](https://cipherstash.com/docs/reference/eql/dates-and-times) for SQL domain variants, operators, and query examples." +)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] diff --git a/packages/eql/crates/eql-codegen/src/bindings.rs b/packages/eql/crates/eql-codegen/src/bindings.rs index 271fd71ee..84bdedea5 100644 --- a/packages/eql/crates/eql-codegen/src/bindings.rs +++ b/packages/eql/crates/eql-codegen/src/bindings.rs @@ -126,6 +126,29 @@ fn struct_doc_lines(full: &str, domain: &Domain) -> [String; 3] { [summary, String::new(), detail] } +/// Rust API navigation, separate from the shared wire-format descriptions +/// exported to TypeScript and JSON Schema. The site groups domain variants by +/// plaintext family, including their query operands. +fn reference_docs(family: &DomainFamily) -> TokenStream { + let page = match family.name { + "integer" | "smallint" | "bigint" | "numeric" | "real" | "double" => "numbers", + "date" | "timestamp" => "dates-and-times", + "text" => "text", + "boolean" => "booleans", + "json" => "json", + other => panic!("missing CipherStash documentation page for {other:?}"), + }; + let reference = format!( + " See the [EQL {} reference](https://cipherstash.com/docs/reference/eql/{page}) \ + for SQL domain variants, operators, and query examples.", + family.name + ); + quote! { + #[cfg_attr(doc, doc = "")] + #[cfg_attr(doc, doc = #reference)] + } +} + /// One payload struct + its three-method `DomainType` impl. A catalog-derived /// struct doc (summary + operators + required keys — see [`struct_doc_lines`]), /// no field docs. Term fields come from `Term::payload_terms`, matching on the @@ -136,6 +159,8 @@ fn render_struct(family: &DomainFamily, domain: &Domain) -> TokenStream { let ident = format_ident!("{}", domain.struct_ident(family.name)); let sql_domain = crate::context::domain_name(&full); let [doc_summary, doc_blank, doc_detail] = struct_doc_lines(&full, domain); + let reference = reference_docs(family); + let (encryption, version, context) = encryption_attrs(family, domain, false); // The envelope triple is hardcoded (not looped over `ENVELOPE_KEYS`) because // each key maps to a distinct Rust type: `v: SchemaVersion`, `i: Identifier`, @@ -143,8 +168,8 @@ fn render_struct(family: &DomainFamily, domain: &Domain) -> TokenStream { // `eql_domains::ENVELOPE_KEYS` — `envelope_fields_match_catalog_keys` (below) // fails if that ever diverges. let mut fields = TokenStream::new(); - fields.extend(quote! { pub v: SchemaVersion, }); - fields.extend(quote! { pub i: Identifier, }); + fields.extend(quote! { #version pub v: SchemaVersion, }); + fields.extend(quote! { #context pub i: Identifier, }); fields.extend(quote! { pub c: Ciphertext, }); for term in Term::payload_terms(domain.terms) { let fid = format_ident!("{}", term.json_key()); @@ -163,6 +188,8 @@ fn render_struct(family: &DomainFamily, domain: &Domain) -> TokenStream { #[doc = #doc_summary] #[doc = #doc_blank] #[doc = #doc_detail] + #reference + #encryption #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -206,6 +233,8 @@ fn render_query_struct(family: &DomainFamily, domain: &Domain) -> TokenStream { // Query operands live in the public-API schema, NOT `public`: they are // never valid column types. let sql_domain = format!("eql_v3.{query_name}"); + let reference = reference_docs(family); + let (encryption, version, context) = encryption_attrs(family, domain, true); // Query doc: same capability label + operator union as storage, but the // required-key list drops `c` (query operands omit the ciphertext). @@ -230,8 +259,8 @@ fn render_query_struct(family: &DomainFamily, domain: &Domain) -> TokenStream { // Envelope minus `c`: `v`/`i` only. Kept in lockstep with the storage // struct's envelope triple (see `envelope_fields_match_catalog_keys`). let mut fields = TokenStream::new(); - fields.extend(quote! { pub v: SchemaVersion, }); - fields.extend(quote! { pub i: Identifier, }); + fields.extend(quote! { #version pub v: SchemaVersion, }); + fields.extend(quote! { #context pub i: Identifier, }); for term in Term::payload_terms(domain.terms) { let fid = format_ident!("{}", term.json_key()); let tid = format_ident!("{}", term.binding_newtype()); @@ -243,6 +272,8 @@ fn render_query_struct(family: &DomainFamily, domain: &Domain) -> TokenStream { #[doc = #summary] #[doc = ""] #[doc = #detail] + #reference + #encryption #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TS, JsonSchema)] #[ts(export, export_to = "v3/")] #[serde(deny_unknown_fields)] @@ -273,6 +304,42 @@ fn render_query_struct(family: &DomainFamily, domain: &Domain) -> TokenStream { } } +/// Text equality is the first supported encryption domain. Keep attributes in +/// the generator so regeneration preserves the opt-in derives without enabling +/// other domains before their operations and plaintext contracts are supported. +fn encryption_attrs( + family: &DomainFamily, + domain: &Domain, + query: bool, +) -> (TokenStream, TokenStream, TokenStream) { + if family.name != "text" || domain.name != "eq" { + return Default::default(); + } + let decrypt = (!query).then( + || quote!(#[cfg_attr(feature = "stack-encrypt", derive(stack_encrypt::DecryptInto))]), + ); + let plaintext = if query { + " Plaintext input: [`String`]. With the `stack-encrypt` feature, implements \ + `EncryptFrom` to build equality query terms. Query operands do not decrypt." + } else { + " Plaintext input and decrypted output: [`String`]. With the `stack-encrypt` \ + feature, implements `EncryptFrom` and `DecryptInto`." + }; + ( + quote! { + #[cfg_attr(doc, doc = "")] + #[cfg_attr(doc, doc = #plaintext)] + #[cfg_attr(doc, doc = " Encryption context: `NonEmpty`, constructed with `Identifier::for_column(table, column)` and stored in `i`.")] + #[cfg_attr(all(doc, feature = "stack-encrypt"), doc = " See the [complete encryption example](crate::encryption#example).")] + #[cfg_attr(feature = "stack-encrypt", derive(stack_encrypt::EncryptFrom))] + #decrypt + #[cfg_attr(feature = "stack-encrypt", stash(plaintext = String))] + }, + quote!(#[cfg_attr(feature = "stack-encrypt", stash(default))]), + quote!(#[cfg_attr(feature = "stack-encrypt", stash(context_field))]), + ) +} + /// Render a whole family module (`integer.rs`, `text.rs`, …): the import header /// (exactly the term newtypes the family uses) followed by every domain's /// storage struct + impl, then a query twin for each term-bearing domain. diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint.json index dcf39ca1d..f2d22fb58 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_eq.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_eq.json index 376e97e59..895726c7e 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_eq.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_ord.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_ord.json index 4dd53489d..4087631d9 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_ord.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_ord_ope.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_ord_ope.json index c9b7f2155..b48b3b984 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_ord_ope.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_ord_ore.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_ord_ore.json index ec0620b71..643631c7e 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_ord_ore.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_bigint_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_boolean.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_boolean.json index feee8688d..d8a5ad205 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_boolean.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_boolean.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date.json index 7265731c5..a0eedd9e6 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_eq.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_eq.json index 87c588b18..659840e85 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_eq.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_ord.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_ord.json index e7a1898bd..39485b088 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_ord.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_ord_ope.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_ord_ope.json index 67d2daa5b..8f4cf8216 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_ord_ope.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_ord_ore.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_ord_ore.json index 010869e58..63caa1ed2 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_ord_ore.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_date_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double.json index 2b2dc709f..bbad0b189 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_eq.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_eq.json index fea7dbc50..6338de607 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_eq.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_ord.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_ord.json index d636c06d7..da2e629f3 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_ord.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_ord_ope.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_ord_ope.json index 6a1ddba44..b27cdb37c 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_ord_ope.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_ord_ore.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_ord_ore.json index ebc8a6ded..e95ad4033 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_ord_ore.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_double_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer.json index 92d36fa97..15ba554eb 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_eq.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_eq.json index 7a07dc8dc..7d83e20ea 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_eq.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_ord.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_ord.json index 096415e90..40684c7df 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_ord.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_ord_ope.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_ord_ope.json index 7a9173d07..bec37060d 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_ord_ope.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_ord_ore.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_ord_ore.json index b270f38f9..3cdd5a4f9 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_ord_ore.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_integer_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_json.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_json.json index 5a206f9d9..67a7488ba 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_json.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_json.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric.json index 8d2d08a06..fb76317a5 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_eq.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_eq.json index 741c95904..de4c798bc 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_eq.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_ord.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_ord.json index ae0074cf0..de1e85247 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_ord.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_ord_ope.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_ord_ope.json index 2ffee02ff..09886d191 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_ord_ope.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_ord_ore.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_ord_ore.json index 9db393f7a..e3ad24415 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_ord_ore.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_numeric_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real.json index 52da42ac2..7e12f7197 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_eq.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_eq.json index ce0f03141..a0d474ca5 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_eq.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_ord.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_ord.json index 69aeb260e..08ab922bb 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_ord.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_ord_ope.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_ord_ope.json index 548832cd3..d6bc7fdec 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_ord_ope.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_ord_ore.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_ord_ore.json index c6b5ca349..bc8fdd5d8 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_ord_ore.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_real_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint.json index f04378a6f..7d3e346b4 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_eq.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_eq.json index a793597d4..342927953 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_eq.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_ord.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_ord.json index 5e95b20ac..806ef68d3 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_ord.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_ord_ope.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_ord_ope.json index 63f1b3dd2..627c73238 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_ord_ope.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_ord_ore.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_ord_ore.json index 8b84af97c..395c2a733 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_ord_ore.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_smallint_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text.json index 60a7fdafd..e50fcb359 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_eq.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_eq.json index b7d94f830..89be47f98 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_eq.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_match.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_match.json index e7f9f34cf..df5e41012 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_match.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_match.json @@ -11,7 +11,7 @@ "type": "array" }, "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_ord.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_ord.json index 7ef5a1242..efd68d5b7 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_ord.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_ord_ope.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_ord_ope.json index 0d6a0ab29..10151de25 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_ord_ope.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_ord_ore.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_ord_ore.json index 5f97ccc7d..ccd48ea8b 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_ord_ore.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_search.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_search.json index ee05c7bfc..bd942a291 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_search.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_search.json @@ -11,7 +11,7 @@ "type": "array" }, "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_search_ore.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_search_ore.json index 17121f697..3567eac0d 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_search_ore.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_text_search_ore.json @@ -11,7 +11,7 @@ "type": "array" }, "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp.json index 16e97bd9d..853050330 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_eq.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_eq.json index c76a60ade..97e064b29 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_eq.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_eq.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Hmac256": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_ord.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_ord.json index e0a74f83a..4462017f6 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_ord.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_ord.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_ord_ope.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_ord_ope.json index cdf411d46..da2ae0deb 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_ord_ope.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_ord_ope.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_ord_ore.json b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_ord_ore.json index 0a286d1c1..e5c5eefcc 100644 --- a/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_ord_ore.json +++ b/packages/eql/packages/eql/src/generated/schema/v3/eql_v3_timestamp_ord_ore.json @@ -1,7 +1,7 @@ { "$defs": { "Ciphertext": { - "description": "mp_base85 source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", + "description": "Producer-encoded source ciphertext — the `c` envelope key.\n\nRequired by every v3 domain CHECK; present on every payload.", "type": "string" }, "Identifier": { diff --git a/packages/eql/packages/eql/src/generated/v3/Ciphertext.ts b/packages/eql/packages/eql/src/generated/v3/Ciphertext.ts index 7beff648e..01c400762 100644 --- a/packages/eql/packages/eql/src/generated/v3/Ciphertext.ts +++ b/packages/eql/packages/eql/src/generated/v3/Ciphertext.ts @@ -1,7 +1,7 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. /** - * mp_base85 source ciphertext — the `c` envelope key. + * Producer-encoded source ciphertext — the `c` envelope key. * * Required by every v3 domain CHECK; present on every payload. */ diff --git a/packages/eql/tasks/dev/with-stack-encrypt.sh b/packages/eql/tasks/dev/with-stack-encrypt.sh new file mode 100644 index 000000000..b9aac6f78 --- /dev/null +++ b/packages/eql/tasks/dev/with-stack-encrypt.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# Use the unpublished sibling suite without committing a machine-specific path. +# Usage: tasks/dev/with-stack-encrypt.sh /path/to/cipherstash-suite test -p eql-bindings --features stack-encrypt +set -euo pipefail +suite_root=$(cd "${1:?supply the cipherstash-suite checkout}" && pwd) +shift +patch_file=$(mktemp) +trap 'rm -f "$patch_file"' EXIT +python3 - "$suite_root" > "$patch_file" <<'PY' +import json, pathlib, sys +suite = pathlib.Path(sys.argv[1]) +print('[patch.crates-io]') +for name in ('stack-encrypt', 'stack-kms'): + path = suite / 'packages' / name + if not (path / 'Cargo.toml').is_file(): + raise SystemExit(f'missing {path}/Cargo.toml') + print(f'{name} = {{ path = {json.dumps(str(path))} }}') +PY +command=${1:?supply a Cargo command such as test or check} +shift +# External subcommands (notably clippy) need the override after their name. +cargo "$command" --config "$patch_file" "$@" diff --git a/packages/eql/tests/encryption/Cargo.toml b/packages/eql/tests/encryption/Cargo.toml new file mode 100644 index 000000000..aec904647 --- /dev/null +++ b/packages/eql/tests/encryption/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "eql-encryption-tests" +version = "0.1.0" +edition = "2021" +publish = false + +# Execute the exact source included in the public Rustdoc example. Keep its +# test key source and async runtime out of eql-bindings' default test build. +[[test]] +name = "text_eq_example" +path = "../../crates/eql-bindings/src/encryption/example.rs" +harness = false + +# Keep crypto/Postgres test dependencies out of eql-bindings' default test build. +[dev-dependencies] +eql-bindings = { path = "../../crates/eql-bindings", features = ["stack-encrypt"] } +stack-encrypt = { version = "0.1.0", default-features = false } +stack-kms = { version = "0.1.0", default-features = false, features = ["test-support"] } +serde = "1" +serde_json = "1" +uuid = "1" +tokio = { version = "1", features = ["rt", "macros"] } +postgres = "0.19" diff --git a/packages/eql/tests/encryption/tests/common/mod.rs b/packages/eql/tests/encryption/tests/common/mod.rs new file mode 100644 index 000000000..e64883b5c --- /dev/null +++ b/packages/eql/tests/encryption/tests/common/mod.rs @@ -0,0 +1,68 @@ +use std::borrow::Cow; +use std::sync::{Arc, Mutex}; + +use stack_encrypt::StackCipher; +use stack_kms::{ + DataKey, DataKeySource, DataKeyWithTag, FakeDataKeySource, GenerateKeyPayload, IdentifiedBy, + IndexKey, IndexKeySource, RetrieveKeyPayload, UnverifiedContext, +}; +use uuid::Uuid; + +#[derive(Default)] +pub struct Calls { + pub generate: Vec>, + pub retrieve: Vec>, +} + +pub struct Observed { + inner: FakeDataKeySource, + calls: Arc>, +} +impl DataKeySource for Observed { + async fn generate_keys( + &self, + payloads: Vec>, + keyset: Option, + context: Option>, + ) -> Result, stack_kms::Error> { + self.calls + .lock() + .unwrap() + .generate + .push(payloads.iter().map(|p| p.descriptor.to_owned()).collect()); + self.inner.generate_keys(payloads, keyset, context).await + } + async fn retrieve_keys( + &self, + payloads: Vec>, + keyset: Option, + context: Option<&UnverifiedContext>, + ) -> Result, stack_kms::Error> { + self.calls + .lock() + .unwrap() + .retrieve + .push(payloads.iter().map(|p| p.descriptor.to_owned()).collect()); + self.inner.retrieve_keys(payloads, keyset, context).await + } +} +impl IndexKeySource for Observed { + async fn load_index_key( + &self, + keyset: Option, + ) -> Result<(Uuid, IndexKey), stack_kms::Error> { + self.inner.load_index_key(keyset).await + } +} +pub async fn cipher() -> (StackCipher, Arc>) { + let calls = Arc::new(Mutex::new(Calls::default())); + let cipher = StackCipher::builder() + .kms(Observed { + inner: FakeDataKeySource::new(), + calls: calls.clone(), + }) + .init() + .await + .unwrap(); + (cipher, calls) +} diff --git a/packages/eql/tests/encryption/tests/text_eq.rs b/packages/eql/tests/encryption/tests/text_eq.rs new file mode 100644 index 000000000..006ff6597 --- /dev/null +++ b/packages/eql/tests/encryption/tests/text_eq.rs @@ -0,0 +1,319 @@ +mod common; + +use eql_bindings::v3::terms::{Ciphertext, Hmac256}; +use eql_bindings::v3::text::{TextEq, TextEqQuery}; +use eql_bindings::{Identifier, SchemaVersion}; +use stack_encrypt::target::transcode::{Reader, Transcode, Visitor}; +use stack_encrypt::{ + Cipher, CipherText, Encrypt, Error, IntoAad, NonEmpty, SealedValue, StackCipherText, +}; + +fn column() -> NonEmpty { + Identifier::for_column("users", "email").unwrap() +} +struct NativeLeaf; +impl Visitor for NativeLeaf { + type Value = StackCipherText; + fn sealed(self, leaf: SealedValue) -> Result { + Ok(CipherText::Single(leaf)) + } +} + +#[tokio::test] +async fn text_round_trips_through_json_and_both_canonical_directions() { + let (cipher, _) = common::cipher().await; + let keyset = cipher.default_keyset(); + for text in [ + "alice@example.com", + "", + "雪☃", + "caf\u{e9}", + "cafe\u{301}", + "a\0b", + ] { + let value = text.to_owned(); + let stored: TextEq = keyset.encrypt_as(&value, column()).await.unwrap(); + let json = serde_json::to_value(&stored).unwrap(); + assert_eq!(json["v"], 3); + assert_eq!(json["i"], serde_json::json!({"t":"users", "c":"email"})); + assert_eq!(json.as_object().unwrap().len(), 4); + let stored: TextEq = serde_json::from_value(json).unwrap(); + let native = stored.c.clone().read(NativeLeaf).unwrap(); + let opened: String = cipher.decrypt(native, column()).await.unwrap(); + assert_eq!( + opened, value, + "EQL adds no plaintext encoding or envelope-field AAD" + ); + let opened: String = cipher.decrypt_as(stored, Default::default()).await.unwrap(); + assert_eq!(opened, value); + + let native = keyset.encrypt(value.clone(), column()).await.unwrap(); + let stored = TextEq { + v: SchemaVersion::CURRENT, + i: column().into_inner(), + c: native.read(Ciphertext::visitor()).unwrap(), + hm: keyset + .equality_term(value.clone(), column()) + .await + .unwrap() + .read(Hmac256::visitor()) + .unwrap(), + }; + let opened: String = cipher.decrypt_as(stored, column().into()).await.unwrap(); + assert_eq!( + opened, value, + "native ciphertext opens through the EQL target" + ); + } +} + +#[tokio::test] +async fn independent_queries_match_native_terms_without_requesting_data_keys() { + let (writer, _) = common::cipher().await; + let (reader, calls) = common::cipher().await; + let value = "café".to_owned(); + let stored: TextEq = writer + .default_keyset() + .encrypt_as(&value, column()) + .await + .unwrap(); + let query: TextEqQuery = reader + .default_keyset() + .encrypt_as(&value, column()) + .await + .unwrap(); + assert_eq!(query.hm, stored.hm); + let canonical = reader + .default_keyset() + .equality_term(value.clone(), column()) + .await + .unwrap() + .read(Hmac256::visitor()) + .unwrap(); + assert_eq!(query.hm, canonical); + assert_eq!(query.hm.0.len(), 64); + assert!(query.hm.0.bytes().all(|b| b.is_ascii_hexdigit())); + let json = serde_json::to_value(&query).unwrap(); + assert!(json.get("c").is_none()); + assert_eq!(serde_json::from_value::(json).unwrap(), query); + for different in ["CAFÉ", "cafe\u{301}", "café "] { + let probe: TextEqQuery = reader + .default_keyset() + .encrypt_as(&different.to_owned(), column()) + .await + .unwrap(); + assert_ne!(query.hm, probe.hm, "no added normalization or case folding"); + } + let calls = calls.lock().unwrap(); + assert!(calls.generate.is_empty()); + assert!(calls.retrieve.is_empty()); +} + +#[tokio::test] +async fn identifier_components_are_nonempty_and_keep_their_boundaries() { + assert!(Identifier::for_column("", "email").is_err()); + assert!(Identifier::for_column("users", "").is_err()); + let (cipher, calls) = common::cipher().await; + let keyset = cipher.default_keyset(); + let value = "text".to_owned(); + let mut outputs = Vec::new(); + for (t, c) in [ + ("ab", "c"), + ("a", "bc"), + ("users", "email"), + ("users", "name"), + ("other", "email"), + ] { + let stored: TextEq = keyset + .encrypt_as(&value, Identifier::for_column(t, c).unwrap()) + .await + .unwrap(); + for previous in &outputs { + assert_ne!(previous, &stored.hm); + } + outputs.push(stored.hm); + } + let calls = calls.lock().unwrap(); + let descriptors: std::collections::HashSet<_> = calls.generate.iter().flatten().collect(); + assert_eq!( + descriptors.len(), + 5, + "ZeroKMS descriptors also preserve identifier boundaries" + ); +} + +#[tokio::test] +async fn context_and_encoding_failures_are_rejected_before_retrieving_keys() { + let (cipher, calls) = common::cipher().await; + let stored: TextEq = cipher + .default_keyset() + .encrypt_as(&"secret".to_owned(), column()) + .await + .unwrap(); + let wrong = Identifier::for_column("users", "name").unwrap(); + assert!(cipher + .decrypt_as::(stored.clone(), wrong.clone().into()) + .await + .is_err()); + for empty_table in [true, false] { + let mut invalid = stored.clone(); + if empty_table { + invalid.i.t.clear(); + } else { + invalid.i.c.clear(); + } + assert!(cipher + .decrypt_as::(invalid, Default::default()) + .await + .is_err()); + } + for encoded in [ + "legacy-ciphertext", + "stack-encrypt:2:00000", + "stack-encrypt:1:", + "stack-encrypt:1:~", + "stack-encrypt:1:00000", + "stack-encrypt:1:AAAA", + "stack-encrypt:1:雪", + ] { + let mut invalid = stored.clone(); + invalid.c = Ciphertext(encoded.into()); + assert!(cipher + .decrypt_as::(invalid, Default::default()) + .await + .is_err()); + } + assert!(calls.lock().unwrap().retrieve.is_empty()); + let mut moved = stored; + moved.i = wrong.into_inner(); + assert!( + cipher + .decrypt_as::(moved, Default::default()) + .await + .is_err(), + "a different nonempty stored identifier fails authentication" + ); + assert_eq!(calls.lock().unwrap().retrieve.len(), 1); +} + +#[tokio::test] +async fn a_column_batches_generation_and_retrieval_under_the_same_descriptors() { + let (cipher, calls) = common::cipher().await; + let values = vec!["one".to_owned(), "two".to_owned(), "three".to_owned()]; + let records: Vec = cipher + .default_keyset() + .encrypt_as(&values, column()) + .await + .unwrap(); + let json = serde_json::to_string(&records).unwrap(); + let records: Vec = serde_json::from_str(&json).unwrap(); + let opened: Vec = cipher.decrypt_as(records, column().into()).await.unwrap(); + assert_eq!(opened, values); + let calls = calls.lock().unwrap(); + assert_eq!(calls.generate.len(), 1); + assert_eq!(calls.retrieve.len(), 1); + assert_eq!(calls.generate[0].len(), 3); + assert_eq!(calls.generate, calls.retrieve); +} + +#[derive(Clone)] +struct WithoutSerde(String); +impl Encrypt for WithoutSerde { + fn encrypt_with_aad<'a, C: Cipher, A: IntoAad<'a>>( + self, + cipher: C, + aad: A, + ) -> Result { + self.0.encrypt_with_aad(cipher, aad) + } +} +#[tokio::test] +async fn leaf_transcoding_requires_no_serde_and_refuses_container_shapes() { + let (cipher, _) = common::cipher().await; + let keyset = cipher.default_keyset(); + let leaf: Ciphertext = keyset + .encrypt_as(&WithoutSerde("native".into()), column().into()) + .await + .unwrap(); + let text: String = cipher.decrypt_as(leaf, column().into()).await.unwrap(); + assert_eq!(text, "native"); + assert!(keyset + .encrypt_as::<_, Ciphertext>(&vec!["one".to_owned()], column().into()) + .await + .is_err()); +} + +/// Needs an EQL v3 installation; uses fresh real ciphertext with a fake key source. +#[test] +#[ignore = "requires EQL_TEST_DATABASE_URL pointing to an EQL v3 database"] +fn postgres_stores_queries_indexes_and_returns_decryptable_text() { + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + let (cipher, _) = runtime.block_on(common::cipher()); + let keyset = cipher.default_keyset(); + let mut db = postgres::Client::connect( + &std::env::var("EQL_TEST_DATABASE_URL").expect("EQL_TEST_DATABASE_URL"), + postgres::NoTls, + ) + .unwrap(); + db.batch_execute( + "CREATE TEMP TABLE text_eq_roundtrip (id int PRIMARY KEY, email public.eql_v3_text_eq); + CREATE INDEX text_eq_email_idx ON text_eq_roundtrip (eql_v3.eq_term(email));", + ) + .unwrap(); + for (id, value) in [ + (1, "alice@example.com"), + (2, "bob@example.com"), + (3, "alice@example.com"), + (4, "ALICE@example.com"), + ] { + let record: TextEq = runtime + .block_on(async { keyset.encrypt_as(&value.to_owned(), column()).await }) + .unwrap(); + let json = serde_json::to_string(&record).unwrap(); + db.execute( + "INSERT INTO text_eq_roundtrip VALUES ($1, $2::text::jsonb::public.eql_v3_text_eq)", + &[&id, &json], + ) + .unwrap(); + } + let (query_cipher, _) = runtime.block_on(common::cipher()); + let query: TextEqQuery = runtime + .block_on(async { + query_cipher + .default_keyset() + .encrypt_as(&"alice@example.com".to_owned(), column()) + .await + }) + .unwrap(); + let json = serde_json::to_string(&query).unwrap(); + let rows = db.query("SELECT id, email::text FROM text_eq_roundtrip WHERE email = $1::text::jsonb::eql_v3.query_text_eq ORDER BY id", &[&json]).unwrap(); + assert_eq!( + rows.iter().map(|r| r.get::<_, i32>(0)).collect::>(), + [1, 3] + ); + for row in rows { + let record: TextEq = serde_json::from_str(row.get::<_, &str>(1)).unwrap(); + let value: String = runtime + .block_on(async { cipher.decrypt_as(record, column().into()).await }) + .unwrap(); + assert_eq!(value, "alice@example.com"); + } + let different = db.query("SELECT id FROM text_eq_roundtrip WHERE email <> $1::text::jsonb::eql_v3.query_text_eq ORDER BY id", &[&json]).unwrap(); + assert_eq!( + different + .iter() + .map(|r| r.get::<_, i32>(0)) + .collect::>(), + [2, 4] + ); + db.batch_execute("SET enable_seqscan = off").unwrap(); + let plan = db.query("EXPLAIN SELECT * FROM text_eq_roundtrip WHERE email = $1::text::jsonb::eql_v3.query_text_eq", &[&json]).unwrap(); + assert!( + plan.iter() + .any(|r| r.get::<_, &str>(0).contains("text_eq_email_idx")), + "equality can use the extractor index" + ); +}