From 02f919763d0bf69524493b4056d84a2e322bc59c Mon Sep 17 00:00:00 2001 From: Darren Hickling Date: Fri, 26 Jun 2026 19:12:20 +0100 Subject: [PATCH 1/4] fix(justfile): prompt for sudo via --ask-become-pass on macOS The macOS os_config role has privileged tasks (Touch ID for sudo, firewall) but a cached `sudo -v` credential does not reach Ansible's tty-less become, so install failed with 'a password is required'. Use --ask-become-pass on the macOS install recipe (prompts once, feeds sudo over stdin) and split the Ubuntu/WSL recipe out so passwordless-sudo CI stays prompt-free. --- Justfile | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Justfile b/Justfile index 7e968ef..8da875d 100644 --- a/Justfile +++ b/Justfile @@ -18,10 +18,22 @@ bootstrap: *) echo "On Windows, run: bootstrap\bootstrap_windows.ps1 in PowerShell" ;; esac -# Install and configure everything on this machine (macOS / Ubuntu / WSL2) +# Install and configure everything on this machine (macOS) [group('ansible')] -[linux] [macos] +install: + # The os_config role has privileged tasks (Touch ID for sudo, firewall). + # --ask-become-pass prompts once and feeds the password to sudo over + # stdin; a cached `sudo -v` credential does not reach Ansible's tty-less + # become, so the prompt is required. + ansible-playbook ansible/playbooks/install.yml \ + -i ansible/inventory/localhost.yml \ + -e "repo_root=$(pwd)" \ + --ask-become-pass + +# Install and configure everything on this machine (Ubuntu / WSL2) +[group('ansible')] +[linux] install: ansible-playbook ansible/playbooks/install.yml \ -i ansible/inventory/localhost.yml \ From de12550cb07a3ea92f9ec4317412a22eb1829e74 Mon Sep 17 00:00:00 2001 From: Darren Hickling Date: Fri, 26 Jun 2026 19:12:37 +0100 Subject: [PATCH 2/4] fix(os_config): use int type for trackpad tap-to-click keys macOS stores the trackpad Clicking key as an integer, so declaring type: bool made osx_defaults fail with 'Type mismatch. Type in defaults: int'. Use type: int with value: 1 for both the Bluetooth and built-in trackpad domains. --- ansible/roles/os_config/tasks/darwin.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ansible/roles/os_config/tasks/darwin.yml b/ansible/roles/os_config/tasks/darwin.yml index 70a4439..6f3eaf1 100644 --- a/ansible/roles/os_config/tasks/darwin.yml +++ b/ansible/roles/os_config/tasks/darwin.yml @@ -248,16 +248,16 @@ community.general.osx_defaults: domain: com.apple.driver.AppleBluetoothMultitouch.trackpad key: Clicking - type: bool - value: true + type: int + value: 1 notify: Restart SystemUIServer - name: Enable tap-to-click on the built-in trackpad community.general.osx_defaults: domain: com.apple.AppleMultitouchTrackpad key: Clicking - type: bool - value: true + type: int + value: 1 notify: Restart SystemUIServer # Interface From 4f9ef0916caba8ce130c457594b021609afe172f Mon Sep 17 00:00:00 2001 From: Darren Hickling Date: Fri, 26 Jun 2026 19:12:51 +0100 Subject: [PATCH 3/4] fix(upgrade): avoid sudo hang by scoping brew upgrade to formulae + sudo-free casks The homebrew module's bare brew upgrade also touches casks, and .pkg/installer casks (e.g. microsoft-teams) shell out to sudo with no TTY, hanging the run. Restrict the module to formulae, then upgrade only sudo-free casks detected structurally from brew info --json. pkg casks are reported for a manual brew upgrade --cask. --- ansible/playbooks/upgrade.yml | 41 ++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/ansible/playbooks/upgrade.yml b/ansible/playbooks/upgrade.yml index fc629c7..eb6b4fb 100644 --- a/ansible/playbooks/upgrade.yml +++ b/ansible/playbooks/upgrade.yml @@ -12,12 +12,51 @@ PATH: "{{ homebrew_bin }}:{{ local_bin }}:{{ ansible_env.PATH }}" tasks: - - name: Upgrade Homebrew packages and casks + - name: Upgrade Homebrew formulae community.general.homebrew: update_homebrew: true upgrade_all: true + upgrade_options: formula when: ansible_os_family == "Darwin" + # The homebrew module's bare `brew upgrade` also touches casks, and + # .pkg/installer casks (e.g. microsoft-teams) shell out to sudo with no + # TTY — hanging the run. Restrict the module to formulae above, then + # upgrade only the sudo-free casks here. pkg/installer casks are detected + # structurally from `brew info --json` (never a hardcoded list) and left + # for a manual `brew upgrade --cask `. + - name: Upgrade sudo-free Homebrew casks, skipping pkg/installer casks + ansible.builtin.shell: | + set -euo pipefail + sudo_free="" + skipped="" + for cask in $(brew outdated --cask --quiet); do + if brew info --cask --json=v2 "$cask" \ + | jq -e '.casks[0].artifacts[] | (.pkg? // .installer?) | select(.)' >/dev/null 2>&1; then + skipped="$skipped $cask" + else + sudo_free="$sudo_free $cask" + fi + done + [ -n "$sudo_free" ] && brew upgrade --cask $sudo_free + [ -n "$skipped" ] && echo "SKIPPED (need sudo, upgrade manually):$skipped" + exit 0 + args: + executable: /bin/bash + environment: + PATH: "{{ homebrew_bin }}:{{ ansible_env.PATH }}" + register: cask_upgrade + changed_when: "'Upgrading' in cask_upgrade.stdout" + when: ansible_os_family == "Darwin" + + - name: Report casks skipped because they require sudo + ansible.builtin.debug: + msg: "{{ cask_upgrade.stdout_lines | select('match', '^SKIPPED') | list }}" + when: + - ansible_os_family == "Darwin" + - cask_upgrade.stdout is defined + - "'SKIPPED' in cask_upgrade.stdout" + - name: Upgrade apt packages ansible.builtin.apt: upgrade: full From 7a534bdd7439b1d7b5ac392ffce9288238446bf9 Mon Sep 17 00:00:00 2001 From: Darren Hickling Date: Fri, 26 Jun 2026 19:17:48 +0100 Subject: [PATCH 4/4] fix(ansible): raise become timeout to 30s for Touch ID sudo Once sudo_local enables pam_tid, the first privileged task pops a Touch ID dialog and produces no output until you tap. Ansible's 10s default connection timeout expired first, failing with 'Timed out waiting for become success'. Raise timeout to 30s to allow time to authenticate. --- ansible.cfg | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ansible.cfg b/ansible.cfg index a7ecced..7e6cb25 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -10,3 +10,7 @@ gather_subset = !all,!min,distribution,env,platform inject_facts_as_vars = True result_format = yaml callbacks_enabled = ansible.builtin.timer, ansible.posix.profile_tasks, community.general.selective +# Wait longer for become (sudo) to succeed. On macOS, Touch ID via pam_tid +# pops a GUI dialog and the 10s default expires before a slow fingerprint +# tap, failing with "Timed out waiting for become success". +timeout = 30