Skip to content

Fix #143: ask for the Maintenance admin password once - #145

Merged
iliyami merged 2 commits into
iliyami:mainfrom
Borisserz:fix/maintenance-auth-once
Sep 16, 2026
Merged

iliyami merged 2 commits into
iliyami:mainfrom
Borisserz:fix/maintenance-auth-once

Conversation

@Borisserz

Copy link
Copy Markdown
Contributor

Closes #143.

The bug

On Maintenance, every admin task asks for the password again. Reporter on macOS 14.7.5 / Mac Sai 1.19.0:

运行维护任务时,每一个任务都需要输入密码。是否能改成一次输入密码即可。

Root cause: each admin task spawned a new /usr/bin/osascript process for do shell script … with administrator privileges. macOS caches that authorization for about five minutes per process, so a fresh osascript cannot reuse the previous password. "Run Safe Tasks" already runs sequentially (issue #82) to avoid stacked dialogs, but it still prompted three times (RAM, purgeable space, maintenance scripts).

Fix

Run the same AppleScript in-process via NSAppleScript on a dedicated serial queue.

  • Sequential admin tasks share the process-level credential cache — one password for the session.
  • Commands still come only from the fixed MaintenanceTask enum (never user input). POSIX quoting + AppleScript string escaping is unchanged, now in MaintenanceShell.appleScriptSource.
  • Missing binaries still fail before the password prompt (issue Bug: Run Maintenance Scripts #129).
  • User-cancel (-128) still maps to the existing friendly message.
  • Long jobs (periodic) stay off the main thread so the UI does not freeze. NSAppleScript calls are serialized on one queue because the class is not thread-safe.

No privileged helper / XPC daemon. That matches the current "standard macOS admin prompt" design.

Verification

  • 17 new/updated tests for quoting, cancel detection, executor routing, missing-binary-before-prompt, unprivileged tasks not touching the admin runner, and compileAndReturnError on every admin systemCommand.
  • testSequentialAdminTasksReuseTheSameRunner proves routing through one in-process runner (the OS credential cache itself cannot be asserted in CI without a GUI password).
  • testDoShellScriptWorksOffMainThread runs real NSAppleScript do shell script "echo ok" on a background queue (no admin).
  • bash scripts/check-version-sync.sh && swift build && swift test815 tests, 3 skipped, 0 failures. Same commands as .github/workflows/ci.yml.

Test plan

  • Open Maintenance
  • Click Run Safe Tasks
  • Type the admin password once
  • Confirm RAM / purgeable space / maintenance scripts all complete without a second prompt
  • Click Flush DNS Cache — no password prompt
  • Dismiss the password dialog on an admin task — friendly cancel message, not -128

Choices worth your review

  1. In-process NSAppleScript, not a privileged helper. A LaunchDaemon would auth once at install, but this repo already chose the standard admin dialog over a persistent root helper. This PR keeps that boundary.
  2. Dedicated serial queue, not MainActor. Putting executeAndReturnError on the main thread would freeze the window for the length of periodic. SecurityAgent still presents the password dialog from a background wait.

@Borisserz

Copy link
Copy Markdown
Contributor Author

@iliyami ping for review when you have a minute — Maintenance currently asks for the admin password on every task (#143). This keeps the existing prompt, but runs it in-process so one password covers the session.

@iliyami iliyami self-assigned this Sep 16, 2026
Borisserz and others added 2 commits September 16, 2026 13:42
Each admin task spawned a new osascript process, so macOS could not
cache credentials. Run do shell script in-process via NSAppleScript.
@iliyami
iliyami force-pushed the fix/maintenance-auth-once branch from f137d1b to 90d6856 Compare September 16, 2026 17:47
@iliyami

iliyami commented Sep 16, 2026

Copy link
Copy Markdown
Owner

Excellent fix, and thank you. Running the admin do-shell-script in-process via NSAppleScript so macOS's per-process credential cache covers the sequential tasks is exactly the right approach, no persistent root helper, same standard prompt. I audited it carefully: commands still come only from the fixed MaintenanceTask enum (no user input), the two-layer escaping is preserved (sh quote + AppleScript string), it's serialized off-main so long jobs don't freeze the UI, the missing-binary gate still runs before the prompt, and cancel now uses the real error number. 17 tests, strong coverage. Rebased, bumped to 1.19.2, full suite green at 819. Merging. Thanks @Borisserz!

@iliyami
iliyami merged commit 588b3fc into iliyami:main Sep 16, 2026
2 checks passed
@iliyami iliyami mentioned this pull request Sep 16, 2026
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.

[Bug] 维护

2 participants