Skip to content

feat(eql-bindings): put the by-name dispatch behind a targets feature, and keep dynamic out of stack-encrypt - #1260

Merged
coderdan merged 3 commits into
nextfrom
feat/eql-bindings-targets-feature
Oct 18, 2026
Merged

coderdan merged 3 commits into
nextfrom
feat/eql-bindings-targets-feature

Conversation

@coderdan

@coderdan coderdan commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

eql-bindings' stack-encrypt feature turned on Stack Encrypt's dynamic layer for everyone who used it. Only the by-name dispatch a language binding needs uses dynamic; it names an EQL type at run time and takes a ValueFrame. So a Rust program that encrypts an IntegerEq through the typed encrypt_as compiled the whole dynamic layer for nothing. Now stack-encrypt gives the typed EQL v4 types alone, and a new targets feature adds the dispatch. This is step 2 of #1252.

Changes

  • packages/eql/crates/eql-bindings/Cargo.toml:
    • stack-encrypt builds Stack Encrypt with no default features and no dynamic.
    • targets turns on stack-encrypt, stack-encrypt/dynamic, and zeroize and thiserror, which only the dispatch uses.
    • docs.rs documents targets.
  • src/encryption.rs, src/v4/mod.rs: encryption::targets and the generated v4::targets compile under targets only. Two doc links that pointed at them now resolve under either feature set.
  • Consumers: the Go guest's eql build (languages/golang/encrypt/guest/Cargo.toml) and the encryption test crate enable targets.
  • packages/eql/mise.toml: test:encryption tests eql-bindings under both feature sets and runs clippy with -D warnings on each. check:encryption:wasi builds both stack-encrypt alone and targets (as the guest does) for wasm32.
  • Docs:
    • the README gains a Features section;
    • the CHANGELOG has a new "targets feature" entry, and the dispatch entries now name targets;
    • three unreleased changesets are updated;
    • two eql-codegen doc comments are fixed.

Verification

  • Which features Stack Encrypt is built with: cargo's JSON build output reports [] under --features stack-encrypt and ["dynamic"] under --features targets.
  • EQL: mise run types:check, test:encryption and test:crates pass. Clippy is clean, and cargo doc -p eql-bindings with -D warnings is clean under both features.
  • Go guest: the eql builds (deterministic and not) build, and the guest's own cargo test --locked --features eql passes.
  • Go and wasm32: go test ./encrypt/... passes, and so does cargo check -p eql-bindings --features targets --target wasm32-wasip1.
  • Lockfiles: cargo metadata --locked passes for the EQL, Go guest and protect-ffi workspaces, and no lockfile changed.

Related

Refs #1252 (proposal step 2). Stacked on #1259.

Review notes

@changeset-bot

changeset-bot Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: e43dfaf

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 changesets to release 12 packages
Name Type
@cipherstash/eql Minor
stash Patch
@cipherstash/stack-prisma Patch
@cipherstash/basic-example Patch
@cipherstash/e2e Patch
@cipherstash/prisma-example Patch
@cipherstash/stack-drizzle Patch
@cipherstash/stack-supabase Patch
@cipherstash/stack Patch
@cipherstash/wizard Patch
@cipherstash/bench Patch
@cipherstash/test-kit Patch

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 Oct 18, 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
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f2f69413-a362-4fde-aeae-7bd780ade9a3

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
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@coderdan coderdan left a comment

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.

Automated high-effort review by a Claude Code sub-agent. I reviewed only this PR's diff on top of #1259.

What I ran (fresh worktree at 27db82f1f, separate CARGO_TARGET_DIR):

  • cargo check -p eql-bindings --all-targets with --features stack-encrypt, --features targets and --no-default-features: all pass.
  • cargo clippy -p eql-bindings --all-targets -D warnings with --features stack-encrypt and with no features: clean.
  • RUSTDOCFLAGS="-D warnings" cargo doc -p eql-bindings --no-deps with --features stack-encrypt and with --features targets: clean.
  • Stack Encrypt's features from cargo's JSON output: [] for both cargo build and cargo test --no-run under --features stack-encrypt. So the stack-encrypt line in test:encryption really builds without dynamic, and no dev-dependency turns it back on.
  • mise run check:encryption:wasi and mise run test:encryption: pass (108 unit tests under stack-encrypt, 115 under targets; targets 16, v4_types 12 + 3 ignored, heap_hygiene 2).
  • Go guest: cargo check --locked --features eql passes, both natively (--all-targets) and for wasm32-wasip1.
  • cargo publish -p eql-bindings --dry-run --all-features --allow-dirty fails because stack-encrypt 0.3.0 is not on crates.io yet (only 0.1.0 and 0.2.0). That is expected and is not a finding.

Consumers and gating: no problems.

  • Nothing outside encryption::targets and v4::targets uses zeroize, thiserror or stack_encrypt::dynamic. So the stack-encrypt set builds without them, and I found no targets-gated item that a typed encrypt_as user needs. Identifier::from_label moves behind targets, but it returns TargetError, and the CHANGELOG already lists it under the dispatch entry.
  • Every user of the dispatch now enables targets: the Go guest (languages/golang/encrypt/guest/src/targets.rs) and eql-encryption-tests. protect-ffi and tests/sqlx depend on eql-bindings with no features and don't use the dispatch.
  • release-plz (publish_all_features) and the test-eql.yml dry run both use all features, so both pick up targets.
  • The CHANGELOG entries are all under [Unreleased], and the three changesets are consistent with the code.

Findings (all low; none blocks):

  1. CI now checks the stack-encrypt-only feature set less than before. Before this PR, stack-encrypt was the only feature, so every check covered it. Now three checks cover only the full targets set:

    • clippy in test:encryption (mise.toml:318, --all-features);
    • the wasm32 check (mise.toml:354, --features targets);
    • the registry builds: the --all-features dry run in test-eql.yml and publish_all_features in release-plz.

    The typed-only set is built only by the in-tree cargo test --features stack-encrypt, without -D warnings and only on the host. So nothing would catch these:

    • an unused import or dead code that shows up only without targets;
    • a wasm32 break in the typed path;
    • a crates.io stack-encrypt that puts something the typed path uses behind dynamic.

    Today all of these are clean (I ran clippy and the docs build on the stack-encrypt set by hand). Inline comments suggest small additions.

  2. The docs don't say the dispatch needs targets. docs.rs builds with targets, and the crate has no doc(cfg). So a reader on docs.rs sees encryption::targets with no hint that it needs a feature, and the src/encryption/targets.rs module docs never mention it. Also, encryption.rs:48 drops the [targets] intra-doc link even when the module exists. See the inline comment.

Comment thread packages/eql/mise.toml
Comment thread packages/eql/mise.toml
Comment thread packages/eql/crates/eql-bindings/src/encryption.rs Outdated
@coderdan
coderdan marked this pull request as ready for review October 18, 2026 07:32
@coderdan
coderdan requested a review from a team as a code owner October 18, 2026 07:32
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 18, 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-10-18T07:34:55.002772Z 27db82f Draft marked ready
🔒 Security Review ✅ Completed 2026-10-18T07:35:47.952635Z 27db82f 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 — Claude Code /code-review medium + /cross-check-review-findings, head 27db82f.

Result: no findings. No critical or blocking issues.

Checked against the PR diff and a local checkout:

  • cargo check --locked -p eql-bindings --features stack-encrypt and --features targets both build.
  • cargo test --no-run --features stack-encrypt compiles every test target without zeroize/thiserror, so moving them behind targets leaves no dangling use.
  • RUSTDOCFLAGS="-D warnings" cargo doc --features stack-encrypt is clean.
  • Every user of encryption::targets / v4::targets in the tree (Go guest eql build, tests/encryption) now enables targets.
  • protect-ffi depends on eql-bindings with no features, so it is unaffected.
  • The // (not ///) on the targets module declarations is correct for the reason given in the PR.
  • Changesets and CHANGELOG match the new feature split.

Not run here: Go tests, wasm32 check, and the mise tasks. CI covers those.


Generated by Claude Code

…, and keep dynamic out of stack-encrypt

eql-bindings' stack-encrypt feature turned on Stack Encrypt's dynamic
layer for every user, although only the by-name dispatch a language
binding needs uses it: encryption::targets and the generated v4::targets
take a ValueFrame and name an EQL type at run time. A Rust program that
encrypts an IntegerEq through encrypt_as compiled the whole dynamic layer
for nothing.

stack-encrypt now gives the typed EQL v4 types alone, with Stack
Encrypt's default features off and no dynamic. A new targets feature turns
on stack-encrypt, Stack Encrypt's dynamic feature, and zeroize and
thiserror, which only the dispatch uses, and compiles the two targets
modules. The Go guest's eql build and the encryption tests enable
targets. test:encryption tests eql-bindings under both feature sets, and
the wasm32 check builds targets, as the guest does. docs.rs documents
targets.

The comment on the encryption::targets declaration is a plain comment: a
doc comment there would resolve the module's own intra-doc links from the
parent scope.

Refs #1252.
Before the targets split, stack-encrypt was the only feature, so clippy
with -D warnings and the wasm32-wasip1 check covered the typed path. After
it, both ran only with targets on, and the typed set was built only by a
host cargo test without -D warnings. A lint that fires only without
targets, or a wasm32 break in the typed path, would have passed CI.

test:encryption now also runs clippy on eql-bindings with
--features stack-encrypt alone, and check:encryption:wasi also checks that
set for wasm32-wasip1. Both are clean.

Refs #1252
The encryption module docs lost their link to `targets` when the module
went behind the feature, because a link to a missing module fails the doc
build. Link it with cfg_attr when the feature is on, as lib.rs does, and
keep the plain text otherwise.

docs.rs builds with targets and the crate has no docsrs cfg, so no feature
badge shows. Say in the targets module docs that it needs the feature.

Refs #1252
@coderdan
coderdan force-pushed the feat/eql-bindings-targets-feature branch from 27db82f to e43dfaf Compare October 18, 2026 07:49
@coderdan

Copy link
Copy Markdown
Contributor Author

Reply to the review body. Both findings have inline threads; this covers the one part that only the body raised.

  • Finding 1, registry builds. Not changed. The --all-features dry run in test-eql.yml:660 and publish_all_features in release-plz still build only the targets set against crates.io. A typed-only dry run would catch a published stack-encrypt that puts something the typed path uses behind dynamic. But that dry run cannot build on a PR today (stack-encrypt 0.3.0 is not on crates.io, so the step only warns), and stack-encrypt's own tests build its typed API without dynamic. The new clippy and wasm32 lines cover the in-tree typed set (52e6fd2). If you want the registry side covered too, it is one more cargo publish --dry-run --features stack-encrypt line in the same step.
  • Finding 1, clippy and wasm32: fixed in 52e6fd2 (inline threads).
  • Finding 2, docs: fixed in e43dfaf (inline thread). No doc(cfg) badge, because the crate has no docsrs cfg and doc(cfg) is nightly-only.

Checks on e43dfaf, from packages/eql: cargo fmt --all --check, mise run test:encryption (both clippy runs), mise run check:encryption:wasi (both lines), cargo doc with -D warnings under --features stack-encrypt and --features targets, cargo check -p eql-bindings --no-default-features and mise run types:check pass. vitest run scripts/__tests__/eql-suite-ci.test.mjs scripts/__tests__/eql-workflow-filters.test.mjs passes (59 tests).

This branch is rebased onto #1259's new head 75336d3. I updated the mise.toml line in the PR description to match.

@coderdan
coderdan removed the request for review from a team October 18, 2026 07:59
Base automatically changed from test/eql-bindings-no-ffivalue to next October 18, 2026 08:15
@coderdan
coderdan merged commit 3167e75 into next Oct 18, 2026
42 checks passed
@coderdan
coderdan deleted the feat/eql-bindings-targets-feature branch October 18, 2026 08:16
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