feat(disk-tools): add standalone File Shredder tool#53
Conversation
Add a new File Shredder under the Disk Tools menu that lets users securely destroy arbitrary files and folders on demand. Data is overwritten with random bytes then zeroed (2-pass) before deletion, making recovery virtually impossible. Safety measures: - Protected-path blocklist (system dirs, user profile roots) - Root-level directory rejection - Symlink skipping throughout (lstat, isSymbolicLink checks) - Recursion depth limit (50) to prevent stack overflow - Confirmation dialog before shredding - Cancellation support mid-operation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3b187da1c5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Address three review findings:
- P1: Check isProtectedPath() on every child directory during recursion,
not just on the top-level user-selected paths. Prevents shredding
.ssh, Desktop, Documents etc. inside a selected home folder.
- P1: Replace rm(dir, { recursive: true }) with bottom-up rmdir() that
only removes empty directories. If the depth limit (50) truncated
collection, files beyond that depth were never shredded — recursive rm
would have silently deleted them without the overwrite pass.
- P2: Add `cancelled` boolean to ShredderResult. Final progress event
now reports actual progress instead of blanket 100%. UI returns to
idle on cancel so remaining entries stay visible for retry.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e445f6bf09
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… cleanup - P1: Check `cancelled` between each 1 MB chunk inside shredFile() so a multi-GB overwrite can be interrupted within ~1 MB of the cancel request, instead of running both passes to completion. - P2: Deduplicate collected file list before processing. Overlapping selections (parent folder + child, or folder + explicit file inside it) no longer shred the same file twice / report a bogus ENOENT failure on the second attempt. - P2: removeEmptyDirs() now checks isProtectedPath() on each child directory before recursing, matching the guard in collectFiles(). Prevents rmdir() from removing an empty protected directory (e.g. .ssh, Desktop) that was correctly skipped during shredding. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 982d2a5732
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| await shredFile(filePath) | ||
| await rm(filePath, { force: true }) | ||
| const fileSize = fileSizes.get(filePath) || 0 | ||
| bytesShredded += fileSize | ||
| shredded++ |
There was a problem hiding this comment.
Do not delete the current file after a cancel
shredFile() now returns early when cancelled flips, but this caller treats that as success and immediately runs rm(filePath, { force: true }) and increments the shredded counters. If the user cancels while a large file is mid-overwrite, the current file is still deleted and reported as fully shredded even though only part of the overwrite pass actually ran.
Useful? React with 👍 / 👎.
|
|
||
| function isProtectedPath(targetPath: string): boolean { | ||
| const normalized = normalize(resolve(targetPath)).replace(/\\/g, '/') | ||
| const name = basename(normalized).toLowerCase() |
There was a problem hiding this comment.
Reject paths nested under protected directories
isProtectedPath() only checks the final path segment against the blocklist, so nested selections like ~/.ssh/id_rsa or %USERPROFILE%\\AppData\\Roaming\\Vendor pass validation because their basename is not .ssh/appdata. That bypasses the safety guard for the exact directory trees this feature is trying to protect, as soon as the user selects a child path directly instead of its parent.
Useful? React with 👍 / 👎.
| for (const entry of entries) { | ||
| if (entry.isSymbolicLink()) continue | ||
| const fullPath = join(dirPath, entry.name) | ||
| if (entry.isDirectory()) { | ||
| if (isProtectedPath(fullPath)) continue |
There was a problem hiding this comment.
Honor cancellation while enumerating selected folders
The cancel IPC only flips a module flag, but collectFiles() never observes it while walking directories. On a large folder selection, clicking Cancel does nothing until the entire tree has been enumerated and the handler finally reaches the later if (cancelled) break in the shred loop, so the longest phase of the operation remains uninterruptible.
Useful? React with 👍 / 👎.
Summary
/file-shredder)datasync) beforerm— same algorithm as the cleaner's secure delete, but as a standalone on-demand toollstat, recursion depth limit (50), confirmation dialog, and cancellation supportFiles changed
src/main/ipc/file-shredder.ipc.ts— file/folder pickers, shred logic, progress, cancelShredderEntry,ShredderProgress,ShredderResultinsrc/shared/types.tsshredder:*IPC channelswindow.kuduAPI methodssrc/renderer/src/stores/file-shredder-store.tsFileShredderPage.tsx— full UI with add/remove items, progress bar, results summaryfileShredder.jsonTest plan
🤖 Generated with Claude Code