macOS 11 and Semantic Versioning

Last week at WWDC 2020, Apple announced macOS 11 (Big Sur). One of the questions that has come up in the MacAdmins Slack come up is whether macOS is really macOS 11 or macOS 10.16. Right now, we have nothing more to go by then what is in the betas which I won’t discuss, but it’s my understanding that Apple does indeed intend to go by macOS 11 in the end.

Many admins who write scripts that check for the OS version tend to rely on sw_vers -productVersion which would normally spit out a value such as 10.15.5. The first of the 3 digit groups has not changed in 20 years which means many scripts simply don’t check for that change. That leaves the last 2 digit groups which often get referred to as major and minor versions.

With macOS 11, it’s going to be important to check all 3 digit groups for backwards and forwards compatibility. We do have a point of reference on how these changes should go if we look at iOS, iPadOS, tvOS, and watchOS which have 3 digit versions.

This changes things a bit and I’m proposing that it’d be great if other IT admins used similar naming convention when referring to the the variable names representing each digit group should you need to split each value up.

I propose using the following semantic version guidance on how to refer to 3 digit group separated versions from https://semver.org/:

1. MAJOR version when you make incompatible API changes,
2. MINOR version when you add functionality in a backwards compatible manner, and
3. PATCH version when you make backwards compatible bug fixes.

Obviously, we cannot know for sure what next year may bring, but I’m hoping that Apple sticks to these changes and continues to increment the macOS major version as it has on its other platforms. This would mean that macOS 11 would then move on to macOS 12 by the end of 2021.

Presumably if the same behavior from iOS comes to macOS, the days of “supplemental updates” should be no more. If macOS 11.0.0 releases today and a “supplemental update” needs to come out a few days later then that’s really just a patch and the macOS version would increment from 11.0.0 to 11.0.1. However when macOS gets its minor OS releases that tend to come out every 6-8 weeks then we might go from say 11.1.0 to 11.2.0. That’s a simple change to track in most version comparison logic found in programs or scripts.

To highlight the issue a bit more clearly, a “supplemental update” would in the past would usually mean we’d go from macOS 10.15.5 to macOS 10.15.5 with the only way to know the difference being the build number which has always been incremented. Although not impossible, it’s a little less straight forward to compare a mix of alphanumeric characters vs integers. Here’s a really good blog post by Armin Briegel: https://scriptingosx.com/2017/11/on-the-macos-version/ that covers OS versioning and build numbers in more detail.

These are going to be very welcomed changes going forward because right now once macOS has hit the last minor update the only way to determine if it was on the latest version was to look at the build number of the OS.

However in shell scripting languages, it is much easier to just focus on splitting the version number into different groups since most admins will be familiar with the marketing version compared to dissecting the build numbers. Here is one way to do this going forward in a shell language:

Major Version: /usr/bin/sw_vers -productVersion | /usr/bin/cut -d . -f 1

Minor Version: /usr/bin/sw_vers -productVersion | /usr/bin/cut -d . -f 2

Patch Version: /usr/bin/sw_vers -productVersion | /usr/bin/cut -d . -f 3

Here’s a shell example on how this might be used:

[[ "$os_major_ver" -ge 11 || "$os_major_ver" -eq 10 && "$os_minor_ver" -gt 12 || "$os_major_ver" -eq 10 && "$os_minor_ver" -eq 12 && "$os_patch_ver" -ge 3 ]]

In this example, I’m testing for a condition that means either:

macOS major version is greater than or equal to 11
OR
macOS major version equals 10 AND macOS minor version is greater than 12
OR
macOS major version equals 10 AND macOS minor version equals 12 AND macOS patch version is greater than 3

In any case, this blog post is mostly going out as a reminder to admins that if you haven’t already heard of this coming change, I would suggest that you review any scripts that rely on checking the OS version as they may need some updating.

Managing Google Chrome Auto Updates

Google Chrome has a few ways in which you can manage its update mechanism which I wanted to post about.

Google Chrome Enterprise Installer

If you’re not already doing so, I recommend you start using the enterprise Google Chrome installer package. This package installs Google Chrome but also configures the Google Software Update Agent which many admins were doing with a separate script. Once Chrome is registered with the Google Software Update agent, there’s a few options for managing it to ensure that Google Chrome stays up to date.

Options for Managing Google Software Update/Keystone

Configuration Profiles

Here is an article that talks about how to manage Google Chrome updates: https://support.google.com/chrome/a/answer/7591084

By generating a configuration profile that manages the domain com.google.Keystone.plist, you can ensure that Google’s auto update mechanism is configured according to your needs. Keep in mind that the Google Software Update Agent can manage the updates for various Google apps on macOS. Unfortunately, the Google Software Update Agent won’t necessarily force users to do anything as it’s pretty transparent in the background and its job when unmanaged is just to check for updates and stage them for installation on a relaunch of a Google application. Once a registered Google application is relaunched, it will ensure the app is running the latest version.

Chrome Browser Cloud Management

Here is an article that talks about how to manage Chrome using the Chrome Browser Cloud Management console: https://support.google.com/chrome/a/answer/9116814

This would allow you to manage the Chrome web browser from a single console. To do so, you would generate a token that would get pushed out through a configuration profile to your Macs. Once enrolled, you can manage the same settings through the Google Admin console for each Chrome web browser. Please note that the user does not need to be signed in with their Google account for this option to work.

You are able to combine both options if you wish: 1) push configuration profiles from your MDM server to manage settings and enroll the device into Chrome Browser Cloud Management and 2) use Chrome Browser Cloud Management for reporting only.

Managing Update Notifications

Fortunately, Google has provided a way for admins to notify users that a Chrome update is pending and force them to relaunch. This article talks about how to manage relaunch notifications: https://support.google.com/chrome/a/answer/7679871?hl=en&ref_topic=9023245

RelaunchNotification

Tells users to relaunch Chrome Browser or restart their device running Chrome OS to get the latest update. Choose one of the options:

Relaunch recommended—Users can close the notification and keep using the old version of Chrome Browser or Chrome OS until they choose to relaunch Chrome Browser or restart their Chrome device.
Relaunch required—Users can close the notification but will see a recurring message that Chrome Browser will automatically relaunch or their Chrome device will restart after a certain time. Use the RelaunchNotificationPeriod policy to set the relaunch time (details below).

Unset: On the toolbar, the More icon More changes to indicate that an update is available but users aren’t forced to relaunch.

RelaunchNotificationPeriod

Sets the time period, in milliseconds (ms), that a user is repeatedly notified to relaunch Chrome Browser or restart their Chrome device to apply an update.

Unset: The default time period is 604,800,000 ms (7 days).

In our environment, we’ve got it set to  86400000 ms (or 24 hours). It has worked out pretty well for us. As an aside, I have no idea why Google chose to work with milliseconds.

Here is an example screenshot of what the notification looks like in Google Chrome if you set it to require a relaunch in 4 days:

Screen Shot 2019-06-21 at 9.39.38 AM

When does Google Software Update run?

The last part of the equation to account for is controlling when Google Software Update Agent runs. At the moment, there is no way to do so. Google Software Update Agents runs based on a launch daemon in /Library/LaunchDaemons/com.google.keystone.daemon.plist and 2 launch agents in /Library/LaunchAgents/com.google.keystone.agent.plist and /Library/LaunchAgents/com.google.keystone.xpcservice.plist.

Here are my observations:

  • The agent will automatically check for updates when the user logs into macOS.
  • The agent will automatically check for updates when Google Chrome is launched. However, it will only install any updates after a relaunch of Chrome.
  • The agent is supposed to automatically check for updates every 3623 seconds (this may be randomized on each device). As someone who does not use Chrome, I found that the app remained unpatched for days even when updates were definitely available which leads me to believe that this is not checking aggressively enough or there are some strings attached. I purposely did not launch Chrome to see how long it would take for it to auto update.

This becomes a bit of a problem because most people rarely restart their web browser, let alone log out and log back into their computer. I wanted a more guaranteed way that would ensure that Chrome was at least regularly checking for updates in the background. The idea here is if someone is not using Chrome then I want it to be updated as soon as they do decide to launch it the next time. I don’t want to try and check for updates in the background only when the browser is launched.

I did a bit of searching and found the following discussion on Jamf Nation which shows you can run the following command as the user (it will not work if you run this as root or a user other than the one in the current session):

"/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/Resources/GoogleSoftwareUpdateAgent.app/Contents/MacOS/GoogleSoftwareUpdateAgent" -runMode oneshot -userInitiated YES "$@"

That eventually led me to create a launch agent that I could then deploy myself to devices:

<?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”&gt;
<plist version=”1.0″>
<dict>
<key>Label</key>
<string>com.company.google.softwareupdatecheck</string>
<key>LimitLoadToSessionType</key>
<string>Aqua</string>
<key>ProgramArguments</key>
<array>
<string>/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/Resources/GoogleSoftwareUpdateAgent.app/Contents/MacOS/GoogleSoftwareUpdateAgent</string>
<string>-runMode</string>
<string>oneshot</string>
<string>-userInitiated</string>
<string>YES</string>
<string>”$@”</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>21600</integer>
</dict>
</plist>
I was able to push this out through a simple package that installed this at /Library/LaunchAgents/ with permissions set to 644 and owner/group set to root:wheel. The idea here is that the launch agent will run every 21600 seconds (or 6 hours). I chose 6 hours because it would at least ensure that the Google Software Update agent checks for an update at least once a day during the work day. Feel free to change those values for yourself.
If you think I missed anything or have something useful to add, feel free to write in the comments. I hope you’ve found this at least somewhat informative.