Repository navigation
Description
Background
Stack Encrypt (packages/stack-encrypt) is the Rust engine that every CipherStash language SDK runs on. A Rust program encrypts a record by deriving traits on an encrypted struct. Each field's type says how that field is stored. A field's indexes come from its target type, such as SearchableEmail or IntegerOrd.
The scalar API already uses the owned traits EncryptTarget and DecryptSource (#1404), and collections do too (#1501). Records, derives, plans, and dynamic targets still use the older EncryptFrom and DecryptInto.
The Stack Encrypt API plan, merged in pull request #1365, describes the record derives.
Problem
Until records move to the owned traits, the old traits cannot be removed (#1488). Two record APIs also make the right one hard to find.
Proposal
- Derive
EncryptTargetandDecryptSourceon the encrypted struct. That struct is the declaration. The plaintext struct carries no attributes, so it can come from another crate. - Support passthrough fields, nested records, and stored context. The existing
fromattribute renames a source field. Extend it to passthrough fields. - Apply two safety rules. A plaintext field with no counterpart in the encrypted struct is a compile error, so no field is dropped silently. A field is stored in the clear only where
passthroughis written on it. - Enforce required, optional, and omitted caller context through types, with compile errors that name the field.
- Keep plaintext cleanup, passthrough ownership transfer, and collection batching.
- Update these against the same engine: plan lowering, the dynamic consumers, the guest, and the EQL adapters.
Pull request #1504 does this work and closes this issue.
Decision needed
Pull request #1504 uses #[stash(context = "..")] and adds ContextExtension. The naming review on 8 November 2026 replaced context = with scope = and removed ContextExtension. Choose one:
- change feat(stack-encrypt)!: derive owned record declarations with EncryptTarget and DecryptSource #1504 to the new names before it merges; or
- merge feat(stack-encrypt)!: derive owned record declarations with EncryptTarget and DecryptSource #1504 as it is, and make the change in stack-encrypt refactor: finalize crate ownership, naming and coordinated migration #1489.
Acceptance
- A mixed record, with passthrough and encrypted fields, round-trips as a test.
- A searchable record round-trips as a test.
- A
tests/uicase shows that a plaintext field with no counterpart fails to compile. - Typed, dynamic, and generated code produce the same results for the record and batch examples.
- Behaviour that already works is kept. Old APIs are removed only in stack-encrypt refactor: remove transitional traits and redundant execution APIs #1488, after every consumer has a replacement.
Relationship to other work
- Builds on stack-encrypt refactor: extend owned target conversions to collections #1482 (collections, done in feat(stack-encrypt): encrypt and decrypt owned
Vec<S>collections as one batch #1501) and stack-encrypt conformance: specify and test context composition #1475 (context baseline). - Field markers and
encryption_plan()are in stack-encrypt refactor: complete configured definitions and typed query APIs #1486. - The renames are in stack-encrypt refactor: finalize crate ownership, naming and coordinated migration #1489.
Plans: the Stack Encrypt API plan and the conformance roadmap.
Activity
feat(stack-encrypt)!: derive owned record declarations with EncryptTa…
feat(stack-encrypt)!: derive owned record declarations with EncryptTa…
feat(stack-encrypt)!: derive owned record declarations with EncryptTa…
feat(stack-encrypt)!: derive owned record declarations with EncryptTa…
feat(stack-encrypt)!: derive owned record declarations with EncryptTa…
feat(stack-encrypt)!: derive owned record declarations with EncryptTa…
coderdan commentedon Nov 9, 2026
Follow-up work for the EQL types, which #1504 leaves out:
EncryptFromandDecryptInto— addEncryptTargetandDecryptSource#1585: the EQL v4 types implementEncryptTargetandDecryptSource, beside the old derives. Item 6 of this issue ("the EQL adapters") moves there, so it stays tracked after feat(stack-encrypt)!: derive owned record declarations with EncryptTarget and DecryptSource #1504 closes this issue.Encryption::context_from, and test a v3-to-v4 migration shim #1586:Encryption::context_from, so a target can take its context from the plaintext it encrypts, with a test of an EQL v3 to v4 migration shim. It depends on eql-bindings: EQL v4 types implement only the oldEncryptFromandDecryptInto— addEncryptTargetandDecryptSource#1585.coderdan commentedon Nov 9, 2026
Done by #1504, which merged into
nexton 2026-11-09. GitHub closes an issue only from the default branch, so this one is closed by hand.