You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 7bbf8d0
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: .cargo/mutants.toml
+4Lines changed: 4 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -73,6 +73,10 @@ exclude_re = [
73
73
'stack-encrypt/src/sem/mod\.rs:\d+:\d+: replace <impl MatchConfig for DefaultMatch>::options -> MatchOptions with Default::default\(\)$',
74
74
# Both unit-context conversions explicitly return Self::default().
75
75
'stack-encrypt/src/target/context\.rs:\d+:\d+: replace <impl From<\(\)> for (DeclaredContext|ExpectedContext<T>)>::from -> Self with Default::default\(\)$',
76
+
# The resolver of a build without EQL types holds none: its `targets` IS
77
+
# the empty list (`dynamic::target::NoTargets`), which a test asserts on
78
+
# and `resolve` turns into `TargetError::NoTargets`; `vec![]` is the body.
79
+
'stack-encrypt/src/dynamic/target\.rs:\d+:\d+: replace <impl TargetResolver for NoTargets>::targets -> Vec<TargetDescriptor> with vec!\[\]$',
76
80
]
77
81
78
82
# Headroom over the measured baseline before a slow-but-correct mutant is
**The `eql-bindings` crate resolves an EQL type named as a string to its own Stack Encrypt plan** (`stack-encrypt` feature). `eql_bindings::encryption::targets` carries a catalog-generated table of every EQL type a data plan may name as a field target — its name across languages, family and suffix, the plaintext `ValueKind` it takes, the indexes it carries, its query twin, and whether the engine can produce it today with the reason when not — and `encrypt` / `decrypt` / `query` entry points that dispatch on the name and run the type's derived `EncryptFrom` / `DecryptInto`, resolving to the EQL value's JSON bytes through the engine's `Pending` so a guest batches it with the rest of a plan. This is the EQL half of EQL types as plan field targets (cipherstash/stack#1062): a Go data plan names `TextEq` and the guest returns the finished EQL value instead of assembling one. `TextEq` is the only producible type; every other name is refused with the plan's reason. The SQL surface and the TypeScript package are unchanged.
Copy file name to clipboardExpand all lines: .github/workflows/tests-golang.yml
+28-5Lines changed: 28 additions & 5 deletions
Original file line number
Diff line number
Diff line change
@@ -8,8 +8,9 @@ name: Tests (Go)
8
8
# wasi-check the stack crates build for wasm32-wasip1 with no JS-host or
9
9
# native-HTTP dependencies, the no-http shape passes its tests
10
10
# and docs, both guests pass lint and tests and are built with
11
-
# their import surfaces checked (the stack-encrypt guest twice:
12
-
# the real build and the deterministic-kms test build), their
11
+
# their import surfaces checked (the stack-encrypt guest four
12
+
# times: the real build, the build with the EQL types, and the
13
+
# deterministic-kms test build of each), their
13
14
# sha256 is recorded, `go:test` runs against them, and
14
15
# `go generate` leaves the tree unchanged.
15
16
# go-lint golangci-lint, Linux only.
@@ -32,6 +33,9 @@ on:
32
33
- packages/stack-encrypt/**
33
34
- packages/stack-encrypt-derive/**
34
35
- packages/stack-guest-abi/**
36
+
# The eql guest build links eql-bindings.
37
+
- packages/eql/crates/eql-bindings/**
38
+
- packages/eql/crates/eql-domains/**
35
39
- languages/golang/**
36
40
- scripts/check-wasm-imports.py
37
41
- scripts/go-binding-test.sh
@@ -54,6 +58,9 @@ on:
54
58
- packages/stack-encrypt/**
55
59
- packages/stack-encrypt-derive/**
56
60
- packages/stack-guest-abi/**
61
+
# The eql guest build links eql-bindings.
62
+
- packages/eql/crates/eql-bindings/**
63
+
- packages/eql/crates/eql-domains/**
57
64
- languages/golang/**
58
65
- scripts/check-wasm-imports.py
59
66
- scripts/go-binding-test.sh
@@ -156,6 +163,18 @@ jobs:
156
163
- name: stack-encrypt guest deterministic test build
157
164
run: mise run wasm:guest:build:deterministic
158
165
166
+
# The build with the EQL types (ADR-0007, amended 2026-10-06), which
167
+
# package encrypt/eql embeds and registers on import, and its
168
+
# deterministic test build, which the hermetic tests of a TextEq field
169
+
# load. Same import-surface gate. The build task prints both builds'
170
+
# sizes: the plan asks for that measurement before the SDK settles on
171
+
# one build or two.
172
+
- name: stack-encrypt guest eql build and import-surface gate
173
+
run: mise run wasm:guest:build:eql
174
+
175
+
- name: stack-encrypt guest eql deterministic test build
176
+
run: mise run wasm:guest:build:eql:deterministic
177
+
159
178
- name: Credential guest lint and tests
160
179
run: mise run wasm:auth-guest:test
161
180
@@ -167,7 +186,7 @@ jobs:
167
186
# same bytes rather than a stale or rebuilt guest.
168
187
- name: Record the guests' checksums
169
188
run: |
170
-
for guest in encrypt/wasm/stack_encrypt_guest.wasm encrypt/testdata/stack_encrypt_guest_deterministic.wasm auth/wasm/stack_auth_guest.wasm; do
189
+
for guest in encrypt/wasm/stack_encrypt_guest.wasm encrypt/testdata/stack_encrypt_guest_deterministic.wasm encrypt/eql/wasm/stack_encrypt_guest_eql.wasm encrypt/testdata/stack_encrypt_guest_eql_deterministic.wasm auth/wasm/stack_auth_guest.wasm; do
- name: The guests are the ones Linux built and checked
291
314
run: |
292
315
cd languages/golang
293
-
for guest in encrypt/wasm/stack_encrypt_guest.wasm encrypt/testdata/stack_encrypt_guest_deterministic.wasm auth/wasm/stack_auth_guest.wasm; do
316
+
for guest in encrypt/wasm/stack_encrypt_guest.wasm encrypt/testdata/stack_encrypt_guest_deterministic.wasm encrypt/eql/wasm/stack_encrypt_guest_eql.wasm encrypt/testdata/stack_encrypt_guest_eql_deterministic.wasm auth/wasm/stack_auth_guest.wasm; do
- name: The guests are the ones the wasi-check job built and checked
357
380
run: |
358
381
cd languages/golang
359
-
for guest in encrypt/wasm/stack_encrypt_guest.wasm encrypt/testdata/stack_encrypt_guest_deterministic.wasm auth/wasm/stack_auth_guest.wasm; do
382
+
for guest in encrypt/wasm/stack_encrypt_guest.wasm encrypt/testdata/stack_encrypt_guest_deterministic.wasm encrypt/eql/wasm/stack_encrypt_guest_eql.wasm encrypt/testdata/stack_encrypt_guest_eql_deterministic.wasm auth/wasm/stack_auth_guest.wasm; do
Copy file name to clipboardExpand all lines: AGENTS.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -92,7 +92,7 @@ Every npm package except EQL lives under `languages/typescript/`: packages in `l
92
92
links are provenance only.
93
93
-`packages/stack-auth`, `packages/stack-profile`, `packages/stack-kms`, `packages/stack-encrypt`, `packages/stack-encrypt-derive`, `packages/stack-guest-abi`: The Rust crates imported from `cipherstash/cipherstash-suite` with their history — `stack-auth` and `stack-profile` (published to crates.io, one version group), `stack-kms` (published to crates.io from 0.1.0, its own version group, re-exported by `stack-encrypt` as `stack_encrypt::kms`), `stack-encrypt` and `stack-encrypt-derive` (published to crates.io from 0.1.0, one version group; `eql-bindings`' `stack-encrypt` feature depends on them from the registry), and `stack-guest-abi` (`publish = false`). They are the members of the **root Cargo workspace**, with the three node binding crates below. See "Working on the Rust crates".
94
94
-`languages/typescript/packages/auth`, `languages/typescript/packages/profile`, `languages/typescript/packages/stack-auth-wasm`: The node bindings of those crates. `@cipherstash/auth` (napi-rs v2) and its six `platforms/*` packages are published to npm from this repository by `release.yml` (`auth-artifacts`, `publish-auth`); a change to what it ships, the `stack-auth` crate included, needs an `@cipherstash/auth` changeset (`require-auth-npm-changeset.yml`). `@cipherstash/profile` and its platforms are private and never published; `@cipherstash/stack-auth-wasm` is private and builds the wasm that `@cipherstash/auth` ships. Their `build` and `test` scripts never invoke cargo; `build:native`, `build:debug` and `test:cargo` do.
95
-
-`languages/golang`: The Go module — the SDK `encrypt` with its generated-code support `encrypt/gensupport` and the policy packages `encrypt/policy` and `encrypt/policy/protosource`; the credential package `auth`; the generator `stashgen` and its command `cmd/stashgen`; and `internal` (the shared guest plumbing and the `record` wire model). A wazero host with no cgo. Its two WASI guests (`encrypt/guest`, `auth/guest`) are detached Cargo workspaces built by `mise run wasm:guest:build` and `mise run wasm:auth-guest:build`; `mise run wasm:guest:build:deterministic` builds the seeded TEST build the hermetic Go tests use; the `.wasm` files they embed are gitignored. Generated `*_stash.go` files are committed and CI fails when `go generate ./...` changes one. There is no Go release process yet.
95
+
- `languages/golang`: The Go module — the SDK `encrypt` with its generated-code support `encrypt/gensupport` and the policy packages `encrypt/policy` and `encrypt/policy/protosource`; the credential package `auth`; the generator `stashgen` and its command `cmd/stashgen`; and `internal` (the shared guest plumbing and the `record` wire model). A wazero host with no cgo. Its two WASI guests (`encrypt/guest`, `auth/guest`) are detached Cargo workspaces built by `mise run wasm:guest:build` and `mise run wasm:auth-guest:build`; `mise run wasm:guest:build:deterministic` builds the seeded TEST build the hermetic Go tests use; the `.wasm` files they embed are gitignored. The stack-encrypt guest has a second build with the EQL types (`mise run wasm:guest:build:eql`, cargo feature `eql`, linking `eql-bindings` by path; `wasm:guest:build:eql:deterministic` is its test build), embedded by `encrypt/eql` and registered on import, so a program whose generated code names an EQL type runs it (ADR-0007, amended). `encrypt/eql`'s types and `Types` table are generated from the EQL catalog by `eql-codegen` (`eql_gen.go`, written by `mise run types:generate` in `packages/eql` and drift-gated by `types:check` and `cargo test -p eql-codegen`). Generated `*_stash.go` files are committed and CI fails when `go generate ./...` changes one. There is no Go release process yet.
Copy file name to clipboardExpand all lines: docs/plans/2026-10-04-plan-builder.md
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -667,6 +667,9 @@ The ciphertext inside it is a Stack Encrypt ciphertext, which starts with `stack
667
667
"EQL v4" in this plan is the name of that form, and not a new envelope.
668
668
669
669
The engine produces one EQL type today: `TextEq`.
670
+
Status (2026-10-06, #1062): `TextEq` is producible through the data plan's target form.
671
+
`stashgen` accepts `encrypt_into=TextEq`, the guest build with the EQL types returns the finished value, and `encrypt/eql` holds the generated Go types; every other type is listed by `se_targets` with the reason it is not producible, and `stashgen` refuses it.
672
+
Open question for Dan: an EQL value is stored under a table and a column, so a target field's label must be exactly `<table>/<column>`; a cipher extended with a tenant part has no column for the extended label, and a plan with a target field refuses the extension rather than dropping it.
670
673
The other types wait for work in the engine:
671
674
672
675
-**Every family but `Text`:** how the family encodes a plaintext is not specified.
Each sealed field is one or more byte columns: `Email.Ciphertext`, `Email.Equality`, `Email.Match`.
48
-
`encrypt.Ciphertext` and each term type implement `driver.Valuer` and `sql.Scanner`, so a database library binds and scans each one as bytes; map each one to its own column.
47
+
Each `encrypt_into` field is one EQL column: `eql.TextEq` implements `driver.Valuer` and `sql.Scanner`, so a database library binds and scans it as the JSON a `public.eql_v3_text_eq` column holds.
49
48
50
49
7. Run the generator again after each change to the struct or to a tag.
51
50
A change to the fields of the struct stops the build until you do.
@@ -148,10 +147,14 @@ It ignores its own output file when it loads the package, so a stale file does n
148
147
The same input always gives the same file: fields keep their declared order, and the file carries no version and no time.
149
148
150
149
`stashgen` checks each declaration with the engine, and holds no copy of the engine's rules: it runs the WASI guest the SDK embeds and asks it, one field at a time, so the error names the field.
151
-
It asks the engine for the EQL types it holds: each name, its plaintext type, its indexes and its query form.
152
-
This build of the engine produces no EQL type, so `encrypt_into` is refused with "EQL types are not available yet"; the next release adds `TextEq` and `encrypt/eql`.
150
+
It asks the engine for the EQL types it holds: each name, its plaintext type, its indexes, its query form, and whether the engine produces it today.
151
+
The command links the build of the engine that holds the EQL types (`encrypt/eql`), so it can answer for every type; a generated file imports `encrypt/eql` only when it names one.
152
+
The engine produces `TextEq` today; `encrypt_into` with any other type is refused with the type's name.
153
153
Separate columns work today for four indexes: `equality`, `match`, `ore` and `ope`.
154
154
155
+
A field with `encrypt_into` is stored under its table and column, which is what an EQL value records in its `i`.
156
+
A cipher extended with a tenant part (`cipher.Extend(...)`) has no column for the extended label, so it refuses a struct with an `encrypt_into` field; use `index=` columns for a tenant-extended struct until that rule is settled.
157
+
155
158
## When stashgen stops
156
159
157
160
`stashgen` stops with an error, and writes no file, for each of these.
@@ -225,5 +228,5 @@ A protobuf message with a `oneof` cannot be generated from a policy: protoc-gen-
225
228
226
229
## Status
227
230
228
-
The command runs the WASI guest the SDK embeds, so it needs the guest built: `mise run wasm:guest:build`.
231
+
The command runs the WASI guest the SDK embeds, so it needs the guests built: `mise run wasm:guest:build wasm:guest:build:eql`.
229
232
The library, `github.com/cipherstash/stack/languages/golang/stashgen`, takes any `Engine`; `stashgen.Generate` takes one with `WithEngine`, and `stashgen/enginetest` has a static one for tests.
0 commit comments