Webinar: WWDC 26: What's new for security, developers and IT teams
Register now
Guide

Preserve app settings during cask upgrades

Petros Amoiridis

This guide shows you how to deploy a configuration profile that grants the Workbrew Agent Full Disk Access, so that cask upgrades update apps in place instead of deleting and reinstalling them. Without it, upgrading a cask can reset an app's settings, and adopting an existing app can fail and leave it uninstalled. For why Full Disk Access is the permission that fixes this, see Why Workbrew needs Full Disk Access to update apps in place.

Recognize the symptom

This affects casks for apps installed in /Applications. The signs are:

  • After a managed cask upgrade, the app loses settings such as its Dock position, notification permissions, or login-item status.
  • A cask adoption fails partway through and the app is left uninstalled, often with an Operation not permitted error on the app bundle.
  • A brew upgrade logs Your terminal does not have App Management permissions, so Homebrew will delete and reinstall the app.

These happen because modifying files inside an existing .app bundle on macOS requires a privacy permission the Workbrew Agent does not have by default. Without it, Homebrew deletes the whole app and reinstalls it, which macOS treats as an uninstall, dropping the app's settings.

Deploy the configuration profile

Deploy the following Privacy Preferences Policy Control (PPPC) profile through your MDM. It grants the Workbrew Agent at /opt/workbrew/bin/brew both Full Disk Access (SystemPolicyAllFiles) and App Management (SystemPolicyAppBundles), pinned to the signed Workbrew Agent by its code requirement.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
	<dict>
		<key>PayloadContent</key>
		<array>
			<dict>
				<key>PayloadDisplayName</key>
				<string>Privacy Preferences Policy Control</string>
				<key>PayloadIdentifier</key>
				<string>com.apple.TCC.configuration-profile-policy.A1B2C3D4-E5F6-7890-ABCD-EF1234567890</string>
				<key>PayloadType</key>
				<string>com.apple.TCC.configuration-profile-policy</string>
				<key>PayloadUUID</key>
				<string>A1B2C3D4-E5F6-7890-ABCD-EF1234567890</string>
				<key>PayloadVersion</key>
				<integer>1</integer>
				<key>Services</key>
				<dict>
					<key>SystemPolicyAllFiles</key>
					<array>
						<dict>
							<key>Allowed</key>
							<true/>
							<key>CodeRequirement</key>
							<string>identifier "com.workbrew.workbrew-agent" 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] = "676JW3JDLF"</string>
							<key>Identifier</key>
							<string>/opt/workbrew/bin/brew</string>
							<key>IdentifierType</key>
							<string>path</string>
							<key>StaticCode</key>
							<false/>
						</dict>
					</array>
					<key>SystemPolicyAppBundles</key>
					<array>
						<dict>
							<key>Allowed</key>
							<true/>
							<key>CodeRequirement</key>
							<string>identifier "com.workbrew.workbrew-agent" 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] = "676JW3JDLF"</string>
							<key>Identifier</key>
							<string>/opt/workbrew/bin/brew</string>
							<key>IdentifierType</key>
							<string>path</string>
							<key>StaticCode</key>
							<false/>
						</dict>
					</array>
				</dict>
			</dict>
		</array>
		<key>PayloadDisplayName</key>
		<string>Workbrew App Management Permission</string>
		<key>PayloadIdentifier</key>
		<string>com.workbrew.tcc-permissions.F9E8D7C6-B5A4-3210-FEDC-BA9876543210</string>
		<key>PayloadScope</key>
		<string>System</string>
		<key>PayloadType</key>
		<string>Configuration</string>
		<key>PayloadUUID</key>
		<string>F9E8D7C6-B5A4-3210-FEDC-BA9876543210</string>
		<key>PayloadVersion</key>
		<integer>1</integer>
		<key>TargetDeviceType</key>
		<integer>5</integer>
	</dict>
</plist>

Before uploading, replace each PayloadUUID and the UUID suffix in each PayloadIdentifier with values you generate yourself (run uuidgen once per UUID). This keeps the profile from colliding with other profiles in your MDM. Leave the CodeRequirement, Identifier, and Services keys exactly as shown.

Upload it to your MDM

PPPC profiles must be delivered by MDM; macOS does not let a user grant these permissions to a background tool interactively. Upload the .mobileconfig as a custom configuration profile and scope it to your managed Macs.

  • Jamf Pro: Computers > Configuration Profiles > Upload, then set the scope.
  • Other MDMs: upload the raw .mobileconfig through your provider's custom or configuration-profile mechanism and scope it to the target Devices.

The profile takes effect on the next MDM check-in and does not require a reboot.

Apply it to already-affected apps

The profile prevents the problem going forward, but an app that was already deleted and reinstalled, or left uninstalled by a failed adoption, needs to be reinstalled once more so it is installed cleanly with the permission in place. Re-run the affected cask (for example by re-running the Brewfile that installs it) after the profile is deployed.

Verify

On a managed Mac, confirm the profile is installed:

sudo profiles list

Look for the Workbrew App Management Permission payload. Then upgrade a cask and confirm the app keeps its settings and that the delete and reinstall warning no longer appears in the command output.

We use cookies to analyze traffic and improve your experience. You can accept all cookies or decline non-essential ones. Read our Privacy Policy for details.