show the triggering brew command in the sudo password dialog

The askpass script is now rewritten before each brew invocation with
the current command baked into the dialog text ("...to run: brew
upgrade tailscale-app") instead of a generic message written once at
launch. The command text is whitelisted to characters that cannot
break out of the shell/AppleScript quoting it is embedded in.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
maxsoch 2026-07-06 22:41:42 +02:00
parent 421ae5c40d
commit 89921275b8

View file

@ -145,22 +145,29 @@ class AppDelegate: NSObject, NSApplicationDelegate {
return "brew"
}
/// Written once per launch; sudo runs it to show a GUI password dialog
/// whenever brew needs admin rights (no terminal is attached to Process).
static let askpassURL: URL = {
/// Rewritten before each brew command so the sudo password dialog can say
/// which command needs it. Sudo runs this script to show a GUI password
/// prompt whenever brew needs admin rights (no terminal is attached to
/// Process). If two brew commands overlap, the later one's text wins
/// harmless, since prompts realistically only appear during upgrades.
static func writeAskpassScript(for command: String) -> URL {
let dir = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
.appendingPathComponent("BrewBar", isDirectory: true)
try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
// the text lands inside shell single quotes AND an AppleScript string;
// whitelist characters that cannot break out of either
let safeCommand = command.filter { $0.isLetter || $0.isNumber || " ._@+=:/-".contains($0) }
let url = dir.appendingPathComponent("askpass.sh")
let script = """
#!/bin/zsh
osascript -e 'display dialog "BrewBar needs your administrator password to continue:" default answer "" with hidden answer with title "BrewBar" with icon caution buttons {"Cancel", "OK"} default button "OK"' -e 'text returned of result'
osascript -e 'display dialog "BrewBar needs your administrator password to run:\\n\\nbrew \(safeCommand)" default answer "" with hidden answer with title "BrewBar" with icon caution buttons {"Cancel", "OK"} default button "OK"' -e 'text returned of result'
"""
try? script.write(to: url, atomically: true, encoding: .utf8)
try? FileManager.default.setAttributes([.posixPermissions: 0o700], ofItemAtPath: url.path)
return url
}()
}
func runBrew(_ command: String, completion: @escaping (String) -> Void = { _ in }) {
DispatchQueue.global().async {
@ -177,7 +184,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
process.arguments = arguments
var environment = ProcessInfo.processInfo.environment
environment["SUDO_ASKPASS"] = Self.askpassURL.path
environment["SUDO_ASKPASS"] = Self.writeAskpassScript(for: cleaned).path
process.environment = environment
let pipe = Pipe()