Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 9 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# hisaac-ci

Ansible-first automation for provisioning macOS CI agents using Tart for VM management.
Ansible-first automation for provisioning macOS 26 CI agents using Tart for VM management.

## Overview

This repository provisions macOS Tart VMs using Ansible roles and playbooks.
This repository provisions macOS 26 (Tahoe) Tart VMs using Ansible roles and playbooks. Other macOS versions are not supported; provisioning assumes the guest already runs macOS 26.

The current active stack is:

Expand All @@ -22,9 +22,7 @@ The current active stack is:
├── inventory/
│ ├── macos_inventory.py
│ └── group_vars/
│ ├── macos_agents.yml
│ ├── macos_15_agents.yml
│ └── macos_26_agents.yml
│ └── macos_agents.yml
├── playbooks/
│ └── provision.yml
├── roles/
Expand Down Expand Up @@ -52,8 +50,8 @@ The current active stack is:

- macOS host for Tart-based workflows
- [mise](https://mise.jdx.dev)
- Tart VMs prepared locally (if using dynamic Tart inventory)
- Pre-staged Xcode `.xip` and Simulator Runtime `.dmg` assets for the target OS version(s)
- macOS 26 Tart VMs prepared locally
- Pre-staged Xcode `.xip` and Simulator Runtime `.dmg` assets for the configured Xcode and iOS versions

## Setup

Expand Down Expand Up @@ -82,12 +80,10 @@ Pass `-i inventory/macos_inventory.py` and set `VM_NAME` to the Tart VM to provi

- `inventory/macos_inventory.py` discovers the VM IP via `tart ip <vm_name>`
- The VM belongs directly to `macos_agents`
- The playbook loads version-specific configuration after detecting the guest macOS version
- All agents use the same macOS 26 configuration; there is no OS-version selection or per-version preset loading
- macOS updates are restricted to 26.x; provisioning does not upgrade guests to a newer major release

Primary variable files:

- `inventory/group_vars/macos_agents.yml`: agent settings (admin credentials, Homebrew packages including `tart-guest-agent`, the `openai/tools` tap, and Dock config)
- `inventory/group_vars/macos_15_agents.yml` and `inventory/group_vars/macos_26_agents.yml`: Xcode/runtime/simulator presets
`inventory/group_vars/macos_agents.yml` contains all agent settings: admin credentials, Homebrew packages including `tart-guest-agent`, the `openai/tools` tap, Dock config, and Xcode/runtime/simulator presets.

## Xcode Cache Inputs

Expand Down Expand Up @@ -130,7 +126,7 @@ Playbook role order in `playbooks/provision.yml` is intentional:
- `mise run run-tart-vm macos:26`: starts the named Tart VM and waits for SSH readiness
- `mise run provision macos:26`: starts the named Tart VM, then runs the provisioning playbook

Replace `macos:26` with your local Tart VM name.
Replace `macos:26` with your local macOS 26 Tart VM name. The name identifies the VM; it does not select an OS version.

## Linting and Formatting

Expand Down
22 changes: 0 additions & 22 deletions inventory/group_vars/macos_15_agents.yml

This file was deleted.

19 changes: 0 additions & 19 deletions inventory/group_vars/macos_26_agents.yml

This file was deleted.

17 changes: 17 additions & 0 deletions inventory/group_vars/macos_agents.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,23 @@ ansible_ssh_password_mechanism: ssh_askpass
xcode_install_enabled: true
macos_update_enabled: true

# Xcode

# Xcode .xip files must be pre-staged in the admin user's Downloads folder before provisioning.
xcode_default_version: "26.5.0"
xcode_simruntime_downloads:
- build_version: "26.0.1"
architecture_variant: arm64
- build_version: "26.5"
architecture_variant: arm64
xcode_simulators:
- name: "iPhone 17"
device_type: "iPhone 17"
runtime: "com.apple.CoreSimulator.SimRuntime.iOS-26-0"
- name: "iPhone 17"
device_type: "iPhone 17"
runtime: "com.apple.CoreSimulator.SimRuntime.iOS-26-5"

# Homebrew

homebrew_upgrade_all_packages: true
Expand Down
4 changes: 2 additions & 2 deletions mise.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ run = "hk fix --all"
run = "scripts/cache-xcodes.bash"

[tasks.run-tart-vm]
usage = 'arg "<vm>" help="Specific Tart VM to start (e.g. macos:15). Starts all VMs if omitted." default=""'
usage = 'arg "<vm>" help="Specific macOS 26 Tart VM to start (e.g. macos:26). Starts all VMs if omitted." default=""'
run = '''
nohup tart run "$vm" > /dev/null 2>&1 &
echo "Waiting for $vm to have an IP..."
Expand All @@ -66,7 +66,7 @@ echo "$vm is ready"
'''

[tasks.provision]
usage = 'arg "<vm>" help="Name of the Tart VM to provision"'
usage = 'arg "<vm>" help="Name of the macOS 26 Tart VM to provision"'
depends = ["run-tart-vm {{ usage.vm }}"]

run = 'VM_NAME="{{ usage.vm }}" ansible-playbook playbooks/provision.yml -i inventory/macos_inventory.py'
Expand Down
9 changes: 0 additions & 9 deletions playbooks/provision.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,6 @@
when: xcode_clt_update_label != ''
changed_when: true

- name: Load macOS version-specific configuration
hosts: macos_agents
gather_facts: true
tasks:
- name: Load macOS version vars
ansible.builtin.include_vars:
file: "{{ playbook_dir }}/../inventory/group_vars/macos_{{ ansible_facts['distribution_major_version'] }}_agents.yml"
failed_when: false

- name: Install macOS updates
hosts: macos_agents
tags: [macos_updates]
Expand Down
2 changes: 1 addition & 1 deletion roles/macos_updates/tasks/update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
async: 1800
poll: 30
when: >-
not item.label.startswith('macOS') or item.version.split('.')[0] == ansible_facts['distribution_version'].split('.')[0]
not item.label.startswith('macOS') or item.version.split('.')[0] == '26'

- name: Check if any updates were actually installed
ansible.builtin.set_fact:
Expand Down
1 change: 0 additions & 1 deletion roles/rosetta/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
failed_when: false
when: ansible_facts['architecture'] == 'arm64'

# On macOS Sonoma (14.0) a benign "Package Authoring Error" may appear in output but installation succeeds.
- name: Install Rosetta 2
ansible.builtin.command:
cmd: softwareupdate --install-rosetta --agree-to-license
Expand Down
10 changes: 0 additions & 10 deletions roles/system_config/tasks/gatekeeper.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
---
# Note: These tasks require SIP to be disabled on the target system.

# Note: On macOS 26+, spctl --master-disable requires GUI interaction in
# System Settings to fully take effect. This command alone is insufficient
# but is kept for reference and for older macOS versions.
- name: Disable Gatekeeper
ansible.builtin.command:
cmd: spctl --master-disable
become: true
changed_when: true
failed_when: false

- name: Enable Developer Mode for Terminal
ansible.builtin.command:
cmd: spctl developer-mode enable-terminal
Expand Down