Skip to content

fix: re-encrypt file metadata on move and bin restore#507

Merged
FSM1 merged 15 commits into
mainfrom
fix/decrypt-fail-after-move
Jun 17, 2026
Merged

fix: re-encrypt file metadata on move and bin restore#507
FSM1 merged 15 commits into
mainfrom
fix/decrypt-fail-after-move

Conversation

@FSM1

@FSM1 FSM1 commented Jun 17, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes a repeatable CryptoError: Decryption failed when previewing/editing/downloading a file after it's moved into a subfolder (reported on staging), and the same latent bug on bin restore.

Root cause: a file's FileMetadata IPNS record is AES-256-GCM encrypted with its parent folder's folderKey at upload (sdk-core/file/index.ts). Re-parenting a file moved only the FilePointer between folders without re-encrypting the per-file record, so the decrypt path (which uses the current parent's folderKey) failed. Listing worked because that only reads the FilePointer (not folder-key-encrypted).

Changes

fix(sdk) — move re-encrypt

CipherBoxClient.moveItem: when the moved child is a file, unwrap its IPNS key, resolve FileMetadata with source.folderKey, then updateFileMetadata under dest.folderKey (createVersion: false) before the folder publishes, so a failure aborts cleanly. Folders skip it (children keep the subfolder's own key).

fix(sdk) + feat(core,sdk) — bin restore re-encrypt (robust)

restoreFromBin had the same gap. It now re-encrypts when the restore target differs from the original parent. To survive "delete file → delete its parent → restore elsewhere" (where the original parent's key is no longer in the live tree), addToBin captures the source folderKey on the BinEntry (originalFolderKeyEncrypted, ECIES-wrapped for the vault); restore prefers it and falls back to the folder tree for legacy entries. Adds the BinEntry field + schema validation.

test(e2e) — content verification

  • Web e2e (move-restore-content.spec.ts, validated locally — 3/3): asserts decrypted content (not just listing) after a move into a subfolder and after delete-to-bin + restore, read via the text editor (a fresh decrypt under the destination key — the exact path the bug broke).
  • Desktop e2e (test-cross-client-sync.sh): moves a file via the FUSE mount and verifies content through a fresh SDK read under the destination key. verify-filepointer.mjs gained --folder-name to traverse one subfolder level. Runs in desktop-e2e.yml (needs FUSE) — not validated locally.

Sibling-path triage

Path Status
Private move ✅ fixed
Bin restore (incl. orphaned-parent) ✅ fixed
Batch move ✅ routes per-item through moveItem
Folder move ✅ unaffected (children keep subfolder key)
Shared-folder move ⚠️ not implemented; todo filed with the re-encrypt requirement

Verification

  • sdk unit: client-move-reencrypt (3) + bin.test (15: captured-key, legacy-fallback, skip-in-place, missing-parent-throw) green; core bin/schema green (196).
  • tsc + eslint clean across changed packages.
  • Web e2e move-restore-content.spec.ts3/3 against the local full stack.
  • Desktop e2e move-content check — runs in desktop-e2e.yml (FUSE), not validated locally. Note: that workflow triggers on apps/desktop/crates changes, so it won't auto-run on this PR's paths; can be dispatched manually.

Notes

  • The exact "restore c.txt to ~/a/b/ after deleting b" sequence fails earlier at requireFolder (target parent gone) — restore-b-first works; the captured key now also enables restoring such a file to any existing folder.
  • Auto-recreating a deleted parent path on restore remains a separate UX feature (not in scope).

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fixed decryption failures that occurred after moving files between folders
  • New Features

    • Added automatic file metadata re-encryption when moving files to different folders
    • Enhanced restore functionality to support restoring files to different destinations while maintaining accessibility
  • Tests

    • Added end-to-end tests verifying file integrity survives move and restore operations

FSM1 and others added 5 commits June 17, 2026 21:24
A file's FileMetadata IPNS record is AES-256-GCM encrypted with its parent
folder's folderKey at upload (sdk-core file/index.ts). moveItem only moved the
FilePointer between folders without re-encrypting the per-file record, so
preview/edit/download after a move decrypted with the destination folderKey and
failed with CryptoError: Decryption failed.

In CipherBoxClient.moveItem, when the moved child is a file, unwrap its IPNS key,
resolve FileMetadata with source.folderKey, then updateFileMetadata with
folderKey=dest.folderKey and createVersion=false — before the folder publishes,
so a failure aborts the move. Folders skip re-encryption (children keep the
subfolder's own folderKey).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: b5de67334463
restoreFromBin re-inserted the FilePointer and published folder metadata but
never re-encrypted the file's FileMetadata IPNS record, which addToBin leaves
encrypted under the original parent's folderKey. Restoring to a folder with a
different folderKey (the SDK accepts an arbitrary target) would make the file
undecryptable — same root cause as the moveItem bug.

Re-encrypt only when the restore target differs from the original parent
(restoring in place is a no-op): resolve FileMetadata with the original
parent's folderKey, then updateFileMetadata under the target folderKey with
createVersion=false, before the folder publish so a failure aborts cleanly. If
the original parent is not loaded, throw rather than risk corruption. Also
guard the moveItem re-encrypt path against a missing file IPNS key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: ee9f190ef86c
…store

Extend the bin-restore re-encryption to survive the case where the original
parent folder no longer exists (delete file, delete its parent, then restore
elsewhere). addToBin now captures the source folder's folderKey on the BinEntry
(originalFolderKeyEncrypted, ECIES-wrapped for the vault) at delete time;
restoreFromBin prefers it as the source decryption key and falls back to the
live folder tree for legacy entries. Adds the BinEntry field + schema
validation. Restore can now re-encrypt a file's metadata to any destination
regardless of whether its original parent survives.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: da44d706495c
Web e2e (move-restore-content.spec.ts): upload a file with known content, move
it into a subfolder, and assert the decrypted content via the text editor (a
fresh decrypt under the destination folderKey — the exact path the bug broke);
same for delete-to-bin + restore. Desktop e2e (test-cross-client-sync.sh): move
a file via the FUSE mount and verify content through a fresh SDK read under the
destination folderKey. verify-filepointer.mjs gains optional --folder-name to
traverse one subfolder level (unwraps the child folderKey from its FolderEntry).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: 9567670ea97c
…ove todo

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: bb3068e0d9ff
@github-actions github-actions Bot added release:sdk:feat Minor version bump (new feature) for sdk release:core:feat Minor version bump (new feature) for core release:web:fix Patch version bump (bug fix) for web release:sdk-core:fix Patch version bump (bug fix) for sdk-core release:tee-worker:fix Patch version bump (bug fix) for tee-worker labels Jun 17, 2026
@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Release Preview

Package Bump Label Source
cipherbox-core patch release:cipherbox-core:fix Direct (fix commit)
cipherbox-fuse patch release:cipherbox-fuse:fix Direct (fix commit)
cipherbox-sdk patch release:cipherbox-sdk:fix Cascade (cipherbox-core patch)
core minor release:core:feat Direct (feat commit)
desktop minor release:desktop:fix Cascade (cipherbox-core patch)
sdk minor release:sdk:feat Direct (feat commit)
sdk-core patch release:sdk-core:fix Cascade (core minor)
tee-worker patch release:tee-worker:fix Cascade (core minor)
web minor release:web:fix Cascade (sdk minor)

Cascade Details

  • sdk minor -> web patch (direct dependency)
  • core minor -> sdk-core patch (direct dependency)
  • core minor -> tee-worker patch (direct dependency)
  • cipherbox-core patch -> cipherbox-sdk patch (direct dependency)
  • cipherbox-core patch -> desktop patch (direct dependency)

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@FSM1, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 46 minutes and 16 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4f410fbc-2127-4dbc-907c-c69898ef2f9b

📥 Commits

Reviewing files that changed from the base of the PR and between f6c720f and 7e8091d.

📒 Files selected for processing (1)
  • packages/sdk/src/__tests__/client-move-reencrypt.test.ts

Walkthrough

Fixes a deterministic CryptoError: Decryption failed after cross-folder file moves by re-encrypting each file's per-file IPNS FileMetadata record from the source folderKey to the destination folderKey. The fix is applied in CipherBoxClient.moveItem, restoreFromBin (capturing the source key at soft-delete time), and desktop FUSE/WinFsp rename handlers, with idempotent retry semantics throughout.

Changes

FileMetadata Re-encryption on Move and Bin Restore

Layer / File(s) Summary
BinEntry type and schema extension
packages/core/src/bin/types.ts, packages/core/src/bin/schema.ts, crates/core/src/bin.rs
Adds optional originalFolderKeyEncrypted to BinEntry in TypeScript and Rust; the TypeScript schema validates it as an even-length hex string, while Rust applies camelCase/skip-if-None serde directives. Tests cover round-trip, camelCase naming, and legacy deserialization.
reencryptFileMetadataForFolderChange helper
packages/sdk/src/reencrypt.ts
New module implementing idempotent re-keying: resolves FileMetadata under the source key, handles DECRYPTION_FAILED by checking the destination key for a prior partial attempt, and re-seals under the destination key with createVersion: false.
moveItem file re-encryption
packages/sdk/src/client.ts
moveItem destructures movedItem from sdkCore.moveItem(); for file moves, unwraps the IPNS private key and calls reencryptFileMetadataForFolderChange(source.folderKey → dest.folderKey) after destination publish and before source publish.
addToBin key capture and restoreFromBin re-encryption
packages/sdk/src/bin/index.ts
addToBin wraps and stores originalFolderKeyEncrypted on file bin entries. restoreFromBin computes mustReencrypt, validates pre-conditions, drops duplicate child entries for idempotency, then post-publish unwraps keys and calls the re-encryption helper.
Desktop FUSE/WinFsp background re-encryption
crates/fuse/src/lib.rs, crates/fuse/src/write_ops.rs, crates/fuse/src/platform/windows/write_ops.rs
Adds spawn_file_meta_reencrypt with ReencryptOutcome enum, exponential-backoff retry loop, and PublishCoordinator locking. Both macOS and Windows unlink capture original_folder_key_encrypted on bin entries; cross-folder renames precompute re-encryption inputs and fire-and-forget the background task.
verify-filepointer.mjs subfolder support
packages/sdk-core/scripts/verify-filepointer.mjs
Adds --folder-name CLI argument; when provided, unwraps the subfolder's folderKey and passes it to resolveFileMetadata to verify post-move decryptability.
moveItem re-encryption unit tests
packages/sdk/src/__tests__/client-move-reencrypt.test.ts, packages/sdk/src/__tests__/client-extended.test.ts
New suite asserts source/destination key usage, folder-skip behavior, publish ordering, all failure paths, and idempotent retry with destination-key fallback. Updates existing mock setup with unwrapKey/hexToBytes and concrete metadata return values.
restoreFromBin re-encryption unit tests
packages/sdk/src/__tests__/bin.test.ts
Eight new scenarios covering same-folder skip, cross-folder re-encryption, missing original parent, publish-before-reencrypt ordering, idempotency, no-duplicate child, missing IPNS key abort, and legacy entry error.
SDK-core file test type safety
packages/sdk-core/src/__tests__/file.test.ts
Switches any-casts in existing mock assertions to satisfies-based typing using local FileMetadata/EncryptedFileMetadata mirrors; no runtime behavior changed.
Web and desktop e2e regression tests
tests/web-e2e/tests/move-restore-content.spec.ts, tests/desktop-e2e/scripts/test-move-content.mjs, tests/desktop-e2e/scripts/run-all.sh, tests/desktop-e2e/scripts/run-all.ps1, tests/desktop-e2e/scripts/test-cross-client-sync.sh
New Playwright spec asserts content survives move-into-subfolder and bin delete/restore. New desktop script verifies filesystem-level decryptability pre/post-move with retry/nudge. Both shell orchestrators gain a Step 7 wiring the new script.
Planning docs and release versions
.planning/debug/resolved/..., .planning/todos/pending/..., .planning/todos/completed/..., release-please-config.json
Resolved debug doc, pending shared-folder move todo, completed partial-failure recovery todo. Release versions bumped: apps/web0.45.0, packages/core0.31.0, packages/sdk0.36.0, crates/core0.5.1.

Sequence Diagrams

sequenceDiagram
  participant UI as Web/FUSE Client
  participant Client as CipherBoxClient
  participant reencrypt as reencryptFileMetadataForFolderChange
  participant sdkCore
  participant Crypto as crypto

  UI->>Client: moveItem(srcFolderId, dstFolderId, childId)
  Client->>sdkCore: moveItem(srcFolderId, dstFolderId, childId)
  sdkCore-->>Client: movedItem {type:"file", ipnsPrivateKeyEncrypted}
  Client->>sdkCore: updateFolderMetadataAndPublish(dest)
  Client->>Crypto: unwrapKey(ipnsPrivateKeyEncrypted, vaultPrivateKey)
  Crypto-->>Client: ipnsPrivateKey
  Client->>reencrypt: fileMetaIpnsName, ipnsPrivateKey, src.folderKey, dest.folderKey
  reencrypt->>sdkCore: resolveFileMetadata(ipnsName, src.folderKey)
  sdkCore-->>reencrypt: FileMetadata
  reencrypt->>sdkCore: updateFileMetadata(ipnsKey, dest.folderKey, createVersion=false)
  sdkCore-->>reencrypt: updated record
  reencrypt-->>Client: done
  Client->>sdkCore: updateFolderMetadataAndPublish(source)
  Client-->>UI: move complete
Loading
sequenceDiagram
  participant Caller
  participant restoreFromBin
  participant Crypto as crypto
  participant reencrypt as reencryptFileMetadataForFolderChange
  participant sdkCore

  Caller->>restoreFromBin: restore(binEntry, targetFolderId)
  restoreFromBin->>restoreFromBin: compute mustReencrypt, validate preconditions
  restoreFromBin->>sdkCore: updateFolderMetadataAndPublish(target)
  restoreFromBin->>Crypto: unwrapKey(originalFolderKeyEncrypted)
  Crypto-->>restoreFromBin: srcFolderKey
  restoreFromBin->>Crypto: unwrapKey(ipnsPrivateKeyEncrypted)
  Crypto-->>restoreFromBin: ipnsPrivateKey
  restoreFromBin->>reencrypt: fileMetaIpnsName, ipnsPrivateKey, srcFolderKey, dstFolderKey
  reencrypt->>sdkCore: resolveFileMetadata(ipnsName, srcFolderKey)
  sdkCore-->>reencrypt: FileMetadata
  reencrypt->>sdkCore: updateFileMetadata(ipnsKey, dstFolderKey, createVersion=false)
  sdkCore-->>reencrypt: updated
  reencrypt-->>restoreFromBin: done
  restoreFromBin-->>Caller: restore complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • FSM1/cipher-box#262: The BinEntry type extension and restoreFromBin re-encryption logic in this PR directly builds on the Phase 17 recycle-bin BinEntry/bin service implementation introduced in this earlier PR.
  • FSM1/cipher-box#488: The CipherBoxClient.moveItem changes in this PR modify the same move path (packages/sdk/src/client.ts) and interact with the same sdkCore file metadata update/publish contract touched in that PR.

Suggested labels

release:sdk:fix, release:core:fix

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and concisely describes the main change: re-encryption of file metadata during move and bin restore operations, which directly addresses the root cause of the CryptoError bug documented in the PR objectives.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/decrypt-fail-after-move

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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: 4

Caution

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

⚠️ Outside diff range comments (1)
packages/sdk/src/client.ts (1)

715-760: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Re-encryption happens before destination publish, which breaks crash-safety on partial failure.

At Line 737 the file metadata is re-published under dest.folderKey before any folder publish. If the destination publish at Line 749 fails, the file remains referenced only from the source folder, but its metadata is no longer decryptable with source.folderKey.

This creates a deterministic undecryptable state on one failed call path. Please enforce an ordering/compensation strategy that preserves at least one readable pointer-key pair across partial failures.

🤖 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/sdk/src/client.ts` around lines 715 - 760, The file metadata
re-encryption block that re-publishes the FileMetadata under dest.folderKey (the
section checking for ipnsPrivateKeyEncrypted and calling
sdkCore.updateFileMetadata) is executing before the destination folder metadata
is published at line 749. Move this entire re-encryption block to execute after
the destResult from sdkCore.updateFolderMetadataAndPublish completes, so that
the destination folder is published first with the moved file reference before
re-encrypting the file's metadata. This preserves crash-safety by ensuring at
least one valid readable pointer-key pair exists at any failure point.
🧹 Nitpick comments (3)
packages/sdk/src/__tests__/bin.test.ts (1)

308-563: ⚡ Quick win

Add a direct test assertion that addToBin persists originalFolderKeyEncrypted for files.

Current new restore tests hand-craft this field, so they don’t prove the capture path in addToBin works. Please assert it in the existing addToBin file case (and/or add a folder case asserting it stays undefined).

✅ Minimal test addition
-import { unwrapKey } from '`@cipherbox/crypto`';
+import { unwrapKey, wrapKey } from '`@cipherbox/crypto`';
@@
       expect(result.updatedBinState.entries).toHaveLength(1);
       expect(result.updatedBinState.entries[0].name).toBe('doc.txt');
+      expect(result.updatedBinState.entries[0].originalFolderKeyEncrypted).toBe('aabb');
+      expect(wrapKey).toHaveBeenCalledTimes(1);
       expect(result.updatedBinState.sequenceNumber).toBe(1);

As per coding guidelines, "**/*.test.ts: Focus on test coverage, edge cases, and test quality. Ensure tests are meaningful and not just for coverage metrics."

🤖 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/sdk/src/__tests__/bin.test.ts` around lines 308 - 563, The restore
tests hand-craft the originalFolderKeyEncrypted field in BinState objects, but
there is no direct test asserting that the addToBin function actually captures
and persists this field when deleting files. Add an assertion to the existing
addToBin file test case that verifies the persisted entry in the binState
contains the originalFolderKeyEncrypted field with the correct folder key value.
Optionally, add a test case for folder items to verify that
originalFolderKeyEncrypted remains undefined for non-file items, ensuring the
capture path in addToBin is properly tested rather than just assuming it works
through the restore tests.

Source: Coding guidelines

tests/web-e2e/tests/move-restore-content.spec.ts (1)

130-156: ⚡ Quick win

Restore e2e currently misses the cross-folder re-encryption path.

This test restores to the original parent (Line 146), so it does not exercise the “restore to different destination folderKey” branch that required this fix. Please add a variant restoring into a different folder and assert decrypted content there.

🤖 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 `@tests/web-e2e/tests/move-restore-content.spec.ts` around lines 130 - 156, The
test '3. Content survives delete-to-bin then restore' currently only restores
content to the original parent folder (root), missing the cross-folder
re-encryption scenario. Add a test variant that creates or navigates to a
different folder before restoring the deleted content, then uses
binPage.restoreItem to restore it to that different destination folder. After
restoration, verify that readContentViaEditor still returns the correct
decrypted content in the new folder location to ensure the re-encryption with
the different folderKey works properly.
packages/sdk/src/__tests__/client-move-reencrypt.test.ts (1)

188-243: ⚡ Quick win

Add an edge-case test for missing ipnsPrivateKeyEncrypted on moved files.

moveItem now has a hard guard for this malformed pointer path, but this suite only covers valid file pointers and folder moves. A dedicated test for the throw path will prevent silent regressions in this safety check.

As per coding guidelines, **/*.test.ts: “Focus on test coverage, edge cases, and test quality.”

🤖 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/sdk/src/__tests__/client-move-reencrypt.test.ts` around lines 188 -
243, Add a new test case within this suite to verify that moveItem throws an
error when encountering a file pointer missing the ipnsPrivateKeyEncrypted
field. Create a test similar to the "does NOT re-encrypt file metadata when
moving a folder" test by constructing a fileChild object without the
ipnsPrivateKeyEncrypted property, setting it in the source folder tree, calling
client.moveItem with this invalid file, and asserting that the expected error is
thrown. This will ensure the guard validation in moveItem catches this malformed
pointer edge case and prevents silent regressions.

Source: Coding guidelines

🤖 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/sdk-core/scripts/verify-filepointer.mjs`:
- Around line 130-133: The `unwrapKey` function call with its arguments is not
formatted according to Prettier's style rules. Reformat the multiline function
call starting with `const subFolderKey = await unwrapKey(` by either condensing
it to a single line if it fits within the line length limit, or if it must
remain multiline, adjust the indentation and argument placement to match
Prettier's expected formatting rules for function calls with multiple arguments.

In `@packages/sdk/src/bin/index.ts`:
- Around line 277-283: The computation of originalFolderKeyEncrypted using the
wrapKey function is currently occurring after updateFolderMetadataAndPublish,
which creates a race condition where if wrapKey fails, the file has already been
removed from the folder but never committed to bin metadata. Move the wrapKey
call that computes originalFolderKeyEncrypted to execute before the
updateFolderMetadataAndPublish call to ensure that any wrapping failures occur
before the folder deletion is published, preventing the split state condition.
- Around line 381-416: The unwrapped key material (sourceFolderKey and
fileIpnsPrivateKey) created in this block are sensitive and must be cleared from
memory after use. Wrap the entire code block starting from where sourceFolderKey
is first assigned through the completion of the updateFileMetadata call in a
try-finally statement. In the finally block, zeroize both sourceFolderKey and
fileIpnsPrivateKey using the appropriate zeroization function to ensure these
sensitive bytes are cleared from memory regardless of whether updateFileMetadata
succeeds or throws an error.

In `@packages/sdk/src/client.ts`:
- Around line 728-746: The variable fileIpnsPrivateKey contains sensitive
cryptographic material that is not being cleared from memory if
resolveFileMetadata or subsequent operations throw an exception. Wrap the code
block starting with the fileIpnsPrivateKey unwrapping through the
sdkCore.updateFileMetadata call in a try-finally block, placing the cleanup code
(clearing fileIpnsPrivateKey) in the finally block to ensure it always executes
regardless of whether any operation throws an error, following the security
guideline to clear sensitive data from memory after use.

---

Outside diff comments:
In `@packages/sdk/src/client.ts`:
- Around line 715-760: The file metadata re-encryption block that re-publishes
the FileMetadata under dest.folderKey (the section checking for
ipnsPrivateKeyEncrypted and calling sdkCore.updateFileMetadata) is executing
before the destination folder metadata is published at line 749. Move this
entire re-encryption block to execute after the destResult from
sdkCore.updateFolderMetadataAndPublish completes, so that the destination folder
is published first with the moved file reference before re-encrypting the file's
metadata. This preserves crash-safety by ensuring at least one valid readable
pointer-key pair exists at any failure point.

---

Nitpick comments:
In `@packages/sdk/src/__tests__/bin.test.ts`:
- Around line 308-563: The restore tests hand-craft the
originalFolderKeyEncrypted field in BinState objects, but there is no direct
test asserting that the addToBin function actually captures and persists this
field when deleting files. Add an assertion to the existing addToBin file test
case that verifies the persisted entry in the binState contains the
originalFolderKeyEncrypted field with the correct folder key value. Optionally,
add a test case for folder items to verify that originalFolderKeyEncrypted
remains undefined for non-file items, ensuring the capture path in addToBin is
properly tested rather than just assuming it works through the restore tests.

In `@packages/sdk/src/__tests__/client-move-reencrypt.test.ts`:
- Around line 188-243: Add a new test case within this suite to verify that
moveItem throws an error when encountering a file pointer missing the
ipnsPrivateKeyEncrypted field. Create a test similar to the "does NOT re-encrypt
file metadata when moving a folder" test by constructing a fileChild object
without the ipnsPrivateKeyEncrypted property, setting it in the source folder
tree, calling client.moveItem with this invalid file, and asserting that the
expected error is thrown. This will ensure the guard validation in moveItem
catches this malformed pointer edge case and prevents silent regressions.

In `@tests/web-e2e/tests/move-restore-content.spec.ts`:
- Around line 130-156: The test '3. Content survives delete-to-bin then restore'
currently only restores content to the original parent folder (root), missing
the cross-folder re-encryption scenario. Add a test variant that creates or
navigates to a different folder before restoring the deleted content, then uses
binPage.restoreItem to restore it to that different destination folder. After
restoration, verify that readContentViaEditor still returns the correct
decrypted content in the new folder location to ensure the re-encryption with
the different folderKey works properly.
🪄 Autofix (Beta)

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: CHILL

Plan: Pro

Run ID: 6e5a7d7a-d110-423f-ab2f-57bdb914927a

📥 Commits

Reviewing files that changed from the base of the PR and between 3a92dd1 and 6dd7f98.

📒 Files selected for processing (13)
  • .planning/debug/resolved/decrypt-fail-after-move.md
  • .planning/todos/pending/2026-06-17-shared-folder-move-must-reencrypt-file-metadata.md
  • packages/core/src/bin/schema.ts
  • packages/core/src/bin/types.ts
  • packages/sdk-core/scripts/verify-filepointer.mjs
  • packages/sdk/src/__tests__/bin.test.ts
  • packages/sdk/src/__tests__/client-extended.test.ts
  • packages/sdk/src/__tests__/client-move-reencrypt.test.ts
  • packages/sdk/src/bin/index.ts
  • packages/sdk/src/client.ts
  • release-please-config.json
  • tests/desktop-e2e/scripts/test-cross-client-sync.sh
  • tests/web-e2e/tests/move-restore-content.spec.ts

Comment thread packages/sdk-core/scripts/verify-filepointer.mjs Outdated
Comment thread packages/sdk/src/bin/index.ts Outdated
Comment thread packages/sdk/src/bin/index.ts Outdated
Comment thread packages/sdk/src/client.ts
FSM1 and others added 2 commits June 17, 2026 23:12
- verify-filepointer.mjs: apply prettier formatting on the --folder-name
  unwrap call that was failing the Lint CI job.
- file.test.ts: replace 10 `any` annotations with precise types via local
  FileMetadata/EncryptedFileMetadata mirrors and SdkContext/IpfsAddResult.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: effbeaf44cb9
…re folder key on delete

The desktop FUSE/WinFsp filesystem implements rename and unlink in Rust,
bypassing the SDK moveItem/addToBin paths fixed for the web client. A file's
FileMetadata is AES-256-GCM sealed with its parent folderKey, so:

- handle_rename now re-encrypts a moved file's FileMetadata to the destination
  folderKey before the move settles, via a new spawn_file_meta_reencrypt that
  resolves under the source key and republishes under the dest key. Mirrored in
  the FUSE and WinFsp handlers. Without it, fresh resolves under the new folder
  key fail with the staging 'Decryption failed' bug.
- handle_unlink now captures the file's parent folderKey, ECIES-wrapped to the
  user, into a new BinEntry.originalFolderKeyEncrypted field, so a later SDK
  restore can re-encrypt to any destination even if the original parent is gone.

The Rust BinEntry gains original_folder_key_encrypted, JSON-compatible with the
TypeScript schema the web restore reads.

Tests: the per-platform shell/PowerShell move test is replaced by one
cross-platform test-move-content.mjs run on macOS, Linux and Windows. It moves a
file through the mount and reads it back via a fresh SDK client under the
destination folderKey, strict on every platform.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: 90bd3edfdce4
@github-actions github-actions Bot added release:cipherbox-core:fix Patch version bump (bug fix) for cipherbox-core release:cipherbox-fuse:fix Patch version bump (bug fix) for cipherbox-fuse release:cipherbox-sdk:fix Patch version bump (bug fix) for cipherbox-sdk release:desktop:fix Patch version bump (bug fix) for desktop labels Jun 17, 2026
github-actions Bot and others added 2 commits June 17, 2026 21:14
- addToBin: compute originalFolderKeyEncrypted (wrapKey) BEFORE publishing the
  folder deletion, so a wrap failure aborts before any folder/bin mutation
  rather than leaving a split state.
- restoreFromBin: wrap the restore-time re-encryption in try/finally and zeroize
  the unwrapped source folderKey and file IPNS private key. Only the freshly
  unwrapped key is cleared, never the shared folderTree key from the legacy
  fallback.
- moveItem: guard fileIpnsPrivateKey with try/finally so it is cleared even if
  resolveFileMetadata throws before updateFileMetadata runs.
- bin.test.ts: add clearBytes to the @cipherbox/crypto mock.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: 8ffe6d7ccf28
@codecov

codecov Bot commented Jun 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 31.69643% with 153 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.88%. Comparing base (3a92dd1) to head (7e8091d).

Files with missing lines Patch % Lines
crates/fuse/src/lib.rs 0.00% 105 Missing ⚠️
crates/fuse/src/write_ops.rs 0.00% 37 Missing ⚠️
packages/core/src/bin/schema.ts 0.00% 8 Missing ⚠️
packages/sdk/src/client.ts 86.95% 3 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #507      +/-   ##
==========================================
+ Coverage   63.92%   66.88%   +2.96%     
==========================================
  Files         141      158      +17     
  Lines       10875    17588    +6713     
  Branches     1209     1226      +17     
==========================================
+ Hits         6952    11764    +4812     
- Misses       3678     5579    +1901     
  Partials      245      245              
Flag Coverage Δ
api 84.69% <82.53%> (-0.03%) ⬇️
api-client 84.69% <82.53%> (-0.03%) ⬇️
core 84.69% <82.53%> (-0.03%) ⬇️
crypto 84.69% <82.53%> (-0.03%) ⬇️
desktop 18.21% <ø> (-13.11%) ⬇️
rust 62.80% <11.80%> (?)
sdk 84.69% <82.53%> (-0.03%) ⬇️
sdk-core 84.69% <82.53%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
crates/core/src/bin.rs 98.02% <100.00%> (ø)
packages/sdk/src/reencrypt.ts 100.00% <100.00%> (ø)
packages/sdk/src/client.ts 81.06% <86.95%> (+0.08%) ⬆️
packages/core/src/bin/schema.ts 78.18% <0.00%> (-6.14%) ⬇️
crates/fuse/src/write_ops.rs 24.11% <0.00%> (ø)
crates/fuse/src/lib.rs 46.89% <0.00%> (ø)

... and 70 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Add failure-path tests for CipherBoxClient.moveItem re-encryption, addressing
the CodeRabbit CLI review:

- unwrapKey / resolveFileMetadata / updateFileMetadata failures reject the move
  with no folder publish (re-encrypt-before-publish aborts cleanly).
- A destination-publish failure after a successful re-encryption pins the known
  non-atomic window where the FileMetadata is re-keyed but the pointer remains in
  the source folder.

File a follow-up todo for a retry-safe recovery mechanism, since neither publish
ordering closes that window without idempotent re-encryption.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: d0c14b0318f6

@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: 3

Caution

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

⚠️ Outside diff range comments (1)
packages/sdk/src/client.ts (1)

715-752: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Avoid re-encrypting before the move is durably visible.

Line 740 persists the file metadata under dest.folderKey before either folder publish runs. If Line 755 or Line 766 fails afterward, the source folder can remain authoritative while its FilePointer now points at metadata that only decrypts with the destination key. Reorder this so a successful destination publish is visible before re-encryption, or add rollback/recovery for failures after the metadata update.

As per coding guidelines, “Include proper error handling for crypto operations.”

🤖 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/sdk/src/client.ts` around lines 715 - 752, The updateFileMetadata
call is re-encrypting the file metadata under dest.folderKey before the
destination folder publish becomes visible, creating a state mismatch if
subsequent folder publish operations fail. Reorder the code so that
updateFileMetadata is called after the destination folder publish completes
successfully, or implement rollback/recovery logic to handle failures that occur
after the metadata re-encryption. This ensures the destination folder is durably
visible before re-encrypting metadata under its key, maintaining consistency
between the source folder's state and the FilePointer's decryption requirements.

Source: Coding guidelines

🤖 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 `@crates/fuse/src/lib.rs`:
- Around line 718-764: The file metadata re-encryption after a cross-folder move
is currently performed as a detached, best-effort background task spawned with
std::thread::spawn that only logs errors. This can leave the system in an
inconsistent state if the task fails, crashes, or is interrupted. Instead of
spawning a detached thread that ignores failures, refactor the rename operation
to either wait for the re-encryption to complete synchronously before the rename
commits (ensuring atomicity between the folder move and metadata key
transition), or implement a persistent retry journal that logs failed
re-encryption attempts so they can be retried and never silently lost. This
ensures the destination folder key and FileMetadata encryption state cannot
diverge.

In `@release-please-config.json`:
- Around line 141-142: The "release-as" value for crates/core is currently set
to "0.5.1" which indicates a patch version bump, but it should be changed to
"0.6.0" to reflect a minor version bump. This is required because a public
optional field was added to a public struct without the #[non_exhaustive]
attribute, which under Rust semver conventions necessitates a minor version bump
rather than a patch bump. Update the "release-as" configuration value from
"0.5.1" to "0.6.0".

In `@tests/desktop-e2e/scripts/test-move-content.mjs`:
- Around line 92-97: The spawnSync() call in the verify() function lacks a
timeout and maxBuffer configuration, causing indefinite hangs if the child
process stalls, with no recovery possible from the pollVerify() retry loop. Add
timeout: 60_000 and maxBuffer: 1024 * 1024 to the options object passed to
spawnSync(), and after the call, check result.error to handle spawn failures
before evaluating result.status === 0.

---

Outside diff comments:
In `@packages/sdk/src/client.ts`:
- Around line 715-752: The updateFileMetadata call is re-encrypting the file
metadata under dest.folderKey before the destination folder publish becomes
visible, creating a state mismatch if subsequent folder publish operations fail.
Reorder the code so that updateFileMetadata is called after the destination
folder publish completes successfully, or implement rollback/recovery logic to
handle failures that occur after the metadata re-encryption. This ensures the
destination folder is durably visible before re-encrypting metadata under its
key, maintaining consistency between the source folder's state and the
FilePointer's decryption requirements.
🪄 Autofix (Beta)

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: CHILL

Plan: Pro

Run ID: 67f09364-b428-4ad5-bbad-166fa2db19b5

📥 Commits

Reviewing files that changed from the base of the PR and between 6dd7f98 and e1fec32.

📒 Files selected for processing (16)
  • .planning/todos/pending/2026-06-17-move-restore-reencrypt-partial-failure-recovery.md
  • crates/core/src/bin.rs
  • crates/fuse/src/lib.rs
  • crates/fuse/src/platform/windows/write_ops.rs
  • crates/fuse/src/write_ops.rs
  • packages/sdk-core/scripts/verify-filepointer.mjs
  • packages/sdk-core/src/__tests__/file.test.ts
  • packages/sdk/src/__tests__/bin.test.ts
  • packages/sdk/src/__tests__/client-move-reencrypt.test.ts
  • packages/sdk/src/bin/index.ts
  • packages/sdk/src/client.ts
  • release-please-config.json
  • tests/desktop-e2e/scripts/run-all.ps1
  • tests/desktop-e2e/scripts/run-all.sh
  • tests/desktop-e2e/scripts/test-cross-client-sync.sh
  • tests/desktop-e2e/scripts/test-move-content.mjs
✅ Files skipped from review due to trivial changes (3)
  • .planning/todos/pending/2026-06-17-move-restore-reencrypt-partial-failure-recovery.md
  • tests/desktop-e2e/scripts/test-cross-client-sync.sh
  • packages/sdk-core/src/tests/file.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/sdk-core/scripts/verify-filepointer.mjs
  • packages/sdk/src/tests/bin.test.ts
  • packages/sdk/src/bin/index.ts

Comment thread crates/fuse/src/lib.rs
Comment thread release-please-config.json
Comment thread tests/desktop-e2e/scripts/test-move-content.mjs
FSM1 and others added 2 commits June 17, 2026 23:58
spawnSync had no timeout, so a stalled verify-filepointer.mjs would hang the
whole desktop E2E suite (pollVerify cannot recover from a blocking spawnSync).
Add timeout (60s) + maxBuffer, and surface spawn failures via result.error.

Addresses CodeRabbit review.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: 3585dd5af847
Reorders moveItem to publish dest -> re-encrypt FileMetadata -> publish source
(was re-encrypt -> publish dest -> publish source). The metadata is re-keyed to
the destination only once the destination folder is durably visible, so at every
intermediate failure the file stays readable from a folder that still lists it
under the matching key (source before re-encrypt, destination after) instead of
being readable from neither. Add-before-remove crash safety is preserved.

Addresses the CodeRabbit out-of-diff review on client.ts (move re-encryption
before the move is durably visible).

Rewrites the failure-path tests to pin the new ordering and adds an ordering
invariant test. Narrows the follow-up todo: moveItem is now reorder-hardened; the
residual is idempotent retry, the same reorder for restoreFromBin, and a desktop
re-encrypt retry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: 597561399b8b
@FSM1

FSM1 commented Jun 17, 2026

Copy link
Copy Markdown
Owner Author

Addressed the out-of-diff CodeRabbit comment on packages/sdk/src/client.ts (715-752, "Avoid re-encrypting before the move is durably visible") in 8daec72.

moveItem now runs publish dest → re-encrypt → publish source (was re-encrypt → publish dest → publish source). The FileMetadata is re-keyed to the destination only after the destination folder is durably published, so at every intermediate failure the file stays readable from a folder that still lists it under the matching key — from the source before the re-encrypt, from the destination after — instead of being stranded under the destination key while only the source points at it. Add-before-remove crash safety is preserved (dest still published before source).

Failure-path tests rewritten to pin the new ordering (+ an ordering-invariant test): destination-publish failure now aborts cleanly before any re-encrypt; a re-encrypt failure leaves the file readable from the source; a source-publish failure leaves it readable from the destination. The residual (idempotent clean-retry, the same reorder for restoreFromBin, and a desktop re-encrypt retry) is tracked in .planning/todos/pending/2026-06-17-move-restore-reencrypt-partial-failure-recovery.md.

…ial failures

Extract a shared idempotent re-key helper used by moveItem and restoreFromBin: if
the source-key resolve fails to decrypt, confirm the record under the destination
key and treat the re-encryption as already done, so a retry after a partial
failure completes instead of throwing.

Reorder restoreFromBin to publish the target folder before re-keying, mirroring
moveItem, and validate preconditions up front so a guaranteed failure aborts
without a broken listing. Make the restore add idempotent by child id so a retry
after a post-publish failure replaces rather than duplicates the listing.

Add a bounded in-memory retry with exponential backoff to the desktop FUSE/WinFsp
spawn_file_meta_reencrypt, with the same dest-key idempotency check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: 6f1555823b1f
@FSM1

FSM1 commented Jun 17, 2026

Copy link
Copy Markdown
Owner Author

Recovery hardening for move/restore re-encryption (f6c720f48)

Completed the partial-failure-recovery follow-up flagged by the CodeRabbit review of this PR — three changes, plus one fix surfaced by an adversarial self-review of the diff:

  1. Shared idempotent re-key helper (packages/sdk/src/reencrypt.ts) used by both moveItem and restoreFromBin. If the source-key resolve fails to decrypt, it confirms the record under the destination key and treats the re-key as already complete — so a retry after a partial failure completes instead of throwing. Non-decrypt errors (e.g. missing record) still propagate.

  2. restoreFromBin reorder — publish target → re-key → remove from bin (mirrors moveItem), with preconditions validated up front so a guaranteed failure aborts before publishing. At every intermediate failure the file stays readable from somewhere that lists it under the matching key (the bin, by the source key, before the re-key; the target, by the target key, after) — never readable from neither.

  3. Desktop bounded retry (spawn_file_meta_reencrypt, Rust FUSE/WinFsp) — transient resolve/fetch/publish errors retry with exponential backoff (5 attempts), the coordinator lock released across the backoff sleep; a record undecryptable under both keys is terminal (not retried). In-memory retry, not a durable journal entry (intentional scope — see the completed todo).

  4. Idempotent-by-id restore add — the reorder opened a post-publish window where a retry of a partially-applied restore would double-list the file (same id, renamed by the collision handler) since the no-conflict publish path doesn't dedup by id. Fixed by dropping any prior copy of the child id before the add, so a retry replaces rather than duplicates. (moveItem was checked and does not have this issue — it commits dest state after the re-key, so a retry reconciles via the CAS merge.)

Verified: tsc + eslint clean; SDK unit tests pass (added idempotent-retry / reorder / no-duplicate-on-retry tests for both move and restore); cargo check + crate tests under the fuse feature pass. CI E2E dispatched against this branch.

@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: 1

🤖 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/sdk/src/__tests__/client-move-reencrypt.test.ts`:
- Around line 246-269: The test for moveItem uses identical 'publish' markers
for both the destination and source folder publishes, which means the order
array cannot distinguish between them and could pass with an incorrect sequence.
Modify the vi.mocked(sdkCore.updateFolderMetadataAndPublish).mockImplementation
to distinguish the destination publish from the source publish by using
different markers or by asserting on the specific payload parameters (such as
checking the ipnsName argument to identify whether it's the destination or
source), then update the expected order array to reflect these distinct markers
so the invariant is properly enforced.
🪄 Autofix (Beta)

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: CHILL

Plan: Pro

Run ID: 4dc26613-f40a-4e3c-a1b3-d4692f48d0e2

📥 Commits

Reviewing files that changed from the base of the PR and between e1fec32 and f6c720f.

📒 Files selected for processing (8)
  • .planning/todos/completed/2026-06-17-move-restore-reencrypt-partial-failure-recovery.md
  • crates/fuse/src/lib.rs
  • packages/sdk/src/__tests__/bin.test.ts
  • packages/sdk/src/__tests__/client-move-reencrypt.test.ts
  • packages/sdk/src/bin/index.ts
  • packages/sdk/src/client.ts
  • packages/sdk/src/reencrypt.ts
  • tests/desktop-e2e/scripts/test-move-content.mjs
✅ Files skipped from review due to trivial changes (1)
  • .planning/todos/completed/2026-06-17-move-restore-reencrypt-partial-failure-recovery.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/desktop-e2e/scripts/test-move-content.mjs
  • packages/sdk/src/client.ts
  • packages/sdk/src/bin/index.ts

Comment thread packages/sdk/src/__tests__/client-move-reencrypt.test.ts
…ertion

Tag each updateFolderMetadataAndPublish call by its target folder so the ordering
invariant rejects a wrong source-then-destination sequence, which a bare
publish/reencrypt/publish marker would have passed (CodeRabbit review).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: 04ad6af54908
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release:cipherbox-core:fix Patch version bump (bug fix) for cipherbox-core release:cipherbox-fuse:fix Patch version bump (bug fix) for cipherbox-fuse release:cipherbox-sdk:fix Patch version bump (bug fix) for cipherbox-sdk release:core:feat Minor version bump (new feature) for core release:desktop:fix Patch version bump (bug fix) for desktop release:sdk:feat Minor version bump (new feature) for sdk release:sdk-core:fix Patch version bump (bug fix) for sdk-core release:tee-worker:fix Patch version bump (bug fix) for tee-worker release:web:fix Patch version bump (bug fix) for web

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant