Skip to content
Merged
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
80 changes: 63 additions & 17 deletions ansible/roles/contributor/tasks/git_scrub.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,72 @@
# failure: gitleaks scans FULL history, so a secret removed from HEAD still
# fails `hyperi-ci check`. soe inherits it through meta/dependencies.
#
# GitHub release tarball on every platform (Tier 3). hyperi-update pulls the
# latest on Linux. On macOS only a re-run of this role does, because the macOS
# updater leaves everything to brew. It is the only rung: not on crates.io, no
# git-scrub path on downloads.hyperi.io, and the release's git-scrub.rb is not
# in the hyperi-io tap. Move macOS to community.general.homebrew once that
# formula is tapped.
# macOS takes the formula in the hyperi-io tap, which each git-scrub release
# rewrites, so brew upgrade keeps it current. Linux takes the GitHub release
# tarball (Tier 3) and hyperi-update re-fetches it: not on crates.io and no
# git-scrub path on downloads.hyperi.io.
#
# The asset unpacks into a directory named after itself, so the extracted binary
# path carries the version. The tag has a leading `v`; the filename does not.

- name: Install git-scrub (re-fetched GitHub release, Tier 3)
- name: Install git-scrub (macOS)
when: ansible_facts['distribution'] == 'MacOSX'
block:
- name: Tap the hyperi-io formulae (macOS)
community.general.homebrew_tap:
name: hyperi-io/tap
state: present
become: false
environment: "{{ homebrew_env }}"

# Earlier runs of this role put the release binary here. On an Intel Mac it
# is also the path brew links into, so it has to go before the install.
- name: Check for a git-scrub binary from the release tarball (macOS)
ansible.builtin.stat:
path: /usr/local/bin/git-scrub
register: contributor_git_scrub_legacy

- name: Remove the release-tarball git-scrub binary (macOS)
ansible.builtin.file:
path: /usr/local/bin/git-scrub
state: absent
become: true
when:
- contributor_git_scrub_legacy.stat.exists
- not contributor_git_scrub_legacy.stat.islnk

- name: Install git-scrub via Homebrew (macOS)
community.general.homebrew:
name: hyperi-io/tap/git-scrub
state: present
become: false
environment: "{{ homebrew_env }}"

- name: Find release tarballs left by earlier runs (macOS)
ansible.builtin.find:
paths: /tmp
patterns: 'git-scrub-*-darwin-*.tar.gz'
register: contributor_git_scrub_tarballs

- name: Remove release tarballs left by earlier runs (macOS)
ansible.builtin.file:
path: "{{ item.path }}"
state: absent
loop: "{{ contributor_git_scrub_tarballs.files }}"
loop_control:
label: "{{ item.path }}"

rescue:
- name: Record that git-scrub did not install (macOS)
# noqa: var-naming[no-role-prefix] -- deploy_warnings is the shared
# accumulator reported by playbooks/main.yml post_tasks.
ansible.builtin.set_fact:
deploy_warnings: >-
{{ deploy_warnings | default([])
+ ['git-scrub: ' ~ (ansible_failed_result.msg | default('brew tap/install failed'))] }}

- name: Install git-scrub (re-fetched GitHub release, Tier 3, Linux)
when: ansible_facts['distribution'] in ['Ubuntu', 'Fedora']
block:
- name: Get latest git-scrub version from GitHub API
ansible.builtin.uri:
Expand All @@ -35,8 +90,7 @@
- name: Build the git-scrub asset name
ansible.builtin.set_fact:
contributor_git_scrub_stem: >-
git-scrub-{{ contributor_git_scrub_ref | regex_replace('^v', '') }}-{{
'darwin' if ansible_facts['distribution'] == 'MacOSX' else 'linux' }}-{{ hyperi_arch_deb }}
git-scrub-{{ contributor_git_scrub_ref | regex_replace('^v', '') }}-linux-{{ hyperi_arch_deb }}

# The tarball is KEPT, and that is what makes the role idempotent: get_url
# re-reports ok for an unchanged asset, so the extract and install below
Expand All @@ -58,14 +112,6 @@
path: /usr/local/bin/git-scrub
register: contributor_git_scrub_installed

# Root-owned on Linux, absent on a fresh Apple Silicon box.
- name: Ensure /usr/local/bin exists
ansible.builtin.file:
path: /usr/local/bin
state: directory
mode: '0755'
become: true

# A new asset OR a missing binary: the second repairs drift on a box where
# the tarball is still cached but the binary was removed.
- name: Install git-scrub
Expand Down
102 changes: 46 additions & 56 deletions ansible/roles/soe/tasks/colima.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
# Docker CLI (bring-your-own-daemon); HyperI Macs get a daemon by default:
# - colima: runs docker-ce in a small Virtualization.framework VM -- the same
# engine Linux runs natively. Homebrew formula (Tier 1, brew upgrade sweeps it).
# - Apple `container`: native per-container micro-VMs on Apple silicon. Ships
# ONLY as a signed .pkg on GitHub releases (no brew channel), so a re-run of
# this role installs the latest. hyperi-update does not touch it. Optional:
# warn, never abort.
# - Apple `container`: native per-container micro-VMs on Apple silicon. The
# homebrew-core formula (Tier 1, brew upgrade sweeps it), which needs Apple
# silicon and macOS 26. Optional: warn, never abort.
# Both are wrapped warn-and-continue so a single failure does not sink the soe run.

- name: Install colima (Docker daemon for macOS)
Expand Down Expand Up @@ -167,66 +166,57 @@
{{ deploy_warnings | default([])
+ ['colima-wiring: ' ~ (ansible_failed_result.msg | default('autostart/socket setup failed'))] }}

# The formula declares `depends_on arch: :arm64` and `macos: :tahoe`, so any
# other Mac would only collect a warning.
- name: Install Apple container (native macOS containers)
when:
- hyperi_arch_deb == 'arm64'
- ansible_facts['distribution_major_version'] | int >= 26
block:
- name: Get the latest Apple container release
ansible.builtin.uri:
url: https://api.github.com/repos/apple/container/releases/latest
return_content: true
headers: "{{ hyperi_github_headers }}"
register: soe_container_release
check_mode: false

# Prefer the signed/notarized .pkg (avoids a Gatekeeper bypass); fall back to
# any .pkg. Concatenating [signed] + [all] and taking `first` gives that
# preference in one expression.
- name: Select the container installer package (prefer the signed .pkg)
ansible.builtin.set_fact:
soe_container_pkg_url: >-
{{ ((soe_container_release.json.assets
| selectattr('name', 'search', '(?i)signed.*\.pkg$')
| map(attribute='browser_download_url') | list)
+ (soe_container_release.json.assets
| selectattr('name', 'search', '\.pkg$')
| map(attribute='browser_download_url') | list)) | first }}

# Root-owned, randomly-named temp (mkstemp, mode 0600) -- NOT a predictable
# world-writable /tmp path a local user could swap before the root installer
# reads it (TOCTOU). The `always` block removes it on success OR failure.
- name: Create a root-owned temp path for the installer
ansible.builtin.tempfile:
state: file
suffix: .pkg
become: true
register: soe_container_tmp

- name: Download the Apple container installer
ansible.builtin.get_url:
url: "{{ soe_container_pkg_url }}"
dest: "{{ soe_container_tmp.path }}"
mode: '0600'
force: true
become: true
- name: Install Apple container via Homebrew
community.general.homebrew:
name: container
state: present
become: false
environment: "{{ homebrew_env }}"

- name: Install Apple container from the signed package
# Earlier runs of this role installed Apple's signed .pkg into /usr/local.
# Its receipt is the record of exactly which files that put there.
- name: Check for the Apple container .pkg receipt
ansible.builtin.command:
cmd: "installer -pkg {{ soe_container_tmp.path }} -target /"
become: true
register: soe_container_install
changed_when: "'successful' in (soe_container_install.stdout | lower)"
cmd: pkgutil --pkg-info com.apple.container-installer
register: soe_container_pkg_receipt
changed_when: false
failed_when: false
check_mode: false

# Removed only once the brew copy is in place, so the host is never left
# without a container CLI.
- name: Remove the Apple container .pkg install
when: soe_container_pkg_receipt.rc == 0
block:
# The uninstaller refuses while the services run, and as root it would
# only look in root's launchd domain, not the user's where they live.
- name: Stop the .pkg container services
ansible.builtin.command:
cmd: /usr/local/bin/container system stop
become: false
register: soe_container_pkg_stop
changed_when: soe_container_pkg_stop.rc == 0
failed_when: false

# -k keeps ~/Library/Application Support/com.apple.container, which the
# brew copy reads as its own data.
- name: Uninstall the .pkg with Apple's own uninstaller
ansible.builtin.command:
cmd: /usr/local/bin/uninstall-container.sh -k
removes: /usr/local/bin/uninstall-container.sh
become: true

rescue:
- name: Record that Apple container did not install
# noqa: var-naming[no-role-prefix] -- shared cross-role accumulator
ansible.builtin.set_fact:
deploy_warnings: >-
{{ deploy_warnings | default([])
+ ['apple-container: ' ~ (ansible_failed_result.msg | default('download/install failed'))] }}

always:
- name: Remove the downloaded installer
ansible.builtin.file:
path: "{{ soe_container_tmp.path }}"
state: absent
become: true
when: soe_container_tmp.path is defined
+ ['apple-container: ' ~ (ansible_failed_result.msg | default('brew install or .pkg removal failed'))] }}
8 changes: 3 additions & 5 deletions docs/install-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,7 @@ table used to say the opposite.
Almost every macOS path resolves to brew or a cask. The language managers that
remain there carry no formula at all: `alint` and `maid` have none, and
semantic-release needs its plugin set installed alongside it, which only npm
gives. `git-scrub` is the one release-tarball exception -- its formula exists in
the release but is not in the hyperi-io tap, so macOS takes the darwin asset
until it is tapped.
gives.

Cloudflare publishes no flarectl binary and no distro packages it, so both
platforms build it from source. It also lives on cloudflare-go's `v0` branch --
Expand Down Expand Up @@ -354,7 +352,7 @@ The one HashiCorp tool installed: BUSL, with no open-source fork, so it is its o
| vulture | all | Ubuntu apt / Fedora uv-tool (Tier 2) / brew |
| typos | all | cargo (Tier 2) / brew |
| maid (mermaid validator, used by `/docs`) | all | npm global (Tier 2) |
| git-scrub (git-history scrubber) | all | github-binary (Tier 3: re-fetch) |
| git-scrub (git-history scrubber) | all | github-binary (Tier 3: re-fetch) / brew tap |
| macbash (macOS bash portability checker) | all | Linux downloads.hyperi.io binary (Tier 3, digest-verified) / brew tap |

`hyperi-ci` is a Python tool from PyPI, installed via `uv tool` and refreshed to
Expand All @@ -374,7 +372,7 @@ hyperi-ci.
| Slack | all | vendor-repo / cask |
| LibreOffice (org office suite) | Linux | distro repo |
| Nemo, GNOME extensions (gext), fonts | Linux | distro / uv-tool / vendored |
| colima + Apple `container` (macOS only) | macOS | brew / github-binary |
| colima + Apple `container` (macOS only; `container` needs Apple silicon and macOS 26) | macOS | brew |
| Arcane container UI (opt-in `soe_arcane_enabled`; `soe_arcane_long_session` for a year-long login) | all | container image |
| Local ClickHouse + Redpanda (opt-in `soe_local_services_enabled`) | all | container image |
| removals / update_command / admin-scripts (opt-in `never`, on for soe) | Linux | tombstones + scripts |
Expand Down
Loading