Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
958 commits
Select commit Hold shift + click to select a range
9f33dae
test(conformance): give every conformance file a profile header
coderdan Nov 3, 2026
b7508e7
test(encrypt): enroll EQL JSON conformance
coderdan Nov 1, 2026
9d788c4
test(encrypt): address EQL conformance review
coderdan Nov 1, 2026
8faeef4
fix(ci): isolate EQL tool setup environment
coderdan Nov 1, 2026
14d9a18
fix(ci): select cached cargo-binstall shim
coderdan Nov 1, 2026
2995fbb
fix(ci): repair CRAP and cached Rust runtimes
coderdan Nov 1, 2026
2828461
test(conformance): name the EQL/JSON files by profile and role
coderdan Nov 3, 2026
07a5a14
test(encrypt): address the EQL/JSON conformance approval review
coderdan Nov 3, 2026
cd1a228
Merge pull request #1491 from cipherstash/feat/stack-encrypt-context-…
coderdan Nov 5, 2026
7abbc01
Merge pull request #1492 from cipherstash/feat/stack-encrypt-eql-json…
coderdan Nov 5, 2026
2dd9b93
test(encrypt): enroll lifecycle conformance
coderdan Nov 3, 2026
0782e8b
test(encrypt): cover the decrypt path and the lifecycle runner's argu…
coderdan Nov 5, 2026
6f0b092
feat(stack-encrypt): encrypt and decrypt owned Vec<S> collections as …
coderdan Nov 2, 2026
c2d7c7c
test(stack-encrypt): enroll owned collection lifecycle evidence
coderdan Nov 2, 2026
585f6a8
fix(stack-encrypt): wipe a column's recovered prefix when an element …
coderdan Nov 2, 2026
34120f5
test(stack-encrypt): pin that no vector encrypts into one ciphertext …
coderdan Nov 2, 2026
c762f40
test(stack-encrypt): enroll the owned-column drop witnesses, which se…
coderdan Nov 2, 2026
4b4a5b4
test(stack-encrypt): pin the borrowed element refusal on the trait, n…
coderdan Nov 2, 2026
a2e4520
Merge pull request #1493 from cipherstash/feat/stack-encrypt-lifecycl…
coderdan Nov 5, 2026
8c4e938
build(stack-encrypt)!: move to vitaminc 0.9
coderdan Nov 5, 2026
1f81e22
feat(stack-encrypt): byte strings are opaque scalars, through vitamin…
coderdan Nov 5, 2026
f4e5ba2
build(stack-encrypt): move the fuzz crates to vitaminc 0.9, and impor…
coderdan Nov 5, 2026
348a92e
docs(stack-encrypt): plain-language pass over the owned collections docs
coderdan Nov 6, 2026
14de0da
docs(stack-encrypt): hide the fake key source in the collections example
coderdan Nov 6, 2026
72ffaf6
docs(stack-encrypt): say collection, not column, and hide the fake ke…
coderdan Nov 6, 2026
4f6a1de
feat(stack-encrypt)!: frame readers take a ProtectedRef<[u8]>
coderdan Nov 6, 2026
0587c4d
fix(golang): the auth guest's tests use vitaminc-protected 0.9.1
coderdan Nov 6, 2026
51e19eb
docs(stack-encrypt): link the scalar docs to collections, and show nu…
coderdan Nov 6, 2026
203f93f
feat(stack-encrypt): ValueFrame compares in constant time, held in an…
coderdan Nov 6, 2026
feee160
test(stack-encrypt): import AsProtectedRef only where json_index's dy…
coderdan Nov 6, 2026
e4990e4
Merge pull request #1501 from cipherstash/feat/stack-encrypt-owned-co…
coderdan Nov 6, 2026
84bf574
docs: rewrite the Stack Encrypt API plans in plain language
coderdan Nov 7, 2026
ab5fea0
docs: reconcile the Stack Encrypt plans with next on 7 November 2026
coderdan Nov 7, 2026
936567a
docs: lead the Stack Encrypt API plan with its target state
coderdan Nov 7, 2026
bbbca0b
docs: pass context by reference in the Stack Encrypt plan
coderdan Nov 7, 2026
7370751
docs: plan IdentifiedBy constructors for keyset selection
coderdan Nov 7, 2026
95bf774
docs: let Stack Encrypt encrypt borrowed values such as &str
coderdan Nov 7, 2026
5641392
docs: say Go already stores EQL types as record fields
coderdan Nov 7, 2026
616be5f
docs: show static Rust queries before the dynamic interface
coderdan Nov 7, 2026
128d7f9
docs: show encrypting straight into JsonTreeDocument first
coderdan Nov 7, 2026
7aaa90b
docs: convert serde_json::Value into JsonPlaintext in the plan
coderdan Nov 7, 2026
b66a5d7
docs: show JSON queries in static Rust, and plan typed operands
coderdan Nov 7, 2026
249a465
docs: drop encrypt_into_for; JSON operands use encrypt_into
coderdan Nov 7, 2026
09820b9
docs: put the static JSON query first, and the plan form in the dynam…
coderdan Nov 7, 2026
d5fa385
docs: shorten a sentence in the JSON query section
coderdan Nov 7, 2026
314efb8
docs: drop the Serde derives from the plan's examples
coderdan Nov 7, 2026
8db9ee7
docs: JSON operand types are the dynamic interface's input types
coderdan Nov 7, 2026
04d1498
docs: settle the JSON operand names
coderdan Nov 7, 2026
da63a38
docs: a byte string encrypts as one value
coderdan Nov 7, 2026
72ff215
docs: a Go byte string takes the same engine path as a Rust one
coderdan Nov 7, 2026
6c7bb9d
docs: plan an opt-in wrapper that authenticates a collection's order
coderdan Nov 7, 2026
40a3b68
docs: show encrypting a Vec<u8> byte by byte through a named type
coderdan Nov 7, 2026
8701a25
docs: show #[derive(Scalar)] for a single-value newtype
coderdan Nov 7, 2026
de3a40e
docs: one context, two scopes
coderdan Nov 7, 2026
8a53d3c
docs: refine and bind are the context verbs
coderdan Nov 7, 2026
dd9017e
docs: the plan builder is the one source of a field's context
coderdan Nov 7, 2026
bf4b3ff
docs: a declaration lists the parts a caller must supply
coderdan Nov 7, 2026
9bb92ba
docs: scope and bind, through paired entry points
coderdan Nov 7, 2026
5cb1445
docs: field markers and encryption_plan() replace definition()
coderdan Nov 7, 2026
3e183db
docs: query context, stored context, and context name
coderdan Nov 7, 2026
06e0eb6
docs: rewrite the context scenarios as seven short examples
coderdan Nov 7, 2026
310d4a1
docs: a developer can see the context a declaration or call uses
coderdan Nov 7, 2026
9ef00b7
docs: assertions over the context for unit tests
coderdan Nov 7, 2026
e5a8d55
docs: two more context scenarios
coderdan Nov 7, 2026
a541941
docs: bindings for access intelligence live inside the EQL payload
coderdan Nov 7, 2026
c6dcfb3
docs: drop the removed-scenarios note from the context examples
coderdan Nov 7, 2026
7726403
docs: scenario 10, the access intelligence shape without EQL
coderdan Nov 7, 2026
65a2c44
docs: drop the match term from scenario 10
coderdan Nov 7, 2026
7af365d
docs: rename SealedNote to EncryptedNoteBody in scenario 10
coderdan Nov 7, 2026
37a65d4
docs: tag refinement and caveats
coderdan Nov 7, 2026
6e33202
docs: Planned, query plans, and marker-first queries
coderdan Nov 7, 2026
6607c8d
docs: one definition of each operator, and the deferred names
coderdan Nov 7, 2026
e47c1db
docs: a hand-built plan returns typed field markers
coderdan Nov 7, 2026
81b076d
docs: the derive lives on the encrypted struct
coderdan Nov 7, 2026
ec47639
docs: one analyzer for match configuration
coderdan Nov 7, 2026
59cb1cd
docs: the query engine's rules, the dynamic plan's shape, and the ord…
coderdan Nov 8, 2026
080af89
docs: consistency pass after the context and query reviews
coderdan Nov 8, 2026
2c6106c
docs: address the 25 October review of the Stack Encrypt plans
coderdan Nov 8, 2026
c042a41
Merge remote-tracking branch 'origin/next' into docs/stack-encrypt-ap…
coderdan Nov 8, 2026
65e55fd
docs: cut the Stack Encrypt plans to what the plan does not already say
coderdan Nov 8, 2026
5922f94
docs: remove the review decision record
coderdan Nov 8, 2026
6e0bb67
docs: restore the deferred-names pointer in the plan's opening
coderdan Nov 8, 2026
db32f95
docs: move the JSON SQL recipes to an EQL v4 reference page
coderdan Nov 8, 2026
f78ce1e
docs: say which half of Cipher each adapter leaves unimplemented
coderdan Nov 8, 2026
b31fd59
docs: split the Cipher clean-up note into two paragraphs
coderdan Nov 8, 2026
9ba5156
docs: fold keyset selection and lock context into the plan, drop the …
coderdan Nov 8, 2026
b8dae3b
docs: drop the customer-release ordering, design lock context, answer…
coderdan Nov 8, 2026
9c3f41d
docs: rephrase the Go lock context sentence
coderdan Nov 8, 2026
15be617
docs: one key policy document for binds, claims, and labels
coderdan Nov 8, 2026
bdcd7ef
docs: name the key request list key context, add contents lists, sett…
coderdan Nov 8, 2026
c402cf2
docs: defer the ZeroKMS side of key policy to the version 2 work
coderdan Nov 8, 2026
86edfb6
docs(eql): say the database holds no key, and drop issue numbers from…
coderdan Nov 8, 2026
0f5a0b1
docs: final consistency pass across the Stack Encrypt plan documents
coderdan Nov 8, 2026
5f47fcc
docs: record the naming review decisions
coderdan Nov 8, 2026
906b41b
docs: Go renames its handles to Cipher and Keyset, matching Rust
coderdan Nov 8, 2026
fdecaef
docs: revise three naming decisions after Dan's questions
coderdan Nov 8, 2026
9efa7c8
docs: say that a record's context attribute is its first scope
coderdan Nov 8, 2026
d0d60f8
docs: a record's name is its first scope, so the attribute and builde…
coderdan Nov 8, 2026
7eeefcf
docs: the one-value example takes a plain string as its context
coderdan Nov 8, 2026
301b2eb
docs: the kind of a context part is not in the derivation
coderdan Nov 8, 2026
15e0c50
docs: ciphertext text encoding is Base64 only
coderdan Nov 8, 2026
98036f8
docs: final consistency pass after the naming review
coderdan Nov 8, 2026
48f94d3
docs: every remaining-work item names the issues and pull requests th…
coderdan Nov 8, 2026
59ce57c
docs: EQL payloads carry a key header beside a Base85 ciphertext
coderdan Nov 8, 2026
b9b6e01
docs: close three open questions
coderdan Nov 8, 2026
5587363
Merge pull request #1365 from cipherstash/docs/stack-encrypt-api-review
coderdan Nov 8, 2026
c0d3cbd
feat(stack-encrypt)!: add OpaqueBlob whole-value encryption
coderdan Nov 2, 2026
9644491
fix(stack-encrypt): refuse a blob's context before encoding it
coderdan Nov 2, 2026
b91ff6f
test(stack-encrypt): witness the Zeroizing result and leaked blob buf…
coderdan Nov 8, 2026
04f93b3
test(conformance): restore the enrollment's format and enroll the new…
coderdan Nov 8, 2026
2f8f803
docs(stack-encrypt): list the SealedValue conversions in the changelog
coderdan Nov 2, 2026
c04c80b
docs(stack-encrypt): state the Kms and Aead outcomes of a wrong blob …
coderdan Nov 2, 2026
ca4532a
test(stack-encrypt): hold the heap spy's gate across a leak watch
coderdan Nov 2, 2026
4d57213
feat(stack-encrypt): a decrypted OpaqueBlob wipes its value on drop
coderdan Nov 8, 2026
64964f8
docs(plans): say how a decrypted OpaqueBlob is wiped
coderdan Nov 8, 2026
9050c36
test(stack-encrypt): group the OpaqueBlob tests by scenario, and cove…
coderdan Nov 9, 2026
e603a8a
test: drop a decrypted blob without wiping it first, and pin Go's blo…
coderdan Nov 9, 2026
67ea47a
docs(stack-encrypt): rewrite the OpaqueBlob docs, changelog and ADR-0…
coderdan Nov 9, 2026
e17f898
Merge pull request #1503 from cipherstash/feat/stack-encrypt-opaque-blob
coderdan Nov 9, 2026
c9a83a2
test(conformance): add the value-kind boundary profile
coderdan Nov 2, 2026
3dd9965
test(conformance): add the shared query-refusal profile
coderdan Nov 2, 2026
d7195d2
test(conformance): add the raw-frame profile and error classes
coderdan Nov 2, 2026
6ab846f
test(conformance): enroll the new profiles and record the checkpoint
coderdan Nov 2, 2026
c8835a5
test(stack-encrypt): pick the typed chain's index by the operator it …
coderdan Nov 2, 2026
da4a92b
test(conformance): widen the value and refusal corpora to their claims
coderdan Nov 2, 2026
a4a4e54
test(stack-encrypt): refuse rounded floats and impossible dates in th…
coderdan Nov 2, 2026
47de5bd
test(golang): refuse a rounded float spelling in the shared corpus re…
coderdan Nov 2, 2026
1c1c85f
test(stack-encrypt): reuse the counting source and preflight shape in…
coderdan Nov 2, 2026
afe64f2
test(golang): hold term refusals and typed stages to the refusal cont…
coderdan Nov 2, 2026
a926583
docs(conformance): say which key-call counts only native Rust observes
coderdan Nov 2, 2026
88225b8
test(conformance): refuse every scalar operator on every field capabi…
coderdan Nov 2, 2026
0e4b85b
docs(conformance): scope the value requirements to non-null inputs an…
coderdan Nov 2, 2026
81ebc54
test(conformance): accept only a float's canonical spelling in the Ru…
coderdan Nov 2, 2026
fee5707
test(golang): hold the raw-frame authentication refusal to its code a…
coderdan Nov 2, 2026
5c25cf3
docs(conformance): point the refusal and value gaps at the API plan
coderdan Nov 8, 2026
f54c541
test(stack-encrypt): pass conformance frames as ProtectedRef under Vi…
coderdan Nov 8, 2026
186de56
test(conformance): name the value, refusal and raw-frame corpora afte…
coderdan Nov 8, 2026
0eeb501
test(conformance): check the unanswered list, the transport refusals …
coderdan Nov 9, 2026
1c7a6e6
test(conformance): exchange fresh values, records, blobs and EQL rows…
coderdan Nov 2, 2026
599a25d
ci(conformance): run the fresh artifact exchange as a required lane
coderdan Nov 2, 2026
fde28dc
docs(conformance): define the artifact exchange contract
coderdan Nov 2, 2026
1d7dcde
test(conformance): share one report writer and clear the exchange's f…
coderdan Nov 2, 2026
a9ab132
test(conformance): name the producer of exchanged EQL rows and compar…
coderdan Nov 2, 2026
78f3008
docs(conformance): state the EQL rows' producer manifest and term com…
coderdan Nov 2, 2026
f2bc0c8
test(stack-encrypt): refuse an exchanged record carrying an undeclare…
coderdan Nov 2, 2026
c5a2fb6
test(golang): refuse an exchanged record carrying an undeclared seale…
coderdan Nov 2, 2026
7684a04
test(conformance): refuse EQL_UPDATE_FIXTURES and keep the exchange d…
coderdan Nov 2, 2026
89e70fa
test(stack-encrypt): split the exchange's sealed-field filter for clippy
coderdan Nov 2, 2026
16388e9
test(conformance): align the artifact exchange with next and the API …
coderdan Nov 8, 2026
e608873
test(stack-encrypt): consolidate duplicate expectations into the shar…
coderdan Nov 2, 2026
0793561
test(stack-encrypt): keep the leaf-record and field-in-message refusa…
coderdan Nov 2, 2026
1cbed60
docs(conformance): correct the consolidation map's counts, stale rows…
coderdan Nov 2, 2026
28b31d7
test(golang): drop the stale doc paragraph from the renamed Verify an…
coderdan Nov 2, 2026
08884c5
Merge pull request #1506 from cipherstash/feat/stack-encrypt-artifact…
coderdan Nov 9, 2026
b89a068
test(stack-encrypt): keep the accepted block-ORE index assertion
coderdan Nov 2, 2026
a3da2b2
test(golang): count the inverted range as accepted, not as a refusal
coderdan Nov 9, 2026
5bd00b1
Merge pull request #1507 from cipherstash/feat/stack-encrypt-test-con…
coderdan Nov 9, 2026
330d881
feat(stack-encrypt)!: derive owned record declarations with EncryptTa…
coderdan Nov 2, 2026
7dc1b2e
fix(stack-encrypt): wipe an owned column's unvisited elements when a …
coderdan Nov 2, 2026
9b6c468
fix(stack-encrypt-derive): refuse an owned struct record that leaves …
coderdan Nov 2, 2026
bc4bfb8
fix(stack-encrypt): wipe the fields a record opened before a later fi…
coderdan Nov 2, 2026
fe49f79
docs(stack-encrypt): renumber the owned-record ADR to 0012 and repair…
coderdan Nov 2, 2026
a8f379b
test(stack-encrypt): enroll the owned-record drop witnesses in the li…
coderdan Nov 2, 2026
f5eb0c1
style(stack-encrypt): apply rustfmt to the wiping zip and the column-…
coderdan Nov 2, 2026
04a74df
fix(stack-encrypt): guard the plaintext while encrypt_into constructs…
coderdan Nov 2, 2026
89eef21
fix(stack-encrypt)!: wipe the parts an owned split has not yet handed…
coderdan Nov 2, 2026
0e174da
test(stack-encrypt): pin the owned MatchTerms index and ContextExtens…
coderdan Nov 2, 2026
f484428
fix(stack-encrypt): make the encrypted_record example follow the misu…
coderdan Nov 6, 2026
4e2f3f8
docs(stack-encrypt): rewrite the owned-record docs in plain language …
coderdan Nov 6, 2026
147fe06
feat(stack-encrypt)!: name a record with scope = "..", and take no ca…
coderdan Nov 9, 2026
161b35d
feat(stack-encrypt): decrypt a record straight into a Protected, and …
coderdan Nov 9, 2026
0038619
feat(stack-encrypt): decrypt a Ciphertext straight into a Protected
coderdan Nov 9, 2026
20a4c21
docs(stack-encrypt): keep risky_ref out of the visible doc examples
coderdan Nov 9, 2026
7861ee6
docs(stack-encrypt): amend ADR-0007, the derive emits the combinators
coderdan Nov 9, 2026
f05e716
docs(plans): bring the API plan in line with the amended ADR-0007
coderdan Nov 9, 2026
d212d9e
docs(stack-encrypt): cite the amendment's pull request in ADR-0007
coderdan Nov 9, 2026
3e90e2f
fix(stack-encrypt): wipe or never make a plaintext copy when a contex…
coderdan Nov 9, 2026
0829076
test(stack-encrypt): exclude the equivalent DeclaredScopes::omitted m…
coderdan Nov 9, 2026
1aa4d6c
fix(stack-encrypt-derive): write a generic plaintext path with a turb…
coderdan Nov 9, 2026
327b693
docs(stack-encrypt): hide project_owned, correct the caller-context s…
coderdan Nov 9, 2026
4d6dcf0
feat(stack-encrypt): encrypt an absent value through the owned API as…
coderdan Nov 9, 2026
e3eec26
feat(eql-bindings): implement EncryptTarget and DecryptSource on the …
coderdan Nov 9, 2026
a7753fb
Merge pull request #1504 from cipherstash/feat/stack-encrypt-owned-re…
coderdan Nov 9, 2026
bf38215
docs(stack-encrypt): address the review findings on the ADR-0007 amen…
coderdan Nov 9, 2026
e794de7
fix(stack-encrypt,eql-bindings): wipe an Option's value when its decl…
coderdan Nov 9, 2026
6ccef66
Merge pull request #1584 from cipherstash/docs/adr-0007-derives-emit-…
coderdan Nov 9, 2026
1f7b7f6
ci: keep Biome off the pinned v4 terms fixture
coderdan Nov 9, 2026
aff24fc
docs(eql-bindings,stack-encrypt): rewrite the prose of the owned EQL …
coderdan Nov 9, 2026
94fa187
refactor(eql-bindings): use MatchTerms, not its deprecated alias Matc…
coderdan Nov 9, 2026
090de62
feat(stack-encrypt): let a target take its context from the plaintext…
coderdan Nov 9, 2026
82496a0
fix(stack-encrypt): context_from picks a stored context field, not an…
coderdan Nov 9, 2026
a9239e0
docs(stack-encrypt): rewrite the context_from prose in plain language
coderdan Nov 9, 2026
7f7d0e4
Merge pull request #1587 from cipherstash/feat/eql-v4-owned-targets
coderdan Nov 9, 2026
c26890b
Merge pull request #1588 from cipherstash/feat/stack-encrypt-context-…
coderdan Nov 9, 2026
d3b4b6d
feat(stack-encrypt): show the context a declaration or a call uses, a…
coderdan Nov 9, 2026
ea41543
fix(stack-encrypt): address the review of the context views
coderdan Nov 9, 2026
9be3f21
fix(stack-encrypt): pass the EQL formatter and the no-default-feature…
coderdan Nov 9, 2026
488426b
test(stack-encrypt): pin the three context-view mutants
coderdan Nov 9, 2026
92ff05f
fix(stack-encrypt): state a one-part list context, and say the borrow…
coderdan Nov 9, 2026
6823833
fix(stack-encrypt): state a context by its parts in Go, and in every …
coderdan Nov 9, 2026
df20a7c
test(golang): a one-part nested list differs from the engine's bare list
coderdan Nov 9, 2026
414bcae
fix(stack-encrypt): show a data plan's EQL fields in the context view
coderdan Nov 10, 2026
9c7a3ec
feat(stack-encrypt): split the context into scopes and bindings
coderdan Nov 9, 2026
20ed5e3
fix(stack-encrypt): address the review of scopes and bindings
coderdan Nov 9, 2026
369b590
test(stack-encrypt): pin the context-view mutants and exclude the equ…
coderdan Nov 9, 2026
08de000
test(stack-encrypt): state the one-part list test through `Stated`
coderdan Nov 9, 2026
ee58a3b
fix(stack-encrypt): open a bound JSON document with its root open, an…
coderdan Nov 9, 2026
4a77e39
docs(stack-encrypt): drop the ADR reference from the context module's…
coderdan Nov 9, 2026
9fe0cf1
fix(stack-encrypt): refuse an empty or grouped bind list, and name th…
coderdan Nov 10, 2026
bb7f174
test(stack-encrypt): pin that a plan with an EQL field refuses a binding
coderdan Nov 10, 2026
e60b511
fix(golang): return copies of byte parts from Scopes and Bindings
coderdan Nov 10, 2026
663b6e5
feat(stack-encrypt)!: declare each operator once and prepare a query …
coderdan Nov 9, 2026
990192f
fix(stack-encrypt): address the review of the query preparation
coderdan Nov 9, 2026
5ea63e4
chore(stack-encrypt): format the declarations corpus and exclude an e…
coderdan Nov 9, 2026
642c5f0
fix(stack-encrypt): check the label on every prepare, whatever check did
coderdan Nov 9, 2026
4a9d31b
docs(stack-encrypt): say that a derived record with two order indexes…
coderdan Nov 10, 2026
972e635
feat(stack-encrypt): field markers and a value under a plan that is data
coderdan Nov 9, 2026
a95a029
fix(stack-encrypt): address the review of the field markers
coderdan Nov 9, 2026
e348a25
fix(stack-encrypt): show EQL fields in a planned context, and copy th…
coderdan Nov 9, 2026
7c0e449
test(stack-encrypt): pin the wipe on drop and the Debug of a planned …
coderdan Nov 9, 2026
4438430
fix(stack-encrypt): a marker's operator methods take the value by value
coderdan Nov 10, 2026
ce7e195
docs(stack-encrypt): say what a plan with scopes is, with a doc test
coderdan Nov 10, 2026
f626ac7
refactor(stack-encrypt): lower a data plan to the combinators through…
coderdan Nov 9, 2026
7ea0378
fix(stack-encrypt): address the review of the planned lowering
coderdan Nov 9, 2026
57f8778
docs(stack-encrypt): drop the two ADR references from the dynamic mod…
coderdan Nov 9, 2026
2e198d5
perf(stack-encrypt): read a record's context field in place
coderdan Nov 10, 2026
6448564
docs(stack-encrypt): say which record functions run the lowered combi…
coderdan Nov 10, 2026
4a0200d
feat(stack-encrypt): operator methods for tuple, nullable and record …
coderdan Nov 9, 2026
880aaeb
fix(stack-encrypt): address the review of the tuple, nullable and rec…
coderdan Nov 9, 2026
99004cd
docs(stack-encrypt): name the error a wrong query type gives, as the …
coderdan Nov 10, 2026
5a7cf4f
Merge pull request #1589 from cipherstash/feat/stack-encrypt-show-con…
coderdan Nov 10, 2026
59a66fd
Merge pull request #1591 from cipherstash/feat/stack-encrypt-scopes-a…
coderdan Nov 10, 2026
1fbe05c
Merge pull request #1592 from cipherstash/feat/stack-encrypt-one-quer…
coderdan Nov 10, 2026
c6f33a2
Merge pull request #1595 from cipherstash/feat/stack-encrypt-field-ma…
coderdan Nov 10, 2026
e269682
Merge pull request #1597 from cipherstash/feat/stack-encrypt-planned-…
coderdan Nov 10, 2026
739b953
Merge pull request #1599 from cipherstash/feat/stack-encrypt-marker-f…
coderdan Nov 10, 2026
4bad95d
docs(stack-encrypt): state the rules the rustdoc cited records for
coderdan Nov 10, 2026
2eff010
docs(stack-encrypt): address the review of the rustdoc rewrite
coderdan Nov 10, 2026
6b6119d
feat(stack-encrypt): typed queries for a nullable record field and an…
coderdan Nov 10, 2026
b0bd936
Refine documentation on row binding and selectors
coderdan Nov 10, 2026
591396f
docs(stack-encrypt): say a row binding does not scope JSON queries
coderdan Nov 10, 2026
da57d77
fix(stack-encrypt): address the review of the nested scope markers
coderdan Nov 10, 2026
fa8a292
Merge pull request #1601 from cipherstash/docs/stack-encrypt-rustdoc-…
coderdan Nov 10, 2026
3f7c991
docs(stack-encrypt): rewrite the nested scope marker docs and errors …
coderdan Nov 11, 2026
7a733f7
feat(stack-encrypt)!: chain nested scopes with Scope::scope
coderdan Nov 11, 2026
783894d
feat(eql-bindings): ship one TargetResolver for the EQL types
coderdan Nov 10, 2026
a721860
fix(eql-bindings): address the review of the shared resolver
coderdan Nov 10, 2026
edc4107
docs(eql-bindings): rewrite the shared resolver docs in plain language
coderdan Nov 11, 2026
363a83a
Merge pull request #1608 from cipherstash/feat/stack-encrypt-nested-s…
coderdan Nov 11, 2026
c8a9c80
Merge pull request #1609 from cipherstash/feat/eql-bindings-shared-re…
coderdan Nov 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
63 changes: 63 additions & 0 deletions .cargo/mutants.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,77 @@ exclude_re = [
'stack-encrypt/src/cipher\.rs:\d+:\d+: replace client_key_provider -> EnvKeyProvider with Default::default\(\)$',
'stack-encrypt/src/target/pending\.rs:443:9: replace <impl IntoFuture for Pending<.*>>::into_future -> Self::IntoFuture with Default::default\(\)$',
# stack-encrypt — equivalent.
# An operator and an index are unit structs, whose `Default` is the value
# `clone` and `case_sensitive` already return.
'stack-encrypt/src/op(/mod)?\.rs:\d+:\d+: replace <impl Clone for Matches<C>>::clone -> Self with Default::default\(\)$',
'stack-encrypt/src/op(/mod)?\.rs:\d+:\d+: replace Matches::case_sensitive -> Matches<CaseSensitive> with Default::default\(\)$',
'stack-encrypt/src/target/index\.rs:\d+:\d+: replace <impl Clone for Match<O>>::clone -> Self with Default::default\(\)$',
'stack-encrypt/src/cipher\.rs:\d+:\d+: replace StackCipher<FromEnv>::builder -> StackCipherBuilder with Default::default\(\)$',
'stack-encrypt/src/sem/mod\.rs:\d+:\d+: replace <impl MatchConfig for DefaultMatch>::options -> MatchOptions with Default::default\(\)$',
# `Orderable`'s default `check_query` refuses nothing: its body is
# `Ok(())`, so the replacement is the body. Text overrides it with
# `query::order_text`, pinned by `an_ordering_refuses_only_text_it_cannot_encode`.
'stack-encrypt/src/sem/mod\.rs:\d+:\d+: replace sealed::Sealed::check_query -> Result<\(\), super::TermError> with Ok\(\(\)\)$',
# Both unit-context conversions explicitly return Self::default().
'stack-encrypt/src/target/context\.rs:\d+:\d+: replace <impl From<\(\)> for (DeclaredContext|ExpectedContext<T>)>::from -> Self with Default::default\(\)$',
# A caller shape with no placeholder IS `CallerShape::default()`:
# `CallerShape::none` returns it, and a context that supplies no part
# (`NoCallerContext`, `DeclaredScopes`) supplies `none()`. Each is
# pinned by `a_caller_shape_holds_its_placeholders` and the derive
# tests' `contexts()` views, which show no placeholder for them.
'stack-encrypt/src/contexts\.rs:\d+:\d+: replace CallerShape::none -> Self with Default::default\(\)$',
# A record with no stored part IS `StoredParts::default()`: `none` returns it.
'stack-encrypt/src/target/context\.rs:\d+:\d+: replace StoredParts::none -> Self with Default::default\(\)$',
'stack-encrypt/src/contexts\.rs:\d+:\d+: replace <impl SuppliedContext for (NoCallerContext|DeclaredScopes)>::supplies -> CallerShape with Default::default\(\)$',
# Omitting an expectation is expecting nothing: `ExpectedContext::omitted`
# returns Self::default(). That an omitted expectation opens under the
# stored context without checking it is pinned by
# `a_stored_context_opens_as_stored_and_checks_an_expectation`.
'stack-encrypt/src/target/input\.rs:\d+:\d+: replace <impl AllowsNoContext for ExpectedContext<T>>::omitted -> Self with Default::default\(\)$',
# Omitting a struct record's caller context declares no extra scope:
# `DeclaredScopes::omitted` returns Self::default().
'stack-encrypt/src/target/input\.rs:\d+:\d+: replace <impl AllowsNoContext for DeclaredScopes>::omitted -> Self with Default::default\(\)$',
# A caller-free declaration adds nothing to the declared context: the
# conversion returns Self::default().
'stack-encrypt/src/target/input\.rs:\d+:\d+: replace <impl From<NoCallerContext> for super::DeclaredContext>::from -> Self with Default::default\(\)$',
# The resolver of a build without EQL types holds none: its `targets` IS
# the empty list (`dynamic::target::NoTargets`), which a test asserts on
# and `resolve` turns into `TargetError::NoTargets`; `vec![]` is the body.
'stack-encrypt/src/dynamic/target\.rs:\d+:\d+: replace <impl TargetResolver for NoTargets>::targets -> Vec<TargetDescriptor> with vec!\[\]$',
# A passthrough, and a typed null as any null, has no kind:
# `KindOf::passthrough` and `KindOf::typed_null` return `Ok(None)`, which
# is `Ok(Default::default())`. `a_frame_names_its_kind` asserts the first.
'stack-encrypt/src/dynamic/value_frame\.rs:\d+:\d+: replace <impl Sink for KindOf>::(passthrough|typed_null) -> Result<Self::Ok, DecodeError> with Ok\(Default::default\(\)\)$',
# `model`'s `admits` guard on a date, decimal or undefined value is checked
# again by vitaminc on every path that reaches it: the frame writer behind
# `Modeled` and `ModelOnly` refuses an inadmissible logical value
# (`FrameWriteError::Invalid`, mapped to the same `Expected`), and
# `ValueFrame::check` only walks frames `Frame::parse` has validated. So
# `true` there refuses the same values with the same error. The guard stays
# so the model says what it holds without leaning on the writer behind it.
'stack-encrypt/src/dynamic/value_frame\.rs:\d+:\d+: replace match guard logical\.admits\(&value\) with true in model$',
# A serde visitor's `expecting` writes only the "expected ..." half of a
# serde error's message, and no caller of these three reads that message:
# a context, statistics and a plan's root are each refused with one fixed
# `Reason` (`ContextKind`, `NotStats`, `NotAnObject`), and the plan's
# field-level reasons are read from the error's path, so writing nothing
# refuses the same input with the same error.
'stack-encrypt/src/dynamic/(context|query|record)\.rs:\d+:\d+: replace <impl (Visitor<\x27de> for ContextVisitor|serde::Deserialize<\x27de> for Confidence>::deserialize::<impl serde::de::Visitor<\x27_> for V|Deserialize<\x27de> for PlanWire>::deserialize::<impl Visitor<\x27de> for V)>::expecting -> fmt::Result with Ok\(Default::default\(\)\)$',
# The same for the visitor that reads a refused plan's keys back
# (`entry_key`): its error is discarded (`.ok()`), so its message is never
# read at all.
'stack-encrypt/src/dynamic/record\.rs:\d+:\d+: replace entry_key::<impl Deserialize<\x27de> for Keys>::deserialize::<impl Visitor<\x27de> for V>::expecting -> fmt::Result with Ok\(Default::default\(\)\)$',
# The JSON index. `unhex` joins a high nibble shifted into the top four
# bits with a low nibble below 16: the bits never overlap, so `^` is `|`.
'stack-encrypt/src/json/mod\.rs:\d+:\d+: replace \| with \^ in unhex$',
# `JsonPath::root` is `Self::default()`.
'stack-encrypt/src/json/path\.rs:\d+:\d+: replace JsonPath::root -> Self with Default::default\(\)$',
# A document always has a root, so its terms are never empty: `false` is
# the value `is_empty` returns. The `true` replacement is still caught.
'stack-encrypt/src/json/derive\.rs:\d+:\d+: replace JsonTerms::is_empty -> bool with false$',
# A JSON operator's input: the `JsonText` visitor's `expecting` writes a
# message `read_frame` discards for its fixed `Reason::JsonInput`.
'stack-encrypt/src/dynamic/json_query\.rs:\d+:\d+: replace <impl Deserialize<\x27de> for JsonText>::deserialize::<impl Visitor<\x27_> for V>::expecting -> std::fmt::Result with Ok\(Default::default\(\)\)$',
]

# Headroom over the measured baseline before a slow-but-correct mutant is
Expand Down
6 changes: 6 additions & 0 deletions .changeset/chacha20-0-10-2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@cipherstash/protect-ffi': patch
'@cipherstash/auth': patch
---

Build the native binaries against `chacha20` 0.10.2. Versions 0.10.0 and 0.10.1 were yanked: on an x86 CPU without AVX2, their SSE2 fallback for the random number generator used an SSE4.1 instruction it had not checked the CPU for. A CPU without SSE4.1 (one from before 2008, or a virtual machine using QEMU's default `qemu64` CPU model) would crash with an illegal-instruction error. Every other CPU produced correct random numbers, so randomness was never weakened. No API change.
2 changes: 1 addition & 1 deletion .changeset/eql-3-1-0-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ constant number of operations whatever two values share, closing a timing
leak. Ordering results are unchanged for well-formed values, but a block-ORE
text value with a malformed or mismatched-width term now raises on every
comparison against it. Check your `_ore` text columns before migrating; see
[U-001](../../../../packages/eql/docs/upgrading/v3.1.md#u-001-block-ore-text-comparisons-check-every-term).
[U-004](../../../../packages/eql/docs/upgrading/v3.1.md#u-004-block-ore-text-comparisons-check-every-term).
No domain, wire format or index term changes.

Two artefacts carry the new bundle:
Expand Down
5 changes: 5 additions & 0 deletions .changeset/eql-bindings-optional-storage-only.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cipherstash/eql": patch
---

`eql-bindings` (the Rust crate released with this package): an EQL v4 type whose terms a null has, a storage-only type (`Date`, `Integer`, `Text`, ...) or one whose only term is equality's (`DateEq`, `IntegerEq`, `TextEq`, ...), now also implements `EncryptFrom` and `DecryptInto` for an `Option` of its plaintext, and its query twin `EncryptFrom` for one. For a type of fixed width a `None` seals as a typed null as long as a value (vitaminc 0.8), so an optional column does not show which rows are absent. For text it seals as a null that is not padded, since text's ciphertext is as long as the text, so its length may show that the value is absent. Either way it opens as `None`; its `hm` is the one term every null shares, and the query of a `None` finds the stored nulls with `=`. A value seals exactly as before. The by-name dispatch (`encryption::targets`) reads, opens and queries these types through the `Option`; a type with an order or match term still refuses a null. eql-bindings' own `Date`, `Timestamp` and `Decimal` plaintexts declare their fixed width to vitaminc, so their `None` is padded too. The SQL bundle and the TypeScript types do not change.
5 changes: 5 additions & 0 deletions .changeset/eql-bindings-shared-resolver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cipherstash/eql": minor
---

`eql-bindings` (the Rust crate released with this package) now ships a resolver for Stack Encrypt's dynamic interface: `eql_bindings::encryption::EqlTargets`, behind the `targets` feature. The dynamic interface runs a plan that arrives as data, and a field of that plan can name an EQL type, such as `"TextEq"`. A program gives Stack Encrypt the EQL types through its `TargetResolver` trait. Until now each program wrote its own resolver over `encryption::targets`. `EqlTargets` holds every type in `targets::targets()` and runs a named type's `encrypt_with`, `decrypt` and `query`. Two conversions come with it: `From<&Target>` for Stack Encrypt's `TargetDescriptor`, and `From<targets::TargetError>` for Stack Encrypt's `TargetError`. Stored bytes and query operands do not change. The SQL bundle and the TypeScript types do not change.
5 changes: 5 additions & 0 deletions .changeset/eql-domains-refuse-null-version.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@cipherstash/eql': patch
---

The stored and query-operand domains (`eql_v3_*`, `eql_v4_*`, `eql_v3.query_*`, `eql_v4.query_*`) now refuse a payload whose `v` is JSON `null`. The CHECK compared `v` with the bundle's version, and a comparison with `null` is NULL, which a CHECK lets through, so such a payload fitted both a v3 and a v4 domain. The range domains already refused it. A NULL value still fits every domain.
5 changes: 5 additions & 0 deletions .changeset/eql-encrypted-json-operations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cipherstash/eql": minor
---

**`JsonSearch` answers its JSON operators by name.** `eql-bindings`' target table row now tells Stack Encrypt the domain an ordering at a path binds as (`Target::leaf_query_sql_domain`, `eql_v4.query_json_leaf`), so a data plan's `lt_at`, `lte_at`, `gt_at`, `gte_at` and `between_at` bind their operand as that domain, beside `contains`, `contained_by` and `eq_at`, which bind the needle as `eql_v4.query_json`. No SQL changes.
5 changes: 5 additions & 0 deletions .changeset/eql-encrypted-json-target.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cipherstash/eql": minor
---

**The `json_tree` family is in the EQL catalog as EQL v4's searchable JSON document, and a data plan can produce `public.eql_v4_json_search` by name: the target `JsonSearch`.** A language SDK names it in a plan field with the `json` type, gives it the JSON index's options (`{"name": "JsonSearch", "options": {"sealed_root": true, "ordered": ["$.age"]}}`, or the bare name for the defaults), and hands each document over as UTF-8 JSON text; the `eql-bindings` crate's by-name dispatch (`encryption::targets::encrypt_with`, `decrypt`) seals it through the same JSON index layout typed Rust uses and opens it back to its text. The text is parsed by Stack Encrypt's rules, before any key is requested: an object that names a member twice, an integer literal outside the 64-bit range, and text that is not JSON are refused (`TargetError::Json`, with a code and never a byte of the text). The catalog lists the family once (`eql_domains::DOCUMENT_FAMILIES`), so the target table, `v4::all()` / `v4::all_query()` and the Go types (`eql.JSONSearch`, `JSONSearchQuery`, `JSONSearchLeafQuery`, `JSONEntry`) are generated from it. The types take the names EQL v3 gives its searchable JSON document: `Json` (`public.eql_v4_json`) stays the storage-only type, `JsonSearch` is the searchable document, queried with `JsonSearchQuery` (`eql_v4.query_json`) and `JsonSearchLeafQuery` (`eql_v4.query_json_leaf`), and `JsonEntry` (`public.eql_v4_json_entry`) is one node as `->` and the reads return it. The JSON tree SQL domains are renamed to match: `public.eql_v4_json_tree` is now `public.eql_v4_json_search`, `public.eql_v4_json_tree_entry` is `public.eql_v4_json_entry`, `eql_v4.query_json_tree` is `eql_v4.query_json` and `eql_v4.query_json_tree_leaf` is `eql_v4.query_json_leaf`; the `eql_v4.json_tree_*` functions keep their names. The v4 bundle no longer carries the SteVec domains: in v4, `json_tree` implements `json_search`. The SteVec SQL (`src/v3/json/`) and the generated `json_entry_<T>` cross operators are confined to EQL v3 with `-- ONLY EQL VERSION: 3`, and the v4 target table drops its unproducible `SteVecDocument` row. The v3 bundle gains only those directive comment lines.
7 changes: 7 additions & 0 deletions .changeset/eql-identifier-borrowed-context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@cipherstash/eql": patch
---

`eql-bindings` (the Rust crate released with this package): a borrowed `&Identifier` is now a Stack Encrypt context, the same context as the `Identifier`. A program can hold one identifier and pass `&column` to the cipher-directed API, or build a `NonEmpty<&Identifier>` for a term, without a clone. The stored EQL (Encrypt Query Language) types still take their `NonEmpty<Identifier>` by value.

The EQL types also gain `contexts()`, from Stack Encrypt. The method shows the context each stored field is sealed and indexed under, before any key is requested. The SQL bundle and the TypeScript types do not change.
5 changes: 5 additions & 0 deletions .changeset/eql-json-tree-cascade-and-random-order.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cipherstash/eql": patch
---

EQL v4 `json_tree` (unreleased): a stored document's entries are now in a random order, root first, an object's members get a random permutation as their ordinals (the `o` the server probes a node's children at, which was a keyed rank), and its containment projection `q` is shuffled the same way, so the stored order no longer shows each row's tree, the size of every subtree or the byte order of sibling key names (#1357). A containment or equality needle is sent in a random order of its own too, so a query no longer shows sibling key order either. Every entry's ciphertext now also commits to its children's AEAD tags, so the client checks a subtree read's rows by the chain rather than by their positions, and a row swapped, dropped, added, reordered or moved beneath the node read is refused by the cipher. Nothing stored changes shape; `json_tree_children` returns a node's children in ordinal order (an array's elements by position), where it returned them by stored slot, and no other SQL function changes (three doc comments stop promising document order); documents sealed by the earlier build of this unreleased family no longer open. `->`, `->>` and an ordering on `eql_v4.ord_term(col -> sel)` at a wildcard path now return an unspecified element of the row (the same one every time), not element 0; read every element with `json_tree_path_query`. `->` on an object or array with members no longer opens on the client (the entry's ciphertext commits to its children, which `->` does not return): Stack Encrypt reports `JsonNotALeaf`, which is also what an altered entry looks like through `->`; read a container with a subtree read. `docs/reference/json-tree-leakage.md` says what the stored row still shows and what a read now proves.
9 changes: 9 additions & 0 deletions .changeset/eql-json-tree-derivable-tokens.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@cipherstash/eql": minor
---

EQL v4 `json_tree` (unreleased): a subtree read sends the token of exactly the node it reads, and returns that node. Every token is now derivable from its node's path alone: an object member's is `H("t" ‖ t(parent) ‖ s)`, with no ordinal, and an array element's keeps its index. Every stored entry gains a self tag `x`, the first eight bytes of `H("x" ‖ iv ‖ t)`, by which the server finds the node a token names; the entry validator requires it, so a document written by the earlier build of this unreleased family is refused. A read of `$.profile.address.city` used to send `$.profile`'s token, a capability over that whole field in every row, and walk to the leaf through gates; it now sends the leaf's token and nothing that covers any node above it.

**SQL signature changes.** `eql_v4.json_tree_subtree(doc, tokens text[], budget integer DEFAULT 64)` replaces `json_tree_subtree(doc, token, budget)` and `json_tree_subtree_at(doc, token, gates, budget)`, which is removed: for each token in order it returns the entry whose `x` matches at `d = 0`, then its descendants with `d` their depth below it, so `{}`, `[]`, a scalar and a missing node are four answers, as `jsonb` gives them (#1356). The budget counts rows across all the tokens. `json_tree_children(doc, token)` and `json_tree_child_count(doc, token)` lose their `gates` argument and take the token of any node; `json_tree_child_count` of a token that names no node is NULL, as `jsonb_array_length` of a missing path is (it was 0), and so is the sealed root's, whose top-level fields chain from nothing. `eql_v4_internal.json_tree_child_token` is replaced by `json_tree_member_token`, `json_tree_element_token`, `json_tree_self_tag`, `json_tree_hit_token` and `json_tree_index`, which maps every entry's `x`, and every chained entry's `p`, to its position in `sv`; `json_tree_by_parent` is removed. The chain primitives carry the `eql-inline-critical` marker, so the post-install step leaves their `search_path` unpinned and the planner inlines them: pinned, every probe of a walk was a full SQL-function call, which was most of a read's cost.

A wildcard (`$.items[*].price`) is expanded by the client into one token per position below a bound, 64 by default, plus a probe at the bound; a row where the probe finds an element fails the read with the bound rather than return part of the list, walked or fallen back to the sealed root. A read of `$` is legal under the sealed root and returns the root entry, which opens to the whole document. Stored documents grow by about a tenth in characters (+9.8% on a nested document, +9.4% on a flat one). `JsonHeader::FORMAT_VERSION` and the document's `v` are unchanged. In `eql-bindings`, `JsonTreeEntry` gains `x` and `JsonTreeSubtree` opens to `Option<Value>`; in Stack Encrypt, `JsonSubtreeKey` carries the token list (`tokens()`, `probes()`, `bound()`), `KeysetCipher::json_subtree_key_with_bound` sets the bound, `Error::JsonWildcardTruncated` and `TermError::JsonWildcardTooWide` are new, and `TermError::JsonSealedRoot` is removed. What the database learns is in `docs/reference/json-tree-leakage.md`; the design and the decisions behind it are in `docs/plans/2026-10-17-json-tree-index.md`, "Design change (2026-10-24)".
Loading