Skip to content

Update Docker Desktop FMA install script - #45244

Merged
allenhouchins merged 4 commits into
mainfrom
45242-show-update-available-status-library-and-self-service-only-if-the-top-level-app-is-outdated
May 13, 2026
Merged

Update Docker Desktop FMA install script#45244
allenhouchins merged 4 commits into
mainfrom
45242-show-update-available-status-library-and-self-service-only-if-the-top-level-app-is-outdated

Conversation

@allenhouchins

@allenhouchins allenhouchins commented May 12, 2026

Copy link
Copy Markdown
Member

This pull request improves the handling and installation of Docker Desktop in Fleet, with a focus on addressing issues caused by leftover .back app bundles after in-app updates. It also introduces a custom installation script for Docker Desktop to ensure correct app replacement and relaunch behavior. The test coverage and configuration for Docker Desktop have been updated accordingly.

Docker Desktop patch policy and installation improvements:

  • Updated the patch policy query for Docker Desktop in ingester.go to ignore any .back app bundles, preventing false "out of date" patch status when stale bundles are present after self-updates.
  • Added a custom install script (docker_desktop_install.sh) that safely quits Docker Desktop, removes .back bundles, moves the new app into place, relaunches the app if it was running, and sets up CLI symlinks.
  • Linked the new install script in the Docker Desktop Homebrew input JSON (docker-desktop.json).
  • Updated the Docker Desktop output JSON to use the improved patch query and reference the new install script.

Test enhancements:

  • Expanded test coverage in ingester_test.go to include Docker Desktop, verifying the correct patch and exists queries for this special case. [1] [2] [3]

Support providing a custom patch policy file to the Homebrew ingester: if input.PatchPolicyPath is set the ingester reads the file, substitutes __VERSION__ and uses that as the patched query; otherwise it generates the policy as before. Tests updated to cover the override behavior. Add Docker Desktop-specific assets: input JSON now references an install script and patch policy, a patch SQL file and a bash install script are added, and the darwin output is updated to ignore Docker.app.back bundles in the patched query and to point to the new install script ref.
fleet-release
fleet-release previously approved these changes May 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Script Diff Results

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

=== Install // fe655671 -> 1c6cc2fd ===

--- /tmp/old.etPIo7	2026-05-12 16:13:07.381713401 +0000
+++ /tmp/new.4xkAnA	2026-05-12 16:13:07.381713401 +0000
@@ -104,6 +104,11 @@
 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.
+sudo rm -rf "$APPDIR/Docker.app.back"
 sudo cp -R "$TMPDIR/Docker.app" "$APPDIR"
 relaunch_application 'com.electron.dockerdesktop'
 mkdir -p /usr/local/cli-plugins

=== Uninstall Script (no changes) ===

Simplify Homebrew ingester by removing support for a provided patch policy file: always call patch_policy.GenerateQueryForManifest to populate out.Queries.Patched. Update tests accordingly (remove temporary patch policy file and related assertions). Remove the docker_desktop.sql input file and its reference in the docker-desktop input JSON, and adjust the expected docker-desktop output patched query to match the generated query (removed the path NOT LIKE '%.back' condition).
@allenhouchins allenhouchins changed the title Add patch policy path and Docker Desktop scripts Update Docker Desktop FMA install script May 12, 2026
fleet-release
fleet-release previously approved these changes May 12, 2026
Handle Docker Desktop's updater creating Docker.app.back by excluding paths ending with `.back` when computing patch status. Adds a special-case patched query in the Homebrew ingester to ignore `.back` installs, updates unit tests to cover the `docker-desktop` token and assert the modified query, and updates the docker-desktop darwin output fixture to match the new SQL that filters out `%.back` paths.
@codecov

codecov Bot commented May 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 66.77%. Comparing base (117a137) to head (136abf1).
⚠️ Report is 22 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #45244      +/-   ##
==========================================
+ Coverage   66.73%   66.77%   +0.03%     
==========================================
  Files        2732     2728       -4     
  Lines      218551   218358     -193     
  Branches    10803    10613     -190     
==========================================
- Hits       145857   145802      -55     
+ Misses      59480    59388      -92     
+ Partials    13214    13168      -46     
Flag Coverage Δ
backend 68.63% <100.00%> (+0.06%) ⬆️

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

☔ View full report in Codecov by Sentry.
📢 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.

…nd-self-service-only-if-the-top-level-app-is-outdated
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: test-go (mysql, mysql:9.5.0) / test

Failed stage: Run Go Tests [❌]

Failed test name: TestJobs/QueueAndProcessJobs

Failure summary:

The action failed during make .run-go-tests PKG_TO_TEST="./server/datastore/mysql/..." because the
MySQL-backed Go test suite lost its database connection mid-run.
- The first clear failure is
TestJobs/QueueAndProcessJobs in server/datastore/mysql/jobs_test.go (errors at lines 40 and 90),
reporting invalid connection and MySQL driver packets.go:58 unexpected EOF.
- After the initial DB
disconnect, many subsequent tests fail with the same root cause (e.g., create transaction: invalid
connection from server/platform/mysql/testing_utils/testing_utils.go:60 via
server/datastore/mysql/testing_utils.go:465), indicating the MySQL container/connection became
unusable for the remainder of the run.
- The job ends with make[1]: *** [Makefile:280:
.run-go-tests] Error 1 and make: *** [Makefile:395: test-go] Error 2 due to the test failures.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

1541:  �[36;1mattempt=1�[0m
1542:  �[36;1m�[0m
1543:  �[36;1mwhile [ $attempt -le $max_attempts ]; do�[0m
1544:  �[36;1m  echo "Attempt $attempt of $max_attempts"�[0m
1545:  �[36;1m�[0m
1546:  �[36;1m  # Try to connect to MySQL�[0m
1547:  �[36;1m  if wait_for_mysql "mysql_test"; then�[0m
1548:  �[36;1m    # If MySQL is ready, try to connect to MySQL replica�[0m
1549:  �[36;1m    if wait_for_mysql "mysql_replica_test"; then�[0m
1550:  �[36;1m      # Both are ready, we're done�[0m
1551:  �[36;1m      echo "All MySQL connections successful"�[0m
1552:  �[36;1m      exit 0�[0m
1553:  �[36;1m    fi�[0m
1554:  �[36;1m  fi�[0m
1555:  �[36;1m�[0m
1556:  �[36;1m  # If we get here, at least one connection failed�[0m
1557:  �[36;1m  echo "Failed to connect to MySQL on attempt $attempt"�[0m
1558:  �[36;1m�[0m
1559:  �[36;1m  if [ $attempt -lt $max_attempts ]; then�[0m
1560:  �[36;1m    echo "Restarting containers and trying again..."�[0m
1561:  �[36;1m    restart_containers�[0m
1562:  �[36;1m  else�[0m
1563:  �[36;1m    echo "Maximum attempts reached. Failing the job."�[0m
1564:  �[36;1m    exit 1�[0m
...

1617:  RACE_ENABLED: false
1618:  GO_TEST_TIMEOUT: 20m
1619:  DOCKER_COMMAND: docker compose -f docker-compose.yml -f docker-compose-redis-cluster.yml up -d mysql_test mysql_replica_test redis redis-cluster-1 redis-cluster-2 redis-cluster-3 redis-cluster-4 redis-cluster-5 redis-cluster-6 redis-cluster-setup s3 saml_idp mailhog mailpit smtp4dev_test
1620:  RUN_TESTS_ARG: 
1621:  CI_TEST_PKG: mysql
1622:  NEED_DOCKER: 1
1623:  ARTIFACT_PREFIX: mysql-mysql9.5.0
1624:  GOTOOLCHAIN: local
1625:  FLEET_PREVIEW_TAG: main
1626:  ##[endgroup]
1627:  make .run-go-tests PKG_TO_TEST="./server/datastore/mysql/..."
1628:  make[1]: Entering directory '/home/runner/work/fleet/fleet'
1629:  Running Go tests with gotestsum:
1630:  gotestsum --format=testdox --jsonfile=/tmp/test-output.json -- -tags full,fts5,netgo -run=  -v -race=false -timeout=20m  -parallel 8 -coverprofile=coverage.txt -covermode=atomic -coverpkg=github.com/fleetdm/fleet/v4/... ././server/datastore/mysql/... 
1631:  go: downloading github.com/aws/aws-sdk-go-v2 v1.41.5
1632:  go: downloading github.com/pkg/errors v0.9.1
1633:  go: downloading github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.6.16
1634:  go: downloading github.com/shogo82148/rdsmysql/v2 v2.5.0
1635:  go: downloading github.com/go-sql-driver/mysql v1.9.3
1636:  go: downloading github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f
1637:  go: downloading github.com/WatchBeam/clock v0.0.0-20170901150240-b08e6b4da7ea
1638:  go: downloading github.com/XSAM/otelsql v0.39.0
1639:  go: downloading github.com/cenkalti/backoff/v4 v4.3.0
1640:  go: downloading github.com/doug-martin/goqu/v9 v9.18.0
1641:  go: downloading github.com/google/go-cmp v0.7.0
1642:  go: downloading github.com/google/uuid v1.6.0
1643:  go: downloading github.com/hashicorp/go-multierror v1.1.1
1644:  go: downloading github.com/jmoiron/sqlx v1.3.5
...

1771:  go: downloading github.com/googleapis/gax-go/v2 v2.17.0
1772:  go: downloading go.opencensus.io v0.24.0
1773:  go: downloading google.golang.org/grpc v1.79.3
1774:  go: downloading google.golang.org/protobuf v1.36.11
1775:  go: downloading github.com/nats-io/nkeys v0.4.15
1776:  go: downloading github.com/nats-io/nuid v1.0.1
1777:  go: downloading github.com/armon/go-radix v1.0.0
1778:  go: downloading go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352
1779:  go: downloading github.com/go-logfmt/logfmt v0.5.1
1780:  go: downloading cloud.google.com/go/pubsub/v2 v2.0.0
1781:  go: downloading github.com/gorilla/schema v1.4.1
1782:  go: downloading google.golang.org/genproto/googleapis/rpc v0.0.0-20260319201613-d00831a3d3e7
1783:  go: downloading cloud.google.com/go/compute/metadata v0.9.0
1784:  go: downloading google.golang.org/genproto v0.0.0-20260128011058-8636f8732409
1785:  go: downloading google.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20
1786:  go: downloading github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901
1787:  go: downloading github.com/prometheus/procfs v0.15.1
...

1846:  �[32m✓�[0m Activity list host upcoming activities 1: fleet. list options{ page: 0x 1, per page: 0x 4, order key:"", order direction: 0, match query:"", after:"", include metadata:false, test secondary order key:"", test secondary order direction: 0} (0.01s)
1847:  �[32m✓�[0m Activity list host upcoming activities 1: fleet. list options{ page: 0x 2, per page: 0x 2, order key:"", order direction: 0, match query:"", after:"", include metadata:false, test secondary order key:"", test secondary order direction: 0} (0.01s)
1848:  �[32m✓�[0m Activity list host upcoming activities 1: fleet. list options{ page: 0x 2, per page: 0x 4, order key:"", order direction: 0, match query:"", after:"", include metadata:false, test secondary order key:"", test secondary order direction: 0} (0.01s)
1849:  �[32m✓�[0m Activity list host upcoming activities 1: fleet. list options{ page: 0x 3, per page: 0x 2, order key:"", order direction: 0, match query:"", after:"", include metadata:false, test secondary order key:"", test secondary order direction: 0} (0.01s)
1850:  �[32m✓�[0m Activity list host upcoming activities 1: fleet. list options{ page: 0x 3, per page: 0x 4, order key:"", order direction: 0, match query:"", after:"", include metadata:false, test secondary order key:"", test secondary order direction: 0} (0.00s)
1851:  �[32m✓�[0m Activity list host upcoming activities 1: fleet. list options{ page: 0x 4, per page: 0x 2, order key:"", order direction: 0, match query:"", after:"", include metadata:false, test secondary order key:"", test secondary order direction: 0} (0.01s)
1852:  �[32m✓�[0m Activity list host upcoming activities 2: fleet. list options{ page: 0x 0, per page: 0x 5, order key:"", order direction: 0, match query:"", after:"", include metadata:false, test secondary order key:"", test secondary order direction: 0} (0.00s)
1853:  �[32m✓�[0m Activity list host upcoming activities 3: fleet. list options{ page: 0x 0, per page: 0x 0, order key:"", order direction: 0, match query:"", after:"", include metadata:false, test secondary order key:"", test secondary order direction: 0} (0.00s)
1854:  �[32m✓�[0m Activity list host upcoming activities 4: fleet. list options{ page: 0x 0, per page: 0x 0, order key:"", order direction: 0, match query:"", after:"", include metadata:false, test secondary order key:"", test secondary order direction: 0} (0.00s)
1855:  �[32m✓�[0m Activity list host upcoming activities rejects unknown order key (0.00s)
1856:  �[32m✓�[0m Activity set result after cancel upcoming activity (1.08s)
1857:  �[32m✓�[0m Activity unblock hosts upcoming activity queue (1.14s)
1858:  �[32m✓�[0m Activity username change (0.94s)
1859:  �[32m✓�[0m Aggregated stats (2.45s)
1860:  �[32m✓�[0m Aggregated stats queries (0.69s)
1861:  �[32m✓�[0m Already exists error (0.00s)
1862:  �[32m✓�[0m Already exists error is error (0.00s)
1863:  �[32m✓�[0m Already exists error with team ID (0.00s)
1864:  �[32m✓�[0m Already exists error with team name (0.00s)
1865:  �[32m✓�[0m Android (35.44s)
1866:  �[32m✓�[0m Android add delete android app with configuration (1.17s)
1867:  �[32m✓�[0m Android android BYOD detection (0.98s)
1868:  �[32m✓�[0m Android android BYOD detection company enrollment (0.01s)
1869:  �[32m✓�[0m Android android BYOD detection personal enrollment with UUID (0.02s)
1870:  �[32m✓�[0m Android android BYOD detection update existing host enrollment status (0.02s)
1871:  �[32m✓�[0m Android android MDM stats (1.37s)
1872:  �[32m✓�[0m Android android app configuration cascade delete team (0.96s)
1873:  �[32m✓�[0m Android android app configuration global vs team (0.89s)
1874:  �[32m✓�[0m Android android host storage data (1.02s)
1875:  �[32m✓�[0m Android batch set MDM android profiles associations (0.83s)
1876:  �[32m✓�[0m Android bulk delete MDM android host profiles (0.85s)
1877:  �[32m✓�[0m Android bulk delete MDM android host profiles deletes pending or failed remove profiles with policy version lower than or equal to passed (0.01s)
1878:  �[32m✓�[0m Android bulk delete MDM android host profiles does not delete install operation types (0.01s)
...

1913:  �[32m✓�[0m Android has android app configuration changed (0.87s)
1914:  �[32m✓�[0m Android has android app configuration changed boolean instead of object (0.00s)
1915:  �[32m✓�[0m Android has android app configuration changed empty compared to non-existing (0.00s)
1916:  �[32m✓�[0m Android has android app configuration changed empty managed configuration (0.00s)
1917:  �[32m✓�[0m Android has android app configuration changed empty new config (0.00s)
1918:  �[32m✓�[0m Android has android app configuration changed empty object (0.00s)
1919:  �[32m✓�[0m Android has android app configuration changed expanded different config (0.00s)
1920:  �[32m✓�[0m Android has android app configuration changed same config (0.00s)
1921:  �[32m✓�[0m Android has android app configuration changed slightly different config (0.00s)
1922:  �[32m✓�[0m Android has android app configuration changed some config compared to non-existing (0.00s)
1923:  �[32m✓�[0m Android has android app configuration changed very different config (0.00s)
1924:  �[32m✓�[0m Android insert and get android app configuration (0.86s)
1925:  �[32m✓�[0m Android list MDM android profiles to send (1.16s)
1926:  �[32m✓�[0m Android list MDM android profiles to send with exclude any (1.22s)
1927:  �[32m✓�[0m Android list host MDM android profiles pending install with version (0.87s)
1928:  �[32m✓�[0m Android list host MDM android profiles pending install with version does list pending install profiles and failed install profiles with can reverify (0.01s)
1929:  �[32m✓�[0m Android list host MDM android profiles pending install with version does list pending install profiles with version less than or equal to applied policy version (0.01s)
...

1988:  �[32m✓�[0m Campaigns cleanup completed campaign targets (0.98s)
1989:  �[33m∅�[0m Campaigns cleanup completed campaign targets large batch (0.69s)
1990:  �[32m✓�[0m Campaigns cleanup distributed query (0.91s)
1991:  �[32m✓�[0m Campaigns completed campaigns (1.06s)
1992:  �[32m✓�[0m Campaigns distributed query (0.88s)
1993:  �[32m✓�[0m Campaigns save distributed query (0.84s)
1994:  �[32m✓�[0m Carves (6.49s)
1995:  �[32m✓�[0m Carves blocks (1.03s)
1996:  �[32m✓�[0m Carves cleanup (0.98s)
1997:  �[32m✓�[0m Carves list (1.00s)
1998:  �[32m✓�[0m Carves list allowed order block count (0.00s)
1999:  �[32m✓�[0m Carves list allowed order block size (0.00s)
2000:  �[32m✓�[0m Carves list allowed order carve id (0.00s)
2001:  �[32m✓�[0m Carves list allowed order carve size (0.00s)
2002:  �[32m✓�[0m Carves list allowed order created at (0.00s)
2003:  �[32m✓�[0m Carves list allowed order error (0.00s)
2004:  �[32m✓�[0m Carves list allowed order expired (0.00s)
...

2006:  �[32m✓�[0m Carves list allowed order id (0.00s)
2007:  �[32m✓�[0m Carves list allowed order max block (0.00s)
2008:  �[32m✓�[0m Carves list allowed order name (0.00s)
2009:  �[32m✓�[0m Carves list allowed order request id (0.00s)
2010:  �[32m✓�[0m Carves list allowed order session id (0.00s)
2011:  �[32m✓�[0m Carves list rejects unknown key (0.00s)
2012:  �[32m✓�[0m Carves metadata (0.90s)
2013:  �[32m✓�[0m Carves update (0.89s)
2014:  �[32m✓�[0m Certificate authority (6.62s)
2015:  �[32m✓�[0m Certificate authority create certificate authority (0.96s)
2016:  �[32m✓�[0m Certificate authority delete (0.84s)
2017:  �[32m✓�[0m Certificate authority get all certificate authorities (0.81s)
2018:  �[32m✓�[0m Certificate authority get certificate authority by ID (0.82s)
2019:  �[32m✓�[0m Certificate authority list certificate authorities (0.85s)
2020:  �[32m✓�[0m Certificate authority update certificate authority by ID (0.83s)
2021:  �[32m✓�[0m Certificate authority update certificate authority by ID fails if certificate authority is not found (0.00s)
2022:  �[32m✓�[0m Certificate authority update certificate authority by ID successfully updates custom SCEP proxy CA (0.01s)
2023:  �[32m✓�[0m Certificate authority update certificate authority by ID successfully updates custom est proxy CA (0.01s)
2024:  �[32m✓�[0m Certificate authority update certificate authority by ID successfully updates digicert CA (0.01s)
2025:  �[32m✓�[0m Certificate authority update certificate authority by ID successfully updates hydrant CA (0.01s)
2026:  �[32m✓�[0m Certificate authority update certificate authority by ID successfully updates ndes scep proxy CA (0.01s)
2027:  �[32m✓�[0m Certificate authority update certificate authority by ID successfully updates smallstep SCEP proxy CA (0.01s)
2028:  �[32m✓�[0m Certificates (17.10s)
2029:  �[32m✓�[0m Certificates batch delete certificate templates (1.10s)
2030:  �[32m✓�[0m Certificates batch delete certificate templates delete existing certificates (0.56s)
2031:  �[32m✓�[0m Certificates batch delete certificate templates empty slice (0.53s)
2032:  �[32m✓�[0m Certificates batch upsert certificates (1.68s)
2033:  �[32m✓�[0m Certificates batch upsert certificates create certificates (0.52s)
2034:  �[32m✓�[0m Certificates batch upsert certificates empty slice (0.54s)
2035:  �[32m✓�[0m Certificates batch upsert certificates upsert existing certificates (0.61s)
2036:  �[32m✓�[0m Certificates create certificate template (1.78s)
2037:  �[32m✓�[0m Certificates create certificate template certificate template exists, fails to create (0.87s)
2038:  �[32m✓�[0m Certificates create certificate template create certificate template (0.92s)
2039:  �[32m✓�[0m Certificates delete certificate template (1.06s)
2040:  �[32m✓�[0m Certificates delete certificate template delete existing certificate template (0.54s)
2041:  �[32m✓�[0m Certificates delete certificate template delete non-existing certificate template (0.52s)
2042:  �[32m✓�[0m Certificates get certificate template by id (3.42s)
2043:  �[32m✓�[0m Certificates get certificate template by id get existing certificate template (0.86s)
2044:  �[32m✓�[0m Certificates get certificate template by id no existing certificate template (0.83s)
2045:  �[32m✓�[0m Certificates get certificate template by id template with pending host certificate template (0.87s)
2046:  �[32m✓�[0m Certificates get certificate template by id template with verified host certificate template (0.86s)
2047:  �[32m✓�[0m Certificates get certificate template for host (0.59s)
2048:  �[32m✓�[0m Certificates get certificate template for host returns certificate template for host with host certificate template record (0.00s)
2049:  �[32m✓�[0m Certificates get certificate template for host returns certificate template for host without host certificate template record (0.00s)
2050:  �[32m✓�[0m Certificates get certificate template for host returns error for non-existent certificate template (0.00s)
2051:  �[32m✓�[0m Certificates get certificate template for host returns error for non-existent host (0.00s)
2052:  �[32m✓�[0m Certificates get certificate template for host returns error when certificate template doesn't belong to host's team (0.00s)
2053:  �[32m✓�[0m Certificates get certificate templates by ids and team (1.48s)
...

2058:  �[32m✓�[0m Certificates get certificate templates by team ID get existing certificate templates for team (0.67s)
2059:  �[32m✓�[0m Certificates get certificate templates by team ID no existing certificate templates for team (0.75s)
2060:  �[32m✓�[0m Certificates get certificate templates by team ID pagination works (0.57s)
2061:  �[32m✓�[0m Certificates get host certificate template record (0.60s)
2062:  �[32m✓�[0m Certificates get host certificate template record returns not found for non-existent host (0.00s)
2063:  �[32m✓�[0m Certificates get host certificate template record returns not found for non-existent template (0.00s)
2064:  �[32m✓�[0m Certificates get host certificate template record returns record even after parent certificate template is deleted (0.01s)
2065:  �[32m✓�[0m Certificates get host certificate template record returns record when it exists (0.00s)
2066:  �[32m✓�[0m Certificates get host certificate templates (0.58s)
2067:  �[32m✓�[0m Certificates get host certificate templates host UUID is not provided (0.00s)
2068:  �[32m✓�[0m Certificates get host certificate templates no certificate templates found (0.00s)
2069:  �[32m✓�[0m Certificates get host certificate templates returns the certificates available for the host (0.00s)
2070:  �[32m✓�[0m Certificates resend host certificate template (0.67s)
2071:  �[32m✓�[0m Certificates resend host certificate template clears validity fields and deletes challenge (0.02s)
2072:  �[32m✓�[0m Certificates resend host certificate template from delivered (0.01s)
2073:  �[32m✓�[0m Certificates resend host certificate template from failed (0.01s)
2074:  �[32m✓�[0m Certificates resend host certificate template from verified (0.01s)
2075:  �[32m✓�[0m Certificates resend host certificate template returns error for non-existent host (0.00s)
2076:  �[32m✓�[0m Certificates resend host certificate template returns error for non-existent template (0.00s)
2077:  �[32m✓�[0m Cleanup cron stats (1.57s)
...

2089:  �[32m✓�[0m Compare versions equal (0.00s)
2090:  �[32m✓�[0m Compare versions equal-out-of-order (0.00s)
2091:  �[32m✓�[0m Compare versions known-unknown (0.00s)
2092:  �[32m✓�[0m Compare versions missing (0.00s)
2093:  �[32m✓�[0m Compare versions missing-and-unknown (0.00s)
2094:  �[32m✓�[0m Compare versions unknown (0.00s)
2095:  �[32m✓�[0m Compare versions unknowns (0.00s)
2096:  �[32m✓�[0m Conditional access (3.54s)
2097:  �[32m✓�[0m Conditional access SCEP (4.68s)
2098:  �[32m✓�[0m Conditional access SCEP certificate lifecycle (0.77s)
2099:  �[32m✓�[0m Conditional access SCEP expired certs not returned (0.79s)
2100:  �[32m✓�[0m Conditional access SCEP get cert by serial and created at (0.82s)
2101:  �[32m✓�[0m Conditional access SCEP revoked certs not returned (0.73s)
2102:  �[32m✓�[0m Conditional access bypass (9.00s)
2103:  �[32m✓�[0m Conditional access bypass conditional access bypass allowed with CA enabled non critical policy (0.89s)
2104:  �[32m✓�[0m Conditional access bypass conditional access bypass allowed with non CA failing critical policy (0.87s)
2105:  �[32m✓�[0m Conditional access bypass conditional access bypass deleted with host (0.94s)
...

2123:  �[32m✓�[0m Disk encryption (3.32s)
2124:  �[32m✓�[0m Disk encryption test cleanup disk encryption keys on team change (0.95s)
2125:  �[32m✓�[0m Disk encryption test delete LUKS data (0.88s)
2126:  �[32m✓�[0m Email changes (2.61s)
2127:  �[32m✓�[0m Email changes confirm (0.96s)
2128:  �[32m✓�[0m Extract windows build version (0.00s)
2129:  �[32m✓�[0m Extract windows build version empty string (0.00s)
2130:  �[32m✓�[0m Extract windows build version leading whitespace (0.00s)
2131:  �[32m✓�[0m Extract windows build version no spaces (0.00s)
2132:  �[32m✓�[0m Extract windows build version single word (0.00s)
2133:  �[32m✓�[0m Extract windows build version trailing whitespace (0.00s)
2134:  �[32m✓�[0m Extract windows build version windows 10 pro (0.00s)
2135:  �[32m✓�[0m Extract windows build version windows server 2025 datacenter (0.00s)
2136:  �[32m✓�[0m Get MDM apple OS updates settings by host serial (2.00s)
2137:  �[32m✓�[0m Get context try stmt (0.00s)
2138:  �[32m✓�[0m Get context try stmt get with other error (0.00s)
2139:  �[32m✓�[0m Get context try stmt get with unknown statement error (0.00s)
2140:  �[32m✓�[0m Get host operating system (1.34s)
2141:  �[32m✓�[0m Get latest cron stats (1.53s)
2142:  �[32m✓�[0m Health check detects read only (0.00s)
2143:  �[32m✓�[0m Host DEPAs signments (2.12s)
2144:  �[32m✓�[0m Host DEPAs signments DEP enrollment (0.20s)
2145:  �[32m✓�[0m Host DEPAs signments DEP enrollment with migration (0.20s)
2146:  �[32m✓�[0m Host DEPAs signments manual enrollment (0.05s)
2147:  �[32m✓�[0m Host certificate templates (37.95s)
2148:  �[32m✓�[0m Host certificate templates bulk insert and delete host certificate templates (4.17s)
2149:  �[32m✓�[0m Host certificate templates bulk insert and delete host certificate templates bulk inserts and deletes specific records (0.81s)
2150:  �[32m✓�[0m Host certificate templates bulk insert and delete host certificate templates deletes multiple records at once (0.88s)
2151:  �[32m✓�[0m Host certificate templates bulk insert and delete host certificate templates no error when deleting non-existent records (0.89s)
2152:  �[32m✓�[0m Host certificate templates bulk insert and delete host certificate templates no error with empty list (0.81s)
2153:  �[32m✓�[0m Host certificate templates certificate template full state machine (0.59s)
2154:  �[32m✓�[0m Host certificate templates certificate template reinstalled after transfer back to original team (0.58s)
2155:  �[32m✓�[0m Host certificate templates create pending certificate templates for existing hosts (2.27s)
2156:  �[32m✓�[0m Host certificate templates create pending certificate templates for existing hosts creates pending records for all enrolled android hosts in team (0.58s)
2157:  �[32m✓�[0m Host certificate templates create pending certificate templates for existing hosts does not create records for non-android hosts (0.56s)
2158:  �[32m✓�[0m Host certificate templates create pending certificate templates for existing hosts does not create records for unenrolled hosts (0.54s)
2159:  �[32m✓�[0m Host certificate templates create pending certificate templates for new host (2.24s)
2160:  �[32m✓�[0m Host certificate templates create pending certificate templates for new host creates pending records for newly enrolled host (0.57s)
2161:  �[32m✓�[0m Host certificate templates create pending certificate templates for new host no-op when team has no certificate templates (0.56s)
2162:  �[32m✓�[0m Host certificate templates create pending certificate templates for new host resets verified certs to pending on re-enrollment (0.56s)
2163:  �[32m✓�[0m Host certificate templates delete host certificate template (2.17s)
2164:  �[32m✓�[0m Host certificate templates delete host certificate template no error when deleting non-existent record (0.79s)
2165:  �[32m✓�[0m Host certificate templates delete host certificate template only deletes specified record (0.72s)
2166:  �[32m✓�[0m Host certificate templates get and transition certificate templates to delivering includes removal (0.59s)
2167:  �[32m✓�[0m Host certificate templates get android certificate templates for renewal (0.64s)
2168:  �[32m✓�[0m Host certificate templates get certificate template for host no team (3.61s)
2169:  �[32m✓�[0m Host certificate templates get certificate template for host no team returns certificate template for host with team (0.91s)
2170:  �[32m✓�[0m Host certificate templates get certificate template for host no team returns certificate template for no team host (0.97s)
2171:  �[32m✓�[0m Host certificate templates get certificate template for host no team returns not found for non-existent host (0.89s)
2172:  �[32m✓�[0m Host certificate templates get or create fleet challenge for certificate template (0.56s)
2173:  �[32m✓�[0m Host certificate templates get or create fleet challenge for certificate template creates challenge on first call and returns same on subsequent calls (0.01s)
2174:  �[32m✓�[0m Host certificate templates get or create fleet challenge for certificate template returns error for non-delivered status (0.01s)
2175:  �[32m✓�[0m Host certificate templates get or create fleet challenge for certificate template returns error for non-existent template (0.00s)
2176:  �[32m✓�[0m Host certificate templates list android host UUIDs with deliverable certificate templates (5.45s)
...

2184:  �[32m✓�[0m Host certificate templates list android host UUIDs with pending certificate templates includes removal (0.56s)
2185:  �[32m✓�[0m Host certificate templates list android host UUIDs with pending certificate templates respects pagination (0.58s)
2186:  �[32m✓�[0m Host certificate templates list android host UUIDs with pending certificate templates returns hosts with pending install certificates (0.55s)
2187:  �[32m✓�[0m Host certificate templates list certificate templates for hosts (3.65s)
2188:  �[32m✓�[0m Host certificate templates list certificate templates for hosts host with existing host certificate templates (0.94s)
2189:  �[32m✓�[0m Host certificate templates list certificate templates for hosts host with no existing host certificate templates (0.96s)
2190:  �[32m✓�[0m Host certificate templates list certificate templates for hosts includes removal after team transfer (0.57s)
2191:  �[32m✓�[0m Host certificate templates list certificate templates for hosts no team host returns no team certificate templates (0.88s)
2192:  �[32m✓�[0m Host certificate templates retry host certificate template (0.54s)
2193:  �[32m✓�[0m Host certificate templates revert stale certificate templates (2.15s)
2194:  �[32m✓�[0m Host certificate templates revert stale certificate templates does not revert non-delivering statuses (0.56s)
2195:  �[32m✓�[0m Host certificate templates revert stale certificate templates returns zero when no stale templates (0.51s)
2196:  �[32m✓�[0m Host certificate templates revert stale certificate templates reverts stale delivering templates (0.52s)
2197:  �[32m✓�[0m Host certificate templates set android certificate templates for renewal (0.58s)
2198:  �[32m✓�[0m Host certificate templates set host certificate templates to pending remove (2.16s)
2199:  �[32m✓�[0m Host certificate templates set host certificate templates to pending remove deletes pending and failed rows and updates others to pending remove (0.56s)
2200:  �[32m✓�[0m Host certificate templates set host certificate templates to pending remove for host (0.55s)
2201:  �[32m✓�[0m Host certificate templates set host certificate templates to pending remove for host deletes pending and failed installs, updates other installs, leaves removes unchanged (0.03s)
2202:  �[32m✓�[0m Host certificate templates set host certificate templates to pending remove handles no matching rows gracefully (0.54s)
...

2272:  �[32m✓�[0m Hosts enroll orbit scenario c ubuntu (0.02s)
2273:  �[32m✓�[0m Hosts enroll orbit scenario c windows (0.02s)
2274:  �[32m✓�[0m Hosts enroll orbit scenario d darwin (3.06s)
2275:  �[32m✓�[0m Hosts enroll orbit scenario d ubuntu (3.09s)
2276:  �[32m✓�[0m Hosts enroll orbit scenario d windows (3.06s)
2277:  �[32m✓�[0m Hosts enroll orbit scenario e from darwin to darwin (3.07s)
2278:  �[32m✓�[0m Hosts enroll orbit scenario e from darwin to ubuntu (3.07s)
2279:  �[32m✓�[0m Hosts enroll orbit scenario e from darwin to windows (3.07s)
2280:  �[32m✓�[0m Hosts enroll orbit scenario e from ubuntu to darwin (3.06s)
2281:  �[32m✓�[0m Hosts enroll orbit scenario e from ubuntu to ubuntu (3.07s)
2282:  �[32m✓�[0m Hosts enroll orbit scenario e from ubuntu to windows (3.06s)
2283:  �[32m✓�[0m Hosts enroll orbit scenario e from windows to darwin (3.07s)
2284:  �[32m✓�[0m Hosts enroll orbit scenario e from windows to ubuntu (3.07s)
2285:  �[32m✓�[0m Hosts enroll orbit scenario e from windows to windows (3.06s)
2286:  �[32m✓�[0m Hosts enroll updates missing info (0.56s)
2287:  �[32m✓�[0m Hosts failing policies count (1.22s)
2288:  �[32m✓�[0m Hosts failing policies count no policies (0.02s)
2289:  �[32m✓�[0m Hosts failing policies count with policies and memberships (0.22s)
2290:  �[31m✖�[0m Hosts generate status statistics (0.04s)
2291:  �[31m✖�[0m Hosts generate status statistics ABM pending exclusion (0.04s)
2292:  �[31m✖�[0m Hosts generate status statistics DEP errors (0.05s)
2293:  �[31m✖�[0m Hosts get device auth token (0.05s)
...

2332:  �[32m✓�[0m Hosts hostnames by identifiers no match (0.00s)
2333:  �[32m✓�[0m Hosts hostnames by identifiers single match (0.00s)
2334:  �[32m✓�[0m Hosts hostnames by identifiers two matches (0.00s)
2335:  �[32m✓�[0m Hosts hosts add to team cleans up team query results (0.65s)
2336:  �[31m✖�[0m Hosts hosts all pack stats (0.05s)
2337:  �[32m✓�[0m Hosts hosts enroll orbit with platform like (0.62s)
2338:  �[32m✓�[0m Hosts hosts expiration (1.24s)
2339:  �[31m✖�[0m Hosts hosts includes scheduled queries in pack stats (0.05s)
2340:  �[31m✖�[0m Hosts hosts list batch script execution (0.89s)
2341:  �[31m✖�[0m Hosts hosts list by OS name and version (0.03s)
2342:  �[31m✖�[0m Hosts hosts list by disk encryption status (0.03s)
2343:  �[31m✖�[0m Hosts hosts list by operating system ID (0.03s)
2344:  �[31m✖�[0m Hosts hosts list by software (0.04s)
2345:  �[31m✖�[0m Hosts hosts list by software changed at (0.04s)
2346:  �[31m✖�[0m Hosts hosts list by vulnerability (0.04s)
2347:  �[31m✖�[0m Hosts hosts list failing policies (0.03s)
2348:  �[31m✖�[0m Hosts hosts no seen time (0.05s)
2349:  �[31m✖�[0m Hosts hosts pack stats for platform (0.04s)
2350:  �[31m✖�[0m Hosts hosts pack stats multiple hosts (0.04s)
2351:  �[31m✖�[0m Hosts hosts pack stats no duplication (0.04s)
2352:  �[31m✖�[0m Hosts hosts reads less rows (0.02s)
2353:  �[31m✖�[0m Hosts list MDM (0.04s)
2354:  �[31m✖�[0m Hosts list MDM android (0.04s)
2355:  �[31m✖�[0m Hosts list by policy (0.05s)
2356:  �[31m✖�[0m Hosts list filter additional (0.04s)
2357:  �[32m✓�[0m Hosts list hosts DEP filters (0.65s)
2358:  �[32m✓�[0m Hosts list hosts DEP filters deleted DEP assignment is excluded from dep assign profile response filter (0.01s)
2359:  �[32m✓�[0m Hosts list hosts DEP filters deleted DEP assignment is excluded from dep profile error=true (0.01s)
2360:  �[32m✓�[0m Hosts list hosts DEP filters dep assign profile response with no matching hosts returns empty (0.01s)
2361:  �[32m✓�[0m Hosts list hosts DEP filters dep assign profile response= FAILED (0.01s)
2362:  �[32m✓�[0m Hosts list hosts DEP filters dep assign profile response= NOT ACCESSIBLE (0.01s)
2363:  �[32m✓�[0m Hosts list hosts DEP filters dep assign profile response= SUCCESS (0.01s)
2364:  �[32m✓�[0m Hosts list hosts DEP filters dep assign profile response= THROTTLED (0.01s)
2365:  �[32m✓�[0m Hosts list hosts DEP filters dep profile error=false returns all hosts without a DEP error (0.01s)
2366:  �[32m✓�[0m Hosts list hosts DEP filters dep profile error=true combined with team filter (0.02s)
2367:  �[32m✓�[0m Hosts list hosts DEP filters dep profile error=true returns only FAILED and THROTTLED hosts (0.01s)
2368:  �[32m✓�[0m Hosts list hosts DEP filters nil dep profile error returns all hosts (0.01s)
2369:  �[32m✓�[0m Hosts list hosts by profile UUID and status (0.99s)
...

2386:  �[32m✓�[0m Hosts list hosts lite by UUIDs team 1 maintainer team 2 observer sees team 1 (0.00s)
2387:  �[32m✓�[0m Hosts list hosts lite by UUIDs team 1 maintainer team 2 observer sees team 1 and 2 with observer (0.00s)
2388:  �[32m✓�[0m Hosts list hosts lite by UUIDs team 1 observer sees nothing (0.00s)
2389:  �[32m✓�[0m Hosts list hosts lite by UUIDs team 1 observer sees team 1 hosts with observer allowed (0.00s)
2390:  �[32m✓�[0m Hosts list hosts lite by UUIDs team 2 admin sees team 2 hosts (0.00s)
2391:  �[32m✓�[0m Hosts list hosts lite by UUIDs team 2 maintainer sees team 2 hosts (0.00s)
2392:  �[32m✓�[0m Hosts list hosts lite by UUIDs team 2 observer sees nothing (0.00s)
2393:  �[32m✓�[0m Hosts list hosts lite by UUIDs team 2 observer sees team 2 hosts with observer allowed (0.00s)
2394:  �[32m✓�[0m Hosts list hosts lite by UUIDs team 3 admin sees nothing even with observer (0.00s)
2395:  �[32m✓�[0m Hosts list hosts with pagination (0.98s)
2396:  �[31m✖�[0m Hosts list munki issue ID (0.04s)
2397:  �[31m✖�[0m Hosts list query (0.05s)
2398:  �[31m✖�[0m Hosts list status (0.04s)
2399:  �[32m✓�[0m Hosts list upcoming host maintenance windows (0.55s)
2400:  �[31m✖�[0m Hosts load host by device auth token (0.09s)
2401:  �[31m✖�[0m Hosts load host by device auth token fast fail (0.05s)
2402:  �[31m✖�[0m Hosts load host by node key (0.04s)
...

2472:  �[31m✖�[0m In house apps software title display name (0.05s)
2473:  �[32m✓�[0m In house apps test in house apps crud (1.00s)
2474:  �[32m✓�[0m Ingest MDM apple devices from DEP sync (1.85s)
2475:  �[32m✓�[0m Insert update cron stats (1.44s)
2476:  �[31m✖�[0m Invites (1.21s)
2477:  �[31m✖�[0m Jobs (2.51s)
2478:  �[31m✖�[0m Jobs cleanup worker jobs (0.04s)
2479:  �[31m✖�[0m Jobs queue and process jobs (0.04s)
2480:  �[31m✖�[0m Jobs queue and process jobs# 01 (0.04s)
2481:  �[32m✓�[0m Labels (40.46s)
2482:  �[32m✓�[0m Labels IDs by name (0.90s)
2483:  �[32m✓�[0m Labels add all hosts deferred (0.94s)
2484:  �[32m✓�[0m Labels add all hosts not deferred (1.01s)
2485:  �[32m✓�[0m Labels add delete labels to from host (1.92s)
2486:  �[32m✓�[0m Labels apply label spec serial UUID (0.82s)
2487:  �[32m✓�[0m Labels apply label specs errors when label exists on another team (0.91s)
2488:  �[32m✓�[0m Labels apply label specs manual nil hosts (1.00s)
...

2556:  �[32m✓�[0m Labels record non existent query label execution (0.89s)
2557:  �[32m✓�[0m Labels save (0.93s)
2558:  �[32m✓�[0m Labels search (0.83s)
2559:  �[32m✓�[0m Labels set aside labels (1.31s)
2560:  �[32m✓�[0m Labels set aside labels cannot set aside global labels when applying to global (0.01s)
2561:  �[32m✓�[0m Labels set aside labels cannot set aside labels from the same team we're applying to (0.01s)
2562:  �[32m✓�[0m Labels set aside labels empty names list is a no-op (0.00s)
2563:  �[32m✓�[0m Labels set aside labels global admin can set aside global labels when applying to a team (0.03s)
2564:  �[32m✓�[0m Labels set aside labels global gitops can set aside global labels (0.03s)
2565:  �[32m✓�[0m Labels set aside labels global maintainer can set aside global labels (0.03s)
2566:  �[32m✓�[0m Labels set aside labels global observer cannot set aside global labels (0.01s)
2567:  �[32m✓�[0m Labels set aside labels global technician can set aside global labels (0.03s)
2568:  �[32m✓�[0m Labels set aside labels multi-team user can set aside labels from teams they have write access to (0.03s)
2569:  �[32m✓�[0m Labels set aside labels multi-team user cannot set aside labels from teams they don't have write access to (0.01s)
2570:  �[32m✓�[0m Labels set aside labels multiple labels can be set aside at once (0.03s)
2571:  �[32m✓�[0m Labels set aside labels non-existent label should fail (0.01s)
2572:  �[32m✓�[0m Labels set aside labels team admin can set aside their own team's labels if they can also edit the not-on team (0.03s)
...

2592:  �[32m✓�[0m List vulns by multiple OS versions empty input (0.98s)
2593:  �[32m✓�[0m List vulns by multiple OS versions mixed platforms (0.89s)
2594:  �[32m✓�[0m List vulns by multiple OS versions multiple linux OS with many kernels (1.04s)
2595:  �[32m✓�[0m List vulns by multiple OS versions non existent OS (0.89s)
2596:  �[32m✓�[0m List vulns by multiple OS versions with CVSS (1.10s)
2597:  �[32m✓�[0m List vulns by multiple OS versions with max vulnerabilities (1.07s)
2598:  �[32m✓�[0m List vulns by multiple OS versions with max vulnerabilities combined all OS types with max=2 (0.00s)
2599:  �[32m✓�[0m List vulns by multiple OS versions with max vulnerabilities combined os versions + linux OS with max=0 (0.00s)
2600:  �[32m✓�[0m List vulns by multiple OS versions with max vulnerabilities combined os versions + linux OS with max=1 (0.00s)
2601:  �[32m✓�[0m List vulns by multiple OS versions with max vulnerabilities max = 0 returns empty array with count (0.00s)
2602:  �[32m✓�[0m List vulns by multiple OS versions with max vulnerabilities max = 1 for linux kernel vulnerabilities (0.01s)
2603:  �[32m✓�[0m List vulns by multiple OS versions with max vulnerabilities max = 1 limits to 1 vulnerability (0.00s)
2604:  �[32m✓�[0m List vulns by multiple OS versions with max vulnerabilities max exceeds total returns all vulnerabilities (0.00s)
2605:  �[32m✓�[0m List vulns by multiple OS versions with max vulnerabilities multi-arch with max returns correct count (0.00s)
2606:  �[32m✓�[0m List vulns by multiple OS versions with max vulnerabilities multi-arch with max=0 returns correct count (0.00s)
2607:  �[32m✓�[0m List vulns by multiple OS versions with max vulnerabilities negative value returns error (0.00s)
2608:  �[32m✓�[0m List vulns by multiple OS versions with team filter (0.89s)
...

2640:  �[32m✓�[0m MDM apple batch set MDM apple declarations case change (1.30s)
2641:  �[32m✓�[0m MDM apple batch set MDM apple declarations case change no team (0.10s)
2642:  �[32m✓�[0m MDM apple batch set MDM apple declarations case change no team host profile reflects name change (0.00s)
2643:  �[32m✓�[0m MDM apple batch set MDM apple declarations case change no team pending install not disrupted (0.01s)
2644:  �[32m✓�[0m MDM apple batch set MDM apple declarations case change no team preserves declaration UUID (0.00s)
2645:  �[32m✓�[0m MDM apple batch set MDM apple declarations case change no team verified install not disrupted (0.01s)
2646:  �[32m✓�[0m MDM apple batch set MDM apple declarations case change team (0.09s)
2647:  �[32m✓�[0m MDM apple batch set MDM apple declarations case change team host profile reflects name change (0.00s)
2648:  �[32m✓�[0m MDM apple batch set MDM apple declarations case change team pending install not disrupted (0.01s)
2649:  �[32m✓�[0m MDM apple batch set MDM apple declarations case change team preserves declaration UUID (0.01s)
2650:  �[32m✓�[0m MDM apple batch set MDM apple declarations case change team verified install not disrupted (0.01s)
2651:  �[32m✓�[0m MDM apple claim hosts for recovery lock clear (1.84s)
2652:  �[32m✓�[0m MDM apple claim hosts for recovery lock clear claims no-team host when appconfig disabled (0.04s)
2653:  �[32m✓�[0m MDM apple claim hosts for recovery lock clear claims verified host when config disabled (0.05s)
2654:  �[32m✓�[0m MDM apple claim hosts for recovery lock clear clears stale auto rotate at when flipping to remove (0.04s)
2655:  �[32m✓�[0m MDM apple claim hosts for recovery lock clear does not claim pending or failed hosts (0.07s)
2656:  �[32m✓�[0m MDM apple claim hosts for recovery lock clear get operation type (0.04s)
2657:  �[32m✓�[0m MDM apple claim hosts for recovery lock clear no hosts to clear returns empty (0.47s)
2658:  �[32m✓�[0m MDM apple claim hosts for recovery lock clear retries failed clear attempts (0.04s)
2659:  �[32m✓�[0m MDM apple claim hosts for recovery lock clear returns pending when operation type is install and status is NULL (0.01s)
...

2661:  �[32m✓�[0m MDM apple claim hosts for recovery lock clear soft delete marks password record as deleted (0.04s)
2662:  �[31m✖�[0m MDM apple cleanup orphaned nano refetch commands (0.05s)
2663:  �[32m✓�[0m MDM apple cleanup stale nano refetch commands (0.97s)
2664:  �[32m✓�[0m MDM apple delete MDM apple declaration by name cancels installs (1.71s)
2665:  �[32m✓�[0m MDM apple delete MDM apple declaration by name cancels installs no team (0.11s)
2666:  �[32m✓�[0m MDM apple delete MDM apple declaration by name cancels installs team (0.09s)
2667:  �[32m✓�[0m MDM apple delete host preserves recovery lock password (1.02s)
2668:  �[31m✖�[0m MDM apple device location (0.04s)
2669:  �[32m✓�[0m MDM apple file vault summary (2.24s)
2670:  �[31m✖�[0m MDM apple get MDM apple enrolled device deleted from fleet (0.04s)
2671:  �[32m✓�[0m MDM apple get and update ABM token (1.00s)
2672:  �[32m✓�[0m MDM apple get enrollment IDs with pending MDM apple commands (1.40s)
2673:  �[31m✖�[0m MDM apple get host recovery lock password status (0.21s)
2674:  �[31m✖�[0m MDM apple get host recovery lock password status returns enforcing status for pending install (0.02s)
2675:  �[31m✖�[0m MDM apple get host recovery lock password status returns enforcing status when status column is NULL (retry state) (0.02s)
2676:  �[31m✖�[0m MDM apple get host recovery lock password status returns failed status when operation type is remove and status is failed (0.02s)
2677:  �[31m✖�[0m MDM apple get host recovery lock password status returns failed status with error message (0.02s)
2678:  �[31m✖�[0m MDM apple get host recovery lock password status returns nil for host without recovery lock password (0.02s)
2679:  �[31m✖�[0m MDM apple get host recovery lock password status returns removing enforcement status for pending removal after populate status (0.02s)
2680:  �[31m✖�[0m MDM apple get host recovery lock password status returns verified status (0.02s)
2681:  �[31m✖�[0m MDM apple get host recovery lock password status returns verifying status (0.02s)
2682:  �[31m✖�[0m MDM apple get hosts for recovery lock action (0.05s)
2683:  �[32m✓�[0m MDM apple get nano MDM enrollment details (0.79s)
2684:  �[32m✓�[0m MDM apple get nano MDMUs er enrollment (0.79s)
2685:  �[32m✓�[0m MDM apple host MDM commands (0.96s)
2686:  �[32m✓�[0m MDM apple host recovery lock status matrix (1.09s)
2687:  �[32m✓�[0m MDM apple host recovery lock status matrix NULL status remove -> removing enforcement (clear retry) (0.02s)
2688:  �[32m✓�[0m MDM apple host recovery lock status matrix NULL status, install, password stored -> pending (0.01s)
2689:  �[32m✓�[0m MDM apple host recovery lock status matrix failed install + rotation in flight -> failed (0.01s)
2690:  �[32m✓�[0m MDM apple host recovery lock status matrix failed install -> failed with detail (0.01s)
2691:  �[32m✓�[0m MDM apple host recovery lock status matrix failed remove -> failed (0.01s)
2692:  �[32m✓�[0m MDM apple host recovery lock status matrix pending install + rotation in flight -> pending (0.01s)
2693:  �[32m✓�[0m MDM apple host recovery lock status matrix pending install, no rotation -> pending (0.01s)
2694:  �[32m✓�[0m MDM apple host recovery lock status matrix pending remove -> removing enforcement (0.01s)
2695:  �[32m✓�[0m MDM apple host recovery lock status matrix soft-deleted row is invisible to readers (0.01s)
2696:  �[32m✓�[0m MDM apple host recovery lock status matrix verified install -> verified (0.01s)
2697:  �[32m✓�[0m MDM apple ingest MDM apple device from OTA enrollment (1.24s)
2698:  �[32m✓�[0m MDM apple ingest MDM apple devices from DEP sync IOSI pad OS (0.84s)
2699:  �[32m✓�[0m MDM apple list IOS and i pad OS to refetch (1.09s)
2700:  �[32m✓�[0m MDM apple lock unlock wipe mac OS (1.06s)
2701:  �[32m✓�[0m MDM apple profile verification (3.11s)
2702:  �[32m✓�[0m MDM apple profile verification earliest install date (0.07s)
2703:  �[32m✓�[0m MDM apple profile verification expected profile (0.20s)
2704:  �[32m✓�[0m MDM apple profile verification expected profile failed then found expected (0.05s)
2705:  �[32m✓�[0m MDM apple profile verification expected profile pending then found expected (0.05s)
2706:  �[32m✓�[0m MDM apple profile verification expected profile verified then found expected (0.06s)
2707:  �[32m✓�[0m MDM apple profile verification expected profile verifying then found expected (0.05s)
2708:  �[32m✓�[0m MDM apple profile verification missing profile with retry (0.41s)
2709:  �[32m✓�[0m MDM apple profile verification outdated profile (0.20s)
2710:  �[32m✓�[0m MDM apple profile verification outdated profile failed then found outdated (0.05s)
2711:  �[32m✓�[0m MDM apple profile verification outdated profile pending then found outdated (0.05s)
2712:  �[32m✓�[0m MDM apple profile verification outdated profile verified then found outdated (0.05s)
2713:  �[32m✓�[0m MDM apple profile verification outdated profile verifying then found outdated (0.05s)
2714:  �[32m✓�[0m MDM apple profile verification unexpected profile (0.30s)
2715:  �[32m✓�[0m MDM apple profile verification unexpected profile failed then found expected and unexpected (0.05s)
2716:  �[32m✓�[0m MDM apple profile verification unexpected profile pending then found expected and unexpected (0.05s)
...

2730:  �[31m✖�[0m MDM apple recovery lock password bulk set (0.04s)
2731:  �[31m✖�[0m MDM apple recovery lock password get not found (0.04s)
2732:  �[32m✓�[0m MDM apple recovery lock password set and get (0.85s)
2733:  �[31m✖�[0m MDM apple recovery lock password set overwrite (0.04s)
2734:  �[31m✖�[0m MDM apple recovery lock password updated at changes (0.04s)
2735:  �[32m✓�[0m MDM apple recovery lock readers return not found for soft deleted (1.04s)
2736:  �[32m✓�[0m MDM apple recovery lock reset on MDM re enrollment (1.09s)
2737:  �[32m✓�[0m MDM apple recovery lock reset on MDM re enrollment nulls auto rotate at on soft-delete (0.03s)
2738:  �[32m✓�[0m MDM apple recovery lock reset on MDM re enrollment nulls pending rotation fields on soft-delete (0.03s)
2739:  �[32m✓�[0m MDM apple recovery lock reset on MDM re enrollment preserves row during SCEP renewal (0.02s)
2740:  �[32m✓�[0m MDM apple recovery lock reset on MDM re enrollment re-animation after soft-delete yields clean state (0.04s)
2741:  �[32m✓�[0m MDM apple recovery lock reset on MDM re enrollment soft-deletes stuck-pending install row ( clear queue scenario) (0.02s)
2742:  �[32m✓�[0m MDM apple recovery lock reset on MDM re enrollment soft-deletes verified install row (0.04s)
2743:  �[32m✓�[0m MDM apple recovery lock rotation (1.18s)
2744:  �[32m✓�[0m MDM apple recovery lock rotation clear recovery lock rotation removes pending (0.02s)
2745:  �[32m✓�[0m MDM apple recovery lock rotation clear recovery lock rotation restores failed status (0.02s)
2746:  �[32m✓�[0m MDM apple recovery lock rotation complete recovery lock rotation success (0.02s)
2747:  �[32m✓�[0m MDM apple recovery lock rotation fail recovery lock rotation preserves pending password (0.02s)
2748:  �[32m✓�[0m MDM apple recovery lock rotation get recovery lock rotation status not found (0.00s)
2749:  �[32m✓�[0m MDM apple recovery lock rotation get recovery lock rotation status returns all fields (0.02s)
2750:  �[32m✓�[0m MDM apple recovery lock rotation has pending recovery lock rotation returns false for no record (0.00s)
2751:  �[32m✓�[0m MDM apple recovery lock rotation initiate recovery lock rotation allows failed status (0.01s)
2752:  �[32m✓�[0m MDM apple recovery lock rotation initiate recovery lock rotation rejects if already pending (0.12s)
2753:  �[32m✓�[0m MDM apple recovery lock rotation initiate recovery lock rotation rejects pending status (0.01s)
2754:  �[32m✓�[0m MDM apple recovery lock rotation initiate recovery lock rotation success (0.02s)
2755:  �[31m✖�[0m MDM apple recovery lock status methods (0.20s)
2756:  �[31m✖�[0m MDM apple recovery lock status methods clear recovery lock pending status (0.03s)
2757:  �[31m✖�[0m MDM apple recovery lock status methods clear recovery lock pending status only clears pending (0.02s)
2758:  �[31m✖�[0m MDM apple recovery lock status methods reset recovery lock for retry (0.02s)
2759:  �[31m✖�[0m MDM apple recovery lock status methods reset recovery lock for retry from failed state (0.03s)
2760:  �[31m✖�[0m MDM apple recovery lock status methods set hosts recovery lock passwords sets pending status atomically (0.02s)
2761:  �[31m✖�[0m MDM apple recovery lock status methods set recovery lock failed (0.02s)
2762:  �[31m✖�[0m MDM apple recovery lock status methods set recovery lock verified (0.03s)
...

2777:  �[32m✓�[0m MDM apple test MDM apple delete host DEPAs signments no matching serials (0.02s)
2778:  �[32m✓�[0m MDM apple test MDM apple delete host DEPAs signments no serials provided (0.02s)
2779:  �[32m✓�[0m MDM apple test MDM apple delete host DEPAs signments partial matches (0.08s)
2780:  �[32m✓�[0m MDM apple test MDM apple enrollment profile (0.86s)
2781:  �[32m✓�[0m MDM apple test MDM apple hosts disk encryption (1.05s)
2782:  �[32m✓�[0m MDM apple test MDM apple hosts profiles status (2.43s)
2783:  �[32m✓�[0m MDM apple test MDM apple id p account (0.95s)
2784:  �[31m✖�[0m MDM apple test MDM apple profile labels (0.04s)
2785:  �[32m✓�[0m MDM apple test MDM apple profile management (1.18s)
2786:  �[32m✓�[0m MDM apple test MDM apple profile management batch 2 (1.14s)
2787:  �[32m✓�[0m MDM apple test MDM apple profile management batch 3 (1.16s)
2788:  �[32m✓�[0m MDM apple test MDM apple reset enrollment (1.02s)
2789:  �[32m✓�[0m MDM apple test MDM apple reset on reenrollment (0.94s)
2790:  �[32m✓�[0m MDM apple test MDM apple reset on reenrollment clears expected tables and leaves other hosts untouched (0.07s)
2791:  �[32m✓�[0m MDM apple test MDM apple reset on reenrollment preserve host activities flag controls past activity history (0.09s)
2792:  �[32m✓�[0m MDM apple test MDM apple reset on reenrollment returns error and changes nothing when host UUID does not exist (0.02s)
2793:  �[32m✓�[0m MDM apple test MDM apple setup assistant (3.11s)
...

2796:  �[32m✓�[0m MDM apple test aggregate mac OS settings status with file vault (1.38s)
2797:  �[32m✓�[0m MDM apple test batch set MDM apple profiles (3.01s)
2798:  �[32m✓�[0m MDM apple test batch set MDM apple profiles clears stale broken labels (1.00s)
2799:  �[32m✓�[0m MDM apple test bulk upsert MDM apple config profiles (2.98s)
2800:  �[32m✓�[0m MDM apple test delete MDM apple config profile (1.02s)
2801:  �[32m✓�[0m MDM apple test delete MDM apple config profile by team and identifier (0.91s)
2802:  �[32m✓�[0m MDM apple test delete MDM apple config profile with pending installs (1.06s)
2803:  �[32m✓�[0m MDM apple test delete MDM apple declaration with pending installs (0.86s)
2804:  �[32m✓�[0m MDM apple test delete MDM apple profiles for host (0.90s)
2805:  �[31m✖�[0m MDM apple test get DEPAs sign profile expired cooldowns (0.05s)
2806:  �[32m✓�[0m MDM apple test get MDM apple command results (1.08s)
2807:  �[32m✓�[0m MDM apple test get MDM apple profiles contents (0.83s)
2808:  �[31m✖�[0m MDM apple test get latest apple MDM command of type (0.04s)
2809:  �[32m✓�[0m MDM apple test host details MDM profiles (1.11s)
2810:  �[32m✓�[0m MDM apple test host details MDM profiles IOSI pad OS (0.93s)
2811:  �[32m✓�[0m MDM apple test ignore MDM client error (0.89s)
2812:  �[32m✓�[0m MDM apple test list MDM apple commands (1.12s)
...

2905:  �[32m✓�[0m MDM shared test list MDM commands pagination page-based across branches (0.02s)
2906:  �[32m✓�[0m MDM shared test list MDM commands requires per page (0.85s)
2907:  �[32m✓�[0m MDM shared test list MDM commands with team filter (1.10s)
2908:  �[31m✖�[0m MDM shared test list MDM config profiles (3.69s)
2909:  �[32m✓�[0m MDM shared test list next pending MDM windows host UUIDs cursor (1.71s)
2910:  �[31m✖�[0m MDM windows (72.62s)
2911:  �[31m✖�[0m MDM windows test MDM windows awaiting configuration CAS (0.17s)
2912:  �[31m✖�[0m MDM windows test MDM windows awaiting configuration CAS active row with expect from= pending is no-op (mismatched) (0.02s)
2913:  �[31m✖�[0m MDM windows test MDM windows awaiting configuration CAS active-> none matched (0.02s)
2914:  �[31m✖�[0m MDM windows test MDM windows awaiting configuration CAS awaiting configuration at preserved across transitions (0.02s)
2915:  �[31m✖�[0m MDM windows test MDM windows awaiting configuration CAS concurrent CAS yields exactly one winner (0.02s)
2916:  �[31m✖�[0m MDM windows test MDM windows awaiting configuration CAS none row with expect from= pending is no-op (idempotent retry) (0.02s)
2917:  �[31m✖�[0m MDM windows test MDM windows awaiting configuration CAS pending row with expect from= active is no-op (mismatched) (0.02s)
2918:  �[31m✖�[0m MDM windows test MDM windows awaiting configuration CAS pending-> active matched (0.02s)
2919:  �[31m✖�[0m MDM windows test MDM windows awaiting configuration CAS pending-> none matched (timeout-during-pending shortcut) (0.02s)
2920:  �[31m✖�[0m MDM windows test MDM windows awaiting configuration CAS unknown device id returns false without error (0.02s)
2921:  �[31m✖�[0m MDM windows test MDM windows awaiting configuration by host UUID (0.88s)
2922:  �[32m✓�[0m MDM windows test MDM windows awaiting configuration by host UUID does not cross-leak between hosts (0.02s)
2923:  �[31m✖�[0m MDM windows test MDM windows awaiting configuration by host UUID returns current state and reflects transitions (0.02s)
2924:  �[32m✓�[0m MDM windows test MDM windows awaiting configuration by host UUID returns most recent enrollment when host has multiple (0.03s)
2925:  �[32m✓�[0m MDM windows test MDM windows awaiting configuration by host UUID unknown host UUID returns not found (0.00s)
2926:  �[32m✓�[0m MDM windows test MDM windows command results (0.97s)
2927:  �[32m✓�[0m MDM windows test MDM windows command results with pending result (1.04s)
2928:  �[32m✓�[0m MDM windows test MDM windows config profiles (0.99s)
2929:  �[32m✓�[0m MDM windows test MDM windows config profiles with fleet vars (0.95s)
2930:  �[32m✓�[0m MDM windows test MDM windows disk encryption (7.78s)
2931:  �[32m✓�[0m MDM windows test MDM windows disk encryption disk encryption disabled (0.12s)
2932:  �[32m✓�[0m MDM windows test MDM windows disk encryption disk encryption enabled (6.69s)
2933:  �[32m✓�[0m MDM windows test MDM windows disk encryption disk encryption enabled OS settings filters include windows and mac OS hosts (0.03s)
2934:  �[32m✓�[0m MDM windows test MDM windows disk encryption disk encryption enabled bit locker failed status (1.14s)
2935:  �[32m✓�[0m MDM windows test MDM windows disk encryption disk encryption enabled bit locker host disks must update to transition from verifying to verified (0.47s)
...

2970:  �[32m✓�[0m MDM windows test MDM windows insert command and upsert host profiles for hosts batching works correctly (0.02s)
2971:  �[32m✓�[0m MDM windows test MDM windows insert command and upsert host profiles for hosts duplicate command uuid returns already exists (0.01s)
2972:  �[32m✓�[0m MDM windows test MDM windows insert command and upsert host profiles for hosts empty host list is a noop (0.00s)
2973:  �[32m✓�[0m MDM windows test MDM windows insert command and upsert host profiles for hosts inserts command and profiles for multiple hosts (0.02s)
2974:  �[32m✓�[0m MDM windows test MDM windows insert command and upsert host profiles for hosts upserts update existing host profiles (0.02s)
2975:  �[32m✓�[0m MDM windows test MDM windows insert command for hosts (1.95s)
2976:  �[31m✖�[0m MDM windows test MDM windows insert command skips unenrolled hosts (0.05s)
2977:  �[31m✖�[0m MDM windows test MDM windows profile labels (0.04s)
2978:  �[32m✓�[0m MDM windows test MDM windows profile management (1.06s)
2979:  �[32m✓�[0m MDM windows test MDM windows profiles summary (7.68s)
2980:  �[31m✖�[0m MDM windows test MDM windows profiles summary enumeration (30.55s)
2981:  �[32m✓�[0m MDM windows test MDM windows profiles summary profiles summary accounts for bitlocker status (4.16s)
2982:  �[32m✓�[0m MDM windows test MDM windows profiles summary profiles summary accounts for bitlocker status bitlocker disabled (0.80s)
2983:  �[32m✓�[0m MDM windows test MDM windows profiles summary profiles summary accounts for bitlocker status bitlocker enabled (3.37s)
2984:  �[32m✓�[0m MDM windows test MDM windows profiles summary profiles summary accounts for bitlocker status bitlocker enabled bit locker host disks must update to transition from verifying to verified (0.24s)
2985:  �[32m✓�[0m MDM windows test MDM windows profiles summary profiles summary accounts for bitlocker status bitlocker enabled bitlocker failed (0.64s)
2986:  �[32m✓�[0m MDM windows test MDM windows profiles summary profiles summary accounts for bitlocker status bitlocker enabled bitlocker pending (0.88s)
...

3019:  �[32m✓�[0m Maintained apps list and get available apps order id (0.01s)
3020:  �[32m✓�[0m Maintained apps list and get available apps order name (0.00s)
3021:  �[32m✓�[0m Maintained apps list and get available apps order platform (0.01s)
3022:  �[32m✓�[0m Maintained apps list and get available apps order slug (0.01s)
3023:  �[32m✓�[0m Maintained apps list and get available apps rejects unknown key (0.00s)
3024:  �[32m✓�[0m Maintained apps list available apps windows (1.00s)
3025:  �[32m✓�[0m Maintained apps software title renaming windows (1.19s)
3026:  �[32m✓�[0m Maintained apps sync (1.86s)
3027:  �[32m✓�[0m Maintained apps sync and remove apps (4.44s)
3028:  �[32m✓�[0m Maintained apps upsert maintained app updates software (0.95s)
3029:  �[32m✓�[0m Maintained apps upsert maintained apps (2.82s)
3030:  �[32m✓�[0m Managed local account (2.05s)
3031:  �[32m✓�[0m Managed local account clear rotation (0.02s)
3032:  �[32m✓�[0m Managed local account complete rotation (0.03s)
3033:  �[32m✓�[0m Managed local account deferred rotation (0.02s)
3034:  �[32m✓�[0m Managed local account fail rotation (0.02s)
3035:  �[32m✓�[0m Managed local account get by command UUID (0.03s)
...

3070:  �[32m✓�[0m Operating system vulnerabilities list OS vulnerabilities returns matching (0.00s)
3071:  �[32m✓�[0m Operating system vulnerabilities list vulns by os name and version (1.04s)
3072:  �[32m✓�[0m Operating system vulnerabilities refresh OS version vulnerabilities (1.07s)
3073:  �[32m✓�[0m Operating system vulnerabilities refresh OS version vulnerabilities cleans up stale entries on refresh (0.02s)
3074:  �[32m✓�[0m Operating system vulnerabilities refresh OS version vulnerabilities populates all-teams aggregated vulnerabilities (0.00s)
3075:  �[32m✓�[0m Operating system vulnerabilities refresh OS version vulnerabilities populates per-team vulnerabilities (0.00s)
3076:  �[32m✓�[0m Operating system vulnerabilities refresh OS version vulnerabilities updates existing vulnerabilities on refresh (0.01s)
3077:  �[32m✓�[0m Operating system vulnerabilities test kernel vulns host count (1.41s)
3078:  �[32m✓�[0m Operating system vulnerabilities test list kernels by OS (1.64s)
3079:  �[32m✓�[0m Operating system vulnerabilities test list kernels by OS RHEL with team (0.15s)
3080:  �[32m✓�[0m Operating system vulnerabilities test list kernels by OS amazon linux with team (0.16s)
3081:  �[32m✓�[0m Operating system vulnerabilities test list kernels by OS ubuntu no team (0.20s)
3082:  �[32m✓�[0m Operating system vulnerabilities test list kernels by OS ubuntu with team (0.20s)
3083:  �[32m✓�[0m PBT scoped listing equivalence (2.16s)
3084:  �[32m✓�[0m Packs (14.10s)
3085:  �[32m✓�[0m Packs apply spec fails on target ID null (0.91s)
3086:  �[32m✓�[0m Packs apply spec missing name (0.96s)
...

3227:  �[32m✓�[0m Scim set or update host SCIMUs er mapping (1.01s)
3228:  �[32m✓�[0m Scim trigger resend id p profiles (1.71s)
3229:  �[32m✓�[0m Scim trigger resend id p profiles on team (1.08s)
3230:  �[31m✖�[0m Scripts (1.59s)
3231:  �[32m✓�[0m Search like (0.00s)
3232:  �[32m✓�[0m Search like #00 (0.00s)
3233:  �[32m✓�[0m Search like #01 (0.00s)
3234:  �[32m✓�[0m Search like #02 (0.00s)
3235:  �[32m✓�[0m Search like #03 (0.00s)
3236:  �[32m✓�[0m Search like #04 (0.00s)
3237:  �[32m✓�[0m Search like #05 (0.00s)
3238:  �[32m✓�[0m Search like #06 (0.00s)
3239:  �[32m✓�[0m Search like #07 (0.00s)
3240:  �[32m✓�[0m Secret variables (9.18s)
3241:  �[32m✓�[0m Secret variables create secret variable (0.95s)
3242:  �[32m✓�[0m Secret variables create secret variable duplicate name error (0.00s)
3243:  �[32m✓�[0m Secret variables create secret variable successful creation (0.00s)
...

3282:  �[32m✓�[0m Setup experience set setup experience titles only marks active installer (0.99s)
3283:  �[32m✓�[0m Setup experience setup experience script CRUD (0.95s)
3284:  �[32m✓�[0m Setup experience test enqueue setup experience items windows (1.03s)
3285:  �[32m✓�[0m Setup experience test get setup experience script by ID (0.88s)
3286:  �[32m✓�[0m Setup experience test host in setup experience (0.89s)
3287:  �[32m✓�[0m Setup experience test update setup experience script while enqueued (0.95s)
3288:  �[32m✓�[0m Setup experience update status guards terminal states (1.20s)
3289:  �[31m✖�[0m Software (34.13s)
3290:  �[32m✓�[0m Software CPE (0.89s)
3291:  �[31m✖�[0m Software all software iterator (0.04s)
3292:  �[31m✖�[0m Software all software iterator for custom linux images (0.04s)
3293:  �[32m✓�[0m Software check for deleted installed software (1.47s)
3294:  �[32m✓�[0m Software check for deleted installed software host software installs row isnt removed (0.07s)
3295:  �[32m✓�[0m Software check for deleted installed software installer host count is correct (0.30s)
3296:  �[32m✓�[0m Software count host software install attempts (1.14s)
3297:  �[31m✖�[0m Software create intermediate install failure record (0.10s)
3298:  �[31m✖�[0m Software delete host software installed paths (0.04s)
...

3338:  �[32m✓�[0m Software installers get or generate software installer title ID installer: has upgrade code and FM A, existing title: different name, same upgrade code (0.01s)
3339:  �[32m✓�[0m Software installers get or generate software installer title ID installer: has upgrade code, existing title: same name, different upgrade code (0.01s)
3340:  �[32m✓�[0m Software installers get or generate software installer title ID installer: has upgrade code, existing title: same name, no upgrade code (0.01s)
3341:  �[32m✓�[0m Software installers get or generate software installer title ID installer: has upgrade code, existing title: same name, same upgrade code (0.01s)
3342:  �[32m✓�[0m Software installers get or generate software installer title ID installer: no upgrade code, existing title: same name, has upgrade code (0.00s)
3343:  �[32m✓�[0m Software installers get or generate software installer title ID installer: no upgrade code, existing title: same name, no upgrade code (0.00s)
3344:  �[32m✓�[0m Software installers get or generate software installer title ID title that already exists but doesn't have a bundle identifier (0.00s)
3345:  �[32m✓�[0m Software installers get or generate software installer title ID title that already exists with bundle identifier (0.00s)
3346:  �[32m✓�[0m Software installers get or generate software installer title ID title that already exists with bundle identifier, different source (0.01s)
3347:  �[32m✓�[0m Software installers get or generate software installer title ID title that already exists, mismatched bundle identifier in payload (0.00s)
3348:  �[32m✓�[0m Software installers get or generate software installer title ID title that already exists, no bundle identifier in d B, bundle identifier in payload (0.00s)
3349:  �[32m✓�[0m Software installers get or generate software installer title ID title that already exists, no bundle identifier in payload (0.00s)
3350:  �[32m✓�[0m Software installers get or generate software installer title ID title that doesn't exist, no bundle identifier in payload (0.01s)
3351:  �[32m✓�[0m Software installers get or generate software installer title ID title that doesn't exist, with bundle identifier in payload (0.01s)
3352:  �[32m✓�[0m Software installers get software install results (1.35s)
3353:  �[32m✓�[0m Software installers get software install results failing install install script (0.12s)
3354:  �[32m✓�[0m Software installers get software install results failing install post install script (0.12s)
3355:  �[32m✓�[0m Software installers get software install results failing install pre install query (0.12s)
3356:  �[32m✓�[0m Software installers get software install results pending install (0.14s)
3357:  �[31m✖�[0m Software installers get software installer metadata by team and title ID (3.29s)
3358:  �[32m✓�[0m Software installers get teams with installer by hash (0.94s)
3359:  �[32m✓�[0m Software installers has sel...

@allenhouchins
allenhouchins marked this pull request as ready for review May 13, 2026 18:07
@allenhouchins
allenhouchins requested a review from a team as a code owner May 13, 2026 18:07
Copilot AI review requested due to automatic review settings May 13, 2026 18:07

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This PR extends the Homebrew maintained-apps pipeline to handle Docker Desktop installation with special patched-status logic. A new Bash install script detects whether Docker Desktop is running, quits and relaunches it when appropriate, installs from a DMG, removes stale .back backup bundles, and recreates CLI symlinks. The ingester special-cases the docker-desktop token to override the patched query with a NOT EXISTS condition that filters by non-.back paths. Config files wire the script into the pipeline and tests validate the new behavior.

Possibly related PRs

  • fleetdm/fleet#45171: Both PRs modify the Docker Desktop macOS manifest SQL patched policy logic for version 4.73.0.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Update Docker Desktop FMA install script' accurately describes the main change in the changeset, which focuses on updating the Docker Desktop installation script and related assets.
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.
Description check ✅ Passed Pull request description clearly outlines all changes including patch policy improvements, new install script, test enhancements, and Docker Desktop handling updates.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 45242-show-update-available-status-library-and-self-service-only-if-the-top-level-app-is-outdated

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 and usage tips.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ee/maintained-apps/inputs/homebrew/scripts/docker_desktop_install.sh`:
- Around line 1-6: Add strict failure handling and guaranteed DMG detach: add
"set -euo pipefail" at the top of the script, initialize a global MOUNT_POINT=""
variable before any hdiutil operations, and implement a cleanup function
(registered via trap EXIT) that checks MOUNT_POINT and calls hdiutil detach if
mounted; also make quit_and_track_application() return a non-zero exit (or exit)
on failure so the script stops instead of continuing to sudo cp when Docker
hasn't quit. Ensure every hdiutil attach error causes immediate exit and the
trap still runs to avoid leaving mounts.
- Around line 49-51: The script currently logs when Docker Desktop failed to
quit (using the quit_success variable and bundle_id) but continues installation;
update both places where quit_success is checked (the block referencing
quit_success and bundle_id around line 49 and the similar check around line 103)
to abort the script on failure by printing a clear error to stderr and exiting
with a non-zero status (e.g., exit 1) so the install stops if Docker Desktop did
not quit; ensure the error message includes the bundle_id for context and that
any cleanup/rollback steps (if present) run before exiting.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 16306a1e-19ee-4129-9edc-b1a8f5e18ac7

📥 Commits

Reviewing files that changed from the base of the PR and between 117a137 and 136abf1.

📒 Files selected for processing (5)
  • ee/maintained-apps/ingesters/homebrew/ingester.go
  • ee/maintained-apps/ingesters/homebrew/ingester_test.go
  • 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

Comment on lines +1 to +6
#!/bin/bash

# variables
APPDIR="/Applications/"
TMPDIR=$(dirname "$(realpath "$INSTALLER_PATH")")
# functions

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.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

cat ee/maintained-apps/inputs/homebrew/scripts/docker_desktop_install.sh

Repository: fleetdm/fleet

Length of output: 4756


Fail fast on DMG operations and always detach mounts.

The script lacks set -e and cleanup mechanisms, allowing it to proceed when hdiutil attach, sudo cp, or hdiutil detach fail. This can leave a partial install or a mounted DMG. Additionally, quit_and_track_application() logs quit failures but doesn't stop execution, risking copy/install failures if Docker is still running.

Add set -euo pipefail at the start, initialize MOUNT_POINT="" before use, and add a cleanup trap to ensure detach runs on exit:

Proposed hardening
 #!/bin/bash
+set -euo pipefail
 
 # variables
 APPDIR="/Applications/"
 TMPDIR=$(dirname "$(realpath "$INSTALLER_PATH")")
+MOUNT_POINT=""
+
+cleanup() {
+  if [[ -n "${MOUNT_POINT}" && -d "${MOUNT_POINT}" ]]; then
+    hdiutil detach "${MOUNT_POINT}" >/dev/null 2>&1 || true
+  fi
+}
+trap cleanup EXIT
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#!/bin/bash
# variables
APPDIR="/Applications/"
TMPDIR=$(dirname "$(realpath "$INSTALLER_PATH")")
# functions
#!/bin/bash
set -euo pipefail
# variables
APPDIR="/Applications/"
TMPDIR=$(dirname "$(realpath "$INSTALLER_PATH")")
MOUNT_POINT=""
cleanup() {
if [[ -n "${MOUNT_POINT}" && -d "${MOUNT_POINT}" ]]; then
hdiutil detach "${MOUNT_POINT}" >/dev/null 2>&1 || true
fi
}
trap cleanup EXIT
# functions
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ee/maintained-apps/inputs/homebrew/scripts/docker_desktop_install.sh` around
lines 1 - 6, Add strict failure handling and guaranteed DMG detach: add "set
-euo pipefail" at the top of the script, initialize a global MOUNT_POINT=""
variable before any hdiutil operations, and implement a cleanup function
(registered via trap EXIT) that checks MOUNT_POINT and calls hdiutil detach if
mounted; also make quit_and_track_application() return a non-zero exit (or exit)
on failure so the script stops instead of continuing to sudo cp when Docker
hasn't quit. Ensure every hdiutil attach error causes immediate exit and the
trap still runs to avoid leaving mounts.

Comment on lines +49 to +51
if [[ "$quit_success" = false ]]; then
echo "Application '$bundle_id' did not quit."
fi

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's locate and read the file
find . -name "docker_desktop_install.sh" -type f

Repository: fleetdm/fleet

Length of output: 128


🏁 Script executed:

#!/bin/bash
# Read the file to examine the context
cat -n ./ee/maintained-apps/inputs/homebrew/scripts/docker_desktop_install.sh

Repository: fleetdm/fleet

Length of output: 5610


🏁 Script executed:

#!/bin/bash
# Check for error handling flags (set -e) and confirm the function behavior
head -20 ./ee/maintained-apps/inputs/homebrew/scripts/docker_desktop_install.sh

Repository: fleetdm/fleet

Length of output: 557


Abort install when Docker Desktop does not quit.

If Docker Desktop continues running when the script attempts to replace its app bundle, the installation will proceed anyway, risking file locks, permission errors, or a corrupted/partially updated installation.

Add error handling to stop the script if quit fails:

Proposed fix
   if [[ "$quit_success" = false ]]; then
     echo "Application '$bundle_id' did not quit."
+    return 1
   fi
 }
 ...
-quit_and_track_application 'com.electron.dockerdesktop'
+quit_and_track_application 'com.electron.dockerdesktop' || {
+  echo "Aborting install because Docker Desktop is still running."
+  exit 1
+}

Also applies to: line 103

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ee/maintained-apps/inputs/homebrew/scripts/docker_desktop_install.sh` around
lines 49 - 51, The script currently logs when Docker Desktop failed to quit
(using the quit_success variable and bundle_id) but continues installation;
update both places where quit_success is checked (the block referencing
quit_success and bundle_id around line 49 and the similar check around line 103)
to abort the script on failure by printing a clear error to stderr and exiting
with a non-zero status (e.g., exit 1) so the install stops if Docker Desktop did
not quit; ensure the error message includes the bundle_id for context and that
any cleanup/rollback steps (if present) run before exiting.

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

This PR updates the Fleet-maintained Docker Desktop (macOS) manifest so installs remove Docker.app.back artifacts and patch compliance no longer gets tripped up by Docker Desktop’s .back bundle behavior. It also adds an ingester-side Docker Desktop override and expands ingestion tests accordingly.

Changes:

  • Add a Docker Desktop-specific Homebrew install script and wire it up via install_script_path.
  • Update Docker Desktop’s generated patched query to ignore bundles whose path ends with .back.
  • Add Homebrew ingester/test logic to special-case Docker Desktop’s patched query.

Reviewed changes

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

Show a summary per file
File Description
ee/maintained-apps/outputs/docker-desktop/darwin.json Updates patch query and install script ref; embeds new install script content.
ee/maintained-apps/inputs/homebrew/scripts/docker_desktop_install.sh New Docker Desktop DMG install script that removes Docker.app.back before copying.
ee/maintained-apps/inputs/homebrew/docker-desktop.json Points Docker Desktop input to the new install script override.
ee/maintained-apps/ingesters/homebrew/ingester.go Adds Docker Desktop-specific override for the generated patched query.
ee/maintained-apps/ingesters/homebrew/ingester_test.go Adds coverage for the Docker Desktop patched query override.
Comments suppressed due to low confidence (1)

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

  • In the embedded uninstall script, commands like sudo rmdir '~/.docker/bin' and sudo rmdir '~/Library/Caches/…' wrap ~ in single quotes, so tilde expansion will not occur and those directories will not be removed. Consider expanding to an absolute path (e.g. via $HOME or /Users/$LOGGED_IN_USER) or using the existing trash helper for these locations.
    "f8ed2624": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nquit_application() {\n  local bundle_id=\"$1\"\n  local timeout_duration=10\n\n  # check if the application is running\n  local app_running\n  app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n  if [[ \"$app_running\" != \"true\" ]]; then\n    return\n  fi\n\n  local console_user\n  console_user=$(stat -f \"%Su\" /dev/console)\n  if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n    echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n    return\n  fi\n\n  echo \"Quitting application '$bundle_id'...\"\n\n  # try to quit the application within the timeout period\n  local quit_success=false\n  SECONDS=0\n  while (( SECONDS < timeout_duration )); do\n    if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n      if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n        echo \"Application '$bundle_id' quit successfully.\"\n        quit_success=true\n        break\n      fi\n    fi\n    sleep 1\n  done\n\n  if [[ \"$quit_success\" = false ]]; then\n    echo \"Application '$bundle_id' did not quit.\"\n  fi\n}\n\n\nremove_launchctl_service() {\n  local service=\"$1\"\n  local booleans=(\"true\" \"false\")\n  local plist_status\n  local paths\n  local should_sudo\n\n  echo \"Removing launchctl service ${service}\"\n\n  for should_sudo in \"${booleans[@]}\"; do\n    plist_status=$(launchctl list \"${service}\" 2>/dev/null)\n\n    if [[ $plist_status == \\{* ]]; then\n      if [[ $should_sudo == \"true\" ]]; then\n        sudo launchctl remove \"${service}\"\n      else\n        launchctl remove \"${service}\"\n      fi\n      sleep 1\n    fi\n\n    paths=(\n      \"/Library/LaunchAgents/${service}.plist\"\n      \"/Library/LaunchDaemons/${service}.plist\"\n    )\n\n    # if not using sudo, prepend the home directory to the paths\n    if [[ $should_sudo == \"false\" ]]; then\n      for i in \"${!paths[@]}\"; do\n        paths[i]=\"${HOME}${paths[i]}\"\n      done\n    fi\n\n    for path in \"${paths[@]}\"; do\n      if [[ -e \"$path\" ]]; then\n        if [[ $should_sudo == \"true\" ]]; then\n          sudo rm -f -- \"$path\"\n        else\n          rm -f -- \"$path\"\n        fi\n      fi\n    done\n  done\n}\n\ntrash() {\n  local logged_in_user=\"$1\"\n  local target_file=\"$2\"\n  local timestamp=\"$(date +%Y-%m-%d-%s)\"\n  local rand=\"$(jot -r 1 0 99999)\"\n\n  # replace ~ with /Users/$logged_in_user\n  if [[ \"$target_file\" == ~* ]]; then\n    target_file=\"/Users/$logged_in_user${target_file:1}\"\n  fi\n\n  local trash=\"/Users/$logged_in_user/.Trash\"\n  local file_name=\"$(basename \"${target_file}\")\"\n\n  if [[ -e \"$target_file\" ]]; then\n    echo \"removing $target_file.\"\n    mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n  else\n    echo \"$target_file doesn't exist.\"\n  fi\n}\n\nremove_launchctl_service 'com.docker.helper'\nremove_launchctl_service 'com.docker.socket'\nremove_launchctl_service 'com.docker.vmnetd'\nquit_application 'com.docker.docker'\nquit_application 'com.electron.dockerdesktop'\nsudo rm -rf '/Library/PrivilegedHelperTools/com.docker.socket'\nsudo rm -rf '/Library/PrivilegedHelperTools/com.docker.vmnetd'\nsudo rmdir '~/.docker/bin'\nsudo rm -rf \"$APPDIR/Docker.app\"\nsudo rm -rf '/usr/local/cli-plugins/docker-compose'\nsudo rm -rf '/usr/local/bin/hub-tool'\nsudo rm -rf '/usr/local/bin/kubectl.docker'\nsudo rm -rf '/usr/local/bin/docker'\nsudo rm -rf '/usr/local/bin/docker-credential-desktop'\nsudo rm -rf '/usr/local/bin/docker-credential-ecr-login'\nsudo rm -rf '/usr/local/bin/docker-credential-osxkeychain'\nsudo rmdir '~/Library/Caches/com.plausiblelabs.crashreporter.data'\nsudo rmdir '~/Library/Caches/KSCrashReports'\ntrash $LOGGED_IN_USER '/usr/local/bin/docker-compose.backup'\ntrash $LOGGED_IN_USER '/usr/local/bin/docker.backup'\ntrash $LOGGED_IN_USER '~/.docker'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.docker.helper'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/group.com.docker'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.docker.helper.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.electron.dockerdesktop.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.bugsnag.Bugsnag/com.docker.docker'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Docker Desktop'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.docker.docker'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.plausiblelabs.crashreporter.data/com.docker.docker'\ntrash $LOGGED_IN_USER '~/Library/Caches/KSCrashReports/Docker'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.docker.docker'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.docker.helper'\ntrash $LOGGED_IN_USER '~/Library/Group Containers/group.com.docker'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.docker.docker'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.docker.docker.binarycookies'\ntrash $LOGGED_IN_USER '~/Library/Logs/Docker Desktop'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.docker.docker.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.electron.docker-frontend.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.electron.dockerdesktop.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.electron.docker-frontend.savedState'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.electron.dockerdesktop.savedState'\n"

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

Comment on lines 187 to +202
// create patch policy
out.Queries.Patched, err = patch_policy.GenerateQueryForManifest(patch_policy.PolicyData{
Platform: "darwin",
Version: out.Version,
ExistsQuery: out.Queries.Exists,
})
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "creating patch policy")
}
if input.Token == "docker-desktop" {
// Docker's updater can leave Docker.app.back; do not treat it as the installed app for patch status.
out.Queries.Patched = fmt.Sprintf(
"SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = '%s' AND path NOT LIKE '%%.back' AND version_compare(bundle_short_version, '%s') < 0);",
out.UniqueIdentifier, out.Version,
)
}
@@ -4,10 +4,10 @@
"version": "4.73.0",
"queries": {
"exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.electron.dockerdesktop';",
@allenhouchins
allenhouchins merged commit d96355a into main May 13, 2026
99 of 106 checks passed
@allenhouchins
allenhouchins deleted the 45242-show-update-available-status-library-and-self-service-only-if-the-top-level-app-is-outdated branch May 13, 2026 20:22
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.

Improve "Update available" status copy in self-service to explain if there is app in multiple locations (paths)

4 participants