Skip to content

feat: eql-types — JSON Schemas (stacked on #268)#269

Merged
coderdan merged 3 commits into
eql_v3from
dan/eql-types-json-schemas
Jun 16, 2026
Merged

feat: eql-types — JSON Schemas (stacked on #268)#269
coderdan merged 3 commits into
eql_v3from
dan/eql-types-json-schemas

Conversation

@coderdan

@coderdan coderdan commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Adds the schemars layer to the eql-types crate. Builds on #236 and #268 (both merged); rebased onto eql_v3.

  • JsonSchema derive on every v3 domain type, the term newtypes, and Identifier; the registry regains its schema fn
  • Checked-in generated schemas: crates/eql-types/schema/v3/<domain>.json (24 files, named after the SQL domain — the protocol identity), each with a canonical $id (https://schemas.cipherstash.com/eql/v3/<domain>.json) injected by tests/export.rs. Term newtypes appear as named definitions $ref'd by every domain schema
  • A third parity gate in catalog_parity.rs: each published schema's required list must equal envelope + catalog term keys (plus a strictness gate)
  • types:generate / types:check and the CI freshness step extended to cover schema/ (footgun-safe temp-dir swap, honoring EQL_TYPES_SCHEMA_DIR)

Closes #288.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 589d3b6e-6201-4d08-86f5-fb725d5ee446

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dan/eql-types-json-schemas

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderdan coderdan force-pushed the dan/eql-types-ts-bindings branch from 944fabd to 5f30374 Compare June 10, 2026 11:46
@coderdan coderdan force-pushed the dan/eql-types-json-schemas branch from 71d6836 to 6fbb949 Compare June 10, 2026 11:50
@coderdan coderdan force-pushed the dan/eql-types-ts-bindings branch from 5f30374 to 025fb41 Compare June 11, 2026 04:09
@coderdan coderdan force-pushed the dan/eql-types-json-schemas branch from 6fbb949 to d8bb343 Compare June 11, 2026 04:11
@coderdan coderdan force-pushed the dan/eql-types-ts-bindings branch from 025fb41 to cfdb58c Compare June 11, 2026 04:19
@coderdan coderdan force-pushed the dan/eql-types-json-schemas branch from d8bb343 to 303aff7 Compare June 11, 2026 04:21
@coderdan coderdan force-pushed the dan/eql-types-ts-bindings branch from cfdb58c to d2b8ae0 Compare June 11, 2026 04:27
@coderdan coderdan force-pushed the dan/eql-types-json-schemas branch from 303aff7 to 1697912 Compare June 11, 2026 04:29
@coderdan coderdan force-pushed the dan/eql-types-ts-bindings branch from d2b8ae0 to 404c053 Compare June 11, 2026 04:58
@coderdan coderdan force-pushed the dan/eql-types-json-schemas branch from 1697912 to bc45122 Compare June 11, 2026 04:59
@coderdan coderdan force-pushed the dan/eql-types-ts-bindings branch from 404c053 to 29418a0 Compare June 11, 2026 06:38
@coderdan coderdan force-pushed the dan/eql-types-json-schemas branch from bc45122 to 8a03896 Compare June 11, 2026 06:41
@coderdan coderdan force-pushed the dan/eql-types-ts-bindings branch from 29418a0 to 16ce202 Compare June 15, 2026 06:28
@coderdan coderdan force-pushed the dan/eql-types-json-schemas branch from 8a03896 to 0680247 Compare June 15, 2026 06:28
@coderdan coderdan force-pushed the dan/eql-types-ts-bindings branch from 16ce202 to 73acb8e Compare June 15, 2026 07:25
@coderdan coderdan force-pushed the dan/eql-types-json-schemas branch from 0680247 to f28b83d Compare June 15, 2026 07:25
@coderdan coderdan force-pushed the dan/eql-types-ts-bindings branch 2 times, most recently from 0250c37 to db988b3 Compare June 16, 2026 05:45
@coderdan coderdan force-pushed the dan/eql-types-json-schemas branch from f28b83d to d4a3e01 Compare June 16, 2026 06:00

@freshtonic freshtonic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. The schemars layer mirrors the ts-rs layer from #268 cleanly, coverage is complete (every domain type + term newtype + Identifier derives JsonSchema; DomainType::schema() is implemented across the board), and I verified the generated schemas against the new tests — all four JSON pointers in schemas_are_strict match the actual output.

Standouts worth calling out: the manual schemas tighten exactly where the derive is too loose (SchemaVersionconst: 2; BloomFilterminimum/maximum i16 bounds rather than the non-validating draft-07 format: "int16"), and the schemas_are_strict test correctly catches the cases the required-keys parity test alone would miss (a struct silently losing deny_unknown_fields, or v swapped for a bare integer). The types:generate temp-dir swap is correctly extended to two output trees, and dropping the explicit trap - EXIT is fine now since both mvs leave an empty $tmp for the EXIT trap to clean.

Minor items posted inline:

  1. Description drift risk in the two manual JsonSchema impls (lib.rs, terms.rs).
  2. The $id injection is untested (tests/export.rs).
  3. A question about the on-wire version value (lib.rs).

One trivial nit not tied to a line: the PR description says "23 files" but there are 24 schema files under schema/v3/ (one per v3 domain). The asymmetry vs the 30 TS bindings is correct and intentional — schemas inline the terms / Identifier / SchemaVersion as definitions rather than as separate files.

const_value: Some(serde_json::json!(EQL_SCHEMA_VERSION)),
metadata: Some(Box::new(schemars::schema::Metadata {
description: Some(
"The envelope version field (`v`) — always exactly `2` on the wire.".to_owned(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: should the on-wire version be 3, not 2, in the eql_v3 tier? It looks deliberate — the EQL_SCHEMA_VERSION doc comment states it's hard-coded to 2 for every payload including v3, mirroring the generated eql_v3 domain CHECK VALUE->>'v' = '2', so the wire envelope version is intentionally decoupled from the eql_v3 SQL schema namespace (consistent with the project's stance that the schema name is independent of the release version). Assuming that's right, no code change needed — but it's a genuine footgun for schema consumers: someone validating against v3/<domain>.json sees a v3 path and a const: 2 and will reasonably suspect a mistake. The Rust doc comment explains the decoupling, but schema consumers never see it. Suggest baking the why into this published description (e.g. "envelope format version 2; independent of the eql_v3 SQL schema namespace") so the artifact is self-explaining.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Waiting on @tobyhede to give the go-ahead to move to v3.

Comment thread crates/eql-types/src/v3/terms.rs
Comment thread crates/eql-types/tests/export.rs Outdated
Base automatically changed from dan/eql-types-ts-bindings to eql_v3 June 16, 2026 07:41
coderdan added 2 commits June 16, 2026 17:52
Stacks on the TypeScript bindings change. Every v3 domain type, the
term newtypes, and Identifier gain a JsonSchema derive; the registry
regains its schema fn; tests/export.rs writes one schema per SQL domain
to crates/eql-types/schema/v3/ (23 files, checked in) with a canonical
$id (https://schemas.cipherstash.com/eql/v3/<domain>.json) injected at
write time (schemars 0.8 emits none). Term newtypes appear as named
definitions that every domain schema $refs.

catalog_parity.rs gains a third gate: each domain's published schema
'required' list must equal envelope + catalog term keys, pinning the
artifact schema consumers validate against (the behavioural serde test
already pins the wire contract). types:generate / types:check and the
CI freshness step now cover schema/ as well as bindings/.
…keys

Review finding: the schema parity gate checked only `required`, so a
future token file losing #[serde(deny_unknown_fields)] or declaring v as
a bare integer would regenerate a permissive schema that types:check
commits as the new baseline — with behavioural spot checks existing for
only 5 of 23 domains. schemas_are_strict now asserts, for every domain:
additionalProperties: false at the root and on the nested Identifier,
v $ref'ing the SchemaVersion definition, and that definition pinning
const: EQL_SCHEMA_VERSION. Drilled: stripping deny_unknown_fields from
DateEq fails the gate with the targeted message.
@coderdan coderdan force-pushed the dan/eql-types-json-schemas branch from d4a3e01 to f49e65c Compare June 16, 2026 07:52
…ion drift

- Factor the published schema `$id` into `DomainType::schema_id`
  (`{SCHEMA_ID_BASE}{domain}.json`); `tests/export.rs` now injects that
  single source of truth, and a new `schema_id_is_canonical` parity test pins
  the URL shape with independent literals (wrong host / dropped `v3/` / wrong
  domain now fails a test, not just the freshness diff).
- Mark the `BloomFilter` and `SchemaVersion` doc comments as the canonical
  source for the descriptions their manual `JsonSchema` impls hand-copy, so
  the two can't silently drift (the derive copies doc comments automatically;
  these manual impls can't).

Schema artifacts regenerate byte-identically (schema_id matches the old inline
format) — verified via `mise run types:check`.
@coderdan coderdan merged commit b08694a into eql_v3 Jun 16, 2026
16 checks passed
@coderdan coderdan deleted the dan/eql-types-json-schemas branch June 16, 2026 09:12
tobyhede pushed a commit that referenced this pull request Jun 20, 2026
…ion drift

- Factor the published schema `$id` into `DomainType::schema_id`
  (`{SCHEMA_ID_BASE}{domain}.json`); `tests/export.rs` now injects that
  single source of truth, and a new `schema_id_is_canonical` parity test pins
  the URL shape with independent literals (wrong host / dropped `v3/` / wrong
  domain now fails a test, not just the freshness diff).
- Mark the `BloomFilter` and `SchemaVersion` doc comments as the canonical
  source for the descriptions their manual `JsonSchema` impls hand-copy, so
  the two can't silently drift (the derive copies doc comments automatically;
  these manual impls can't).

Schema artifacts regenerate byte-identically (schema_id matches the old inline
format) — verified via `mise run types:check`.
tobyhede pushed a commit that referenced this pull request Jun 20, 2026
feat: eql-types — JSON Schemas (stacked on #268)
tobyhede pushed a commit that referenced this pull request Jun 22, 2026
…ion drift

- Factor the published schema `$id` into `DomainType::schema_id`
  (`{SCHEMA_ID_BASE}{domain}.json`); `tests/export.rs` now injects that
  single source of truth, and a new `schema_id_is_canonical` parity test pins
  the URL shape with independent literals (wrong host / dropped `v3/` / wrong
  domain now fails a test, not just the freshness diff).
- Mark the `BloomFilter` and `SchemaVersion` doc comments as the canonical
  source for the descriptions their manual `JsonSchema` impls hand-copy, so
  the two can't silently drift (the derive copies doc comments automatically;
  these manual impls can't).

Schema artifacts regenerate byte-identically (schema_id matches the old inline
format) — verified via `mise run types:check`.
@tobyhede tobyhede mentioned this pull request Jun 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants