Skip to content

feat(encryption): previousMasterKeys keyring rotation surface (LAB-685) - #103

Open
27Bslash6 wants to merge 7 commits into
mainfrom
lab-685-previous-master-keys-keyring
Open

feat(encryption): previousMasterKeys keyring rotation surface (LAB-685)#103
27Bslash6 wants to merge 7 commits into
mainfrom
lab-685-previous-master-keys-keyring

Conversation

@27Bslash6

@27Bslash6 27Bslash6 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Resolves LAB-685 (stage 2 of the LAB-516 key-rotation train).

What

Master-key rotation without invalidating existing entries, per protocol/decisions/key-rotation.md + spec/encryption.md → "Key Rotation (Keyring)" (protocol PR #34):

  • Config: previousMasterKeys: string[] on EncryptionConfig / createCache.secure() (max 3, hex validation identical to masterKey; env fallback CACHEKIT_PREVIOUS_MASTER_KEYS, comma-separated). Load-time rejection with ConfigurationError: >3 keys (never truncates), masterKey in the list (forward-only rule, case-insensitive), duplicate entries.
  • Keyring decrypt loop behind the NAPI boundary via cachekit-core 0.5.0 Keyring: sequential attempts, current key first, identical AAD rebuilt per attempt; only AES-GCM auth failures advance; structural/config errors terminal. The wasm binding mirrors NAPI so the same config works on Workers (manager-core is shared — a platform-conditional config surface would be a security lie).
  • Single-key path unchanged: no keyring, no per-decrypt HKDF when previousMasterKeys is absent.
  • FFI attestation (panel MAJ): both bindings expose keyringEntryCount(); init throws ConfigurationError if a version-skewed native binary silently dropped the keyring argument (NAPI ignores extra args — without this, rotation config would silently no-op into whole-cache misses, LAB-241 class).
  • Key hygiene: key bytes cross the boundary once at init; keyring material zeroizes on drop in cachekit-core; no derived-key bytes retained in JS. "Keyring exposure is all-keys exposure" documented.
  • NonceExhaustedError guidance: forward-only rotation (never re-promote a retired key) + runbook link https://docs.cachekit.io/concepts/key-rotation/ (page authored by LAB-687 — anchor contract noted on the ticket).
  • cachekit-core pins bumped 0.4.0 → 0.5.0 in both crates.

Tests (714 unit + 98 workers, all green)

  • Load-time validation: cap, collision, duplicates, hex rules, env parsing precedence.
  • Real-NAPI keyring round-trip: k₁-encrypted value decrypts with masterKey=k₂, previousMasterKeys=[k₁], fails with []; writes stay on the current key; native-layer invariants (cap/collision/length) asserted directly against the binding.
  • Real-wasm (workerd) keyring round-trip parity.
  • E2E cache rotation: write under k₁ → read through k₂+[k₁] without re-encryption (backend byte-identity + set-spy asserted) → k₁ dropped → miss under default degradation, EncryptionError with degradation: false.
  • FFI-skew attestation: missing/wrong keyringEntryCount refuses init loudly.

Expert panel (critical-stakes crypto gate — mandatory, recorded here)

4-agent panel (bug-hunter-supreme, security-specialist, code-craftsman, catchphrase) on d8f1b7c:

  • security-specialist: NO FINDINGS — verified forward-only enforcement (string-level JS + byte-level Keyring::new, no case bypass), AAD invariance across attempts (single buffer by construction), no key-index oracle (exhaustion collapses to the same AuthenticationFailed as single-key), no truncation path, no key material in errors/logs, LAB-683 config-vs-auth error separation honored (config errors throw synchronously at createCache, before any fail-open path exists).
  • bug-hunter-supreme: 1 MAJ — version-skewed platform binary silently drops the 3rd NAPI arg → keyring never built → silent whole-cache misses. Fixed in 420d6fc (attestation above).
  • code-craftsman: 6 MIN — all applied in 420d6fc: duplicate-entry rejection, per-key error labels, guidance-string dedupe into the NonceExhaustedError default, README env-parsing example cut, MIN_MASTER_KEY_*MASTER_KEY_* rename (internal; "minimum"/"32+ bytes" claims were looser than the exact-length check actually shipped), qualified the "no key bytes retained" comment (hex config strings remain, per the documented masterKey pattern).
  • catchphrase: lean, one cut (same guidance dedupe). wasm mirror explicitly adjudicated as justified, not scope creep; triple validation (JS → binding → core) kept as public-boundary hardening.

Out of scope (per ticket)

Nonce-exhaustion handling (monitoring unchanged), fingerprint frame field (ts is the sequential-attempt branch by spec), runbook page authoring + feature-matrix flip (LAB-687, stage 3).

Dependency / SCA evidence (Kody review, 2026-08-08)

New/changed crates in this PR: cachekit-core 0.4.0 → 0.5.0 (both binding crates) and js-sys (new, wasm crate only — ships from the wasm-bindgen workspace and tracks its ABI). js-sys is now exact-pinned to =0.3.98, the release paired with the already exact-pinned wasm-bindgen =0.2.121 (commit 159e570).

Audit results (2026-08-08):

  • cargo audit on packages/cachekit-core-ts/Cargo.lock (140 crates): 0 vulnerabilities. One pre-existing allowlisted unmaintained notice — RUSTSEC-2024-0436 for paste 1.0.15 via rmp-serde ← cachekit-core; present on main since cachekit-core 0.4.0 (#91), not introduced here.
  • cargo audit on packages/cachekit-core-wasm/Cargo.lock (118 crates): 0 vulnerabilities, 0 warnings.
  • OSV.dev querybatch across all 206 unique crate versions in both lockfiles: the same single paste unmaintained notice, no known vulnerabilities for js-sys 0.3.98, cachekit-core 0.5.0, or any other resolved version.

Summary by CodeRabbit

  • New Features

    • Added master-key rotation support with up to three previous keys for decrypt-only grace periods.
    • New writes always use the current master key, while reads can fall back to previous keys.
    • Added support for configuring previous keys explicitly or through an environment variable.
    • Added keyring entry-count visibility and validation for key lengths, duplicates and limits.
  • Bug Fixes

    • Enforced exactly 32-byte master keys and improved validation and error handling during rotation.

Master-key rotation without invalidating existing entries, per protocol
decisions/key-rotation.md + spec/encryption.md 'Key Rotation (Keyring)':

- previousMasterKeys config (max 3, hex identical to masterKey; env
  CACHEKIT_PREVIOUS_MASTER_KEYS comma-separated). Load-time rejection:
  >3 keys throws (never truncates), masterKey in the list throws
  (forward-only rule, case-insensitive hex compare).
- Keyring decrypt loop behind the NAPI boundary via cachekit-core 0.5.0
  Keyring: sequential attempts, current key first, identical AAD per
  attempt; only auth failures advance. wasm binding mirrors NAPI so the
  same config works on Workers. Single-key path unchanged (no keyring,
  no per-decrypt HKDF).
- Key bytes cross the boundary once at init; keyring material zeroizes
  on drop in cachekit-core. No derived-key bytes retained in JS.
- NonceExhaustedError guidance now names forward-only rotation and links
  the rotation runbook (page authored by LAB-687).
- cachekit-core pins bumped 0.4.0 -> 0.5.0 in both crates.
Expert-panel (critical-stakes) findings applied:

- MAJ: attest the keyring survived the FFI boundary. NAPI silently drops
  extra arguments, so a version-skewed prebuilt binary would build a
  single-key handle and every pre-rotation entry would silently degrade
  to a miss (LAB-241 class). Both bindings now expose keyringEntryCount();
  init throws ConfigurationError on mismatch, and the method's absence
  (pre-keyring binary) is itself the skew signal.
- Reject duplicate previousMasterKeys entries (case-insensitive) — they
  silently burn keyring cap slots.
- Per-key index in validation errors (Previous master key N ...).
- Rotation guidance + runbook URL now lives once, in the
  NonceExhaustedError default message.
- MIN_MASTER_KEY_* renamed MASTER_KEY_* (internal): validation enforces
  exact length, the 'minimum' name and '32+/min 32 bytes' doc claims were
  looser than shipped behavior.
- README manual-config example no longer teaches raw split(',') env
  parsing; the Master-Key Rotation section is the single reference.
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a3230bf7-362e-4fe3-8eb5-8bbe78986807

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Changes

The change adds decrypt-only master-key rotation across TypeScript and WebAssembly bindings. It validates exact key sizes and keyring limits, forwards previous keys through runtime configuration, retains current-key-only writes, and adds native, cache, secure-cache, and Workers coverage.

Master-key rotation contracts

Layer / File(s) Summary
Rotation contracts and configuration
packages/cachekit-core-ts/index.d.ts, packages/cachekit-core-wasm/index.d.ts, packages/cachekit/src/types/cache.ts, packages/cachekit/src/constants.ts, packages/cachekit/README.md
The public APIs document optional previous keys, keyring counts, sequential decryption, exact 32-byte keys, and a maximum of three previous keys.
Native keyring derivation and decryption
packages/cachekit-core-ts/src/lib.rs, packages/cachekit-core-wasm/src/lib.rs, packages/cachekit-core-*/Cargo.toml
The Rust bindings derive keyrings, expose entry counts, validate previous keys, securely handle key material, and select keyring decryption when configured.
Runtime propagation and validation
packages/cachekit/src/encryption/*, packages/cachekit/src/intents-core.ts, packages/cachekit/src/cache.ts, packages/cachekit/src/workers/runtime.ts
Runtime paths pass previous keys to encryption managers, parse environment configuration, attest native keyring counts, and preserve current-key encryption.
Rotation behaviour coverage
packages/cachekit/src/cache.rotation.test.ts, packages/cachekit/src/intents.test.ts, packages/cachekit/src/encryption/*.test.ts, packages/cachekit/test/workers/*, .secrets.baseline
Tests cover grace-window reads, L1 caching, cut-over behaviour, configuration validation, environment parsing, native compatibility, and Workers integration.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SecureCache
  participant EncryptionManagerCore
  participant NativeTenantKeys
  participant CacheBackend
  SecureCache->>EncryptionManagerCore: Configure current and previous master keys
  EncryptionManagerCore->>NativeTenantKeys: Derive tenant keys and keyring
  SecureCache->>CacheBackend: Read encrypted entry
  CacheBackend-->>SecureCache: Return ciphertext
  SecureCache->>NativeTenantKeys: Decrypt with current key, then previous keys
  NativeTenantKeys-->>SecureCache: Return plaintext or decryption failure
  SecureCache->>NativeTenantKeys: Encrypt new entry with current key
Loading

Possibly related PRs

Suggested reviewers: kodus-27b

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies the main change: adding the previousMasterKeys keyring rotation feature for encryption.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lab-685-previous-master-keys-keyring

Comment @coderabbitai help to get the list of available commands.

@kodus-27b

This comment has been minimized.

Comment thread packages/cachekit-core-wasm/Cargo.toml Outdated
Comment thread packages/cachekit/src/cache.rotation.test.ts Outdated
Comment thread packages/cachekit/src/constants.ts
…licit test-key fixture (LAB-685)

- js-sys exact-pinned to =0.3.98, the release paired with the already
  exact-pinned wasm-bindgen 0.2.121 (same ABI-tracking rationale). OSV +
  cargo-audit evidence added to the PR description.
- Drop the unused MIN_MASTER_KEY_BYTES import in the real-crypto
  integration test — the constant was renamed to MASTER_KEY_BYTES in this
  PR and the import was never used, so the integration lane's tsc-less
  vitest run masked it.
- Rotation test master keys now come from a testMasterKeyHex helper that
  documents they are deterministic fixtures, not secrets.
@kodus-27b

This comment has been minimized.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 7, 2026
kodus-27b[bot]
kodus-27b Bot previously approved these changes Aug 7, 2026
@27Bslash6

Copy link
Copy Markdown
Contributor Author

@kody start-review

Resolves the README conflict from #104 (LAB-238, ciphertext in L1): both
sides annotated the same encryption config comment with orthogonal facts —
L1 zero-knowledge parity and the rotation pointer — so the resolution keeps
both rather than picking a side.
…B-685)

Merging main brought in #104 (LAB-238), which makes L1 hold ciphertext for
a secure cache. That creates a path neither branch could test on its own: an
L2 read under a previous key repopulates L1 with bytes the current key
cannot open, so every subsequent L1 hit has to run the keyring loop again.

The existing rotation tests all disable L1 — correct when they were written,
since L1 then held plaintext and rotation could not reach it.

Without keyring coverage on that path decodeL1Entry drops the entry and
falls through to L2 on every read for the whole grace window: a silent L1
bypass under degradation, a throw on every old-key read without it. Verified
by mutation — breaking the L1 decrypt path turns the single backend.get into
two, and the test fails.
@kodus-27b

This comment has been minimized.

kodus-27b[bot]
kodus-27b Bot previously approved these changes Aug 8, 2026
@27Bslash6

Copy link
Copy Markdown
Contributor Author

Resolved merge conflict with main (merge commit 86b211f, no rebase/force-push): single conflicted file packages/cachekit/README.md — union of both sides (LAB-1388's "Value size limits" subsection kept under Manual Configuration, this branch's "Master-Key Rotation" section after it). No production code touched; auto-merged files verified (LAB-1388's changes land in regions disjoint from the keyring surface). Local gates green: 751 unit + 98 workers + 15 real-crypto integration tests, lint/format/type-check. Auto-rebased onto main @ 13a3345; CI will re-run.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cachekit-core-wasm/README.md`:
- Around line 39-43: Update the README example around deriveTenantKeys and
rotating to call rotating.free() deterministically after all demonstrated
operations using the handle are complete.

In `@packages/cachekit-core-wasm/src/lib.rs`:
- Around line 213-217: Wrap the owned key-copy staging buffer created in
derive_tenant_keys with zeroizing::Zeroizing so its contents are wiped on drop,
including early-return paths. Add the required zeroize import and declare the
dependency in the wasm crate’s Cargo.toml, preserving the existing key
conversion behavior.

In `@packages/cachekit/README.md`:
- Around line 210-211: Update the key-material lifecycle statement in the README
to remove the claim that all key material enters native memory once and is fully
zeroized on disposal. Document that derived native keyring material is zeroized
when released, while managed-runtime configuration strings and environment
variables remain sensitive for their entire lifetime because
initialization-retry state is retained.

In `@packages/cachekit/src/encryption/manager-core.test.ts`:
- Around line 223-239: Update the wrong-entry-count test around
EncryptionManagerCore to provide the mocked derived-key handle with a free spy,
then assert that it is called after the version-skew rejection. Match the
sibling skew test’s assertion and preserve the existing deriveTenantKeys
key-count mismatch setup.

In `@packages/cachekit/src/encryption/manager-core.ts`:
- Around line 198-228: Update the key-derivation flow around
native.deriveTenantKeys to zeroize masterKeyBytes and every previousKeyBytes
entry in a finally block, covering successful, validation-failure, and thrown
derivation paths. Correct the nearby comment to state that buffers are
explicitly wiped after use, while preserving the existing keyring attestation
and avoiding key material in errors or logs.

In `@packages/cachekit/src/encryption/manager.integration.test.ts`:
- Around line 369-382: Update the three napi.deriveTenantKeys assertions in the
“enforces the keyring invariants natively too” test to match the exact
cachekit-core error text for the forward-only collision, previous-key cap, and
wrong-length key rules. Use precise error matchers rather than bare toThrow(),
preserving each test case’s existing inputs and rule coverage.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b6279aa3-05eb-406c-a486-0b75c3b0ace8

📥 Commits

Reviewing files that changed from the base of the PR and between 13a3345 and 86b211f.

⛔ Files ignored due to path filters (2)
  • packages/cachekit-core-ts/Cargo.lock is excluded by !**/*.lock
  • packages/cachekit-core-wasm/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (24)
  • .secrets.baseline
  • packages/cachekit-core-ts/Cargo.toml
  • packages/cachekit-core-ts/README.md
  • packages/cachekit-core-ts/index.d.ts
  • packages/cachekit-core-ts/src/lib.rs
  • packages/cachekit-core-wasm/Cargo.toml
  • packages/cachekit-core-wasm/README.md
  • packages/cachekit-core-wasm/index.d.ts
  • packages/cachekit-core-wasm/src/lib.rs
  • packages/cachekit/README.md
  • packages/cachekit/src/cache.rotation.test.ts
  • packages/cachekit/src/cache.ts
  • packages/cachekit/src/constants.ts
  • packages/cachekit/src/encryption/manager-core.test.ts
  • packages/cachekit/src/encryption/manager-core.ts
  • packages/cachekit/src/encryption/manager.integration.test.ts
  • packages/cachekit/src/encryption/manager.ts
  • packages/cachekit/src/errors.ts
  • packages/cachekit/src/intents-core.ts
  • packages/cachekit/src/intents.test.ts
  • packages/cachekit/src/types/cache.ts
  • packages/cachekit/src/workers/runtime.ts
  • packages/cachekit/test/integration/encryption-real-crypto.integration.test.ts
  • packages/cachekit/test/workers/encryption.protocol.workers.test.ts

Comment thread packages/cachekit-core-wasm/README.md
Comment thread packages/cachekit-core-wasm/src/lib.rs Outdated
Comment thread packages/cachekit/README.md Outdated
Comment thread packages/cachekit/src/encryption/manager-core.test.ts
Comment thread packages/cachekit/src/encryption/manager-core.ts
Comment thread packages/cachekit/src/encryption/manager.integration.test.ts
…B-685)

CodeRabbit round (6 findings) + expert-panel follow-up:

- wasm: previous-master-key staging copies wrapped in Zeroizing; master
  key now crosses as a JS handle and is copied under Zeroizing too (the
  &[u8] ABI copied it into linear memory and freed it unwiped — panel
  finding on the CodeRabbit fix)
- manager-core: decoded master/previous key buffers wiped in a finally
  once the binding has consumed them, error paths included
- READMEs: zeroization claim corrected (JS hex strings cannot be
  scrubbed); wasm example frees the rotating keyring handle
- tests: wrong-count skew path asserts the orphaned handle is freed;
  previous-key bytes snapshot at call time + post-call wipe asserted;
  native keyring-invariant errors matched by exact text
@kodus-27b

kodus-27b Bot commented Aug 9, 2026

Copy link
Copy Markdown

Kody Review Complete

Great news! 🎉
No issues were found that match your current review configurations.

Keep up the excellent work! 🚀

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the @kody start-review command at the root of your PR.

  • Validate Business Logic: Ask Kody to validate your code against business rules by adding a comment with the @kody -v business-logic command.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug
Performance
Security
Business Logic

Access your configuration settings here.

@27Bslash6

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@27Bslash6

Copy link
Copy Markdown
Contributor Author

Expert panel (critical-stakes crypto gate) — CodeRabbit remediation round, recorded per project rule.

Scope: the zeroization remediation diff (df0661e). Verdict after fixes: SHIP.

  • bug-hunter: NO FINDINGS — verified the finally wipe is retry-safe (init re-decodes from retained hex), both bindings consume key bytes synchronously before the wipe, no aliasing on the Zeroizing refs, and the new test assertions have teeth (each fails if its target regresses).
  • security: 1 MAJ, fixed in the same commit — the CodeRabbit fix wiped the previous keys' staging copies but the current master key still crossed the wasm ABI as &[u8] (passArray8ToWasm0 copies into linear memory, freed unwiped), contradicting the new README/comment claims. deriveTenantKeys now takes the key as a js_sys::Uint8Array handle and copies under Zeroizing, same as the previous keys. Also verified: no key bytes in any matched error text, zeroize = "1" caret pin consistent with policy (the js-sys/wasm-bindgen exact pins are a CLI-ABI constraint zeroize doesn't have).
  • code-craftsman: 1 MIN applied (wrong-count skew test reuses the factory mock instead of a hand-rolled 14-line handle) + 1 dead assertion cut.
  • catchphrase: NO CUTS — explicitly cleared the "is buffer wiping theater when hex strings remain?" question: the README correction removing the false claim is the load-bearing half, the wipe reduces copies at near-zero cost.

Pre-existing, out of this PR's scope: deriveKey (wasm) also takes &[u8] key material and returns raw key bytes by design — flagged for a follow-up, not touched here.

Local gates on df0661e: 751 unit + 98 workers (rebuilt wasm) + 15 real-crypto integration + 25 manager-integration (exact native error texts verified against the real NAPI binary), lint / format / type-check, cargo clippy -D warnings on the wasm crate.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/cachekit/src/encryption/manager-core.ts (1)

219-239: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Free the key handle on every failed attestation path.

Line 225 can throw before either explicit tenantKeys.free?.() call. The outer catch converts that error but leaves the derived keyring allocated.

Wrap the attestation and disposed checks in a try/finally. Transfer ownership only after assigning this.tenantKeys. Call tenantKeys.free?.() in finally if ownership was not transferred.

Proposed fix
-      if (previousKeyBytes.length > 0) {
+      let transferred = false;
+      try {
+      if (previousKeyBytes.length > 0) {
         const built = tenantKeys.keyringEntryCount?.() ?? 1;
         if (built !== 1 + previousKeyBytes.length) {
-          tenantKeys.free?.();
           throw new ConfigurationError(/* existing message */);
         }
       }
       if (this.disposed) {
-        tenantKeys.free?.();
         throw new EncryptionError('EncryptionManager has been disposed');
       }
       this.tenantKeys = tenantKeys;
+      transferred = true;
+      } finally {
+        if (!transferred) tenantKeys.free?.();
+      }

As per path instructions: “verify buffer lengths, null checks, and that keys/secrets are zeroized on drop.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cachekit/src/encryption/manager-core.ts` around lines 219 - 239,
Update the initialization flow around the keyring attestation and disposed check
to use try/finally cleanup. Track ownership transfer only after assigning
tenantKeys to this.tenantKeys, and invoke tenantKeys.free?.() in finally
whenever ownership was not transferred, including errors from keyringEntryCount
or the disposed check; preserve the existing ConfigurationError and
EncryptionError behavior and ensure key material is zeroized on every failed
path.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/cachekit/src/encryption/manager-core.ts`:
- Around line 219-239: Update the initialization flow around the keyring
attestation and disposed check to use try/finally cleanup. Track ownership
transfer only after assigning tenantKeys to this.tenantKeys, and invoke
tenantKeys.free?.() in finally whenever ownership was not transferred, including
errors from keyringEntryCount or the disposed check; preserve the existing
ConfigurationError and EncryptionError behavior and ensure key material is
zeroized on every failed path.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3a48c615-5880-4507-ba89-7d46ee3dd34b

📥 Commits

Reviewing files that changed from the base of the PR and between 86b211f and df0661e.

⛔ Files ignored due to path filters (1)
  • packages/cachekit-core-wasm/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • packages/cachekit-core-wasm/Cargo.toml
  • packages/cachekit-core-wasm/README.md
  • packages/cachekit-core-wasm/src/lib.rs
  • packages/cachekit/README.md
  • packages/cachekit/src/encryption/manager-core.test.ts
  • packages/cachekit/src/encryption/manager-core.ts
  • packages/cachekit/src/encryption/manager.integration.test.ts

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