Darwin.configure macos 26.yml
#!/usr/bin/env ansible-playbook
#
# Copyright © 2025 Florent Claerhout.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
- name: "macOS 26 Tahoe is configured"
hosts: "all"
vars:
##
## System
##
# hostname:
# domain_name:
# mobile_config_rfile
##
## WindowManager
##
wm_with_stage_manager: true
wm_with_tiled_window_margins: false
##
## Dock
##
dock_with_autohide: true
# time the Dock waits before appearing after the mouse cursor moves to the screen edge
dock_autohide_delay: 0
# duration of the Dock's animation when it appears or disappears
dock_autohide_time_modifier: 0
dock_orientation: "bottom" # left|bottom|right
##
## Finder
##
finder_with_show_all_extensions: true
finder_with_show_all_files: true
finder_with_extension_change_warning: false
finder_with_warn_on_empty_trash: false
##
## Disk Utility
##
diskutility_with_sidebar_show_all_devices: true
handlers:
- name: "Dock is restarted"
listen: "Dock configuration has changed"
command: "killall Dock"
- name: "Finder is restarted"
listen: "Finder configuration has changed"
command: "killall Finder"
force_handlers: true
tasks:
- block:
# NOTICE!
# ansible built-in hostname module does not handle the domain name properly
- name: "HostName is assessed"
changed_when: false
failed_when: false # can fail with "HostName: not set"
register: cmd
command: "scutil --get HostName"
- name: "Hostname is configured"
when: cmd.stdout != (hostname + "." + domain_name)
become: true
command: "scutil --set HostName {{ hostname }}.{{ domain_name }}"
- name: "ComputerName is assessed"
changed_when: false
register: cmd
command: "scutil --get ComputerName"
- name: "ComputerName is configured"
when: cmd.stdout != hostname
become: true
command: "scutil --set ComputerName {{ hostname }}"
- name: "LocalHostName is assessed"
changed_when: false
register: cmd
command: "scutil --get LocalHostName"
- name: "LocalHostName is configured"
when: cmd.stdout != hostname
become: true
command: "scutil --set LocalHostName {{ hostname }}" # NOTICE! .local is added automatically
- name: "WindowManager is configured"
loop:
- domain: "com.apple.WindowManager"
key: "HasDisplayedShowDesktopEducation"
type: "bool"
value: true
present: true
- domain: "com.apple.WindowManager"
key: "GloballyEnabled"
type: "bool"
value: "{{ wm_with_stage_manager }}"
present: wm_with_stage_manager is defined
- domain: "com.apple.WindowManager"
key: "EnableTiledWindowMargins"
type: "bool"
value: "{{ wm_with_tiled_window_margins }}"
present: wm_with_tiled_window_margins is defined
community.general.osx_defaults:
domain: "{{ item.domain }}"
key: "{{ item.key }}"
type: "{{ item.type }}"
value: "{{ item.value }}"
state: "{{ 'present' if item.present else 'absent' }}"
- name: "Dock is configured"
loop:
- domain: "com.apple.dock"
key: "autohide"
type: "bool"
value: "{{ dock_with_autohide }}"
present: dock_with_autohide is defined
- domain: "com.apple.dock"
key: "orientation"
type: "string"
value: "{{ dock_orientation }}"
present: dock_orientation is defined
- domain: "com.apple.dock"
key: "autohide-delay"
type: "int"
value: "{{ dock_autohide_delay }}"
present: dock_autohide_delay is defined
- domain: "com.apple.dock"
key: "autohide-time-modifier"
type: "int"
value: "{{ dock_autohide_time_modifier }}"
present: dock_autohide_time_modifier is defined
community.general.osx_defaults:
domain: "{{ item.domain }}"
key: "{{ item.key }}"
type: "{{ item.type }}"
value: "{{ item.value }}"
state: "{{ 'present' if item.present else 'absent' }}"
notify: "Dock configuration has changed"
- name: "Finder is configured"
loop:
- domain: "NSGlobalDomain"
key: "AppleShowAllExtensions"
type: "bool"
value: "{{ finder_with_show_all_extensions }}"
present: finder_with_show_all_extensions is defined
- domain: "com.apple.finder"
key: "AppleShowAllFiles"
type: "bool"
value: "{{ finder_with_show_all_files }}"
present: finder_with_show_all_files is defined
- domain: "com.apple.finder"
key: "FXEnableExtensionChangeWarning"
type: "bool"
value: "{{ finder_with_extension_change_warning }}"
present: finder_with_extension_change_warning is defined
- domain: "com.apple.finder"
key: "WarnOnEmptyTrash"
type: "bool"
value: "{{ finder_with_warn_on_empty_trash }}"
present: finder_with_warn_on_empty_trash is defined
community.general.osx_defaults:
domain: "{{ item.domain }}"
key: "{{ item.key }}"
type: "{{ item.type }}"
value: "{{ item.value }}"
state: "present"
notify: "Finder configuration has changed"
- name: "Disk Utility is configured"
loop:
- domain: "com.apple.DiskUtility"
key: "SidebarShowAllDevices"
type: "bool"
value: "{{ diskutility_with_sidebar_show_all_devices }}"
present: diskutility_with_sidebar_show_all_devices is defined
community.general.osx_defaults:
domain: "{{ item.domain }}"
key: "{{ item.key }}"
type: "{{ item.type }}"
value: "{{ item.value }}"
state: "present"
- when: mobile_config_rfile is defined
block:
- name: "MDM profile is assessed"
changed_when: false
failed_when: false
register: cmd
command: "python3 -B profiles.py is-installed '{{ mobile_config_rfile }}'"
- name: "MDM profile is installed"
when: ("profile is not installed" in cmd.stderr)
command: "python3 -B profiles.py install '{{ mobile_config_rfile }}'"