Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

feat(disk-maintenance): SSD TRIM page with multi-select and safety rails#150

Merged
dbfx merged 4 commits into
mainAdventDevInc/kudu:mainfrom
feat/disk-maintenance-trimAdventDevInc/kudu:feat/disk-maintenance-trimCopy head branch name to clipboard
May 1, 2026
Merged

feat(disk-maintenance): SSD TRIM page with multi-select and safety rails#150
dbfx merged 4 commits into
mainAdventDevInc/kudu:mainfrom
feat/disk-maintenance-trimAdventDevInc/kudu:feat/disk-maintenance-trimCopy head branch name to clipboard

Conversation

@dbfx

@dbfx dbfx commented May 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • New Disk Maintenance page under Disk Tools (sidebar) — lists every fixed volume with media type, last-TRIM time, and a status pill explaining why TRIM is recommended (or not).
  • Multi-select drives via row checkboxes, one Trim N selected drives button. Confirmation dialog before running.
  • Cross-platform: Windows runs Optimize-Volume -ReTrim, Linux runs fstrim -v, macOS shows drives as Managed by macOS (read-only — Apple SSDs auto-TRIM and we never call trimforce).

Safety rails (all server-side, defense in depth)

  • HDDs filtered server-side and rejected from runs (UI also greys checkbox).
  • 24h throttle per drive via trim-history.json — prevents wasted writes.
  • Admin elevation required to run; non-elevated calls return needsAdmin: true without spawning anything.
  • macOS hard-stop: runTrimForDrive returns immediately on darwin. Test asserts trimforce is never spawned.
  • Network drives, tmpfs, removable filtered during enumeration; removable shown but pre-deselected.
  • Sequential mutex: only one TRIM batch can run at a time; concurrent calls rejected.
  • Drive letter validation (^[A-Za-z]$) and id length cap on all inputs.

Status heuristic (the "why" reasoning)

  • Recently trimmed (green) — last TRIM < 7 days ago
  • OK (default) — 7–30 days, or unknown but healthy
  • Recommended (amber) — > 30 days OR Linux dry-run shows > 1 GiB to discard
  • Not applicable (grey) — HDD, removable, network, macOS-managed
  • Disabled (red) — OS reports TRIM disabled or filesystem doesn't support DISCARD

statusReason is shown as a tooltip on each pill.

Files

New:

  • src/main/ipc/disk-trim.ipc.ts — IPC handler with per-platform enumeration + execution
  • src/main/ipc/disk-trim.ipc.test.ts — 13 unit tests
  • src/main/services/trim-history-store.ts — JSON store for per-drive last-TRIM timestamps
  • src/main/services/trim-history-store.test.ts — 7 unit tests
  • src/renderer/src/pages/DiskMaintenancePage.tsx — Page UI
  • src/renderer/src/stores/disk-maintenance-store.ts — Zustand store + helpers

Modified:

  • src/shared/types.ts — added TrimDriveInfo, TrimRunResult, TrimProgress
  • src/shared/channels.ts — added DISK_TRIM_LIST/RUN/PROGRESS
  • src/main/ipc/index.ts — register handler
  • src/preload/index.ts — expose diskTrimList/Run/onDiskTrimProgress on window.kudu
  • src/renderer/src/App.tsx/disk-maintenance route + page title
  • src/renderer/src/components/layout/Sidebar.tsx — sidebar entry under Disk Tools
  • src/renderer/src/locales/en/disk.json — i18n strings

Test plan

  • npm test — 1983/1983 passing (20 new)
  • npx tsc --noEmit — no new TS errors
  • npm run validate:rules — passes
  • Windows 11 (manual): enumerate drives, verify SSD/NVMe/HDD classification, BitLocker volume shows lock icon, USB stick shows as Removable + deselected, network drive does not appear
  • Windows non-admin: click Trim → admin-required toast, no Optimize-Volume invocation
  • Windows elevated: select C:, confirm dialog appears, run completes, last-TRIM updates to "Just now", pill flips to green
  • Throttle: re-click within 24h → throttled message, no command run
  • Linux non-root: drives enumerate, click Trim → needsAdmin toast
  • Linux as root: trim runs, parses bytes were trimmed, history saved
  • macOS: drives show with grey "Managed by macOS" pill, checkboxes disabled, Trim button never enabled

…y rails

Adds a Disk Maintenance page (sidebar > Disk Tools) that lists every
fixed volume with its media type, last-TRIM time, and a status pill
explaining whether TRIM is recommended. Multi-select drives and run
TRIM in one action.

- Windows uses Optimize-Volume -ReTrim; Linux uses fstrim -v.
- macOS rows are read-only with a "Managed by macOS" badge — trimforce
  is never invoked.
- Server-side rails: HDDs filtered, 24h throttle, admin elevation,
  network/removable filtered, sequential mutex.
- Last-TRIM stored in trim-history.json (best-effort cross-check
  against Windows defrag event log).
- 20 new tests (1983 total passing).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread src/main/ipc/disk-trim.ipc.ts Fixed

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cb32b89df4

ℹ️ 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".

Comment on lines +581 to +584
if (drive.mediaType === 'HDD') {
return failResult(driveId, start, 'TRIM is not applicable to HDDs.')
}
if (drive.trimSupport === 'unsupported' || drive.trimSupport === 'disabled') {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Block removable volumes before dispatching TRIM

The server-side guard in runTrimForDrive rejects HDD and unsupported states but never rejects drive.isRemovable, so a crafted IPC call can still run TRIM against removable media even though the renderer disables those checkboxes. Because disk:trim:run re-lists drives and trusts this function for enforcement, this is a real defense-in-depth gap that can execute maintenance on external drives the UI explicitly marks as not applicable.

Useful? React with 👍 / 👎.

Comment thread src/main/ipc/disk-trim.ipc.ts Outdated
Comment on lines +384 to +386
// findmnt may be missing on busybox/Alpine — fall back to /proc/mounts (best-effort).
return []
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Add actual fallback when findmnt is unavailable

When findmnt fails, the Linux enumerator immediately returns an empty list despite the comment stating there is a /proc/mounts fallback. On systems where findmnt is not installed (common in minimal/containerized distros), Disk Maintenance will always show no drives and TRIM cannot run at all, so this path silently disables the feature instead of degrading gracefully.

Useful? React with 👍 / 👎.

…roc/mounts fallback, unused import

- Server-side reject `drive.isRemovable` in runTrimForDrive (P1
  defense-in-depth gap caught by Codex). The renderer already disables
  removable checkboxes via isSelectable(), but a crafted IPC call could
  bypass that — now the server rejects too.
- Implement actual /proc/mounts fallback when findmnt is unavailable
  (P2 — minimal Linux distros like Alpine/busybox were silently
  showing zero drives instead of degrading gracefully).
- Drop unused BrowserWindow import.

5 new tests covering the removable rejection and /proc/mounts parser
(octal whitespace decode, blank-line handling, missing-file fallback).
1988/1988 passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a9e3204581

ℹ️ 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".

Comment thread src/main/ipc/disk-trim.ipc.ts Outdated
Comment on lines +331 to +334
const name = devPath.replace(/^\/dev\//, '')
if (name.startsWith('mapper/')) return name
// NVMe: nvme0n1p2 -> nvme0n1
const nvme = name.match(/^(nvme\d+n\d+)p\d+$/)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Normalize findmnt source before lsblk media lookup

deviceBaseName assumes findmnt sources are plain /dev/... nodes, but Linux commonly reports values like /dev/nvme0n1p2[/@] for btrfs subvolumes. Because this suffix is never stripped, findLsblkDevice misses the backing block device, mediaType stays Unknown, and the server-side HDD guard in runTrimForDrive (which only blocks mediaType === 'HDD') can be bypassed for HDD-backed mounts on those systems. This causes drives that should be marked non-applicable to remain selectable/runnable.

Useful? React with 👍 / 👎.

Codex flagged that findmnt reports btrfs subvolumes and bind mounts
with a '[/subvol]' suffix on the source field (e.g.
'/dev/nvme0n1p2[/@]'). Without stripping it, the lsblk lookup misses
the backing block device, mediaType stays 'Unknown', and an
HDD-backed btrfs subvolume slips past the HDD safety guard.

Fix: strip the trailing '[...]' before extracting the partition base.
4 new tests covering SATA, NVMe, btrfs subvolumes, and device-mapper
paths (1992/1992 passing).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dbfx
dbfx merged commit dd1846c into main May 1, 2026
9 of 10 checks passed
@dbfx
dbfx deleted the feat/disk-maintenance-trim branch May 1, 2026 08:02

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6018c9fa25

ℹ️ 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".

// the lookup hits the backing block device and mediaType is detected correctly.
const stripped = devPath.replace(/\[[^\]]*\]$/, '')
const name = stripped.replace(/^\/dev\//, '')
if (name.startsWith('mapper/')) return name

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Normalize /dev/mapper names before lsblk lookup

Even after the subvolume-suffix fix, mapped Linux sources are still mis-normalized: deviceBaseName() returns mapper/<name>, but lsblk -o NAME entries are plain device names (e.g. cryptroot/dm-0) and never include mapper/, so findLsblkDevice() misses these mounts. In that case mediaType remains Unknown, and because runTrimForDrive() only blocks mediaType === 'HDD', HDD-backed LUKS/LVM mounts can become runnable instead of being rejected by the server-side safety rail.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Morty Proxy This is a proxified and sanitized view of the page, visit original site.