Skip to content

test(stack-encrypt): enroll EQL and JSON conformance - #1492

Open
coderdan wants to merge 5 commits into
feat/stack-encrypt-context-conformancefrom
feat/stack-encrypt-eql-json-conformance
Open

coderdan wants to merge 5 commits into
feat/stack-encrypt-context-conformancefrom
feat/stack-encrypt-eql-json-conformance

Conversation

@coderdan

@coderdan coderdan commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

EQL/JSON tests already cover the operations, but lack shared requirements and a required, versioned conformance report. This enrolls resolver/catalog capabilities, document writes, queries, request-bound extraction/subtree reads, element-match and predicate-match in the existing Rust, Go and PostgreSQL suites.

Shares 11 valid documents, four invalid documents and 15 predicate refusals across native Rust and Go while retaining typed/generated API assertions and independent PostgreSQL plaintext oracles. The contract documents the supported grammar, null/missing behavior, authentication limits and intentional SQL differences.

Adds required fast and PostgreSQL CI steps. Compiled-test inventory checks and Go result checks reject missing or skipped evidence; reports record engine/binding versions, guest and lockfile hashes, installed PostgreSQL/EQL versions and the exact installed SQL bundle hash. Existing fixture paths remain intact and required runs refuse regeneration.

Validation:

  • Fast profile: 95 native Rust tests and 21 Go tests.
  • PostgreSQL 17.10: 32 native tests and four Go tests, using freshly built EQL v4 SQL.
  • Rust clippy/formatting, Go lint, Biome, 119 CI-wiring checks.
  • Missing-guest and fixture-update refusal regressions; report artifact output.

Stacked on #1491; base is feat/stack-encrypt-context-conformance. No production encryption behavior changes. Python/TypeScript runners, fresh JSON cross-language artifact exchange and release compatibility matrices remain separate work.

Closes #1476

Require named Rust, Go and PostgreSQL evidence, share document and predicate refusal cases, and report engine and SQL bundle identities.

Closes #1476
@changeset-bot

changeset-bot Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 65d4937

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

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
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI; Enforced overrides: Organization
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: cc155b05-eb4b-4dcb-a008-9da17058e667

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

@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Mutation testing (cargo-mutants, --in-diff, stack-auth + stack-encrypt)

No mutants were generated for the changed lines.

@coderdan

coderdan commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

Review: enroll EQL and JSON conformance

Reviewed 7f36ec045 against feat/stack-encrypt-context-conformance, on two axes: the repo's coding standards, and #1476 plus the conformance plan. Locally stack-eql-conformance.test.mjs passed 6/6, and json_operators + json_tree_vectors passed 27/27. The PostgreSQL lane was not run locally, and its CI job had not reported when this was written.

Standards

No hard violations. All three copies of the EQL path filter gained the same conformance/stack-encrypt/** entry, both new root mise tasks have a CI caller, cargo calls pass --locked, and no issue numbers were added. The change is tests and tooling only, so it needs no changeset or CHANGELOG entry.

A defect tooling won't catch:

  • A doc comment now sits on the wrong test. In packages/stack-encrypt/tests/json_operators.rs:2186-2190, shared_predicate_refusals was inserted between the doc comment of is_refused_with_its_reason_and_offset and its #[test]. "A refusal names its reason…" now documents the new test, and the old one (:2213) has none.

Judgement calls against documented rules:

  1. The PostgreSQL job runs nextest without MISE_ENV: test. The eql-postgres job in tests-golang.yml (from line 407) runs cargo nextest through stack-eql-conformance.mjs:126, but only wasi-check (line 143) sets MISE_ENV: test. AGENTS.md: "CI jobs that use them set MISE_ENV: test". Without it, mise-action doesn't install nextest, and mise x builds it uncached.
  2. The SQL bundle is built and installed twice. mise.toml:447-448 runs mise -C packages/eql run clean then build, in the same job where go:test:postgres has just built and installed the bundle, and the script installs it again (:203). That throws away the build cache.
  3. The EQL crates compile under the root Rust version. The script compiles the packages/eql workspace from the repo root, so it uses Rust 1.94.1 rather than the version packages/eql/mise.toml pins. That file "overrides the Rust pin in its folder", and test-eql.yml builds under that pin, so this lane checks the EQL crates with a different compiler.

Code smells (judgement calls):

  • Duplicated code. The eql-json.json loader (parse, assert version == 1) is written inline in json_operators.rs:2191-2195 and again as conformance_cases() in json_tree_data_plan.rs:1149-1156. In Go, json_tree_test.go:32, :88, :103 each call jsonConformanceCases(t), so the file is read once per test.
  • A variable that adds nothing. json_match_test.go:284 adds want := tc.At.
  • A guard keyed to text. The conformance/stack-encrypt/** exemption in eql-suite-ci.test.mjs:410-423 applies only if the .rs file contains the corpus path as text, so a comment with the path would satisfy it.
  • A brittle wiring test. The last test in stack-eql-conformance.test.mjs checks CI wiring, string fields in the script and an exact filter count of 2. A harmless reformat would break it.

Spec

Verified:

  • No assertion was dropped. The documents, invalid documents and refusals moved from json_match_test.go, json_tree_test.go and json_tree_data_plan.rs into conformance/stack-encrypt/v1/eql-json.json. The corpus holds more than any old table: 11 valid documents (Go had 6, Rust 10) and 4 invalid ones (Go 3, Rust 4). Rust and Go both read it.
  • The inventory check uses the compiled tests. It reads nextest list --message-format json and Go's -json pass/skip events, not text in the source.
  • Both new CI steps are required. Neither has continue-on-error or an if:, and the report uploads use if-no-files-found: error.
  • Tampering is tested natively and in PostgreSQL. Go covers only the wrong-column case.
  • Randomized projection order is documented (eql-json-contract.md:83-87).
  • The bundle hash matches what is installed. It is computed from the file on disk (stack-eql-conformance.mjs:199-203), but the script then installs exactly that file and nothing else installs SQL, so the claim holds. It is never read back from the database.

(a) Missing or partial:

  • "Define … extraction, subtree, element-match and predicate-match operation profiles." Extraction and subtree share one requirement, json-request-bound-reads-v1 (eql-json-profiles.json:145), rather than one each. Tamper handling has no requirement ID of its own.
  • "Record engine and SQL bundle versions." The report's schema version is the literal 'schema', 4 in the query (stack-eql-conformance.mjs:214), but eql-json-contract.md:119 presents it as the installed schema version. Read it from the database, or describe it as the expected version.

(b) Scope creep:

  • Every Go EQL test now fails rather than skips in required mode. The change at fixture_conformance_test.go:21 applies to all Go EQL tests, not only the enrolled ones, so a missing EQL guest is now a failure. Probably intended, but not stated.

(c) Implemented but worth fixing:

  • The misplaced doc comment in json_operators.rs:2186-2190 (see Standards).
  • Go's offsets lost their explanation. They were computed with strings.Index from the text they pointed at, which showed which construct each offset names. They are now bare integers: just as strict, but harder to read.
  • The too-deep case no longer tests absent variables. It now passes {} where Go used to pass nil, so it no longer goes through the absent-variables path.

Summary

  • Standards: 1 defect, 3 judgement calls against documented rules and 4 smells. The worst is the doc comment that now documents the wrong test. Close behind: the PostgreSQL job runs nextest without MISE_ENV: test.
  • Spec: 2 partial requirements, 1 undeclared change and 3 implementation issues. The worst is the hard-coded schema version presented as the installed one.

@coderdan
coderdan marked this pull request as ready for review November 1, 2026 10:45
@coderdan
coderdan requested a review from a team as a code owner November 1, 2026 10:45
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-01T10:47:11.646702Z 7f36ec0 Draft marked ready
🔒 Security Review ✅ Completed 2026-11-01T10:47:33.365094Z 7f36ec0 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@cipherstash-agent cipherstash-agent 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.

Automated review attestation: 7f36ec0

Source: Claude Code scheduled routine (/code-review medium plus cross-check-review-findings). It read the full diff against base feat/stack-encrypt-context-conformance and checked each finding against the head commit.

Critical / blocking: none.

New findings: none. Every defect I confirmed at head is already in the existing review, and I have nothing material to add to those items. Confirmed at head:

  • The doc comment for is_refused_with_its_reason_and_offset now sits on shared_predicate_refusals (packages/stack-encrypt/tests/json_operators.rs:2186-2190).
  • The report's 'schema', 4 is hard-coded, not read from the database (scripts/stack-eql-conformance.mjs:214).
  • The eql-postgres job runs nextest through mise x --env test without MISE_ENV: test (.github/workflows/tests-golang.yml).

Checked, no problem found:

  • Both deterministic guests are built before the new fast step (tests-golang.yml lines 202-215, step at 266).
  • checkGoResults fails on skip or fail and requires every selected test to report a pass, so an empty selection cannot pass.
  • checkRustInventory checks ignored status per lane and --run-ignored is set per lane.
  • Fixture-update variables are refused, and the report upload uses if-no-files-found: error.

Not run: the PostgreSQL lane, and the Codex code and security reviews were still running when this was written.


Generated by Claude Code

coderdan commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the standards/spec review and second-agent confirmation in e6ce5d0.

  • Restored the original test's doc comment and documented the shared test separately.
  • Added MISE_ENV: test to the PostgreSQL job, installed EQL's tools in the fast job, and run EQL cargo commands from its workspace so its toolchain configuration applies.
  • go:test:postgres delegates SQL setup and the four JSON suites to the conformance task, then runs its three remaining suites. SQL is built and installed once.
  • Reports now distinguish expected_schema from the actual schema name read from pg_namespace, alongside the installed EQL/PostgreSQL versions and installed bundle hash.
  • Added explicit extraction, subtree and tamper requirement IDs. Documented that required-mode missing-guest failures intentionally cover all users of the EQL test helper.
  • Restored absent variables for the too-deep case, added checked at_text explanations for offsets, and removed the redundant Go offset variable.
  • The external-corpus guard now parses Rust include macros with comments stripped. Workflow filters are checked as parsed YAML rather than source counts, and the wiring check verifies the shared SQL setup path.

I retained the small independent Rust corpus loaders and per-test Go reads: the consumers belong to different Cargo workspaces, and sharing their test-only JSON parsing would add coupling without consolidating any semantic expectations. The corpus itself remains shared; no cache or new dependency is needed for this small fixture.

Validation: required native/Go fast lane; unified PostgreSQL task (32 native JSON tests, four Go JSON tests and three remaining Go database suites); Rust clippy, Go lint, formatting, Biome and CI guards. The database report records actual schema eql_v4 and PostgreSQL 17.10. There were no inline review threads to resolve.

@blacksmith-sh

This comment has been minimized.

coderdan commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up CI fixes are pushed in 64f5163. The EQL mise setup now installs its tools without exporting its local DATABASE_URL into the hermetic Go job. The EQL cache guard also accepts a multi-workspace cache entry that includes the nested EQL workspace. All 78 relevant runner/CI regression tests and formatting checks pass locally; CI is rerunning. Both fixes have been carried into the stacked lifecycle PR #1493.

coderdan commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

Fixed the shared CI bootstrap failure in 7a3dec9 (also merged into #1493). Every failed job stopped before tests with No version is set for shim: cargo-binstall: EQL setup left a cached shim, but the root test environment selected no version. mise.test.toml now pins the prebuilt cargo-binstall installer at 1.26.2, so mise can resolve it before installing nextest and the other cargo tools.

Verified with CI's exact mise 2026.4.0 in isolated tool/Cargo directories: the original configuration reproduces the failure; adding the pin installs and runs cargo-nextest 0.9.146 successfully. All 47 relevant CI/tooling regression tests and formatting checks pass. Fresh CI runs have been triggered on both PRs.

coderdan commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

Fixed in 65d4937 and carried into the stacked PR #1493.

The CRAP failures were executable compatibility failures after coverage tests passed: cargo-crap 0.6.1's downloaded Linux binary requires GLIBC 2.39. Both CRAP jobs now run on Ubuntu 24.04 with matching mise cache keys, and check cargo crap --version before collecting coverage. The scoring thresholds and coverage scope are unchanged.

Also fixed the PostgreSQL job's cached Rust toolchain failure: it now reconciles both configured Rust toolchains and verifies cargo before restoring the build cache.

Verified in GitHub Actions on both PRs: CRAP (stack-auth), CRAP (stack-encrypt), the full WASI/Go job, and Go rows/queries plus JSON conformance in PostgreSQL all passed. Locally, all 116 relevant CI regression tests and the 10 child conformance-runner tests passed.

@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.

Approved. The shared corpus is written by hand and not generated from the code it tests, and no case was dropped. CI runs both lanes: the reports show 41 Rust and 21 Go tests in the fast lane, and 18 Rust and 4 Go tests in the PostgreSQL lane. If one corpus entry is changed, shared_predicate_refusals fails as it must.

The inline comments carry suggestions that you can commit with one click. The two items below are outside the diff, so I cannot attach suggestions to them.

1. Should-fix: the PR description

The description says the PR is test-only, but it does not mention three CI and toolchain changes. Please add a line for each:

  • mise.test.toml pins cargo-binstall 1.26.2 in every MISE_ENV=test job. It is a new tool binary in every test job, so it is a supply-chain decision.
  • crap-crates.yml moves both CRAP jobs from ubuntu-2204 to ubuntu-2404, because cargo-crap 0.6.1 needs GLIBC 2.39.
  • tests-golang.yml adds a mise install --force rust repair step.

Also: CI ran PostgreSQL 17.11, not 17.10. The "95 native / 32 PG native" counts are totals for the whole binary; the corpus names 41 and 18 of those tests.

2. Should-fix: the docs for go:test:postgres

go:test:postgres now starts with test:conformance:eql:postgres. That task runs mise -C packages/eql run clean and build, installs the bundle with psql, runs the Rust --run-ignored only nextest lane, needs both deterministic guests, and refuses STACK_CONFORMANCE_UPDATE, STACK_ENCRYPT_UPDATE_FIXTURES and STACK_ENCRYPT_UPDATE_JSON_TREE_VECTORS. A contributor who has only Go and follows CONTRIBUTING.md now gets a cargo or nextest failure with no explanation. Proposed text:

CONTRIBUTING.md (the paragraph after the mise run go:test block):

For EQL v4 PostgreSQL coverage, set `EQL_TEST_DATABASE_URL` to a disposable
database and run `mise run go:test:postgres`. The task builds the EQL v4 bundle
from this tree and installs it into that database, so it replaces the EQL there.
It needs `psql`, the Rust test tools (`mise install --env test`) and both
deterministic guests. It refuses to run while a fixture-update variable, such as
`STACK_ENCRYPT_UPDATE_FIXTURES`, is set. Go examples that connect to ZeroKMS need
CipherStash credentials. The [Go module guide](languages/golang/README.md)
links to the SDK, generator, credentials, examples and release notes. Commit
generated `*_stash.go` files when changing Go model tags; CI checks for drift.

languages/golang/README.md (the paragraph after the build block):

The `.wasm` files are build outputs and are not committed on development
branches. `mise run go:test:postgres` also runs the PostgreSQL suite against
the EQL v4 bundle built from this tree, and the shared EQL/JSON conformance
lane before it. It needs the disposable database named by
`EQL_TEST_DATABASE_URL`, `psql`, and the Rust test tools
(`mise install --env test`), because the conformance lane runs Rust tests too.
See `mise.toml` and [AGENTS.md](../../AGENTS.md) for the build and release
details.

AGENTS.md (the "CI:" bullet under "Working on the Rust crates"), change the go:test:postgres clause to:

  module on Linux, macOS and Windows, its PostgreSQL tests against the EQL v4
  bundle built from the tree — `mise run go:test:postgres` locally, which also
  runs the Rust and Go EQL/JSON conformance lane and so needs `psql` and the
  `MISE_ENV=test` cargo tools — and the live tests), `crap-crates.yml`,

assert_eq!(payload["at"], case["at"], "{}", case["id"]);
assert_eq!(payload["construct"], case["construct"], "{}", case["id"]);
assert_eq!(error.field(), Some("profile"));
assert!(!format!("{error} {payload:?}").contains("secret"));

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.

Nit: Go (json_match_test.go, TestMatchRefusalsNameTheConstructAndItsOffset) also checks that the error does not hold the predicate text. The contract says "no caller text in diagnostics", so this side must check it too. Without the check, a change that copies $.weight + 1 == 2 into the error still passes.

I ran this with cargo nextest run -p stack-encrypt --all-features --test json_operators shared_predicate_refusals. It passes, and cargo fmt --check is clean.

Suggested change
assert!(!format!("{error} {payload:?}").contains("secret"));
let rendered = format!("{error} {payload:?}");
assert!(
!rendered.contains("secret") && !rendered.contains(predicate),
"{}: the error holds the caller's text: {rendered}",
case["id"]
);


## EQL/JSON operation checkpoint

Implemented the six requirements in

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.

Nit: eql-json-contract.md and eql-json-profiles.json both have nine requirements.

Suggested change
Implemented the six requirements in
Implemented the nine requirements in

Comment thread mise.test.toml
# its prebuilt installer here too: an unselected shim is still found on PATH
# by the cargo backend, then fails before it can install any test tools.
"cargo-binstall" = "1.26.2"
"cargo:cargo-nextest" = "0.9.146"

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.

This adds a pinned tool binary to every MISE_ENV=test job. The comment explains why. Please also say it in the PR description, because the description calls the PR test-only (see the review summary).

This branch has not been deployed

No deployments
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.

3 participants