test(sqlx): eql_v3 SQL-function property tests (CIP-3141)#293
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
376b4a6 to
2ec34d3
Compare
572afcc to
3e57268
Compare
b41e03b to
7725810
Compare
5e0d14f to
cf3e2d5
Compare
cf3e2d5 to
65fe909
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/sqlx/tests/encrypted_domain/property/README.md`:
- Around line 146-147: The cargo test invocation in the README documentation
passes multiple filter arguments separated by spaces, but cargo test only
accepts a single filter string. Fix the command by combining the multiple test
names (fixture_oracle, match_smoke, edge_cases) into a single filter pattern
using regex syntax with the pipe operator, such as combining them into a pattern
that matches all three tests with a single string argument, or alternatively
show multiple separate cargo test invocations if demonstrating individual test
runs is the intent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 03f48300-6987-42a1-9143-c4e9c129717e
📒 Files selected for processing (16)
.github/workflows/README.md.github/workflows/test-eql.ymlCHANGELOG.mdcrates/eql-tests-macros/src/lib.rsmise.tomltasks/docs/validate/source.shtests/sqlx/README.mdtests/sqlx/src/fixtures/driver.rstests/sqlx/src/fixtures/scalar_fixture.rstests/sqlx/src/property.rstests/sqlx/tests/encrypted_domain/property/README.mdtests/sqlx/tests/encrypted_domain/property/e2e_oracle.rstests/sqlx/tests/encrypted_domain/property/edge_cases.rstests/sqlx/tests/encrypted_domain/property/fixture_oracle.rstests/sqlx/tests/encrypted_domain/property/match_smoke.rstests/sqlx/tests/encrypted_domain/property/mod.rs
Adds the eql_v3 encrypted-domain property suite over the committed, curated real-ciphertext fixtures: - shared all-pairs operator oracle (property.rs): = / <> on _eq and the ordered comparisons + ord_term sort order, checked against a plaintext oracle over every ordered pair of fixture rows; - function-double oracles: the generated eql_v3.eq/neq/lt/lte/gt/gte functions across all three overloads (domain-domain, domain-jsonb, jsonb-domain) plus term-extractor identity (eq_term==hm, ord_term==ob); - bloom match smoke for the text _match domain; NULL/blocker/CHECK edge cases; - the e2e suite (gated behind proptest-e2e) over fresh ZeroKMS encryption. Fixtures are generated from the curated catalog values via FixtureSpec::run().
…P-3141) Adds a dedicated test:sqlx:e2e mise task and CI job for the proptest-e2e suite (needs ZeroKMS creds; the credential-free shards run the fixture suite), and runs source doc validation unconditionally.
Documents the three property-test suites (catalog / fixture / e2e) over the committed curated fixtures, the function-double oracles, and term-extractor identity. CHANGELOG entry under [Unreleased].
65fe909 to
34d3e9e
Compare
…le (CIP-3141) The float4/float8 shared-index-term e2e test pulled both `hm` and `ob` via `as_str()`, but the ORE `ob` term is a JSON array of block strings, not a scalar string (only `hm` is a string). `as_str()` returned None on the array, raising "payload missing string `ob`". Split the helper: `hm` stays a string, `ob` extracts the array and compares directly, matching the canonical extractor in property.rs. Latent until the gated e2e suite started running in CI.
There was a problem hiding this comment.
🧹 Nitpick comments (2)
tests/sqlx/tests/encrypted_domain/property/e2e_oracle.rs (2)
253-257: ⚡ Quick winStrengthen
obextractor to validate block element types, not only array shape.At Line 253-257,
obcurrently accepts any JSON array. This can let malformed ORE terms (e.g., non-string elements) pass this test unintentionally.Proposed patch
- let ob = |p: &serde_json::Value| -> Result<serde_json::Value> { - p.get("ob") - .filter(|v| v.is_array()) - .cloned() - .ok_or_else(|| anyhow::anyhow!("payload missing array `ob`: {p}")) - }; + let ob = |p: &serde_json::Value| -> Result<Vec<String>> { + let arr = p + .get("ob") + .and_then(serde_json::Value::as_array) + .ok_or_else(|| anyhow::anyhow!("payload missing array `ob`: {p}"))?; + arr.iter() + .map(|v| { + v.as_str() + .map(str::to_owned) + .ok_or_else(|| anyhow::anyhow!("payload `ob` contains non-string block: {p}")) + }) + .collect() + };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/sqlx/tests/encrypted_domain/property/e2e_oracle.rs` around lines 253 - 257, The `ob` closure at lines 253-257 only validates that the "ob" field is a JSON array but does not validate the types of elements within that array. To strengthen this validation, after confirming that the value is an array, add logic to verify that all elements within the array are of the expected type (likely strings for ORE block elements). If any element fails type validation, return an error with a descriptive message indicating which element or type check failed.
262-270: ⚡ Quick winAvoid panic-prone
[0]indexing in assertions; fail with explicit error context instead.At Line 263 and Line 269, direct indexing can panic if
encrypt_storereturns an empty vec, which obscures the root cause during CI failures.Proposed patch
+ let f4_first = f4_payloads + .first() + .ok_or_else(|| anyhow::anyhow!("no payload returned for float4 encryption"))?; + let f8_first = f8_payloads + .first() + .ok_or_else(|| anyhow::anyhow!("no payload returned for float8 encryption"))?; + assert_eq!( - hm(&f4_payloads[0])?, - hm(&f8_payloads[0])?, + hm(f4_first)?, + hm(f8_first)?, "float4 and float8 of the same value must share the hm equality term" ); // ORE term: same f64 input => same ORE ciphertext, so ordering is identical. assert_eq!( - ob(&f4_payloads[0])?, - ob(&f8_payloads[0])?, + ob(f4_first)?, + ob(f8_first)?, "float4 and float8 of the same value must share the ob ORE term" );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/sqlx/tests/encrypted_domain/property/e2e_oracle.rs` around lines 262 - 270, The test assertions use unsafe direct indexing with [0] on f4_payloads and f8_payloads vectors, which will panic if these vectors are empty without providing any debugging context. Replace the direct indexing [0] accesses with safer methods like .get(0) or .first() that return Option types, then chain with .ok_or() or similar error handling to provide explicit, descriptive error messages when the vectors are unexpectedly empty. Apply this fix to all instances of f4_payloads[0] and f8_payloads[0] in the assertion blocks to ensure clear error context if the encryption operations fail to produce results.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@tests/sqlx/tests/encrypted_domain/property/e2e_oracle.rs`:
- Around line 253-257: The `ob` closure at lines 253-257 only validates that the
"ob" field is a JSON array but does not validate the types of elements within
that array. To strengthen this validation, after confirming that the value is an
array, add logic to verify that all elements within the array are of the
expected type (likely strings for ORE block elements). If any element fails type
validation, return an error with a descriptive message indicating which element
or type check failed.
- Around line 262-270: The test assertions use unsafe direct indexing with [0]
on f4_payloads and f8_payloads vectors, which will panic if these vectors are
empty without providing any debugging context. Replace the direct indexing [0]
accesses with safer methods like .get(0) or .first() that return Option types,
then chain with .ok_or() or similar error handling to provide explicit,
descriptive error messages when the vectors are unexpectedly empty. Apply this
fix to all instances of f4_payloads[0] and f8_payloads[0] in the assertion
blocks to ensure clear error context if the encryption operations fail to
produce results.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b8fb3117-7b5a-4c08-b9c2-8ba478aca589
📒 Files selected for processing (16)
.github/workflows/README.md.github/workflows/test-eql.ymlCHANGELOG.mdcrates/eql-tests-macros/src/lib.rsmise.tomltasks/docs/validate/source.shtests/sqlx/README.mdtests/sqlx/src/fixtures/driver.rstests/sqlx/src/fixtures/scalar_fixture.rstests/sqlx/src/property.rstests/sqlx/tests/encrypted_domain/property/README.mdtests/sqlx/tests/encrypted_domain/property/e2e_oracle.rstests/sqlx/tests/encrypted_domain/property/edge_cases.rstests/sqlx/tests/encrypted_domain/property/fixture_oracle.rstests/sqlx/tests/encrypted_domain/property/match_smoke.rstests/sqlx/tests/encrypted_domain/property/mod.rs
✅ Files skipped from review due to trivial changes (4)
- tests/sqlx/src/fixtures/scalar_fixture.rs
- tests/sqlx/README.md
- mise.toml
- CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (8)
- tests/sqlx/tests/encrypted_domain/property/mod.rs
- tasks/docs/validate/source.sh
- crates/eql-tests-macros/src/lib.rs
- tests/sqlx/tests/encrypted_domain/property/match_smoke.rs
- tests/sqlx/tests/encrypted_domain/property/edge_cases.rs
- tests/sqlx/tests/encrypted_domain/property/fixture_oracle.rs
- tests/sqlx/src/fixtures/driver.rs
- tests/sqlx/src/property.rs
…or (CIP-3141) `float4_and_float8_share_index_terms_for_the_same_value` asserted byte-equality of the raw `ob` ORE arrays of two independently-encrypted payloads. That can never hold: a BlockORE term is `Left (deterministic) ++ Right (16-byte random per-ciphertext nonce + nonce-masked truth tables)`, so two encodings of the SAME value — same width, same cast — are byte-UNEQUAL by construction. Ordering is decided by the ORE compare function, not raw bytes. (The cast is irrelevant: `real`/`double` collapse to one f64 `ColumnType::Float` in cipherstash-client; the deterministic Left halves are byte-identical, which is what proves the two widths share an encoding.) The bug stayed latent because the e2e suite is feature/creds-gated and, when it did run, an earlier `ob`-as-string extraction errored out before the assertion; fixing that extraction (5bbd959) unmasked the wrong assertion. Compare the extracted `ord_term`s through the SQL `eql_v3.ore_block_256` `=` operator (the only correct ORE check) and keep the deterministic `hm` equality term as a direct byte comparison. Also correct the CHANGELOG claim of a "byte-identical ORE term" to "equal under the ORE comparator". Verified: the test now passes against fresh ZeroKMS encryption.
Stacks on #275 (
v3-property-tests) and extends its proptest oracle harness with the #290 function-double pattern: call the generatedeql_v3.*comparison functions and term extractors by name, across all three operand overloads, asserted against #275's existing plaintext oracle over its live-encryption fixtures. (CIP-3141)What this adds (over #275's operator oracles)
eql_v3.eq/neq/lt/lte/gt/gte(andcontains/contained_byfor bloom), not just the infix operators they back.(domain,domain),(domain,jsonb),(jsonb,domain)viaOverload::ALL(the jsonb-cast convenience paths test(v3): property-based tests for the eql_v3 encrypted scalar domains (CIP-3141) #275 never reached).eq_term(payload) == hm,ord_term(payload) == ob(re-rendered hex blocks), catalog-driven sotext_ord/text_searchcheck both.matchsmoke — curated example-basedcontains/contained_by(left-contains-right@>) + non-emptymatch_termover the text fixtures.Coverage: int4/int2/int8/date (ordered) + timestamptz (eq-only) + text (full eq/ord suite +
_search+_matchsmoke). Tier A (free, fixture corpus) is the bulk; Tier B folds the assertions into the corpus #275 already encrypts per case — ~zero marginal ZeroKMS cost.Helpers (
tests/sqlx/src/property.rs)Overload,assert_eq_fn_oracle,assert_ord_fn_oracle,assert_extractor_oracle,assert_match_smoke— reusingRow,cast,connect_pool,ensure_fixture_loadedverbatim.Notes
b632175, also pushed tov3-property-tests): theeql_v3rebase added atokenparam toVariant::supports_ord, butassert_ord_oraclestill called it tokenless, so theeql_testslib did not compile. Fixed withT::PG_TYPE.ord_termre-render fix: test(eql-types): SQL-backed property tests for int4 v3 domains #290'sWITH ORDINALITY AS u(t,n)form expands the single-field compositeore_block_u64_8_256_termintobytea(so(t).bytesfails to resolve); switched togenerate_subscripts, verified the re-rendered blocks equal the payloadob.Cargo.toml/mise.toml/CI changes, no CHANGELOG entry (per CLAUDE.md).Local verification
test:crates(incl. Tier C) ✅ ·test:matrix:inventory✅ (snapshot unperturbed) · all 36property::tests pass against a healthy DB (Tier A + Tier Bproptest-live). The combined fulltest:sqlxrun is deferred to CI here (local Docker/disk constraints); this PR exists to run it.Summary by CodeRabbit
New Features
Tests
Documentation