Repository navigation
fix: audit 2026-10-10 - open rc port visible and closable, no invisible-backup swaps, FD leak, log trim - #22
Merged
Merged
Conversation
The timeout timers held the Process and both pipe readers until timeout + 10 s, so every call with a timeout kept two descriptors open long after the child had exited (+100 for 50 calls; 76-92 pipes in the running app against a soft limit of 256). The timers now hold a small box that is emptied in terminationHandler. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ww8BFyxe5Efb9pvhshhtig
With a limit set, a failed rclone size left the watchdog comparing the last stored reading with the limit regardless of its age, or raising nothing when there was no reading. The limit then guarded nothing and only the panel turned amber. A reading older than usageStaleAfter (or none at all) is now a watchdog problem, drive-usage-unmeasured. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ww8BFyxe5Efb9pvhshhtig
… stall check The log was only rotated when the mount started, and the mount runs for days (257 MB on 10.10, +60 MB a day). The buffer guard now trims it above 100 MB: the last 32 MB go to rclone.log.1 and the live file is truncated (rclone opens it O_APPEND - checked with lsof - so it keeps writing at the new end). The stall and quota checks read the tail of .1 together with the live file when the live file is short, so a trim in the middle of a jam does not read as 'no jam'. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ww8BFyxe5Efb9pvhshhtig
- The panel no longer suggests configure-remote --replace-existing after credentials are saved; on a connected Mac it says to keep the connection (a drive.file sign-in under another client_id cannot see the existing image). - Replacing an existing remote needs --accept-scope-change as well, and even then the new token lists the image (on an in-memory :drive: remote, token via the environment) before rclone.conf is written; if the old connection saw the image and the new one does not, nothing is written. - create-image refuses when Drive shows no image but this Mac remembers one (known-image marker written on create/attach, or the image in the vfs cache): 'check the token', not a second empty backup. - A missing rclone.conf next to cached Drive folders is 'unknown', not 'no remote'; a cached mac-studio folder alone keeps a legacy Mac in mac-studio. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ww8BFyxe5Efb9pvhshhtig
…ut a reboot A mount started before the private socket survives brew upgrade and keeps taking unauthenticated commands on 127.0.0.1:5572 until the Mac restarts. Only one drive-status line said so. - One check (no socket + mount + something accepts on the port) feeds the window, the watchdog and the CLI. - Window: a red card in every section with the explanation, the prepare-shutdown command and a Restart the mount button (confirmation dialog, disabled during a backup); the green badge goes, the headline and the menu bar say it. - Watchdog: a notification of its own (not a backup failure, so not in the exit code): once, then after 1, 2, 4 and every 7 days; undelivered ones are retried. - restart-mount / the button: refuses while Time Machine runs or when that is unknown; detach and drain as prepare-shutdown, then SIGTERM to the mount job (KeepAlive starts the new code; a job launchd cannot spawn is reloaded once it has exited), wait for the socket, attach. Holds the image lock; any doubt before the stop leaves the mount alone and the image re-attached. - drive-status no longer says 'the mount is not running' when the mount table could not be read (N2); MachineIdentity doc comment back on its symbol (N5); docs use the full cask name (S2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ww8BFyxe5Efb9pvhshhtig
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Second-round audit of CloudMachine (2026-10-10), on top of v1.3.8. One commit per finding; every fix has a regression test.
What changes
N-K1 (critical): the open remote-control port is visible and can be closed without a reboot
A mount started by 1.3.7 or older survives
brew upgradeand keeps taking unauthenticated commands on127.0.0.1:5572(includingoperations/purge, with the trash off) until the Mac restarts. Before this PR only onedrive-statusline said so.One check,
DriveBufferService.legacyPortOpen: no socket, plus a mount, plus something accepting connections on the port. The last condition separates the old mount from a socket deleted under a new one. The window, the watchdog and the CLI all use it.Window: a red card in every section with the explanation, the
prepare-shutdowncommand and a Restart the mount button. The button asks for confirmation and is disabled during a backup. In this state the green badge goes away, and the headline and the menu bar say why.Watchdog: has its own notification,
OpenPortAlert. This is not a backup failure, so it does not change the exit code. It fires once, then after 1, 2 and 4 days, then every 7 days. A notification that did not show is retried on the next run.restart-mount/ the button (MountRestart):prepare-shutdown, and looks aterroredFilesin the result.launchctl kill SIGTERMto the mount job, soKeepAlivestarts the new code. If launchd cannot spawn the job, it is reloaded once it has exited.The image lock is held the whole time. If anything is doubtful before the stop, the mount is left alone and the image is attached again.
bootoutandkickstart -kwere rejected; the reasons are in the file header.N-W1 (high): a visible backup is never swapped for an invisible one
configure-remote --replace-existing. On a Mac that is already connected, the panel now says to keep the existing connection.--replace-existing --accept-scope-change. Even then, the new token lists the image on an in-memory:drive:remote (token passed through the environment) beforerclone.confis written. If the old connection saw the image and the new one does not, nothing is written.create-imagerefuses when Drive shows no image but this Mac remembers one. The traces are theknown-imagemarker (written on create and attach) and the image in the vfs cache. The message says "check the token's permissions" and does not create a second, empty backup.W1 remainder (S4): a missing
rclone.confis not "no remote"listremoteslists nothing,rclone config filesays the file does not exist, and this Mac has cached Drive folders (cache/vfs/gdrive{…}/CloudMachine/<folder>), the answer is nownil(unknown) instead offalse.mac-studiofolder alone keeps a legacy Mac inmac-studio.Medium
Processand both pipe readers untiltimeout + 10 s. They now hold a small box that is emptied when the process exits. Test: 50 calls withtimeout: 30leave at most 10 descriptors open. The old code leaves 100.usageStaleAfter, or no measurement at all, is now the watchdog problemdrive-usage-unmeasured. Before, the alarm compared an old reading or stayed silent.rclone.log: the buffer guard trims the log of the running mount above 100 MB. The last 32 MB go to.1and the live file is truncated. rclone opens the fileO_APPEND(checked withlsof +fg:W,AP). The stall and quota checks read the end of.1together with the live file, so a trim in the middle of a jam does not read as "no jam". Rejected alternatives:--log-file-max-size: it only applies after the mount restarts, and its backup files get timestamped names.Low
no socket - UNKNOWN whether the mount is running.MachineIdentity.storedKey.renacode/tap/cloudmachine.remoteConfiguredstarts asfalse, so the first frame can show "not connected". The CLI refuses anyway.config create.rclone config createhas no other input.fileExists. The new port check removes the false "OPEN" warning for a socket deleted under a new mount.Tests
swift build: no warnings in Sources.swift test --skip BackupImageServiceTests: 390 tests, 0 failures (359 before).swift format lint --strict --recursive Sources Tests: clean.testFinishedProcessesReleaseTheirDescriptorsfails on oldProcessRunnerwith 100 descriptors still open.testJamBeforeTheTrimIsStillSeenfails on oldDriveBufferService(false, expectedtrue).problems(usage: nil, limitGB: 1000)used to be asserted empty.MountRestart(launchctl, socket wait) and the:drive:listing with a fresh token. A production backup runs on the development Mac, so neither was exercised there.What happens on
brew upgradefrom 1.3.4 (co się stanie przy brew upgrade z 1.3.4)The cask replaces the app, and Homebrew reopens it.
AgentRepairreloadsbackup-health,gdrive-attachandbuffer-guard.gdrive-buffer(rclone from 1.3.4) keeps running on TCP 5572: no mount restart and no gap in backups.Within one refresh (10 s), the window shows the red "Remote control of the Drive mount is open" card. The menu bar switches to Attention. The next
backup-healthrun prints a WARNING line and shows one notification.On its first tick,
buffer-guardtrims~/.cloudmachine/rclone.log(about 273 MB): the last 32 MB replacerclone.log.1and the live file is truncated. rclone carries on writing at the new end.Within 15 minutes,
gdrive-attachreports "Already attached" and writes theknown-imagemarker.Since fix: audit 2026-10-09 - rclone rc on a private socket, fail-closed remote check, lost process output #21 the 3500 GB limit applies. If
rclone sizefails for more than 12 h, the watchdog now reportsdrive-usage-unmeasured; before, it stayed silent.When the user presses Restart the mount (not during a backup):
mount-driveon~/.cloudmachine/run/rc.sock;For a few minutes Time Machine has no destination, and a watchdog run that lands in that window can report it. If anything has not reached Drive, nothing is stopped. The alternative is still
prepare-shutdownfollowed by a restart of the Mac.Nothing runs
configure-remoteorcreate-imageon its own. The new guards only take effect when someone runs them.Merging this publishes a release (CD). Please do not merge before the review.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Ww8BFyxe5Efb9pvhshhtig