Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
13b2cff
chore(deps): upgrade cipherstash-client to 0.42.0 and EQL to 3.0.1
freshtonic Jul 20, 2026
8374f31
feat(encrypt): produce EQL v3 payloads, retire v2
freshtonic Jul 20, 2026
0e01859
fix(decrypt): implement EQL v3 decrypt for scalar and SteVec payloads
freshtonic Jul 20, 2026
f95faa2
docs(errors): document the EQL v3 SteVec errors
freshtonic Jul 23, 2026
350ea55
chore(deps): pin EQL to 3.0.2
freshtonic Jul 23, 2026
4fdc2b3
chore: remove the unreferenced vendored stack-auth
freshtonic Jul 23, 2026
49f4423
test(proxy): ignore the stale v2 to_ciphertext_* wire fixtures
freshtonic Jul 23, 2026
cb8dae8
refactor(eql): adopt the cipherstash-client 0.42.0 representation
freshtonic Jul 20, 2026
ad029af
refactor(eql): adopt the cipherstash-client 0.42.0 representation
freshtonic Jul 20, 2026
4664a35
docs: handoff for the EQL v3 type checker design
freshtonic Jul 20, 2026
46550ba
docs(eql-mapper): record v3 type-checker design (glossary + ADRs)
freshtonic Jul 21, 2026
0e1de2d
fix(eql-mapper): correct EqlTraits set difference and bound-error ope…
freshtonic Jul 21, 2026
acc019d
feat(eql-mapper): carry inert v3 domain identity in the type carriers
freshtonic Jul 21, 2026
ade7602
feat(proxy): load EQL v3 per-column capability from the domain name
freshtonic Jul 21, 2026
d220700
refactor(eql): make v3 domain identity non-optional; JSON = JsonLike …
freshtonic Jul 22, 2026
ab6b117
docs(eql-mapper): warn that DomainIdentity::canonical may collide wit…
freshtonic Jul 23, 2026
c013ea9
feat(proxy): make the v2-column plaintext warning ops-visible
freshtonic Jul 23, 2026
90e8166
fix(proxy): exclude eql_v3_json_entry from the column-domain catalog
freshtonic Jul 23, 2026
41e6921
docs(eql-mapper): correct Contain and cross-check in the v3 ADRs
freshtonic Jul 22, 2026
2a3511f
feat(eql-mapper): ADR-0003 v3 rewrite pipeline + term-selection found…
freshtonic Jul 22, 2026
999dbca
feat(eql-mapper): rewrite scalar comparisons to the v3 functional-ind…
freshtonic Jul 22, 2026
61b3db2
feat(eql-mapper): retarget aggregate and jsonb functions to eql_v3
freshtonic Jul 22, 2026
a977c50
feat(eql-mapper): retarget JSON containment to eql_v3
freshtonic Jul 22, 2026
6b0d473
feat(eql-mapper): functionalise JSON -> / ->> field access to eql_v3
freshtonic Jul 22, 2026
6f572c9
fix(eql-mapper): route LIKE/ILIKE through TokenMatch capability checking
freshtonic Jul 22, 2026
19a9f04
feat(eql-mapper): rewrite LIKE/ILIKE to the v3 match_term form
freshtonic Jul 22, 2026
badafa0
test(eql-mapper): cover NOT LIKE/ILIKE, UPDATE SET cast, native LIKE,…
freshtonic Jul 23, 2026
3a5a9a7
feat(eql-mapper): support @@ fuzzy match and rewrite to match_term
freshtonic Jul 22, 2026
c92a70d
test(eql-mapper): cover ord_ore rewrite via the explicit domain form
freshtonic Jul 22, 2026
1656a3c
docs(changelog): record the EQL v3 migration
freshtonic Jul 23, 2026
58f60a8
fix(eql-mapper): map JSON domains to the eql_v3.query_json operand twin
freshtonic Jul 24, 2026
62e029f
fix(eql-mapper): emit JSON selectors as text, not a jsonb query cast
freshtonic Jul 24, 2026
7d69bb1
fix(proxy): bind JSON selectors as bare text, not JSON-quoted
freshtonic Jul 24, 2026
54b3ca7
fix(proxy): decrypt JSON field access results and bind selectors as text
freshtonic Jul 24, 2026
c54c4b0
feat(proxy): support encrypted JSON field range comparisons
freshtonic Jul 25, 2026
796a005
docs(eql-mapper): cleanup after the v3 rewrite — stale strings and notes
freshtonic Jul 22, 2026
5ea329d
refactor(showcase): convert the healthcare showcase to EQL v3
freshtonic Jul 22, 2026
5b4e85c
feat(proxy): infer encrypt config from the EQL v3 schema
freshtonic Jul 22, 2026
e24a25f
test(integration): convert the shared test schema to EQL v3 domains
freshtonic Jul 22, 2026
995cc07
test(integration): make the integration tests v3-shaped
freshtonic Jul 22, 2026
b2bc2a4
docs: sweep remaining EQL v2 references to v3
freshtonic Jul 22, 2026
855186c
feat(proxy): index encrypted JSON arrays for search (ArrayIndexMode::…
freshtonic Jul 25, 2026
02bb437
feat(mapper): fuse JSON field equality into a value-selector needle
freshtonic Jul 25, 2026
9eafe69
feat(proxy): compose and encrypt the JSON equality value selector
freshtonic Jul 25, 2026
c8a2aa7
docs: changelog entry for encrypted JSON field equality
freshtonic Jul 25, 2026
4b3ae30
refactor: model output params as derived from N input params
freshtonic Jul 26, 2026
bbcd475
refactor(mapper): each rewrite rule casts its own operands
freshtonic Jul 26, 2026
e2519e8
fix(mapper): ORDER BY an encrypted column must order by its ordering …
freshtonic Jul 26, 2026
2065d74
fix(proxy): project encrypted query operands with into_query_operand
freshtonic Jul 26, 2026
a506d15
fix(mapper): GROUP BY an encrypted column must group by its equality …
freshtonic Jul 26, 2026
c09a3a0
fix(mapper): project grouped columns through eql_v3.grouped_value
freshtonic Jul 27, 2026
6432499
chore(deps): upgrade EQL and eql-bindings to 3.0.3
freshtonic Jul 27, 2026
d962a10
test(integration): align the suite with EQL v3 capability rules
freshtonic Jul 28, 2026
77577f3
fix(mapper): support SELECT DISTINCT ordered by an encrypted column
freshtonic Jul 28, 2026
cbe91b8
fix(mapper): deduplicate SELECT DISTINCT on an encrypted column
freshtonic Jul 28, 2026
3dfe95e
fix(proxy,mapper): address the Codex review findings (CIP-3679)
freshtonic Jul 28, 2026
d348a37
test(python): align the language tests with EQL v3 capability rules
freshtonic Jul 29, 2026
fa5ef70
fix(proxy): clear the cached statement when Parse rebinds its name
freshtonic Jul 29, 2026
724378b
fix: address the straightforward CodeRabbit review findings
freshtonic Jul 29, 2026
edb988d
fix: address the remaining CodeRabbit findings
freshtonic Jul 29, 2026
5ce4d5c
test(integration): pin IN / NOT IN behaviour on encrypted columns
freshtonic Jul 29, 2026
19944fe
test: cover the Fable review's P1 shapes, and audit InferType for mis…
freshtonic Jul 29, 2026
08d41a6
fix(mapper): add the missing capability bounds, and refuse set-op dedup
freshtonic Jul 29, 2026
b4b3120
fix(mapper): key DISTINCT ON an encrypted column on its equality term
freshtonic Jul 29, 2026
0532e2b
fix(mapper): rewrite ordinal sort/group keys and PARTITION BY to use …
freshtonic Jul 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This document describes the internal architecture of CipherStash Proxy. It's int

## Overview

CipherStash Proxy sits between an application and PostgreSQL. It intercepts SQL statements over the PostgreSQL wire protocol, determines which columns are encrypted, rewrites queries to use [EQL v2](https://github.com/cipherstash/encrypt-query-language) operations, encrypts literals and parameters, forwards the transformed query to PostgreSQL, and decrypts results before returning them to the application.
CipherStash Proxy sits between an application and PostgreSQL. It intercepts SQL statements over the PostgreSQL wire protocol, determines which columns are encrypted, rewrites queries to use [EQL v3](https://github.com/cipherstash/encrypt-query-language) operations, encrypts literals and parameters, forwards the transformed query to PostgreSQL, and decrypts results before returning them to the application.

The two most interesting pieces of the system are:

Expand Down Expand Up @@ -112,14 +112,22 @@ When a SQL statement contains DDL (`CREATE TABLE`, `ALTER TABLE`, `DROP TABLE`,

After type inference determines which parts of a statement touch encrypted columns, the transformation pipeline rewrites the AST. Transformation rules are modular and composable — they implement a `TransformationRule` trait and are composed into a single rule via tuple implementation (supporting chains of 1 to 16 rules).

The current rules:
The current rules, in the order they are composed in
`type_checked_statement.rs::make_transformer`:

| Rule | What it does |
|---|---|
| `CastLiteralsAsEncrypted` | Replaces plaintext literals with `eql_v2.cast_as_encrypted(ciphertext)` |
| `CastParamsAsEncrypted` | Wraps parameter placeholders (`$1`, `$2`, ...) with encrypted casts |
| `RewriteContainmentOps` | Transforms `col @> val` to `eql_v2.jsonb_contains(col, val)` |
| `RewriteStandardSqlFnsOnEqlTypes` | Rewrites `min()`, `max()`, `jsonb_path_query()` etc. to `eql_v2.*` equivalents |
| `SubstituteEncryptedLiterals` | Replaces each plaintext literal with its ciphertext, before any rule wraps it |
| `RewriteStandardSqlFnsOnEqlTypes` | Rewrites `min()`, `max()`, `jsonb_path_query()` etc. to their `eql_v3.*` counterparts (`count()` stays native) |
| `RewriteContainmentOps` | Rewrites JSON `@>`/`<@` to `eql_v3.jsonb_contains`/`jsonb_contained_by`, and `->`/`->>` to `eql_v3."->"`/`"->>"` |
| `RewriteJsonValueSelectorEq` | Fuses `col -> 'field' = value` into a single encrypted value-selector needle matched by containment |
| `RewriteEqlComparisonOps` | Rewrites scalar comparisons: `col <op> x` → `eql_v3.<term>(col) <op> eql_v3.<term>(x)` (term chosen from the column's domain: `eq_term`/`ord_term`/`ord_term_ore`) |
| `RewriteEqlMatchOps` | Rewrites `LIKE`/`ILIKE`/`@@` to `eql_v3.match_term(a) @> eql_v3.match_term(b)` |
| `RewriteEqlOrderBy` | Rewrites `ORDER BY col` to order by the column's ordering term, `eql_v3.ord_term(col)` |
| `RewriteEqlDistinct` | Rewrites `SELECT DISTINCT col` to deduplicate on the equality term, `SELECT DISTINCT ON (eql_v3.eq_term(col))` |
| `RewriteEqlDistinctOrderBy` | Wraps a `DISTINCT` query ordered by an encrypted column in a subquery that projects the ordering term, so the outer query can order by it |
| `RewriteEqlGroupBy` | Groups by the equality term, and lifts a projected grouped column through `eql_v3.grouped_value` |
| `CastFullPayloadOperands` | Casts the operands with no rewrite of their own — `INSERT` and `UPDATE` values — to the column's v3 domain (`::public.eql_v3_*`). Query operands are cast to the query twin (`::eql_v3.query_*`) by the rewrite rule that produces them |
| `PreserveEffectiveAliases` | Maintains column aliases through transformations |
| `FailOnPlaceholderChange` | Postcondition check that prepared statement placeholders weren't corrupted |
Comment thread
freshtonic marked this conversation as resolved.

Expand Down Expand Up @@ -191,7 +199,7 @@ When encrypting values for a statement, many columns may be `NULL` or non-encryp

## Schema Management

The proxy discovers the database schema at startup and reloads it periodically. Schema loading queries PostgreSQL's `information_schema` to discover tables and columns, then checks `eql_v2_configuration` to determine which columns are encrypted and what index types they support.
The proxy discovers the database schema at startup and reloads it periodically. Schema loading queries PostgreSQL's `information_schema` to discover tables and columns, including each column's domain type. EQL v3 columns are self-configuring domain types (e.g. `eql_v3_text_search`), so both the type-checker's capability view and the encrypt config are inferred from that single schema load — the column's domain name determines which columns are encrypted, their token type, and their searchable capabilities. There is no `eql_v2_configuration` table.

Schema state is stored behind an `ArcSwap`, which provides lock-free reads with atomic updates. This means query processing never blocks on a schema reload — readers always get a consistent snapshot.

Expand Down
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,42 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

### Changed

- **EQL v3 (searchable encryption)**: Proxy now targets EQL v3. Encrypted columns are declared with self-configuring, typed `jsonb` domains (for example `eql_v3_text_search`, `eql_v3_integer_ord`, `eql_v3_json_search`) that encode both the scalar type and the column's searchable capabilities in the column type itself, replacing EQL v2's opaque `eql_v2_encrypted` composite type and its separate `eql_v2_configuration` table. The bundled `cipherstash-client` is upgraded to 0.42.0 and EQL to 3.0.3. Existing v2-encrypted data and schemas must be migrated to v3.

### Added

- **Encrypted full-text match with `@@`**: The `@@` operator is now supported on encrypted text columns whose domain carries a match (bloom-filter) term, rewritten to the EQL v3 `eql_v3.match_term` form.

- **`SELECT DISTINCT` on an encrypted column now deduplicates**: `DISTINCT` used to compare whole encrypted payloads, whose ciphertext is randomised per row, so equal plaintexts never collapsed and `DISTINCT` silently returned duplicates. It is now keyed on the column's equality term — `SELECT DISTINCT ON (eql_v3.eq_term(col)) col …` — so one row is returned per distinct plaintext. Deduplication is equality, so a column whose domain carries no equality term (`eql_v3_boolean`, for instance, which is storage-only) is now rejected with a capability error rather than silently returning every row.

- **`SELECT DISTINCT` ordered by an encrypted column**: `SELECT DISTINCT … ORDER BY <encrypted column>` now works. Ordering an encrypted column requires its ordering term, which PostgreSQL will not accept under `DISTINCT` unless it also appears in the select list, so the query is rewritten to project the term from a subquery and order the outer query by it. The term is never returned to the client and column names are preserved. Two shapes remain unsupported and are reported as such: `SELECT DISTINCT ON (…)` and `SELECT DISTINCT *`, both when combined with `ORDER BY` on an encrypted column — list the columns explicitly for the latter.

- **Equality on encrypted JSON fields**: `WHERE col -> 'field' = 'value'` now works on encrypted JSON columns, in both the simple and extended query protocols, and in the `->>` and `jsonb_path_query_first(col, path) = value` spellings. `<>` is supported as the negation. The field and the value are combined into a single encrypted value-selector needle and matched by containment, so a query never reveals the field and value separately. Matching is exact and case-sensitive; the value must be a JSON scalar (comparing a whole object or array to a field is rejected — use containment with `@>` instead).

### Fixed

- **A param bound as both a stored value and a query operand**: `UPDATE t SET enc = $1 WHERE enc = $1` failed with a domain CHECK violation. The two occurrences need different payloads — the stored one carries the ciphertext, the query one only search terms — but the role was tracked per input param, so marking the param as a query operand stripped the ciphertext from the value being stored. The role is now taken from the rewritten statement, per occurrence.

- **JSON selector params when the client declares its own types**: a client that sends param OIDs in Parse (pgx in `cache_describe` mode, for example) got `function eql_v3.jsonb_path_exists(eql_v3_json_search, jsonb) does not exist`. A JSON field selector is passed to the rewritten function as bare text, but was being declared as `jsonb` like every other encrypted operand. Affects `->`, `->>`, `jsonb_path_exists`, `jsonb_path_query` and `jsonb_path_query_first`.

- **Binary-format text operands on encrypted JSON fields**: a TEXT/VARCHAR operand arriving in binary format was handed straight to the JSON decoder and rejected, even though the same value in text format was accepted. Textual types are now read as a string first and then given the text format's treatment, so `Alice` behaves like `"Alice"`.

- **Aggregates over a grouped encrypted column**: `SELECT MIN(enc) FROM t GROUP BY enc` produced `grouped_value(eql_v3.min(enc))` — an aggregate inside an aggregate, which PostgreSQL rejects. An aggregate already returns one value per group, so it is no longer lifted; only a direct projection of the grouped column is.

- **`SELECT *` with `GROUP BY` on an encrypted column** is now rejected with an explanatory error instead of PostgreSQL's "column must appear in the GROUP BY clause". A wildcard hides the projected columns, so the grouped column cannot be projected through `eql_v3.grouped_value` — list the columns explicitly. This matches the existing treatment of `SELECT DISTINCT *`.

- **`SELECT DISTINCT *` skipped the encrypted-column protection**: a wildcard hides the columns `DISTINCT` deduplicates on, so neither the equality-term keying nor the capability check applied and duplicates were returned silently. The wildcard is now expanded to its columns, which are keyed like any other; a wildcard hiding a column with no equality term is rejected.

- **`@@` with the encrypted column on the right**: `'pattern' @@ col` produced `match_term('pattern') @> match_term(col)` — a backwards containment, with the pattern never encrypted, that silently matched nothing. `@@` is symmetric in PostgreSQL, so both spellings now produce the same query.

- **Encrypt config could pick up a same-named table from another schema**: the config is keyed on `(table, column)` while the schema query scanned every schema, so a table of the same name elsewhere — another tenant's, a staging copy — could overwrite the served one and give a column the wrong domain config or drop its encryption. The scan is now limited to the connection's search path, in precedence order.

- **A prepared statement name reused for an unmapped statement**: `Parse` rebinds its name, but a statement Proxy does not map — `BEGIN`, `COMMIT`, or anything needing no type check — left the *previous* statement cached under that name. The next `Bind` for the name was then rewritten against a statement the client never parsed, failing with `Rewritten statement binds parameter 1, but only 0 were provided`. Affects any client that reuses the unnamed prepared statement across a transaction, which includes pgbench in extended mode and psycopg with `prepare=False`.

- **`LIKE`/`ILIKE` capability checking**: `LIKE` and `ILIKE` on an encrypted column are now gated by the column's token-match capability. Previously these predicates bypassed capability checking and were silently accepted on columns that do not support fuzzy match; they are now rejected with a capability error.

## [2.2.4] - 2026-06-18

### Fixed
Expand Down
19 changes: 12 additions & 7 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ CipherStash Proxy is a PostgreSQL proxy that provides **transparent, searchable

Key capabilities:
- Zero-change SQL queries - applications connect to Proxy instead of directly to PostgreSQL
- EQL v2 (Encrypt Query Language) for searchable encryption using CipherStash ZeroKMS
- EQL v3 (Encrypt Query Language) for searchable encryption using CipherStash ZeroKMS
- Support for encrypted equality, comparison, ordering, and grouping operations
- Written in Rust for performance with strongly-typed SQL statement mapping

Expand All @@ -34,14 +34,14 @@ Key capabilities:
- Language-specific integration tests (Python, Go)

**Showcase (`packages/showcase/`):**
- Healthcare data model demonstrating EQL v2 encryption
- Healthcare data model demonstrating EQL v3 encryption
- Example of realistic encrypted application with foreign keys and relationships

### Request Flow

1. Application connects to Proxy (port 6432) using standard PostgreSQL protocol
2. Proxy intercepts SQL statements and uses EQL Mapper to analyze query structure
3. For encrypted columns, Proxy transforms SQL using EQL v2 operations
3. For encrypted columns, Proxy transforms SQL using EQL v3 operations
4. Encrypted queries are sent to actual PostgreSQL database
5. Results are decrypted before returning to application

Expand Down Expand Up @@ -166,12 +166,17 @@ Available targets: `DEVELOPMENT`, `AUTHENTICATION`, `CONFIG`, `CONTEXT`, `ENCODI

## EQL Integration

CipherStash Proxy uses EQL v2 for searchable encryption. Key concepts:
CipherStash Proxy uses EQL v3 for searchable encryption. Key concepts:

- **Plaintext columns** - standard PostgreSQL data types
- **Encrypted columns** - use `eql_v2_encrypted` type in schema
- **Searchable operations** - equality, comparison, ordering work on encrypted data
- **Index support** - ORE (Order Revealing Encryption) and Match indexes for performance
- **Encrypted columns** - use a self-configuring EQL v3 domain type in the schema
(e.g. `eql_v3_text_search`, `eql_v3_integer_ord`, `eql_v3_json_search`); the
domain encodes the token type and searchable capabilities, so there is no
separate `add_search_config` call
- **Searchable operations** - equality, comparison, ordering, text match, and JSON
traversal work on encrypted data, gated by the column's domain capability
- **Index support** - functional indexes over the term-extraction functions
(e.g. `CREATE INDEX ON t (eql_v3.ord_term(col))`)

EQL is automatically downloaded and installed during setup. Use `CS_EQL_PATH` to point to local EQL development version.

Expand Down
29 changes: 17 additions & 12 deletions CONTEXT-MAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ resolved — a missing one is expected, not a gap to fill upfront.
| Context | Path | Domain |
|---|---|---|
| Proxy | [`packages/cipherstash-proxy/`](./packages/cipherstash-proxy/CONTEXT.md) | PostgreSQL wire protocol, connection and message handling, client authentication, TLS, ZeroKMS key management, encrypt/decrypt of column values |
| EQL Mapper | [`packages/eql-mapper/`](./packages/eql-mapper/CONTEXT.md) | SQL parsing, type inference over statements, schema analysis, transformation rules that rewrite plaintext SQL into EQL v2 operations |
| EQL Mapper | [`packages/eql-mapper/`](./packages/eql-mapper/CONTEXT.md) | SQL parsing, type inference over statements, schema analysis, transformation rules that rewrite plaintext SQL into EQL v3 operations |
| Integration | `packages/cipherstash-proxy-integration/` | End-to-end test harness — container fixtures, encrypted-scenario coverage across the proxy and mapper together |
| Showcase | `packages/showcase/` | Healthcare example data model demonstrating EQL v2 encryption with realistic relationships |
| Showcase | `packages/showcase/` | Healthcare example data model demonstrating EQL v3 encryption with realistic relationships |

`packages/eql-mapper-macros/` is proc-macro support for EQL Mapper, not a context of its
own — treat it as part of the EQL Mapper context.
Expand All @@ -26,22 +26,27 @@ own — treat it as part of the EQL Mapper context.
- **Identity across the seam**: EQL Mapper's `TableColumn` and Proxy's `Identifier` are
the same `table.column` pair under two names. That pair is the only key joining a typed
AST node to its encryption config.
- **Capability across the seam — currently broken.** Proxy marks every encrypted column
with *all* `EqlTrait`s (`packages/cipherstash-proxy/src/proxy/schema/manager.rs:146`)
because it derives them from the PostgreSQL column type alone. The column encrypt
config, which knows the SEM terms actually configured, is loaded by a separate manager
that never meets the schema loader. EQL Mapper's bound checking is therefore
unreachable in production: a query needing `Ord` on a column with no ordering SEM term
type-checks cleanly and fails later. Read `EqlTraits` on a column as *intended*
capability, not observed.
- **Capability across the seam.** Under EQL v3 each encrypted column is a self-configuring
domain type (e.g. `eql_v3_text_search`) whose typname encodes both the token type and the
searchable capabilities. The schema loader resolves that domain to a `DomainIdentity` and
the exact `EqlTraits` it supports (`packages/cipherstash-proxy/src/proxy/schema/manager.rs`,
via `proxy/schema/eql_domains.rs`), so the traits handed to EQL Mapper are *observed*, not
a blanket grant. EQL Mapper's bound checking is therefore effective in production: a query
needing `Ord` on a column whose domain has no ordering capability is rejected at type-check
time. The encrypt config is derived from the same domain type
(`proxy/encrypt_config/from_domain.rs`), so schema view and encrypt config no longer
disagree.

## Shared vocabulary

Terms defined once for the whole system live here rather than in any one context.

- **EQL v2** — Encrypt Query Language; the SQL-level encoding that makes encrypted
- **EQL v3** — Encrypt Query Language; the SQL-level encoding that makes encrypted
values searchable.
- **`eql_v2_encrypted`** — the PostgreSQL column type holding an encrypted value.
- **EQL v3 domain types** — encrypted columns are self-configuring PostgreSQL DOMAINs over
`jsonb` (e.g. `eql_v3_text_search`, `eql_v3_int8_ord`, `eql_v3_json_search`). The domain's
typname encodes the token type and the searchable capabilities, replacing EQL v2's opaque
`eql_v2_encrypted` type plus a separate `eql_v2_configuration` table.
- **ZeroKMS** — CipherStash's key management service, which the proxy calls to encrypt
and decrypt.
- **Keyset** — the ZeroKMS key collection a workspace encrypts against.
Expand Down
Loading
Loading