Skip to content

feat: cipherstash-client 0.40.0, v3 payload format, and OIDC federation auth#6

Open
calvinbrewer wants to merge 1 commit into
mainfrom
feat/client-0.40-eql-v3
Open

feat: cipherstash-client 0.40.0, v3 payload format, and OIDC federation auth#6
calvinbrewer wants to merge 1 commit into
mainfrom
feat/client-0.40-eql-v3

Conversation

@calvinbrewer

Copy link
Copy Markdown
Contributor

Summary

Upgrades the entire stack — the Rust FFI layer and the Go SDK — from cipherstash-client 0.34.1-alpha.2 to the current crate set, bringing the Go SDK to feature parity with protectjs-ffi v0.29.0:

Crate Before After
cipherstash-client 0.34.1-alpha.2 0.40.0
cts-common 0.34.1-alpha.2 0.40.0
stack-profile 0.34.1-alpha.2 0.40.0
stack-auth 0.40.0 (new — auth strategies)
eql-bindings 3.0.0 (new — EQL 3.0.0 payload format)
cipherstash-config, cipherstash-core direct deps removed (re-exported via cipherstash_client::schema)

OIDC federation without lock context

The headline feature: WithOIDCFederation makes every operation identity-aware at the client level, with no per-operation context.

client, err := protect.NewClient(ctx,
    protect.WithSchemas(users),
    protect.WithOIDCFederation(func(ctx context.Context) (string, error) {
        return idp.AccessToken(ctx) // Clerk / Auth0 / Supabase JWT
    }),
)

Design: the Go side registers a JWT callback across the FFI (//export + runtime/cgo.Handle, panic-safe, result-envelope protocol); stack-auth's native OidcFederationStrategy in Rust does the POST /api/authorise exchange, caches the CTS token until expiry, re-federates on demand, and verifies every token against the workspace CRN. Also included: WithTokenProvider for supplying raw service tokens, and host-side env credential loading (CS_CLIENT_ID/CS_CLIENT_KEY are no longer read by the native layer in 0.40 — the SDK now fills them in, matching protectjs).

Consequences of the platform's auth model change:

  • WithServiceToken is removed — per-operation service tokens were deleted platform-wide in client 0.36.
  • Lock contexts now require identity-bearing auth (i.e. OIDC federation). With plain access-key auth the platform rejects lock-context operations; docs and the example updated accordingly.

v3 payload format

WithEncryptedFormat(EncryptedFormatV3) targets databases provisioned with the EQL 3 schema (typed encrypted columns). V2 remains the default. Notes:

  • Decrypt is version-agnostic (probes v3 first, falls back to v2), so old data stays readable during a migration.
  • The config→column-type mapping is fail-closed: index combinations with no v3 equivalent fail at NewClient with ErrUnsupportedFormat + hint, instead of silently dropping a search capability.
  • Query results are now an opaque *QueryTerm (v3 selector terms are bare JSON strings, which the old *Encrypted return type could not represent). Breaking: EncryptQuery/EncryptQueryBulk signatures changed.
  • README documents the full v3 PostgreSQL setup (column-type mapping table, eql_v3.query_* casts, ordering extractors), taken from protectjs-ffi's live integration tests.

Correctness improvements

  • Exact integer round-trips across the full int64 range — the wire and both conversion layers no longer pass through f64 (values > 2^53 previously rounded). Integer conversions are exact-or-error: fractional/overflow/NaN rejected instead of truncated.
  • decimal values stored exactly (string-parsed, not via float); date/timestamp columns now actually work, accepting time.Time and RFC 3339 strings.
  • Hand-rolled encrypt-config parser (~650 lines) deleted in favor of CanonicalEncryptionConfig; Go normalizes legacy cast names (stringtext, numberfloat, bigintbig_int) on the wire.
  • Struct-tag inference fixed: Go ints now map to big_int (was number/float), time.Time to timestamp.

CI

  • Added the missing linux-arm64-gnu build job (libprotect_ffi_linux_arm64.a was committed but never rebuilt — permanently stale).
  • Fixed arm64-musl builds to actually get +crt-static (the config was hardcoded to the x86_64 target).
  • New test-go job runs the Go suite against freshly built libraries on macOS and Linux.

Important

Only the darwin-arm64 static library in this PR is current; the build workflow on this PR rebuilds and commits all six platforms.

Verification

  • cargo test: 172 passing; cargo clippy --all-targets -- -D warnings clean.
  • go test ./...: passing (pure unit tests, no network).
  • Live E2E against ZeroKMS/CTS: v2 model + bulk + query flows; v3 encrypt/decrypt round-trips (including int64 > 2^53); v3 query operand shapes (all domain terms, no ciphertext); IsEncrypted on both formats; token-provider errors propagating Go→Rust→Go intact; and the OIDC path exercised against the real /api/authorise endpoint (rejected with 401 InvalidToken as expected for a non-IdP JWT — the full pipeline works, only a real IdP token is needed).

Breaking API changes

Change Migration
WithServiceToken removed Use WithOIDCFederation (identity) or WithTokenProvider (raw tokens)
EncryptQuery returns *QueryTerm (was *Encrypted) Bind the term as a SQL parameter; use .String()/.Bytes() to inspect
EncryptQueryBulk returns []*QueryTerm as above
Decrypt returns json.Number for numeric columns (was float64) DecryptModel/BulkDecryptModels coerce automatically; direct Decrypt callers should switch on json.Number
Struct-tag ints infer big_int (was float) Add cast=float to keep old behavior for a column with existing data

🤖 Generated with Claude Code

…ederation

Upgrade the native layer from cipherstash-client 0.34.1-alpha.2 to 0.40.0,
adding eql-bindings 3.0.0 (v3 payload format) and stack-auth 0.40.0 (client
auth strategies including OIDC federation with no lock context required).

Rust: replace the hand-rolled encrypt-config parser with the canonical
schema config, port the v3 conversion layer, add a token-callback auth seam
to the C ABI, and remove per-operation service tokens (deleted platform-wide
in client 0.36).

Go: add WithOIDCFederation / WithTokenProvider / WithEncryptedFormat, an
opaque QueryTerm for query results, canonical cast types, exact int64 /
date / timestamp / decimal round-trips, host-side env credential loading,
and remove WithServiceToken.

CI: add the missing linux-arm64-gnu build, fix arm64-musl static linking,
and run Go tests against the freshly built libraries.

Non-darwin-arm64 static libraries are stale in this commit; the PR build
workflow rebuilds and commits all platforms.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant