homebrew-autoupdate
homebrew-autoupdate copied to clipboard
Handling Casks
Issue:
- Currently Casks that use
sudo
to upgrade can block this command from executing successfully when people useautoupdate
to executeupgrade
on their behalf, because of the hang on silently waiting for sudo authorisation. - Homebrew explicitly does not support launching
brew upgrade
withsudo
, immediately bailing on the command, meaning we can't execute the Cask upgrade command as root to work around the issue.
Potential Fix:
- Using Homebrew's API to work out which Casks are outdated, and which of those Casks need
sudo
usage to upgrade, only passing those non-sudo Casks to theupgrade
command.
Problems with Fix:
- Likely to be computationally expensive, making the command very slow to execute.
- Leaves
sudo
Casks behind intentionally; would need to find a way to gracefully notify the user to their presence & reason for not upgrading. - Leaning on Homebrew's API so heavily to work out what casks are outdated and which of those need
sudo
has a very real potential to be fragile and prone to breaking. - Quite a lot of work for something I'm not sure how widely is a use-case yet.
Hacky Temporary Workaround
- Use
SUDO_ASKPASS
as Homebrew seems to intentionally support that for non-interactive installs, and works when tested locally. - I don't really want to settle on that as a long-term solution because I'm a tad uncomfortable asking people to simply leave their
sudo
passwords sat on the filesystem unguarded in plaintext.
Related Issues:
- https://github.com/DomT4/homebrew-autoupdate/issues/35
Maybe it is possible to make a custom brew-autoupdate
user with special sudo rights that can only install casks?
Follow multi-user homebrew guide: https://medium.com/@leifhanack/homebrew-multi-user-setup-e10cb5849d59
Running autoupdate service under a different use: https://apple.stackexchange.com/a/93174
Allowing sudo without password: add file under /private/etc/sudoers.d/brew-sudo
with brew ALL=(ALL) NOPASSWD: ALL
Use SUDO_ASKPASS as Homebrew seems to intentionally support that for non-interactive installs, and works when tested locally.
Actually I had also encountered such problem when implementing my own auto-updater for Mac, MacDaily. So basically, my solution was to temporarily set SUDO_ASKPASS
to a tailored AppleScript program at runtime to request sudo
password on the fly.
My implementation for the AppleScript is at macdaily/res/askpass.applescript, which was originally inspired from another Homebrew formula called ssh-askpass
.
Out of curiosity @JarryShaw , how hard was it to implement? Tempted to look further into it and attempt it myself, especially if no one else has got around to it yet :)
Hacky Temporary Workaround
- Use
SUDO_ASKPASS
as Homebrew seems to intentionally support that for non-interactive installs, and works when tested locally.- I don't really want to settle on that as a long-term solution because I'm a tad uncomfortable asking people to simply leave their
sudo
passwords sat on the filesystem unguarded in plaintext.
Setting NOPASSWD
in /etc/sudoers
might be a better alternative.
Out of curiosity @JarryShaw , how hard was it to implement? Tempted to look further into it and attempt it myself, especially if no one else has got around to it yet :)
@CiaronHowell It was quite a simple task with some tests lol as you may have known, AppleScript is never well documented but still easy to understand...
Setting
NOPASSWD
in/etc/sudoers
might be a better alternative.
I don't quite like this idea... 🔗
and I suppose doing so may require either user manually editing their /etc/sudoers
or the Command itself modifying the file when installation -- seems not very brew-ish
NOPASSWD should be acceptable as you would only allow the auto update command to be executed. Installation should be a manual action to make the user aware, auto updating with sudo rights is inherently a security risk. That is also why I would understand for brew not to support this. However I hope it will exist anyway, perhaps unofficially.
@CiaronHowell It was quite a simple task with some tests lol as you may have known, AppleScript is never well documented but still easy to understand...
Thank you, I'll give it a go soon 😄
I use PAM for sudo. The issue I encounter is that when autoupdater spawns a new process with sudo, the prompt does not include any useful information about the command which supposed to run. As a Linux user, MacOS messages are not useful at all. I would like to know what exactly sudo tries to run, not just that it wants to escalate permissions. If we were able to change this behavior, PAM authentication would be a perfect solution IMO.
I made a one-liner script to store my password in the keychain following this guide. It should be a lot more secure than storing your password in plaintext.
I made a one-liner script to store my password in the keychain following this guide. It should be a lot more secure than storing your password in plaintext.
Could you share details of how you use that script?
I made a one-liner script to store my password in the keychain following this guide. It should be a lot more secure than storing your password in plaintext.
Could you share details of how you use that script?
I added export SUDO_ASKPASS="/Users/$(whoami)/getpass.sh"
to "/Users/$(whoami)/Library/Application Support/com.github.domt4.homebrew-autoupdate/brew_autoupdate"
. The script is named getpass.sh
.
My implementation for the AppleScript is at macdaily/res/askpass.applescript, which was originally inspired from another Homebrew formula called
ssh-askpass
.
This could be a potential solution if we're able to capture which cask requires sudo privilege
I made a one-liner script to store my password in the keychain following this guide. It should be a lot more secure than storing your password in plaintext.
note that the script in the guide must be slightly modified, since SUDO_ASKPASS expects a script that spits just your password to standard out when invoked.
Here's what my getpass.sh contained:
pw_name="CLI"
pw_account="matt"
if ! cli_password=$(security find-generic-password -w -s "$pw_name" -a "$pw_account"); then
echo "error $?"
exit 1
fi
echo "$cli_password"
I use PAM for sudo .. the prompt does not include any useful information about the command which supposed to run
I was going to suggest this, but you beat me to to it! I check which process is requesting sudo access with sudo procs --tree sudo
. I'm sure there's an equivalent incantation using ps
. And yes, I see the irony of using sudo to check where sudo is being invoked.
I wonder if pinentry could be used via SUDO_ASKPASS
? I believe it doesn't require a terminal for password input as it uses its own gui prompt. This is what the gpgagent
daemon uses (or can be setup to use).
TL;DR solution (using getpass.sh)
(assuming your username is "mateowang" and password is "password123")
-
security add-generic-password -s 'CLI' -a 'mateowang' -w 'password123' -T /usr/bin/security
1 - run
security find-generic-password -w -s 'CLI' -a 'mateowang'
and confirm that it outputs 'password123' 1 - write:
topw_name="CLI" pw_account="mateowang" if ! cli_password=$(security find-generic-password -w -s "$pw_name" -a "$pw_account"); then echo "error $?" exit 1 fi echo "$cli_password"
~/getpass.sh
2 -
chmod +x ~/getpass.sh
- add
export SUDO_ASKPASS="/Users/$(whoami)/getpass.sh"
to"/Users/$(whoami)/Library/Application Support/com.github.domt4.homebrew-autoupdate/brew_autoupdate"
. (Note: you may have to:w!
if you're usingvim
as it is a read-only file.) 3
TL;DR solution (using getpass.sh)
(assuming your username is "mateowang" and password is "password123")
security add-generic-password -s 'CLI' -a 'mateowang' -w 'password123' -T /usr/bin/security
1run
security find-generic-password -w -s 'CLI' -a 'mateowang'
and confirm that it outputs 'password123' 1write:
pw_name="CLI" pw_account="mateowang" if ! cli_password=$(security find-generic-password -w -s "$pw_name" -a "$pw_account"); then echo "error $?" exit 1 fi echo "$cli_password"
to
~/getpass.sh
2
chmod +x ~/getpass.sh
add
export SUDO_ASKPASS="/Users/$(whoami)/getpass.sh"
to"/Users/$(whoami)/Library/Application Support/com.github.domt4.homebrew-autoupdate/brew_autoupdate"
. (Note: you may have to:w!
if you're usingvim
as it is a read-only file.) 3
Any security risks when using this?
Setting
NOPASSWD
in/etc/sudoers
might be a better alternative.I don't quite like this idea... 🔗 and I suppose doing so may require either user manually editing their
/etc/sudoers
or the Command itself modifying the file when installation -- seems not very brew-ish
You don't need to modify /etc/sudoers
, just create a new file in /private/etc/sudoers.d
I wonder if pinentry could be used via
SUDO_ASKPASS
? I believe it doesn't require a terminal for password input as it uses its own gui prompt. This is what thegpgagent
daemon uses (or can be setup to use).
Yes, it can. https://github.com/milanvarady/Applite/issues/5#issuecomment-1692672608
I wonder if pinentry could be used via
SUDO_ASKPASS
? I believe it doesn't require a terminal for password input as it uses its own gui prompt. This is what thegpgagent
daemon uses (or can be setup to use).
Yes, it works and is in my opinion the most secure and user-friendly solution.
Setup
Dependency
brew install pinentry-mac
Create Password Script
nano $HOME/getpass.sh
getpass.sh
:
#!/bin/bash
PW="$(printf "%s\n" "SETOK OK" "SETCANCEL Cancel" "SETDESC homebrew-autoupdate needs your admin password to complete the task" "SETPROMPT Enter Password:$
echo "$PW"
Invoke Password Script when homebrew-autoupdate runs
sudo nano "/Users/$(whoami)/Library/Application Support/com.github.domt4.homebrew-autoupdate/brew_autoupdate"
add: export SUDO_ASKPASS=${HOME}/getpass.sh
before the last line.
Test
Test Password Dialog
export SUDO_ASKPASS=${HOME}/getpass.sh
sudo -i -A
Test homebrew-autoupdate
launchctl start com.github.domt4.homebrew-autoupdate
tail -f ~/Library/Logs/com.github.domt4.homebrew-autoupdate/com.github.domt4.homebrew-autoupdate.out
I wonder if pinentry could be used via
SUDO_ASKPASS
? I believe it doesn't require a terminal for password input as it uses its own gui prompt. This is what thegpgagent
daemon uses (or can be setup to use).Yes, it works and is in my opinion the most secure and user-friendly solution.
Setup
Dependency
brew install pinentry-mac
Create Password Script
nano $HOME/getpass.sh
getpass.sh
:#!/bin/bash PW="$(printf "%s\n" "SETOK OK" "SETCANCEL Cancel" "SETDESC homebrew-autoupdate needs your admin password to complete the task" "SETPROMPT Enter Password:$ echo "$PW"
Invoke Password Script when homebrew-autoupdate runs
sudo nano "/Users/$(whoami)/Library/Application Support/com.github.domt4.homebrew-autoupdate/brew_autoupdate"
add:
export SUDO_ASKPASS=${HOME}/getpass.sh
before the last line.Test
Test Password Dialog
export SUDO_ASKPASS=${HOME}/getpass.sh
sudo -i -A
### Test homebrew-autoupdate `launchctl start com.github.domt4.homebrew-autoupdate `
tail -f ~/Library/Logs/com.github.domt4.homebrew-autoupdate/com.github.domt4.homebrew-autoupdate.out
I guess you could also use TouchID: https://github.com/jorgelbg/pinentry-touchid
I wonder if pinentry could be used via
SUDO_ASKPASS
? I believe it doesn't require a terminal for password input as it uses its own gui prompt. This is what thegpgagent
daemon uses (or can be setup to use).Yes, it works and is in my opinion the most secure and user-friendly solution.
Setup
Dependency
brew install pinentry-mac
Create Password Script
nano $HOME/getpass.sh
getpass.sh
:#!/bin/bash PW="$(printf "%s\n" "SETOK OK" "SETCANCEL Cancel" "SETDESC homebrew-autoupdate needs your admin password to complete the task" "SETPROMPT Enter Password:$ echo "$PW"
Invoke Password Script when homebrew-autoupdate runs
sudo nano "/Users/$(whoami)/Library/Application Support/com.github.domt4.homebrew-autoupdate/brew_autoupdate"
add:export SUDO_ASKPASS=${HOME}/getpass.sh
before the last line.Test
Test Password Dialog
export SUDO_ASKPASS=${HOME}/getpass.sh
sudo -i -A
Test homebrew-autoupdate
launchctl start com.github.domt4.homebrew-autoupdate
tail -f ~/Library/Logs/com.github.domt4.homebrew-autoupdate/com.github.domt4.homebrew-autoupdate.out
I guess you could also use TouchID: https://github.com/jorgelbg/pinentry-touchid
It would be awesome if we could use the touch ID. But I don't think it's as simple as using pinetry-mac. From where would pinetry-touchid receive the sudo password? Maybe you could manually store the password in the keyring and access the secret via pinetry-touchid. Also it would not work for older macs without touch ID.
The argument --sudo
from PR https://github.com/Homebrew/homebrew-autoupdate/pull/110 did solve this issue.
@DomT4 I believe you can now close?
The argument
--sudo
from PR #110 did solve this issue.
@swissbuechi Thank you for this very useful addition to Homebrew Autoupdate!
Out of curiosity, why do you invoke a subshell and then echo the password, when it works as well to not do that?
@toobuntu
Thank you for this very useful addition to Homebrew Autoupdate!
I'm glad you like it 👍🏻
Out of curiosity, why do you invoke a subshell and then echo the password, when it works as well to not do that?
EDIT:
@toobuntu was right, I did not understand his initial question about invoking a subshell, he already fixed it in PR: https://github.com/Homebrew/homebrew-autoupdate/pull/128
@DomT4 I think this issue could now be closed.