Skip to content

Custom Installomator

Build 48: documents how MDM admins can pin App Auto-Patch (AAP) 4.x to an internal Installomator fork instead of upstream. Two workflows are supported; pick the one that matches how tightly your environment controls Installomator source.

AAP shells out to Installomator.sh plus the matching fragments/labels/* directory for every patch run. Out of the box AAP fetches Installomator from the upstream Installomator/Installomator repository and keeps it under /Library/Application Support/AppAutoPatch/Installomator. That default is appropriate for consumer Macs and for most managed fleets.

Some environments need to deviate from that default:

  • Internal fork: your IT team maintains a fork that adds labels for in-house apps, tweaks blocking-process behavior, or pins upstream labels to vetted releases.
  • Air-gapped or proxied networks: the target Macs cannot reach github.com directly and you stage the Installomator payload from your software-distribution server.
  • Change-control: you must vet every change to Installomator before it lands on production Macs.

AAP 4.x exposes two workflows for these cases. They are independent of each other; pick whichever fits.

Section titled “Workflow A — InstallomatorVersion managed preferences (recommended)”

The simplest option. AAP’s preference schema exposes a handful of keys that point its built-in updater at a non-default Installomator source:

Key Type Notes
InstallomatorVersion string release, main, or custom. custom enables the next two keys.
InstallomatorVersionCustomRepoPath string HTTPS git URL of your fork (e.g. https://git.example.com/it/Installomator.git).
InstallomatorVersionCustomBranchName string Branch / tag inside that repo. Defaults to main.
InstallomatorUpdateDisable bool When true, AAP never updates Installomator on its own. See below.

Deploy these via the same configuration profile you use for the rest of AAP’s settings — the manifest in xyz.techitout.appAutoPatch.json (ProfileCreator / iMazing) and xyz.techitout.appAutoPatch.jamf.json (Jamf Pro) already include these keys.

When InstallomatorUpdateDisable is false (the default), the root helper keeps the on-disk copy aligned with InstallomatorVersion. For main and custom it compares the branch’s current commit with source-commit next to Installomator.sh. That sees a same-day push and a fragments/ change that did not regenerate Installomator.sh. For release it compares fragments/version.sh with the latest Installomator release tag. A difference re-downloads that source as a GitHub archive. The check runs when the helper starts and about once a day after that. Restarting the helper checks again immediately. Turning InstallomatorUpdateDisable off while Installomator.sh is missing retries within a minute. If the check cannot reach the source, the installed copy stays.

InstallomatorVersionCustomRepoPath is a GitHub owner/repository (MyOrg/Installomator). A https://github.com/owner/repository URL for that same repository is accepted too.

When InstallomatorUpdateDisable is true, the helper does not download or replace Installomator.sh or fragments/. It still refreshes LabelVersionHelper.zsh. This is the mode to combine with Workflow B when you want full change-control over the Installomator payload. A string TRUE or FALSE from a 3.x profile is accepted.

GitHubAPIAuthEnabled and GitHubAPIToken authenticate the api.github.com calls that check main, custom, and release. Turn authentication on when a fleet or a custom repository is hitting the unauthenticated limit of 60 requests an hour. A fine-grained token needs Contents: Read on the repositories being queried. Archive downloads on github.com stay unauthenticated. Both keys can be set in Settings or in a profile. A managed value wins. The token is not written to the log.

Workflow B — Push your own Installomator payload (Dan’s bundled script)

Section titled “Workflow B — Push your own Installomator payload (Dan’s bundled script)”

Some environments prefer to bypass AAP’s built-in updater entirely and push the Installomator payload through their existing software-distribution pipeline. AAP 4.x ships with a builder script that produces a self-extracting .zsh archive containing Installomator.sh, fragments/functions.sh, and fragments/labels/:

  • Script: Scripts/build-appautopatch-installomator-sfx.zsh
  • Author: Originally authored by Dan Snelson (@dan-snelson) and contributed to AAP under the same license as the rest of the project. See the script’s header comment for the credit line.

Given a git URL + branch, the builder:

  1. Sparse-clones the repo to a temp directory, fetching only Installomator.sh, fragments/functions.sh, and fragments/labels/. functions.sh is what LabelVersionHelper.zsh sources for the fast version check. A payload that omits it makes every label exit 2 and fall back to a full Installomator run.
  2. Zips that subtree into a payload.zip and validates that nothing unexpected slipped in (no .git/, no __MACOSX/, etc.).
  3. Prepends a self-extracting zsh wrapper that, when run on a target Mac, prompts for admin credentials via osascript, extracts the payload into /Library/Application Support/AppAutoPatch/Installomator (configurable via --target-dir), sets root:wheel ownership, and logs the run to /var/log/Installomator-AppAutoPatch-Update.log.
  4. Stamps the source repo URL, branch, and short commit into the generated wrapper’s header so you can audit which Installomator version a given Mac is running.

Typical invocation on a developer’s Mac (where /Users/admin/Installomator is a working clone of your fork):

Terminal window
./Scripts/build-appautopatch-installomator-sfx.zsh \
--repo-url /Users/admin/Installomator \
--branch main-with-our-labels \
--target-dir "/Library/Application Support/AppAutoPatch/Installomator" \
--output-name "/Users/admin/Desktop/Installomator-for-AppAutoPatch-$(date +%F).zsh"

The output is a single executable .zsh file you can hand to MDM as a script policy, or wrap into a .pkg (see caveat below).

Pair Workflow B with InstallomatorUpdateDisable=true

Section titled “Pair Workflow B with InstallomatorUpdateDisable=true”

If you push your own payload but leave AAP’s built-in updater enabled, the next helper start or daily check re-downloads the configured InstallomatorVersion and overwrites whatever you deployed. Set InstallomatorUpdateDisable=true in the AAP managed-preferences profile to disable that download. AAP will then only use the on-disk copy your distribution pipeline maintains.

Jamf Pro currently refuses to upload .zsh files as Mac Apps or Packages. There are two practical workarounds:

  1. Script policy: Upload the self-extracting .zsh as a Script in Jamf and trigger it from a policy. Jamf does not reject .zsh for the Scripts payload; it only rejects the file extension for Mac App / Package uploads.
  2. Wrap in a .pkg: Use pkgbuild (or your build tool of choice) to wrap the .zsh file plus a postinstall that executes it. AAP does not ship a sample wrapper because the choice of signing / notarization / payload-vs-component is environment-specific, but the minimal recipe is:
Terminal window
pkgbuild --identifier com.example.installomator-for-aap \
--version "$(date +%Y.%m.%d)" \
--root /tmp/installomator-payload-root \
--scripts /tmp/installomator-payload-scripts \
/Users/admin/Desktop/Installomator-for-AppAutoPatch.pkg

Sign with productsign before uploading to Jamf if your fleet requires signed packages.

A user piloting build 47 (TechTrekkie) asked whether the custom- Installomator workflow breaks AAP’s LabelVersionHelper.zsh. The short answer: no, the two are independent.

LabelVersionHelper.zsh is the small helper AAP installs alongside Installomator (also under /Library/Application Support/AppAutoPatch/) that AAP uses internally to derive an Installomator label’s appNewVersion when the label’s own metadata doesn’t expose it. It is installed and refreshed by the AAP root-helper daemon’s ensureInstallomator() path, independent of which Installomator source AAP is using.

In practice this means:

  • Workflow A (custom managed-pref repo) refreshes both Installomator.sh and LabelVersionHelper.zsh on the same daemon sweep. No action required from the admin.
  • Workflow B (pushed payload + InstallomatorUpdateDisable=true) controls Installomator.sh, fragments/functions.sh, and fragments/labels/. LabelVersionHelper.zsh is still installed and kept current by AAP’s helper because InstallomatorUpdateDisable is intentionally scoped to the Installomator payload, not to the helper’s own bootstrap files. Rebuild and redeploy any payload built before functions.sh was included. Until that file is on disk, AAP logs one warning and uses the slow Installomator fallback for every label.

If you completely lock down /Library/Application Support/AppAutoPatch/ via filesystem permissions, you must whitelist LabelVersionHelper.zsh so the helper can drop it in place; otherwise the discovery pipeline degrades to metadata-only version comparisons.

After deploying either workflow:

Terminal window
# Which Installomator AAP is actually running:
ls -la "/Library/Application Support/AppAutoPatch/Installomator/Installomator.sh"
/usr/bin/sed -nE 's/^VERSION="([^"]+)".*/\1/p' \
"/Library/Application Support/AppAutoPatch/Installomator/Installomator.sh" | head -n 1
/usr/bin/sed -nE 's/^VERSIONDATE="([^"]+)".*/\1/p' \
"/Library/Application Support/AppAutoPatch/Installomator/Installomator.sh" | head -n 1
# Commit installed for main or custom. Absent on a Workflow B payload.
cat "/Library/Application Support/AppAutoPatch/Installomator/source-commit"

The version line should match the commit / tag your distribution pipeline expects. For main and custom, source-commit is the commit the helper installed. For Workflow B, additionally:

Terminal window
# Header of the most recent self-extracting payload that ran:
sudo head -n 30 /var/log/Installomator-AppAutoPatch-Update.log

That log records the source repo, branch, and short commit each payload was built from.

  • MDM-ServiceManagement.md — approves the helper LaunchDaemon. The helper is what writes Installomator to disk; this profile must be in place for either workflow to run silently.
  • MDM-AppManagement.md — pre-approves the Sequoia App Management TCC permission so Installomator can actually replace .app bundles after writing the new ones.