Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions changelog.d/20260929_lab-523.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
### Encryption — hardware-acceleration detection surfacing in rs/ts (LAB-523)

- [Feature matrix](sdk-feature-matrix.md#encryption) Hardware acceleration
detection row: Rust moves from "core-internal, not re-exported" to 🚧 in
review — [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80)
(`EncryptionLayer::hardware_acceleration_enabled()`, `SecureCache` forwarder);
TypeScript moves from "not exposed" to 🚧 unreleased —
[cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132)
(`TenantKeys.hardwareAccelerationEnabled()` on both bindings,
`EncryptionManager.isHardwareAccelerated()`) is merged to `main`.
Published artifacts are unchanged: crates.io 0.7.0 and npm 0.1.5 (checked
2026-09-29) still expose nothing, so neither cell is ✅.
- Footnote ⁶, now also marked on the Python cell: the flag is informational
only, and it reads `true` on every aarch64 build through `cachekit-core` 0.6.0;
the fix is merged to core `main` but unreleased.
6 changes: 3 additions & 3 deletions sdk-feature-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

**Feature parity and compliance status across all CacheKit SDK implementations.**

*Last updated: 2026-09-02 — LAB-687 keyring conformance and documentation reconciliation (following LAB-1400's matrix baseline correction). Every version-keyed claim is verified against the **published artifact** (registry metadata, and the `.crate`/`.tgz` contents where an embedded dependency version decides the answer), not against a repo branch — see [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md) for why and how. Per-PR fold verdicts are in [CHANGELOG.md](CHANGELOG.md); per-row history is `git log sdk-feature-matrix.md`.*
*Last updated: 2026-09-29 — LAB-523 hardware-acceleration detection (following LAB-687's keyring reconciliation and LAB-1400's matrix baseline correction). Every version-keyed claim is verified against the **published artifact** (registry metadata, and the `.crate`/`.tgz` contents where an embedded dependency version decides the answer), not against a repo branch — see [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md) for why and how. Per-PR fold verdicts are in [CHANGELOG.md](CHANGELOG.md); per-row history is `git log sdk-feature-matrix.md`.*

*__Cells that reversed — check these if you built on them:__ Rust `::secure` preset and Rust sync support (both ✅ → do not exist), Builder API (py/ts ✅ → ❌), Hardware acceleration (rs ✅ → not re-exported, ts N/A → ❌), TypeScript Arrow (🔜 → ❌), Python's encrypted read path (documented fail-closed → **fail-open by default**), and `cache.secure.wrap()` in TypeScript (implied encryption → no guarantee → **enforced since LAB-513: throws without encryption**). The TypeScript protocol-1.1 `bin` rollout also reversed twice in two days: it is **not** shipped on either ts path (per-artifact evidence in the [cachekit-core architecture note](#architecture-notes)).*

Expand Down Expand Up @@ -83,7 +83,7 @@
| Key rotation | ✅ 0.18.0+ — keyring; derived-key fingerprint selection⁵ | 🚧 unreleased — keyring on `main` ([cachekit-rs#63](https://github.com/cachekit-io/cachekit-rs/pull/63)); absent from crates.io 0.7.0⁵ | 🚧 unreleased — keyring on `main` ([cachekit-ts#103](https://github.com/cachekit-io/cachekit-ts/pull/103)); absent from npm 0.1.5⁵ | ❌ |
| **Tamper / wrong-key failure mode** | ⚠️ **fail-OPEN by default** — warn + recompute; switchable with `CACHEKIT_ENCRYPTION_FAIL_CLOSED=true`¹⁸ | ✅ **Fails closed** — `decrypt(…)?` propagates (`client.rs:830`, `:847`), and `#[cachekit(secure)]` emits no fail-open arm (`cachekit-macros/src/lib.rs:439-451`) | ⚠️ **fail-OPEN on reads, silently drops writes, not switchable**⁸ | — |
| **Does the `secure` API enforce encryption?** | ✅ Raises without a key | ✅ `secure()` returns `Err` | ✅ **`cache.secure.wrap()` throws `ConfigurationError` at wrap time** on any instance without `encryption` configured — instance and `withExecutionContext(ctx)` view alike (LAB-513; before it, an unconditional alias for `wrap()`, so on an instance without configured encryption a "secure" registration cached plaintext, CWE-311); see [Intent-preset semantics](#intent-preset-semantics-parity-not-presence) | — |
| Hardware acceleration detection | ✅ surfaced (`hardware_acceleration_enabled()`) | ⚠️ core-internal, not re-exported⁶ | ❌ not exposed⁶ | N/A |
| Hardware acceleration detection | ✅ surfaced (`EncryptionWrapper.hardware_acceleration_enabled`)⁶ | 🚧 in review — [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80); absent from crates.io 0.7.0⁶ | 🚧 unreleased — on `main` ([cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132)); absent from npm 0.1.5⁶ | N/A |
| Counter-based nonces | ✅ via Rust | ✅ | ✅ via NAPI (Rust) | ❌ use random |

> [!IMPORTANT]
Expand All @@ -104,7 +104,7 @@
>
> Degradation is on unless explicitly disabled (`degradationEnabled = config.degradation !== false`, `reliability/executor.ts:39`) and `createCache.secure()` / `.production()` / `.io()` all set it `true` (`intents-core.ts:186`); only `minimal` sets `false`, and `minimal` carries no encryption. **There is no `failClosed` option anywhere in cachekit-ts** — Python's `CACHEKIT_ENCRYPTION_FAIL_CLOSED` has no counterpart, so the only lever is `reliability: { degradation: false }`, which also gives up backend-outage degradation. If you rely on a thrown error as your tamper, wrong-key or nonce alarm, TypeScript raises none; the sole signal is the `errors_total` counter.
>
> ⁶ Runtime AES detection (`is_x86_feature_detected!("aes")`, `cachekit-core/src/encryption/core.rs:243`) lives in the shared core and is **surfaced only by Python** (`encryption_wrapper.py:583`). cachekit-rs never re-exports it — the SDK calls the non-metrics encrypt/decrypt entry points — and the TypeScript NAPI layer exposes nothing — `N/A` there was wrong, since ts runs the same Rust core. Tracked as LAB-523.
> ⁶ AES hardware detection lives in the shared core — `ZeroKnowledgeEncryptor::hardware_acceleration_enabled()` in `cachekit-core/src/encryption/core.rs`: a runtime `is_x86_feature_detected!("aes")` probe on x86/x86_64; on aarch64 it returns `cfg!(target_feature = "neon")`, which every aarch64 target enables, so it is `true` on every aarch64 build whether or not the CPU has the Crypto Extension — a Raspberry Pi 4 (Cortex-A72 without the Crypto Extension) reports `true` while `ring` runs software AES. That holds for every published `cachekit-core` through 0.6.0 (0.4.0 and 0.6.0 included); the fix, [cachekit-core#77](https://github.com/cachekit-io/cachekit-core/pull/77) (LAB-4650), is merged to core `main` but unreleased; always `false` on wasm32 (no AES instructions to detect). It is **informational only** — `ring`/`aes-gcm` choose their implementation independently of the flag. Published artifacts (registries checked 2026-09-29): Python surfaces it (`EncryptionWrapper.hardware_acceleration_enabled`, in `get_info()` and the init log); cachekit-rs 0.7.0 never re-exports it and `@cachekit-io/cachekit` 0.1.5 exposes nothing on either binding — `N/A` for TypeScript was wrong, since both bindings run the same Rust core. The Rust re-export (`EncryptionLayer::hardware_acceleration_enabled()`, forwarded by `SecureCache`) is open in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80): not on `main`, not released. The TypeScript surface (`TenantKeys.hardwareAccelerationEnabled()` on the NAPI and wasm bindings; `EncryptionManager.isHardwareAccelerated()`, which initialises on demand and returns `null` — unknown, not `false` — when the installed binding predates the accessor) is merged to `main` in [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132) but not released. The wasm32 always-`false` claim is asserted by cachekit-ts's workerd test (`encryption.protocol.workers.test.ts`), and the Rust accessor is pinned to `is_x86_feature_detected!("aes")` on x86_64 in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80)'s `encryption.rs` tests (not on `main`). The Rust cell flips to 🚧 unreleased when [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80) merges; each flips to ✅ with a version floor on release, per [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). Tracked as LAB-523.

---

Expand Down
Loading