Skip to content

Commit a432545

Browse files
authored
Merge pull request #658 from cipherstash/docs/eql-v3-sole-approach
2 parents d1f34c1 + 3fdd740 commit a432545

93 files changed

Lines changed: 5978 additions & 1477 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
'stash': minor
3+
---
4+
5+
Add anonymous, opt-out usage analytics to the `stash` CLI, plus a
6+
`stash telemetry [status|enable|disable]` command to manage it.
7+
8+
Only coarse events are collected — command name, CLI version, OS/arch, Node
9+
version, success/failure, duration, and a coarse caller class (e.g.
10+
`claude-code`, `cursor`, `interactive`) derived from environment markers so we
11+
can gauge agent- vs human-driven usage. Events carry a random install
12+
identifier (a locally generated UUID, not derived from any machine or user
13+
attribute) used only to de-duplicate events in aggregate. Plaintext, schema,
14+
table/column names,
15+
connection strings, argument values, and any session/trace identifier are never
16+
collected — enforced by a property-key allowlist at the emitter boundary plus
17+
closed-vocabulary coercion of every argv- or error-derived value (unrecognised
18+
commands, subcommands, and error class names all collapse to `<other>`). A
19+
one-time notice is shown on first run, and nothing is sent on that run.
20+
21+
Telemetry is off by default in CI and can be disabled with `DO_NOT_TRACK=1`
22+
(the cross-tool standard), `STASH_TELEMETRY_DISABLED=1`, or
23+
`stash telemetry disable` (persisted to `~/.cipherstash/telemetry.json`).
24+
25+
Events are sent via a first-party proxy and never block or slow the CLI. The
26+
feature ships dormant — no events are sent until a PostHog project key is
27+
embedded at release. Updates the `stash-cli` skill to document the command and
28+
opt-out controls.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@cipherstash/drizzle': patch
3+
---
4+
5+
Docs: the README's "for new projects" pointer named the removed
6+
`@cipherstash/stack/drizzle` subpath; it now points at the separate
7+
`@cipherstash/stack-drizzle` package (EQL v3 on its `/v3` subpath).

‎.changeset/eql-v3-json-selector.md‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
'@cipherstash/stack-drizzle': minor
3+
'stash': patch
4+
---
5+
6+
Add EQL v3 JSON **selector-with-constraint** querying to the Drizzle integration
7+
(#623). `ops.selector(col, '$.path')` returns comparison methods bound to a
8+
JSONPath into a `types.Json` column — `eq`/`ne`/`gt`/`gte`/`lt`/`lte` — emitting
9+
`col->'<selector>' <op> <value>` over the encrypted document. Its unique power
10+
over `contains` is **ordering at a path** (`col->'$.age' > 21`), which
11+
containment cannot express.
12+
13+
Complements the existing `contains` (JSONB `@>`) containment operator. Core
14+
`@cipherstash/stack` needs no change — the selector hash and comparison entry are
15+
produced by `encryptQuery`/`encrypt` on the existing `types.Json` surface. v1
16+
supports dot-notation object paths; array-index/wildcard paths are rejected with
17+
a clear error. The Supabase adapter is tracked separately.
18+
19+
The right-hand comparison operand is currently a storage-encrypted needle (its
20+
ste_vec entry carries the ordering term), pending a ciphertext-free ordering
21+
query needle from protect-ffi (cipherstash/protectjs-ffi#137); until then the
22+
value's ciphertext appears in the WHERE clause.
23+
24+
The bundled `stash-encryption` and `stash-drizzle` skills document the new
25+
`ops.selector(...)` surface (they previously said JSONPath selector queries were
26+
not yet implemented).

‎.changeset/eql-v3-sole-docs.md‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'stash': patch
3+
'@cipherstash/stack': patch
4+
---
5+
6+
Docs: EQL v3 is now the sole documented approach. The `stash-encryption`,
7+
`stash-drizzle`, and `stash-supabase` skills and the `@cipherstash/stack`
8+
README teach only the v3 typed surface (`EncryptionV3`, `types.*` concrete
9+
domains, `@cipherstash/stack-drizzle/v3`, `encryptedSupabaseV3`); EQL v2
10+
shrinks to one short Legacy section per document. Two explicit exceptions are
11+
called out: DynamoDB still requires the v2 schema surface (#657), and the
12+
encrypt rollout tooling (`stash encrypt backfill`/`cutover`,
13+
`@cipherstash/migrate`) currently targets v2 columns (#648) — its guidance is
14+
kept under a version callout. Also corrects the legacy `@cipherstash/drizzle`
15+
README's pointer to the removed `@cipherstash/stack/drizzle` subpath (now the
16+
separate `@cipherstash/stack-drizzle` package).

‎.changeset/pre.json‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"mode": "pre",
3+
"tag": "rc",
4+
"initialVersions": {
5+
"@cipherstash/e2e": "0.0.2",
6+
"@cipherstash/basic-example": "1.2.13",
7+
"@cipherstash/prisma-next-example": "0.0.5",
8+
"@cipherstash/supabase-worker-example": "0.0.0",
9+
"@cipherstash/bench": "0.0.4",
10+
"stash": "0.17.1",
11+
"@cipherstash/drizzle": "3.0.3",
12+
"@cipherstash/migrate": "0.2.0",
13+
"@cipherstash/nextjs": "4.1.1",
14+
"@cipherstash/prisma-next": "0.3.2",
15+
"@cipherstash/protect": "12.0.1",
16+
"@cipherstash/protect-dynamodb": "12.0.1",
17+
"@cipherstash/schema": "3.0.1",
18+
"@cipherstash/stack": "0.19.0",
19+
"@cipherstash/stack-drizzle": "0.0.0",
20+
"@cipherstash/stack-supabase": "0.0.0",
21+
"@cipherstash/test-kit": "0.0.0",
22+
"@cipherstash/wizard": "0.4.0"
23+
},
24+
"changesets": [
25+
"adapter-package-split",
26+
"adapter-split-skills",
27+
"cli-eql-v3-single-bundle",
28+
"eql-v3-adapter-type-robustness",
29+
"eql-v3-bigint-domains",
30+
"eql-v3-bundle-from-package",
31+
"eql-v3-cli-install",
32+
"eql-v3-drizzle-encrypt-query",
33+
"eql-v3-drizzle-fail-open-guards",
34+
"eql-v3-drizzle",
35+
"eql-v3-ffi-0-28-concrete-types",
36+
"eql-v3-ga-rebaseline",
37+
"eql-v3-json-skills",
38+
"eql-v3-json",
39+
"eql-v3-public-domains",
40+
"eql-v3-rename-contains-to-matches",
41+
"eql-v3-supabase-adapter",
42+
"eql-v3-text-search",
43+
"eql-v3-typed-client",
44+
"eql-v3-typed-schema",
45+
"eql-v3-wasm-inline",
46+
"prisma-next-0-14",
47+
"remove-secrets-leftovers",
48+
"rename-db-install-to-eql-install",
49+
"schema-stevec-standard-pin",
50+
"stack-1-0-0-rc",
51+
"stack-adapter-kit",
52+
"stash-cli-eql-v3-default",
53+
"stash-cli-skill-refresh",
54+
"stash-drizzle-skill-encrypt-query",
55+
"stash-skills-contains-to-matches",
56+
"stash-supabase-contains-substrings",
57+
"supabase-encryption-error",
58+
"supabase-in-list-operands",
59+
"supabase-is-null-operands",
60+
"supabase-or-string-parser",
61+
"supabase-v3-order-by-ope-term",
62+
"wizard-allow-env-templates"
63+
]
64+
}

‎.changeset/stack-1-0-0-rc.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@cipherstash/stack': major
3+
'@cipherstash/stack-drizzle': major
4+
'@cipherstash/stack-supabase': major
5+
'stash': major
6+
---
7+
8+
CipherStash Stack 1.0 (release candidate).
9+
10+
This is the first 1.0-line release of `@cipherstash/stack`, the first published
11+
release of the split-out EQL v3 adapters `@cipherstash/stack-drizzle` and
12+
`@cipherstash/stack-supabase`, and moves the `stash` CLI to 1.0 alongside them.
13+
These four packages now version together as the Stack 1.0 family.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
'@cipherstash/stack-supabase': minor
3+
'@cipherstash/stack': minor
4+
'stash': patch
5+
---
6+
7+
Encrypted-JSON querying on the v3 Supabase surface (#650). A `types.Json`
8+
column now supports exact encrypted containment — `contains(col, subDocument)`
9+
(ste_vec `@>` via PostgREST `cs`, with the sub-document storage-encrypted
10+
against the column) — and JSONPath selector predicates: `selectorEq(col, path,
11+
value)` and `selectorNe(col, path, value)` (dot-notation paths; `ne` includes
12+
rows where the path is absent, mirroring the Drizzle selector's semantics).
13+
Raw `.filter(col, 'cs', subDocument)` and `not(col, 'contains', …)` route
14+
through the same encrypted path. Selector ordering is not expressible over
15+
PostgREST yet (needs an EQL-bundle overload — see
16+
cipherstash/encrypt-query-language#407); the Drizzle integration's
17+
`ops.selector()` covers ordering today.
18+
19+
In core, `QueryTypesForColumn` gains the `searchableJson` arm (a `types.Json`
20+
column no longer resolves to `never`, so typed adapter key sets can include
21+
it), and the JSONPath selector-path helpers the Drizzle adapter introduced in
22+
#651 moved to `@cipherstash/stack/adapter-kit` so both adapters share one
23+
validation surface (`@cipherstash/stack-drizzle` re-exports them unchanged).
24+
25+
The bundled `stash-supabase` and `stash-encryption` skills are updated to
26+
document the new querying surface (including the array-leaf and SQL-NULL
27+
semantics, and the operand-exposure caveat) — skills ship inside the `stash`
28+
tarball, hence the patch.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@cipherstash/wizard': patch
3+
---
4+
5+
Align the wizard's analytics with the `stash` CLI's telemetry privacy contract.
6+
The wizard now honors `DO_NOT_TRACK`, `STASH_TELEMETRY_DISABLED`, and CI
7+
auto-detection; uses a random per-session identifier instead of one derived
8+
from username@hostname; disables IP→geo resolution; and reports error events as
9+
fixed labels / error class names instead of raw messages (which could embed
10+
schema names or connection details). Analytics remain dormant unless a PostHog
11+
key is configured at build time.

‎.github/workflows/integration-drizzle.yml‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@ jobs:
5858
integration:
5959
name: Drizzle v3 integration (db=${{ matrix.db }})
6060
runs-on: blacksmith-4vcpu-ubuntu-2404
61+
# Serialize every job that brings up the SAME docker-compose stack, so no two
62+
# bind the same fixed host ports on a shared runner at once (the "address
63+
# already in use" flake). Keyed by the compose variant, NOT the ref (two PRs
64+
# contend for a host port just as much as two pushes to one PR), so it
65+
# serializes across refs. The `supabase` leg uses the SAME supabase compose
66+
# (55430 / 55433) as the Supabase workflow and shares its key
67+
# (`integration-live-db-supabase`), so the two workflows queue rather than
68+
# collide; the `postgres` leg (55432) has its own key and still runs in
69+
# parallel with them.
70+
concurrency:
71+
group: integration-live-db-${{ matrix.db }}
72+
cancel-in-progress: false
6173
# Fork PRs have no secrets. Skip cleanly rather than fail on something the
6274
# contributor cannot fix — `tests.yml` still gives them a green signal.
6375
if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
@@ -134,6 +146,14 @@ jobs:
134146
client-key: ${{ secrets.CS_CLIENT_KEY }}
135147
client-access-key: ${{ secrets.CS_CLIENT_ACCESS_KEY }}
136148

149+
# Belt-and-braces for the concurrency guard: a run that was hard-killed
150+
# (runner crash / forced cancel) can skip its `down` and leak a container
151+
# holding the host port onto a REUSED runner. Tear any prior stack down
152+
# before starting a fresh one. `|| true` so a clean runner (nothing to
153+
# remove) is not an error.
154+
- name: Clear any leaked containers from a prior run
155+
run: docker compose -f local/docker-compose.${{ matrix.db }}.yml down -v --remove-orphans || true
156+
137157
- name: Start ${{ matrix.db }}
138158
run: docker compose -f local/docker-compose.${{ matrix.db }}.yml up -d --wait
139159

‎.github/workflows/integration-supabase.yml‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ jobs:
5050
integration:
5151
name: Supabase v3 integration (db=${{ matrix.db }})
5252
runs-on: blacksmith-4vcpu-ubuntu-2404
53+
# Serialize every job that brings up the SAME docker-compose stack, so no two
54+
# bind the same fixed host ports (55430 / 55433) on a shared runner at once —
55+
# the "address already in use" flake. The group is keyed by the compose
56+
# variant, NOT the ref: two different PRs contend for the same host port just
57+
# as much as two pushes to one PR, so it must serialize across refs. It is the
58+
# SAME key the Drizzle workflow's matching leg uses (`integration-live-db-<db>`),
59+
# so those two workflows also queue against each other rather than colliding.
60+
# `cancel-in-progress: false` queues (a live-DB job that shares one ZeroKMS
61+
# workspace should finish, not be interrupted mid-run).
62+
concurrency:
63+
group: integration-live-db-${{ matrix.db }}
64+
cancel-in-progress: false
5365
# Fork PRs have no secrets. Skip cleanly rather than fail loudly on something
5466
# the contributor cannot fix — `tests.yml` still gives them a green signal.
5567
if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
@@ -106,6 +118,14 @@ jobs:
106118
client-key: ${{ secrets.CS_CLIENT_KEY }}
107119
client-access-key: ${{ secrets.CS_CLIENT_ACCESS_KEY }}
108120

121+
# Belt-and-braces for the concurrency guard: a run that was hard-killed
122+
# (runner crash / forced cancel) can skip its `down` and leak a container
123+
# holding the host port onto a REUSED runner. Tear any prior stack down
124+
# before starting a fresh one. `|| true` so a clean runner (nothing to
125+
# remove) is not an error.
126+
- name: Clear any leaked containers from a prior run
127+
run: docker compose -f local/docker-compose.${{ matrix.db }}.yml down -v --remove-orphans || true
128+
109129
- name: Start ${{ matrix.db }}
110130
run: docker compose -f local/docker-compose.${{ matrix.db }}.yml up -d --wait
111131

0 commit comments

Comments
 (0)