Skip to content

Fix macOS software titles mis-named from embedded helper bundles (#44199)#47831

Open
mostlikelee wants to merge 9 commits into
mainfrom
fix-embedded-bundle-titles-44199
Open

Fix macOS software titles mis-named from embedded helper bundles (#44199)#47831
mostlikelee wants to merge 9 commits into
mainfrom
fix-embedded-bundle-titles-44199

Conversation

@mostlikelee

@mostlikelee mostlikelee commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Related issue: Resolves #44199

osquery reports an app's embedded login helper under Contents/Library/LoginItems/ as a separate apps row sharing the parent's bundle identifier; whichever row created the software_titles row wins its name, often the helper. Two changes pair:

  • Filter (queries.go): drop rows whose path matches %.app/Contents/%. Prospective.
  • Backfill migration: recompute existing apps titles from sibling software names (FMA → longest-common-prefix → shortest), UPDATE only on diff.

cmd/osquery-perf gains --embedded_bundle_paths to nest duplicate-bundle paths so the bug is reproducible at scale.

Migration perf (osquery-perf library, the largest realistic dataset available)

Titles Software rows Candidates Wall-clock
18,565 60,372 1,146 (6.2%) ~191 ms

EXPLAIN ANALYZE: PK scan on software_titles + title_id-indexed lookups on software. No table scans, no filesort. Linear extrapolation to ~5× scale stays well under 1s.

Checklist for submitter

  • Changes file added for user-visible changes in changes/

  • Input data is properly validated, SELECT * is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters.

Testing

  • Added/updated automated tests
  • QA'd all new/changed functionality manually

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

  • Confirmed that the fix is not expected to adversely impact load test results

Database migrations

  • Checked schema for all modified table for columns that will auto-update timestamps during migration.
  • Confirmed that updating the timestamps is acceptable, and will not cause unwanted side effects.
  • Ensured the correct collation is explicitly set for character columns (COLLATE utf8mb4_unicode_ci).

Summary by CodeRabbit

Release Notes

  • New Features

    • Added an option to generate duplicate bundle paths using nested embedded locations on macOS (disabled by default).
  • Bug Fixes

    • Prevented macOS app display names from being overwritten by embedded login-helper names when bundle identifiers match.
    • Improved macOS software inventory filtering by excluding app bundles nested under Contents.
  • Database / Migration

    • Added a one-time correction to recompute and fix misnamed macOS software titles from related app title sources.

…es under parent

Reproduces #44199 by emitting embedded-helper paths
(/some/path/Common_N.app/Contents/Library/LoginItems/<name>.app) when
the new flag is set, enabling load tests of the ingestion filter and
title backfill migration that follow. Default off — existing
duplicate-bundle behavior unchanged.
…uery

osquery's apps table reports both a parent app and any embedded login
helper under Contents/Library/LoginItems as separate rows, often sharing
a bundle identifier. The helper's name would clobber the software
title's display name (e.g. AmphetamineLoginHelper instead of
Amphetamine). Exclude paths nested under .app/Contents/ so only
top-level bundles are ingested.

Fixes #44199 prospectively. Existing mis-named titles are addressed by
the follow-up backfill migration.
For macOS app titles whose software_titles.name was set from an
embedded helper bundle (e.g. AmphetamineLoginHelper) rather than the
parent app, recompute the name from the title's sibling software rows
using the same precedence as title creation:

  1. Fleet-maintained app canonical name (if bundle id matches), else
  2. longest-common-prefix of sibling names (trailing non-word chars
     trimmed), else
  3. shortest sibling name.

The migration drives off the indexed software_titles JOIN software
join (title_id) and only UPDATEs titles whose name actually changes —
deliberately not path-based, since host_software_installed_paths has
no global per-software source of truth and would force a full
unindexed TEXT scan inside the startup-blocking migration
transaction.

Pairs with the queries.go filter that prevents new mis-named titles
from forming.
@mostlikelee

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jun 18, 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

Run ID: b73af812-c232-401c-ba2a-6da65ae14c49

📥 Commits

Reviewing files that changed from the base of the PR and between f253b69 and bdb9cb2.

📒 Files selected for processing (1)
  • server/datastore/mysql/schema.sql

Walkthrough

This PR fixes a macOS software title naming bug where a login-helper app nested inside another app's bundle (e.g., AmphetamineLoginHelper inside Amphetamine.app/Contents/Library/LoginItems/) was being ingested as the canonical title name because it shared the same bundle identifier.

The fix has two parts: the softwareMacOS SQL query gains a WHERE path NOT LIKE '%.app/Contents/%' filter to exclude embedded sub-bundle paths from future ingestion, and a new migration (20260618124430_FixEmbeddedBundleTitleNames) corrects existing mis-named titles by recomputing names using FMA lookup, longest-common-prefix across sibling software rows, or shortest-name fallback. The osquery-perf agent receives a new --embedded_bundle_paths flag to simulate this embedded path scenario for load testing.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% 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 clearly and specifically describes the main fix: correcting macOS software titles that are incorrectly named from embedded helper bundles.
Description check ✅ Passed The description covers the core problem, both parts of the solution (filter + migration), performance metrics, and checked most critical checklist items for database migrations and testing.
Linked Issues check ✅ Passed The PR fully addresses issue #44199 by fixing the root cause where embedded helper bundles override the correct app name through filtering prospective rows and migrating existing mis-named titles.
Out of Scope Changes check ✅ Passed All changes are directly scoped to resolving issue #44199: the filter to prevent new embedded bundle paths, migration to fix existing titles, supporting osquery-perf changes, and schema updates.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-embedded-bundle-titles-44199

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.

🧹 Nitpick comments (1)
server/datastore/mysql/migrations/tables/20260618124430_FixEmbeddedBundleTitleNames.go (1)

105-120: 💤 Low value

Consider deterministic tie-breaking for equal-length names.

The slice at line 105 is built from map iteration, which is non-deterministic in Go. If two sibling names have identical length, the "shortest" selection depends on iteration order.

For this one-shot migration with typical helper naming patterns, the practical impact is minimal, but sorting names lexicographically before the shortest-selection loop would make results reproducible.

♻️ Optional fix for deterministic selection
+import "sort"
+
 func fixEmbeddedPickTitleName(siblings map[string]struct{}, bundleID string, fmaNames map[string]string) string {
 	if name, ok := fmaNames[bundleID]; ok && name != "" {
 		return name
 	}
 	names := make([]string, 0, len(siblings))
 	for n := range siblings {
 		names = append(names, n)
 	}
+	sort.Strings(names)
 	prefix := fixEmbeddedLongestCommonPrefix(names)
🤖 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
`@server/datastore/mysql/migrations/tables/20260618124430_FixEmbeddedBundleTitleNames.go`
around lines 105 - 120, The names slice is built from non-deterministic map
iteration over the siblings map, which means when multiple sibling names have
identical length, the shortest name selection depends on the iteration order.
Sort the names slice lexicographically before the loop that finds the shortest
name by calling sort.Strings(names) after the prefix check and before the loop
that iterates through names[1:] to select the shortest, ensuring deterministic
results regardless of map iteration order.
🤖 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.

Nitpick comments:
In
`@server/datastore/mysql/migrations/tables/20260618124430_FixEmbeddedBundleTitleNames.go`:
- Around line 105-120: The names slice is built from non-deterministic map
iteration over the siblings map, which means when multiple sibling names have
identical length, the shortest name selection depends on the iteration order.
Sort the names slice lexicographically before the loop that finds the shortest
name by calling sort.Strings(names) after the prefix check and before the loop
that iterates through names[1:] to select the shortest, ensuring deterministic
results regardless of map iteration order.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cfb47ebb-5c84-4c09-90ca-4bffb1a89949

📥 Commits

Reviewing files that changed from the base of the PR and between 443d82d and 2d018f2.

⛔ Files ignored due to path filters (1)
  • docs/Contributing/product-groups/orchestration/understanding-host-vitals.md is excluded by !**/*.md
📒 Files selected for processing (5)
  • changes/44199-embedded-bundle-title-name
  • cmd/osquery-perf/agent.go
  • server/datastore/mysql/migrations/tables/20260618124430_FixEmbeddedBundleTitleNames.go
  • server/datastore/mysql/migrations/tables/20260618124430_FixEmbeddedBundleTitleNames_test.go
  • server/service/osquery_utils/queries.go

@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 61.90476% with 40 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.23%. Comparing base (876449c) to head (bdb9cb2).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
...bles/20260618124430_FixEmbeddedBundleTitleNames.go 68.42% 16 Missing and 14 partials ⚠️
cmd/osquery-perf/agent.go 0.00% 10 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #47831      +/-   ##
==========================================
- Coverage   67.23%   67.23%   -0.01%     
==========================================
  Files        3638     3640       +2     
  Lines      230034   230253     +219     
  Branches    11942    11781     -161     
==========================================
+ Hits       154670   154816     +146     
- Misses      61473    61526      +53     
- Partials    13891    13911      +20     
Flag Coverage Δ
backend 68.85% <61.90%> (-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.

Refactor Up_20260618124430 to delegate the title scan to
fixEmbeddedScanTitles, where defer rows.Close() satisfies
sqlclosecheck without the manual error-path close.

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.

Warning

  • Copilot's review of this pull request may be incomplete because some of the changed files are excluded by your Copilot content exclusion settings. See Excluding content from Copilot for details.

Pull request overview

This PR fixes incorrect macOS software title names caused by embedded helper bundles (e.g., LoginItems) sharing the parent app’s bundle identifier, ensuring the parent app name wins both for new ingests and for existing data.

Changes:

  • Filter macOS apps rows whose path indicates an embedded bundle under *.app/Contents/* during osquery ingestion.
  • Add a one-time MySQL migration to recompute affected software_titles.name values using FMA name override → longest common prefix → shortest fallback.
  • Extend cmd/osquery-perf to optionally generate embedded-bundle installed paths so the scenario is reproducible at scale.

Reviewed changes

Copilot reviewed 5 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
server/service/osquery_utils/queries.go Excludes embedded *.app/Contents/* paths from the macOS apps software query to prevent future mis-naming.
server/datastore/mysql/schema.sql Advances migration_status_tables seed data / AUTO_INCREMENT to include the new migration.
server/datastore/mysql/migrations/tables/20260618124430_FixEmbeddedBundleTitleNames.go Implements the backfill migration that recomputes software_titles.name for affected app titles.
server/datastore/mysql/migrations/tables/20260618124430_FixEmbeddedBundleTitleNames_test.go Adds coverage validating the migration’s name-picking precedence and out-of-scope behavior.
cmd/osquery-perf/agent.go Adds --embedded_bundle_paths option to generate nested Contents/Library/LoginItems/... paths for duplicate-bundle scenarios.
changes/44199-embedded-bundle-title-name User-visible change entry (content excluded from review by policy).
docs/Contributing/product-groups/orchestration/understanding-host-vitals.md Documentation update (content excluded from review by policy).
Files excluded by content exclusion policy (2)
  • changes/44199-embedded-bundle-title-name
  • docs/Contributing/product-groups/orchestration/understanding-host-vitals.md

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

fixEmbeddedLoadFMANamesDarwin now wraps query/scan/iteration errors
with descriptive messages, matching the sibling fixEmbeddedScanTitles
helper. Makes migration failure traces pinpoint the failing step.
@mostlikelee mostlikelee marked this pull request as ready for review June 18, 2026 18:49
@mostlikelee mostlikelee requested review from a team, sgress454 and sharon-fdm as code owners June 18, 2026 18:49

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

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.

Amphetamine app display name is obtained from LoginHelper instead of correct app name

2 participants