[🍺Homebrew] [✦Gemini] [֎Codex] [✴️Claude Code]
Alcoholless is a lightweight security sandbox for macOS programs.
While Alcoholless was originally made for the sake of securing Homebrew, basically it can be used for almost any CLI programs on macOS. Notably, Alcoholless is useful for allowing an AI agent to run shell commands with less risk of breaking the host operating system.
See also my blog article: https://medium.com/nttlabs/alcoholless-lightweight-security-sandbox-for-macos-ccf0d1927301
Alcoholless Homebrew (alcless brew) executes Homebrew in a separate environment
so as to reduce concerns around potential supply chain attacks.
cd ~/SOME_DIRECTORY
alcless brew install xz
alcless xz SOME_FILEIn the example above, xz works as a separate user with an access for the copy of the current directory.
The changed files are synced back to the current directory when the command exits, with a confirmation screen (see below).
Other directories are inaccessible, as long as the permissions are set correctly.
Confirmation screen
$ alcless xz SOME_FILE
0:00AM INF ➡️Syncing the files src=/Users/USER/SOME_DIRECTORY/ dst=default:/Users/alcless_USER_default/Users/USER/SOME_DIRECTORY
0:00AM INF ⬅️Syncing the files back (dry run) src=default:/Users/alcless_USER_default/Users/USER/SOME_DIRECTORY/ dst=/Users/USER/SOME_DIRECTORY
*deleting SOME_FILE
.d..t.... ./
>f+++++++ SOME_FILE.xz
0:00AM INF ⬅️Syncing the files back src=default:/Users/alcless_USER_default/Users/user/tmp/ dst=/Users/USER/tmp
⚠️ The following commands will be executed:
rsync -rai --delete -e '/usr/local/bin/alclessctl shell --workdir=/ --plain' default:/Users/alcless_USER_default/Users/USER/SOME_DIRECTORY/ /Users/USER/SOME_DIRECTORY
❓ Press return to continue, or Ctrl-C to abort
[RETURN]
CONTINUE
*deleting SOME_FILE
.d..t.... ./
>f+++++++ SOME_FILE.xzImportant
Alcoholless uses an unsupported installation mode of Homebrew that uses a custom installation prefix.
Do NOT report any issue that happens with Alcoholless to the upstream Homebrew.
Alcoholless is useful for sandboxing AI coding agents too. The file changes made by the AI are committed to the host filesystem only after the user confirmation.
cd ~/SOME_DIRECTORY
alcless brew install gemini-cli
alcless geminicd ~/SOME_DIRECTORY
alcless brew install codex
alcless codexTip
AI coding agents typically prints the authentication URL on the first run. Make sure to copy and paste the URL in a single line. (Hint: use TextEdit to eliminate extra line delimiters)
Unlike Gemini and Codex, Claude Code needs extra steps for the initial setup (issue #52):
- Switch the desktop user to
alcless_USER_defaultvia the Fast User Switching icon in the macOS menubar. - Run the following commands in the
alcless_USER_defaultdesktop:
brew install claude-code
claude- Authenticate with Anthropic in the initial screen of
claude. - Log out from the
alcless_USER_defaultdesktop. - Run the following commands in the main desktop:
cd ~/SOME_DIRECTORY
alcless zsh -c "security unlock-keychain && claude"Requirements:
- macOS
- Go
To install Alcoholless, run:
make
sudo make installMakefile variables:
PREFIX: installation prefix (default:/usr/local)
To initialize the "default" sandbox (user account alcless_${USER}_default):
alclessctl create default
To run a command:
alclessctl shell default -- brew install xz
or
alcless brew install xz
To run a command, without rsyncing the current directory:
alclessctl shell --plain default bash
or
alcless --plain bash
To remove the sandbox:
alclessctl delete default
The command line is designed to be similar to limactl.
Just plain old utilities under the hood: sudo, su, pam_launchd, and rsync.
A future version may also incorporate FSKit to replace rsync.
Alcoholless creates /etc/sudoers.d/alcless_exampleuser_default for the user exampleuser, with the following content:
exampleuser ALL=(root) NOPASSWD: /usr/bin/su - alcless_exampleuser_default -c *
This sudo configuration allows exampleuser to run /usr/bin/su - alcless_exampleuser_default -c * as the root user,
without the password.
The su command being executed through sudo can run an arbitrary command as the sandbox user alcless_exampleuser_default.
See FAQs for the reason why su is wrapped inside sudo.
Because sudo doesn't isolate "a specific Mach bootstrap subset, audit session and other characteristics not recognized by POSIX" (see launchd(8)),
while su isolates them.
e.g., sudo -u alcless_exampleuser_default open -a TextEdit opens the TextEdit application as the current user, not as alcless_exampleuser_default.
This issue could be solved by copying the pam_launchd.so configuration from /etc/pam.d/su to /etc/pam.d/sudo,
however, touching such system configuration files might be scary.
So, the current workaround is to just wrap su inside sudo.
Because VM has several disadvantages:
- Non-negligible performance overhead
- High disk consumption
- No direct access to the host hardware (GPU, etc.)
- Localhost address inaccessible from the host
- Does not work on GitHub Actions etc. due to lack of the support for nested virtualization
Because Linux and FreeBSD already have containers.
- Alcoholless (Lightweight): run commands as a separate macOS user (not a VM, nor a container)
- Lima (Strong security): run commands in a Linux VM
- Support for macOS VM is also planned
The alclessctl CLI is designed to mimic the limactl CLI for an easier learning,
however, Alcoholless does not use Lima under the hood.