Skip to content

Amend Docker Desktop patch policy SQL - #50041

Merged
lucasmrod merged 2 commits into
mainfrom
amend-docker-desktop-patch-policy-sql
Jul 28, 2026
Merged

Amend Docker Desktop patch policy SQL#50041
lucasmrod merged 2 commits into
mainfrom
amend-docker-desktop-patch-policy-sql

Conversation

@lucasmrod

@lucasmrod lucasmrod commented Jul 28, 2026

Copy link
Copy Markdown
Member

My workstation has Docker Desktop 4.84.0 (latest as of today) and was incorrectly failing the "macOS - Docker Desktop up to date" patch policy.

Summary by CodeRabbit

  • Bug Fixes

    • Improved Docker Desktop patch-status detection on macOS by excluding application paths containing .back anywhere in the path, avoiding incorrect patching of nested/backup bundles.
  • Improvements

    • Enhanced Docker Desktop install and uninstall cleanup to remove stale Docker.app.back artifacts and related staged in-progress update copies (including cleanup during upgrade timing).
  • Tests

    • Updated macOS Docker Desktop ingestion/patched check expectations to match the new .back path filtering behavior.

Copilot AI review requested due to automatic review settings July 28, 2026 12:00
@lucasmrod
lucasmrod requested a review from a team as a code owner July 28, 2026 12:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts the Docker Desktop macOS patch-policy SQL so stale .back bundles created by Docker’s self-updater don’t cause Fleet’s “up to date” check to incorrectly fail.

Changes:

  • Update Docker Desktop’s patched query to exclude any apps.path containing .back anywhere (not only as a suffix).
  • Align the Homebrew ingester’s Docker Desktop special-case query with the updated pattern and clarify the rationale in comments.
  • Update the corresponding ingester test expectation.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
ee/maintained-apps/outputs/docker-desktop/darwin.json Updates the stored Docker Desktop patch-policy SQL to ignore .back paths anywhere in the app path.
ee/maintained-apps/ingesters/homebrew/ingester.go Changes the Docker Desktop patched-query override to use path NOT LIKE '%.back%' and documents the nested-app scenario.
ee/maintained-apps/ingesters/homebrew/ingester_test.go Updates the test to match the new patched-query SQL.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 416273cd-9b7f-48a6-a288-1414528550df

📥 Commits

Reviewing files that changed from the base of the PR and between 1ba74b0 and a426dc0.

📒 Files selected for processing (3)
  • ee/maintained-apps/inputs/homebrew/docker-desktop.json
  • ee/maintained-apps/inputs/homebrew/scripts/docker_desktop_install.sh
  • ee/maintained-apps/outputs/docker-desktop/darwin.json

Walkthrough

Docker Desktop patch-status SQL now excludes installed app paths containing .back anywhere in the path by changing the pattern from %.back to %.back%. The Homebrew ingester comment, validation expectation, and macOS policy query were updated. Installation and uninstallation scripts now remove stale .back bundles and staged in-progress application copies.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description only states the bug and omits the required template sections, checklist, and testing details. Fill in the template sections, including the related issue, applicable checklist items, and testing performed.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title succinctly names the main change and matches the patch policy SQL update.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch amend-docker-desktop-patch-policy-sql

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 67.97%. Comparing base (0504e59) to head (a426dc0).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #50041      +/-   ##
==========================================
- Coverage   67.98%   67.97%   -0.01%     
==========================================
  Files        3923     3923              
  Lines      250102   250102              
  Branches    13361    13361              
==========================================
- Hits       170022   170015       -7     
- Misses      64779    64786       +7     
  Partials    15301    15301              
Flag Coverage Δ
backend 69.38% <100.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Docker Desktop's self-updater leaves stale copies of the old app that
osquery's apps table picks up by bundle_identifier:

- /Applications/Docker.app.back
- ~/Library/Application Support/com.docker.install/in_progress/Docker.app

The install script now removes the staged in_progress copy (in addition
to Docker.app.back) both before copying the new bundle and at the end of
the script, so patch policies report correctly after an install.

The uninstall script now removes Docker.app.back and the
com.docker.install staging directory via post_uninstall_scripts, so
uninstalled hosts with leftovers no longer report Docker as installed.
Copilot AI review requested due to automatic review settings July 28, 2026 13:43
@allenhouchins

Copy link
Copy Markdown
Member

In general I am not a fan of amending our patch policies to address multiple copies of an app being reported on a device because it creates a false positive where the patch policy will now pass but there is still an old, vulnerable, or potentially exploitable version of the app on the device. I have improved the install and uninstall scripts to hopefully further remove these backup files, including one that gets created at ~/Library/Application Support/com.docker.install/in_progress/Docker.app.

We should merge this as-is for now since the additional % does address a bug. Once this is merged, I will monitor and make sure the install and uninstall scripts are cleaning up all the appropriate files and hopefully get us back to a non custom patch policy.

@github-actions

Copy link
Copy Markdown
Contributor

Script Diff Results

ee/maintained-apps/outputs/docker-desktop/darwin.json

=== Install // 2c3a200a -> de33e1ce ===

--- /tmp/old.IYnb4O	2026-07-28 13:44:45.300538859 +0000
+++ /tmp/new.sMMJVI	2026-07-28 13:44:45.300538859 +0000
@@ -126,11 +126,14 @@
 if [ -d "$APPDIR/Docker.app" ]; then
 	sudo mv "$APPDIR/Docker.app" "$TMPDIR/Docker.app.bkp"
 fi
-# Docker Desktop's own in-app updater leaves a Docker.app.back bundle alongside
-# Docker.app when it self-updates. osquery's apps table still picks up the
-# stale bundle by its bundle_identifier, which causes Fleet patch policies to
-# report Docker as out of date even after a successful upgrade.
+# Docker Desktop's own in-app updater leaves stale copies of the old app behind:
+# a Docker.app.back bundle alongside Docker.app, and a staged copy at
+# ~/Library/Application Support/com.docker.install/in_progress/Docker.app.
+# osquery's apps table still picks these up by bundle_identifier, which causes
+# Fleet patch policies to report Docker as out of date even after a successful
+# upgrade.
 sudo rm -rf "$APPDIR/Docker.app.back"
+sudo rm -rf /Users/*/Library/"Application Support"/com.docker.install/in_progress/Docker.app
 sudo cp -R "$TMPDIR/Docker.app" "$APPDIR"
 relaunch_application 'com.electron.dockerdesktop'
 mkdir -p /usr/local/cli-plugins
@@ -142,3 +145,8 @@
 /bin/ln -h -f -s -- "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-desktop" "/usr/local/bin/docker-credential-desktop"
 /bin/ln -h -f -s -- "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-ecr-login" "/usr/local/bin/docker-credential-ecr-login"
 /bin/ln -h -f -s -- "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-osxkeychain" "/usr/local/bin/docker-credential-osxkeychain"
+# A staged self-update can fire during the quit/relaunch window above and
+# recreate the stale copies after the earlier removal, so delete them again
+# now that the new bundle is in place.
+sudo rm -rf "$APPDIR/Docker.app.back"
+sudo rm -rf /Users/*/Library/"Application Support"/com.docker.install/in_progress/Docker.app

=== Uninstall // 29483ade -> ba7543f2 ===

--- /tmp/old.TRE0qj	2026-07-28 13:44:45.319538993 +0000
+++ /tmp/new.xaSBWW	2026-07-28 13:44:45.320539000 +0000
@@ -171,6 +171,8 @@
 sudo rm -rf '/Library/PrivilegedHelperTools/com.docker.socket'
 sudo rm -rf '/Library/PrivilegedHelperTools/com.docker.vmnetd'
 sudo rmdir '~/.docker/bin'
+sudo rm -rf '/Applications/Docker.app.back'
+sudo rm -rf /Users/*/Library/'Application Support'/com.docker.install
 sudo rm -rf "$APPDIR/Docker.app"
 sudo rm -rf '/usr/local/bin/docker-credential-ecr-login'
 sudo rm -rf '/usr/local/bin/docker-credential-osxkeychain'
@@ -189,8 +191,11 @@
 trash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.electron.dockerdesktop.sfl*'
 trash $LOGGED_IN_USER '~/Library/Application Support/com.bugsnag.Bugsnag/com.docker.docker'
 trash $LOGGED_IN_USER '~/Library/Application Support/Docker Desktop'
+trash $LOGGED_IN_USER '~/Library/Application Support/docker-secrets-engine'
 trash $LOGGED_IN_USER '~/Library/Caches/com.docker.docker'
 trash $LOGGED_IN_USER '~/Library/Caches/com.plausiblelabs.crashreporter.data/com.docker.docker'
+trash $LOGGED_IN_USER '~/Library/Caches/Docker Desktop'
+trash $LOGGED_IN_USER '~/Library/Caches/docker-secrets-engine'
 trash $LOGGED_IN_USER '~/Library/Caches/KSCrashReports/Docker'
 trash $LOGGED_IN_USER '~/Library/Containers/com.docker.docker'
 trash $LOGGED_IN_USER '~/Library/Containers/com.docker.helper'

@lucasmrod

Copy link
Copy Markdown
Member Author

In general I am not a fan of amending our patch policies to address multiple copies of an app being reported on a device because it creates a false positive where the patch policy will now pass but there is still an old, vulnerable, or potentially exploitable version of the app on the device. I have improved the install and uninstall scripts to hopefully further remove these backup files, including one that gets created at ~/Library/Application Support/com.docker.install/in_progress/Docker.app.

We should merge this as-is for now since the additional % does address a bug. Once this is merged, I will monitor and make sure the install and uninstall scripts are cleaning up all the appropriate files and hopefully get us back to a non custom patch policy.

That is a very good point. Thanks!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

ee/maintained-apps/inputs/homebrew/docker-desktop.json:10

  • post_uninstall_scripts currently removes /Users/*/Library/Application Support/com.docker.install (the entire directory) for all users. The install script’s rationale only requires deleting the staged app bundle at .../com.docker.install/in_progress/Docker.app, so this broader deletion is potentially more destructive than necessary. Consider narrowing the cleanup path to the specific staged bundle and regenerate the corresponding output manifest/scripts.
  "post_uninstall_scripts": [
    "sudo rm -rf '/Applications/Docker.app.back'",
    "sudo rm -rf /Users/*/Library/'Application Support'/com.docker.install"
  ],

@lucasmrod
lucasmrod merged commit 4b8a843 into main Jul 28, 2026
54 checks passed
@lucasmrod
lucasmrod deleted the amend-docker-desktop-patch-policy-sql branch July 28, 2026 17:05
allenhouchins added a commit that referenced this pull request Aug 10, 2026
**Related issue:** Resolves #50875

Docker Desktop on macOS never reported an installed version or
"Installed" status, and offered "Install" on hosts that already had it.

## Root cause

The FMA's `unique_identifier` was `com.electron.dockerdesktop`, which
belongs to the embedded Electron bundle. The installed app reports a
different identifier:

| Path | CFBundleIdentifier |
|---|---|
| `/Applications/Docker.app` | `com.docker.docker` |
| `/Applications/Docker.app/Contents/MacOS/Docker Desktop.app` |
`com.electron.dockerdesktop` |

The identifier was changed from `com.docker.docker` →
`com.electron.dockerdesktop` in #37670 (Jan 5) as "the new bundle
identifier … reflecting the current packaging". The top-level bundle
never changed.

That was latent until #47831 (#44199, Jul 9) added an embedded-bundle
filter to the macOS software inventory query in
`server/service/osquery_utils/queries.go`:

```sql
FROM apps
WHERE path NOT LIKE '%.app/Contents/%'
```

`/Applications/Docker.app/Contents/MacOS/Docker Desktop.app` matches
that pattern, so the only row carrying the embedded identifier is
filtered out and inventory keeps just `/Applications/Docker.app` →
`com.docker.docker`. Since FMA↔inventory matching is by bundle
identifier (`addSoftwareTitleToMatchingSoftware`), the title the FMA
owns had zero installed versions.

**Patch policies kept passing**, because they run the FMA's
`exists`/`patched` SQL directly against the host's *unfiltered* `apps`
table. That's also why #50041 needed a `.back` path exclusion, and why
patch status and the software UI have disagreed since July.

## What changed

**Catalog** — `unique_identifier` is now `com.docker.docker`, with
`docker-desktop/darwin.json` regenerated. `outputs/apps.json` needed a
hand-edit because `updateAppsListFile` (`cmd/maintained-apps/main.go`)
only appends new apps and never updates an existing entry's identifier —
filed separately.

The remaining `com.electron.dockerdesktop` references are intentional
and untouched: the install script's quit/relaunch targets (the Electron
bundle is what responds to AppleScript) and the cask's zap paths. The
`.back` exclusion in the patched query also stays —
`/Applications/Docker.app.back` is a *top-level* bundle reporting
`com.docker.docker` at a path the nested-bundle filter does not match,
so a stale `.back` would otherwise show a false "Update available".

**Migration** (`20260810152924_FixDockerDesktopBundleIdentifier`) —
`fleet_maintained_apps` self-heals on catalog sync
(`UpsertMaintainedApp` updates `unique_identifier` on duplicate slug)
and `ReconcileMaintainedAppSoftwareNames` renames the existing "Docker"
title, but an already-added installer's `software_installers.title_id`
binding does not:

- **No `com.docker.docker` title yet** → relabel the stale title in
place, so everything already pointing at it stays correct.
- **Title already exists** (the normal case — any host with Docker
creates it) → merge the stale title into it: installer, install history,
queued installs, patch policy, `software.title_id`, and per-team
settings (icons, display names, pins, update schedules), then drop the
stale title.

## Notes for reviewers

- **Teams that already have an installer on the target title are
skipped** rather than ending up with two installers on one title.
`dedup_token` is the *version* for FMAs and the *storage_id* otherwise,
so `idx_software_installers_dedup` would not have caught that collision.
Those teams keep the pre-migration state instead of having data silently
reshaped.
- **The stale title is only deleted once nothing depends on it.**
`fk_software_installers_title` is `ON DELETE SET NULL`, so deleting it
while an installer still pointed at it would orphan that installer. Note
also that `fk_patch_software_title_id` is `ON DELETE CASCADE` —
re-pointing the patch policy is what keeps it from being deleted
outright.
- **Dangling-reference check:** the only title-referencing columns
without an FK to `software_titles` are `software.title_id` (re-pointed),
`software_titles_host_counts` (deleted; the cron recomputes), and
`kernel_host_counts` / `in_house_app_install_tokens`, neither of which
can hold a macOS app title.
- **Naming lags briefly.** The existing title is named "Docker" (from
osquery); `ReconcileMaintainedAppSoftwareNames` renames it to "Docker
Desktop" on the next catalog sync, so there is a window after upgrade
where the name is still "Docker". I left that to the sync rather than
duplicating the rename logic in the migration.
- **This fixes one app, not the class.** Any other macOS FMA keyed on a
nested bundle fails the same silent way, and a green patch policy will
not reveal it. An audit is filed separately.

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`.
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements).
Table/column names in the migration's generated SQL come from hardcoded
struct literals, never from data; all values are placeholders.

## Testing

- [x] Added/updated automated tests

Five migration tests cover: relabel-in-place,
merge-into-inventory-title, duplicate per-team settings dropped, teams
with an existing installer skipped (and the stale title consequently
retained), and no-op when the FMA was never added. The merge test also
asserts `updated_at` is not restamped. Updated the homebrew ingester
test expectations for the new identifier.

Verified: full `server/datastore/mysql/migrations/tables` suite passes
(201s), `ee/maintained-apps/...`, `cmd/maintained-apps/...`, and the FMA
datastore tests pass, `make lint-go-incremental` clean.

Root cause was confirmed against real bundles rather than inferred —
`PlistBuddy` on both Docker bundles for the identifiers above, and
`lsregister -dump` to confirm LaunchServices registers the nested
bundles (which is why the raw `apps` table sees them and patch policies
pass).

- [ ] QA'd all new/changed functionality manually

Needs QA on a real instance: add the Docker Desktop FMA, confirm the
installed version and "Installed" status appear on a host that already
has it, and confirm an upgrade over an instance that already had the FMA
added re-points the existing installer.

For unreleased bug fixes in a release candidate, one of:

- [x] Confirmed that the fix is not expected to adversely impact load
test results

The migration touches only rows tied to a single software title, and is
a no-op on instances that never added the Docker Desktop FMA.

## Database migrations

- [x] Checked schema for all modified table for columns that will
auto-update timestamps during migration.
- [x] Confirmed that updating the timestamps is acceptable, and will not
cause unwanted side effects.

Five of the written tables have `updated_at` as `ON UPDATE
CURRENT_TIMESTAMP`: `software_installers`, `host_software_installs`,
`software_install_upcoming_activities`, `policies`, and
`software_title_team_pins`. Since this re-points a foreign key rather
than modifying the records, each statement assigns `updated_at =
updated_at` so MySQL leaves them alone, with a test asserting it.
(Bumping them would have been cosmetic — none of these columns drives
ordering, scheduling, or invalidation; policy membership uses
`policy_membership.updated_at` and `hosts.policy_updated_at`, and the
activity feed orders by the activities table — but preserving them is
more faithful to what the migration actually does.)

- [x] Ensured the correct collation is explicitly set for character
columns (`COLLATE utf8mb4_unicode_ci`). No columns added or altered;
this is a data-only migration.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved macOS Docker Desktop detection so installed versions and
“Installed” status are reported accurately.
* Ensured existing Docker Desktop installations and upgrade history
remain correctly associated after detection updates.
* Improved handling of stale application bundles during patch
evaluation.
* **Maintenance**
* Updated detection data and migration coverage to support the corrected
Docker Desktop identification.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants