App Management permission
Issue #47: pre-approving AAP’s TCC App Management permission via a
com.apple.TCC.configuration-profile-policyprofile.
Why this is needed
Section titled “Why this is needed”macOS Sequoia (15) and later require a new TCC permission called
App Management for any process that wants to modify an installed
.app bundle in /Applications. Installomator’s whole job is to
replace .app bundles in /Applications, so without this permission
patching either silently no-ops on a label or interactively prompts
the user to grant access on first use.
On consumer Macs, the OS prompt is acceptable. On managed Macs the standard practice is to pre-approve the permission via a TCC configuration profile so end-users never see the prompt and admins don’t have to coordinate with help-desk to re-approve after every OS upgrade.
Which process needs the approval
Section titled “Which process needs the approval”This is the part that has historically confused admins (it confused
Dan when he assembled the first attempt for issue #47): the GUI
app — xyz.techitout.appAutoPatch — never modifies installed app
bundles. The actual .app replacement happens inside
Installomator.sh, which is launched as a child process of the root
helper LaunchDaemon (bundle ID xyz.techitout.appAutoPatch.roothelper,
launchd label xyz.techitout.appAutoPatch.roothelper, binary embedded
at Contents/MacOS/AppAutoPatchRootHelper inside the AAP .app bundle).
A TCC profile that only targets the GUI app’s bundle identifier won’t do anything useful — the GUI never asks for App Management because it never modifies installed apps. The grant has to be against the helper. That’s why a manually-assembled profile of the GUI’s identifier alone “appears correct” but “doesn’t show as enabled” in System Settings → Privacy & Security → App Management — the OS quietly drops the rule because the identified subject never requests the right.
Sample profile
Section titled “Sample profile”A ready-to-sign example is at
Profile Manifests/com.apple.TCC.configuration-profile-policy-AppAutoPatch.example.mobileconfig.
It contains two TCC SystemPolicyAppBundles entries — one for the GUI
(used for AppleEvents AAP sends to coordinate with swiftDialog etc.)
and one for the helper (used for the actual app-bundle replacement
during patching) — plus the existing com.apple.servicemanagement
rules so Login Items & Extensions approval comes through the same
profile.
Sign with productsign / your MDM’s own signing flow before
deployment. Sample plist looks like:
<key>Services</key><dict> <key>SystemPolicyAppBundles</key> <array> <!-- 1. GUI app --> <dict> <key>Allowed</key> <true/> <key>Identifier</key> <string>xyz.techitout.appAutoPatch</string> <key>IdentifierType</key> <string>bundleID</string> <key>CodeRequirement</key> <string>identifier "xyz.techitout.appAutoPatch" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = "6GBSVT64FS"</string> </dict> <!-- 2. Root helper --> <dict> <key>Allowed</key> <true/> <key>Identifier</key> <string>xyz.techitout.appAutoPatch.roothelper</string> <key>IdentifierType</key> <string>bundleID</string> <key>CodeRequirement</key> <string>identifier "xyz.techitout.appAutoPatch.roothelper" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = "6GBSVT64FS"</string> </dict> </array></dict>The
subject.OUvalue has to be the Team ID that signed the installed app. The sample uses 6GBSVT64FS. See Which Team ID below before deploying the profile.
Verifying
Section titled “Verifying”After deploying the profile, on a target Mac:
sudo log show --predicate 'subsystem == "com.apple.TCC"' --info --last 5m | grep -i "appauto\|appautopatch"You should see lines like granted permission kTCCServiceSystemPolicyAppBundles
for both bundle identifiers. The tccutil reset path for that service
is also useful when reproducing pre-approval issues:
sudo tccutil reset SystemPolicyAppBundles xyz.techitout.appAutoPatch.roothelperSystem Settings → Privacy & Security → App Management will list the helper as Managed by your organization once the profile is installed and the rule has matched.
Which Team ID
Section titled “Which Team ID”Privacy and Service Management profiles match the app’s signing
certificate. certificate leaf[subject.OU] and a Service Management
TeamIdentifier rule must equal TeamIdentifier from the copy that
is actually installed. The team ID checked into source is not always
that certificate.
| Team ID | Certificate | Use it when |
|---|---|---|
6GBSVT64FS |
Developer ID Application: Robert Schroeder | The package was signed with the repo default (AppAutoPatchConstants.developmentTeamID, AAP_TEAM_ID in Scripts/release.sh). |
4XSYV3BTMX |
Developer ID Application: Andrew Spokes | The build was signed locally or with DEVELOPMENT_TEAM=4XSYV3BTMX. |
Confirm on a Mac that has the build you are deploying:
codesign -dv --verbose=2 "/Applications/App Auto-Patch.app" 2>&1 | grep TeamIdentifierA profile that still names 6GBSVT64FS does not grant Full Disk
Access, App Management, or AppleEvents to a build whose
TeamIdentifier is 4XSYV3BTMX. macOS ignores the rule. Do Not
Disturb detection then fails closed: the GUI log says the assertions
database could not be opened, and focus deferrals do not run (#94).
Replace every 6GBSVT64FS in that profile’s CodeRequirement and
RuleValue strings with 4XSYV3BTMX for those builds.
Full Disk Access is the SystemPolicyAllFiles service on the GUI
bundle xyz.techitout.appAutoPatch. The example profile includes it.
The root helper does not read the Do Not Disturb database.
Designated requirement strings
Section titled “Designated requirement strings”If you need to (re)derive the strings for a fork, run on a built copy of AAP:
codesign -dr - /Applications/App\\ Auto-Patch.appcodesign -dr - /Applications/App\\ Auto-Patch.app/Contents/MacOS/AppAutoPatchRootHelperEach prints a designated => … line; that’s the value to paste into
the profile’s CodeRequirement field.
Related
Section titled “Related”Profile Manifests/MDM-ServiceManagement.md—com.apple.servicemanagementpayload that pre-approves the helper LaunchDaemon’s Login Items & Extensions registration. Different permission, but the two profiles are usually deployed together.Profile Manifests/MDM-Notifications.md— pre-approves user notifications for AAP.Profile Manifests/MDM-LaunchAgent.md— keeps the GUI running silently in the user’s session.
