Skip to content

fix(homebrew): pre-create /usr/local/cli-plugins for docker cask; modernize fact refs#7

Merged
Defilan merged 1 commit into
mainfrom
fix/docker-cask-sudo-and-facts-deprecation
May 23, 2026
Merged

fix(homebrew): pre-create /usr/local/cli-plugins for docker cask; modernize fact refs#7
Defilan merged 1 commit into
mainfrom
fix/docker-cask-sudo-and-facts-deprecation

Conversation

@Defilan

@Defilan Defilan commented May 23, 2026

Copy link
Copy Markdown
Member

What

Two related fixes that surfaced during a fresh Mac Studio bootstrap
run today:

  1. [BUG] homebrew cask install of docker-desktop fails: sudo without TTY when creating /usr/local/cli-plugins #5: Pre-create /usr/local/cli-plugins so the docker-desktop
    cask install no longer needs sudo. Add --ask-become-pass to
    bootstrap.sh so the new become: true pre-task can acquire
    credentials.
  2. [BUG] group_vars/all.yml references deprecated top-level fact var (ansible-core 2.24 removes it) #6: Sweep eight references from the deprecated ansible_user_dir
    top-level fact to the supported ansible_facts['user_dir'] form.

Why

Fixes #5
Fixes #6

./bootstrap.sh died mid-run installing the docker-desktop cask:

sudo: a terminal is required to read the password

Root cause: Docker Desktop's cask postinstall hook does sudo mkdir -p /usr/local/cli-plugins even on Apple Silicon. On a fresh Mac
that directory does not exist, /usr/local/ is root-owned, and brew
runs under become: false so there is no TTY for sudo to prompt.

Pre-creating the directory under the invoking user removes the
sudo step from brew's cask path entirely. The post-fix invocation
of brew install --cask docker-desktop is a pure-user-space install.

The deprecation warning was a free win to bundle with #5: same
playbook file set, easy mechanical sweep, future-proofs against
ansible-core 2.24.

How

#5 — docker-desktop sudo

roles/homebrew/tasks/main.yml gains a pre-task before the cask
loop:

- name: Pre-create /usr/local/cli-plugins for the docker-desktop cask
  become: true
  ansible.builtin.file:
    path: /usr/local/cli-plugins
    state: directory
    owner: "{{ ansible_facts['user_id'] }}"
    group: staff
    mode: '0755'
  when: >-
    homebrew_casks | select('match', '^docker(-desktop)?$') | list | length > 0

The when: clause keeps non-Docker deployments sudo-free.

bootstrap.sh adds --ask-become-pass to the ansible-playbook
invocation so Ansible can prompt for sudo password once when the
new pre-task runs.

#6 — deprecated fact references

Eight occurrences swept from {{ ansible_user_dir }} to
{{ ansible_facts['user_dir'] }}:

  • group_vars/all.yml × 3 (src_dir, model_store, foreman_workspace_root)
  • roles/foreman/tasks/main.yml × 1
  • roles/developer_tools/tasks/main.yml × 2
  • roles/opencode/tasks/main.yml × 2

No behavior change today; the playbook keeps working when
ansible-core 2.24 ships and removes the auto-injection.

Verification

Local:

  • ansible-playbook --syntax-check clean
  • Grep confirms no ansible_user_dir references remain anywhere
  • Diff is mechanical: 6 files, +31/-8

CI:

Related

Checklist

  • Tests / lint pass locally where tools were available
  • Conventional commit + DCO-style sign-off
  • Documentation updated only where the change is observable to
    users (no doc change in this PR; the --ask-become-pass will
    become visible in the form of a one-time sudo prompt)
  • References both issues this PR closes

…ernize fact refs

Two related fixes surfaced during a fresh Mac Studio bootstrap run.

1) docker-desktop cask install failed mid-run with 'sudo: a terminal
is required to read the password' (#5). Docker Desktop's cask
postinstall hook does `sudo mkdir -p /usr/local/cli-plugins` even on
Apple Silicon (it keeps the Intel-era /usr/local convention for CLI
plugins). On a fresh Mac that directory does not exist and
/usr/local/ is root-owned, so the cask's internal sudo call fails
when Ansible runs brew under `become: false` (no TTY).

Fix: new pre-task in roles/homebrew that runs under `become: true`
and creates /usr/local/cli-plugins owned by the invoking user
before the cask install loop. Once the directory exists, brew's
postinstall hook skips its sudo step entirely. The pre-task is
guarded by a `when:` clause that only triggers when the cask list
actually includes docker or docker-desktop, so non-Docker
deployments stay sudo-free.

For the new pre-task to work non-interactively, bootstrap.sh now
passes --ask-become-pass to ansible-playbook so Ansible prompts
the user for sudo password once at the start of the run. This is
a one-time UX cost in exchange for clean idempotent installs.

2) Eight references to the deprecated top-level fact `ansible_user_dir`
across group_vars/all.yml, roles/foreman, roles/developer_tools, and
roles/opencode (#6). ansible-core 2.24 removes auto-injection of
`ansible_*` top-level facts; the supported form is
`ansible_facts['user_dir']`. Swept all occurrences. Behavior
identical today, but the deprecation warning no longer fires and
the playbook will keep working when ansible-core 2.24 lands.

Verification:
- ansible-playbook --syntax-check: clean
- Diff is mechanical (~30 lines across 6 files)
- CI's yamllint + ansible-lint + shellcheck + macos-check +
  macos-homebrew jobs are the safety net; macos-homebrew will exercise
  the cask install end-to-end on a fresh GitHub-hosted Apple Silicon
  runner.

Fixes #5
Fixes #6
@Defilan Defilan added the bug Something isn't working label May 23, 2026
@Defilan Defilan merged commit 554c910 into main May 23, 2026
5 checks passed
@Defilan Defilan deleted the fix/docker-cask-sudo-and-facts-deprecation branch May 23, 2026 23:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

1 participant