Skip to content

Software ingestion fixes - #33399

Merged
getvictor merged 12 commits into
mainfrom
33298-33140-merge
Sep 24, 2025
Merged

Software ingestion fixes#33399
getvictor merged 12 commits into
mainfrom
33298-33140-merge

Conversation

@getvictor

@getvictor getvictor commented Sep 24, 2025

Copy link
Copy Markdown
Member

Related issue:
Resolves #29053
Resolves #33298

For reference, the diffs for merging Konstantin's changes into my original PR are here: #33390

Checklist for submitter

  • Changes file added for user-visible changes in changes/, orbit/changes/ or ee/fleetd-chrome/changes.

Testing

Summary by CodeRabbit

  • Bug Fixes

    • Fixed duplicate macOS software entries caused by users renaming apps, ensuring accurate, consolidated inventory.
  • Documentation

    • Documented improved software ingestion performance by pre-inserting data in smaller batches to reduce database lock times during host check-ins.

@getvictor

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Sep 24, 2025

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@coderabbitai

coderabbitai Bot commented Sep 24, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Reworks host software ingestion in MySQL: adds a two-phase flow with pre-insertion outside the main transaction, host-linking and rename handling inside the transaction, and OpenTelemetry tracing. Updates tests extensively to cover bundle ID renames, name truncation, browser extensions, checksum/id reuse, and pre-insert idempotency. Adds change notes.

Changes

Cohort / File(s) Summary
Docs/Change notes
changes/29053-sw-names-on-ingest, changes/33298-software-ingestion
Notes about fixing macOS software rename-on-ingest and improved lock times via smaller pre-insert batches during host check-ins.
Datastore ingestion logic
server/datastore/mysql/software.go
Adds OpenTelemetry span/attributes to UpdateHostSoftware. Splits ingestion into Phase 1 pre-insert (outside transaction, batched by softwareInventoryInsertBatchSize) and Phase 2 host operations (linking, bundle-ID based updates, rename handling). Adds helpers: preInsertSoftwareInventory, linkSoftwareToHost, linkExistingBundleIDSoftware, updateTargetedBundleIDs. Adds checksum mapping and guard for empty getSoftwareIDsByChecksums input.
Tests
server/datastore/mysql/software_test.go
Removes legacy duplicate/rename tests. Adds comprehensive scenarios: bundle-ID rename handling (no-new/new software), same bundle ID different names, same name different bundle IDs, long-name truncation, browser extensions across browsers, pre-insert behavior and idempotency, title linkage, vulnerabilities/installers interactions. Adds truncateString helper and random checksums via crand. Adjusts expectations for title_id, ID reuse, name_source updates.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Host as Host
  participant Svc as Service
  participant DS as MySQL Datastore
  participant DB as MySQL

  rect rgb(240,248,255)
  note over Svc,DS: Phase 1 — Pre-insert (outside main tx)
  Host->>Svc: Report software inventory (apps, extensions, metadata)
  Svc->>DS: UpdateHostSoftware(host_id, inventory)
  DS->>DB: Pre-insert software_titles/software in batches
  DB-->>DS: IDs for inserted/existing rows
  end

  rect rgb(245,245,245)
  note over DS,DB: Phase 2 — Transactional host linking
  DS->>DB: BEGIN
  DS->>DB: Map checksums/bundle IDs to existing software/title IDs
  DS->>DB: Update targeted bundle-ID name renames (where names differ)
  DS->>DB: Link software to host (host_software inserts)
  DS->>DB: Handle bundle-ID based linking for existing software
  DB-->>DS: Commit results
  DS->>DB: COMMIT
  end

  note over DS: OTel span: UpdateHostSoftware(host_id, software_count)
  DS-->>Svc: Success/summary
  Svc-->>Host: Acknowledgement
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–90 minutes

Suggested labels

#g-software, ~assisting g-software

Suggested reviewers

  • mostlikelee
  • sgress454
  • dantecatalfamo
  • lucasmrod

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The title "Software ingestion fixes" succinctly captures the primary intent of the changeset—fixes to software ingestion behavior and performance—and directly relates to the modified files and tests in this PR, so it is clear and relevant for reviewers scanning history.
Linked Issues Check ✅ Passed The code implements a two-phase ingestion flow that pre-inserts software inventory in batched operations outside the main transaction and then links inventory to hosts while performing bundle-ID-aware name updates and checksum-aware ID mapping. This addresses #33298 by reducing DB lock contention via batched pre-inserts and addresses #29053 by reintroducing targeted bundle-ID/name updates and limiting edits using checksum/ID mappings rather than broad bundle-id edits. The extensive test additions exercise rename, truncation, pre-insert idempotency, and related edge cases, supporting the claimed fixes.
Out of Scope Changes Check ✅ Passed Changes are limited to server/datastore/mysql/software.go, related tests, and changes/ release notes with no modifications to public APIs or unrelated modules; the added OpenTelemetry tracing is relevant for diagnosing ingestion performance. I found no unrelated or extraneous code changes outside the scope of the linked issues. Test and helper additions align with the ingestion and rename behaviors targeted by the issues.
Description Check ✅ Passed The PR description references the related issues (Resolves #29053 and #33298), confirms a changes file was added, and marks automated tests and manual QA as complete, covering the main checklist items from the repository template. It omits a brief implementation summary and explicit notes about database migrations or configuration impacts, which the template allows but reviewers generally expect for clarity. Overall the description is mostly complete and sufficient for review but would benefit from a short summary of the behavioral changes and any migration/compatibility notes.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 33298-33140-merge

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: 0

🧹 Nitpick comments (7)
server/datastore/mysql/software.go (1)

17-17: Consider importing as mysql_common for consistency.

The alias common_mysql is unusual compared to typical Go naming conventions. Consider using mysql_common or just common to align with more conventional import naming.

server/datastore/mysql/software_test.go (6)

1762-1771: Avoid shadowing err for clarity.

Inside validateSoftware, replace the short declaration with assignment to avoid shadowing the outer err.

-			err := ds.writer(ctx).GetContext(
+			err = ds.writer(ctx).GetContext(
 				ctx, &titleID,
 				`SELECT s.title_id FROM software s WHERE s.id = ?`,
 				sw.ID,
 			)

1892-1897: Make name_source assertion resilient to version changes.

Asserting the exact "bundle_4.67" string is brittle. Prefer a prefix check.

-	require.Equal(t, "bundle_4.67", nameSource, "Name source should indicate bundle ID match")
+	require.True(t, strings.HasPrefix(nameSource, "bundle_"), "Name source should indicate bundle ID match, got %q", nameSource)

1918-1948: Use a realistic source for bundle ID semantics.

Using chrome_extensions with BundleIdentifier is atypical and could confuse future readers. apps better reflects bundle ID semantics.

-		{Name: "MyApp", Version: "1.0", Source: "chrome_extensions", BundleIdentifier: "bundle_id1"},
-		{Name: "MyApp", Version: "1.0", Source: "chrome_extensions", BundleIdentifier: "bundle_id2"},
+		{Name: "MyApp", Version: "1.0", Source: "apps", BundleIdentifier: "bundle_id1"},
+		{Name: "MyApp", Version: "1.0", Source: "apps", BundleIdentifier: "bundle_id2"},

8953-8962: Check crand.Read error.

Don’t ignore crypto/rand errors, even if unlikely.

-		_, _ = crand.Read(checksum)
+		if _, errRand := crand.Read(checksum); errRand != nil {
+			require.NoError(t, errRand)
+		}

9095-9101: Make name_source assertion version‑agnostic.

Same concern as above: assert a prefix instead of a fixed string.

-			require.Equal(t, "bundle_4.67", nameSource, "Name source should indicate bundle ID match")
+			require.True(t, strings.HasPrefix(nameSource, "bundle_"), "Name source should indicate bundle ID match, got %q", nameSource)

9138-9258: Use canonical browser-extension source names (e.g. "chrome_extensions")

Repo search shows "chrome_extensions" is used across the codebase while "browser_plugins" only appears in schema and this test (server/datastore/mysql/software_test.go:9138–9258). Update the test to use the canonical source(s) (chrome_extensions / firefox_addons / safari_extensions) or confirm that using "browser_plugins" here is intentional.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ec0ac8 and 0f91a85.

📒 Files selected for processing (4)
  • changes/29053-sw-names-on-ingest (1 hunks)
  • changes/33298-software-ingestion (1 hunks)
  • server/datastore/mysql/software.go (15 hunks)
  • server/datastore/mysql/software_test.go (7 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

⚙️ CodeRabbit configuration file

When reviewing SQL queries that are added or modified, ensure that appropriate filtering criteria are applied—especially when a query is intended to return data for a specific entity (e.g., a single host). Check for missing WHERE clauses or incorrect filtering that could lead to incorrect or non-deterministic results (e.g., returning the first row instead of the correct one). Flag any queries that may return unintended results due to lack of precise scoping.

Files:

  • server/datastore/mysql/software.go
  • server/datastore/mysql/software_test.go
🔇 Additional comments (28)
changes/29053-sw-names-on-ingest (1)

1-1: LGTM!

The change note clearly explains the fix for the macOS software ingestion issue. The wording appropriately describes the prevention of duplicate software entries due to user renaming while maintaining focus on the end-user impact.

changes/33298-software-ingestion (1)

1-1: LGTM!

The change note accurately describes the performance improvement achieved through pre-insertion of software/titles in smaller batches. This directly addresses the database lock time and performance degradation issues mentioned in the linked GitHub issue #33298.

server/datastore/mysql/software.go (21)

24-26: LGTM on OpenTelemetry integration!

The OpenTelemetry imports are properly included and the implementation follows Go OpenTelemetry patterns where spans are created with tracer.Start(ctx, "operation-name") and stored in context.Context.


38-40: LGTM on tracer initialization.

The global tracer initialization follows OpenTelemetry Go best practices where otel.Tracer() creates a tracer that can be used when a TracerProvider is set later. The no-op behavior when OTEL is disabled is also correctly noted.


52-54: Good addition of batch size control.

The new softwareInventoryInsertBatchSize variable properly supports the pre-insertion optimization strategy. The smaller batch size (100 vs 1000) makes sense for reducing lock contention during the pre-insertion phase.


65-72: LGTM on span creation and attributes.

The OpenTelemetry span creation follows proper patterns with tracer.Start() and includes relevant attributes for observability. The host_id and software_count attributes will be valuable for monitoring software ingestion performance.


396-406: Excellent addition of two-phase software ingestion.

The two-phase approach is well-designed:

  • Phase 1: Pre-insert software inventory outside the main transaction to reduce lock contention
  • Phase 2: Host-specific operations within transaction

The comment clearly explains the strategy and the idempotent nature due to INSERT IGNORE. This directly addresses the performance issues mentioned in PR objectives.


417-423: Good documentation of the host linking phase.

The comments clearly explain that the software inventory entries were already created in Phase 1, and this phase handles the host-specific linking. The separation of concerns is well-executed.


425-460: Well-implemented bundle ID handling.

The bundle ID software linking and renaming logic is comprehensive:

  • Handles existing software matching by bundle ID
  • Builds software rename mappings for both inserted and existing software
  • Calls updateTargetedBundleIDs for batch updates
  • Includes proper error handling

The approach addresses the macOS software name fix mentioned in the PR objectives.


483-524: Efficient batch processing for software renames.

The updateTargetedBundleIDs function implements proper batch processing:

  • Uses common_mysql.BatchProcessSimple for efficient batching
  • Builds CASE statements for batch updates
  • Sets name_source = 'bundle_4.67' to track the rename source
  • Includes proper error handling

This efficiently handles the software name updates for bundle ID matches.


648-657: Good handling of bundle ID matches with existing software.

The logic properly handles the case where incoming software has the same bundle ID as existing software but different name:

  • Copies incoming software with existing software's ID
  • Removes from incomingChecksumToSoftware to prevent duplicate processing
  • Maintains data integrity during the rename process

This directly addresses the macOS software ingestion issues.


704-708: Good handling of title mapping edge cases.

The logic properly handles the case where multiple checksums can map to the same title (e.g., when names are truncated). The comment clarifies this edge case and the code iterates through all relevant checksums.


734-741: Proper handling of multiple checksums to single title.

The implementation correctly maps all checksums that correspond to a single title, handling the edge case where software with different versions/checksums may have the same truncated name.


762-769: Consistent mapping pattern for bundle ID titles.

The code follows the same pattern as the non-bundle ID case, properly mapping all checksums that correspond to each title. The consistency in approach is good.


823-837: Well-designed pre-insertion function signature.

The preInsertSoftwareInventory function has a clear purpose and good parameter structure. The function name and documentation clearly indicate it's for Phase 1 of the two-phase approach.


853-857: Efficient batching for pre-insertion.

Using common_mysql.BatchProcessSimple with the smaller softwareInventoryInsertBatchSize is appropriate for reducing lock contention during pre-insertion. The batching strategy aligns with the performance goals.


859-876: Good transaction handling for batches.

Each batch runs in its own transaction via ds.withRetryTxx, which is appropriate for the pre-insertion phase. This allows quick release of locks while maintaining consistency within each batch.


886-909: Efficient title deduplication.

The title deduplication logic using a map with composite keys is well-designed:

  • Prevents unnecessary duplicate INSERTs
  • Uses struct keys for efficient comparison
  • Handles both bundle ID and non-bundle ID cases

This optimization reduces database load during pre-insertion.


959-970: Proper handling of title ID retrieval.

The title ID mapping logic correctly handles the relationship between checksums and titles:

  • Maps titles back to their checksums using name/source/browser/bundle_identifier matching
  • Handles the case where multiple checksums map to the same title
  • Includes helpful comment about the edge case

The logic is sound and handles the complex mapping scenarios.


1014-1026: Good error logging for debugging.

The logging of software without title IDs is helpful for debugging:

  • Logs count and examples of problematic software
  • Limits examples to avoid log spam
  • Uses appropriate error level since this shouldn't happen normally

This will help identify any issues with the title mapping logic.


1039-1108: Well-implemented bundle ID software linking.

The linkExistingBundleIDSoftware function properly handles edge cases:

  • Verifies software still exists before linking (prevents orphaned references)
  • Includes proper error checking for missing software IDs
  • Uses INSERT IGNORE for idempotency
  • Logs warnings for missing software but continues processing

The defensive programming approach is appropriate for this scenario.


1110-1169: Robust implementation of host-software linking.

The linkSoftwareToHost function is well-designed:

  • Verifies software exists before linking (defensive programming)
  • Maps checksums to software for efficient lookup
  • Uses INSERT IGNORE for idempotency
  • Logs warnings for missing software but continues
  • Includes helpful comments explaining the purpose

This replaces insertNewInstalledHostSoftwareDB with the assumption that software inventory already exists from Phase 1.


1171-1175: Good defensive programming for empty input.

The early return for empty checksums prevents unnecessary database queries and follows the fail-fast principle. This is a minor but good optimization.

server/datastore/mysql/software_test.go (5)

54-59: Nice coverage expansion for rename/ID reuse flows.

The added cases exercise critical rename/ID‑reuse scenarios and browser extensions. Good additions.


97-98: Pre-insert idempotency test is valuable.

Good to have a direct check on Phase 1 idempotency.


1705-1713: Local truncation helper is fine.

Matches production behavior closely enough for tests.


1953-2032: Long-name truncation tests look solid.

Good edge coverage around truncation and title_id consistency.


1857-1858: No action required — repo go directive is 1.25.1, so testing.T.Context() is supported.

@codecov

codecov Bot commented Sep 24, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.84848% with 50 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.12%. Comparing base (41f51fe) to head (393ade2).
⚠️ Report is 58 commits behind head on main.

Files with missing lines Patch % Lines
server/datastore/mysql/software.go 84.84% 34 Missing and 16 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #33399      +/-   ##
==========================================
+ Coverage   64.05%   64.12%   +0.06%     
==========================================
  Files        2059     2059              
  Lines      204990   205360     +370     
  Branches     6767     6767              
==========================================
+ Hits       131316   131679     +363     
+ Misses      63304    63300       -4     
- Partials    10370    10381      +11     
Flag Coverage Δ
backend 65.24% <84.84%> (+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.

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

Couple of suggestions but otherwise as far as I can tell it looks good. The design of splitting into two phases makes sense, and the incorporation of @ksykulev's revamped renaming logic looks correct. Question in Slack re: the new logic for dealing with multiple software items w/ the same checksum, but assuming we're good on that this looks 👍

Would definitely want to try a before and after run on load test to make sure there's not some gotcha that will cause software to disappear 😬 .

ctx context.Context,
tx sqlx.ExtContext,
hostID uint,
softwareChecksums map[string]fleet.Software,

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.

would love to take this opportunity to rename this to incomingSoftwareChecksums

Comment on lines +924 to +935
const numberOfArgsPerSoftwareTitles = 5
titlesValues := strings.TrimSuffix(strings.Repeat("(?,?,?,?,?),", len(uniqueTitlesToInsert)), ",")
titlesStmt := fmt.Sprintf("INSERT IGNORE INTO software_titles (name, source, browser, bundle_identifier, is_kernel) VALUES %s", titlesValues)
titlesArgs := make([]any, 0, len(uniqueTitlesToInsert)*numberOfArgsPerSoftwareTitles)

for _, title := range uniqueTitlesToInsert {
titlesArgs = append(titlesArgs, title.Name, title.Source, title.Browser, title.BundleIdentifier, title.IsKernel)
}

if _, err := tx.ExecContext(ctx, titlesStmt, titlesArgs...); err != nil {
return ctxerr.Wrap(ctx, err, "pre-insert software_titles")
}

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.

Perhaps we can use sqlx.NamedExec here to simplify this a bit? There's places where we have no choice but to build these giant strings of ?s but it'd be good to avoid it where we can.

@getvictor
getvictor merged commit 1ae9597 into main Sep 24, 2025
52 of 69 checks passed
getvictor added a commit that referenced this pull request Sep 25, 2025
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:**
Resolves #29053
Resolves #33298

For reference, the diffs for merging Konstantin's changes into my
original PR are here: #33390

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.

## Testing

- [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)
- [x] QA'd all new/changed functionality manually

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

## Summary by CodeRabbit

- Bug Fixes
- Fixed duplicate macOS software entries caused by users renaming apps,
ensuring accurate, consolidated inventory.

- Documentation
- Documented improved software ingestion performance by pre-inserting
data in smaller batches to reduce database lock times during host
check-ins.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

(cherry picked from commit 1ae9597)
getvictor added a commit that referenced this pull request Sep 25, 2025
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:**
Resolves #29053
Resolves #33298

For reference, the diffs for merging Konstantin's changes into my
original PR are here: #33390

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.

## Testing

- [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)
- [x] QA'd all new/changed functionality manually

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

## Summary by CodeRabbit

- Bug Fixes
- Fixed duplicate macOS software entries caused by users renaming apps,
ensuring accurate, consolidated inventory.

- Documentation
- Documented improved software ingestion performance by pre-inserting
data in smaller batches to reduce database lock times during host
check-ins.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

(cherry picked from commit 1ae9597)
@jkatz01

jkatz01 commented Sep 25, 2025

Copy link
Copy Markdown
Member

It could be worth testing if this resolves #28584 as well.

sgress454 pushed a commit that referenced this pull request Sep 26, 2025
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:**
Resolves #29053
Resolves #33298

For reference, the diffs for merging Konstantin's changes into my
original PR are here: #33390

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.

## Testing

- [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host

isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)
- [x] QA'd all new/changed functionality manually

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

## Summary by CodeRabbit

- Bug Fixes
- Fixed duplicate macOS software entries caused by users renaming apps,
ensuring accurate, consolidated inventory.

- Documentation
- Documented improved software ingestion performance by pre-inserting
data in smaller batches to reduce database lock times during host
check-ins.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

(cherry picked from commit 1ae9597)
mostlikelee pushed a commit that referenced this pull request Sep 27, 2025
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:**
Resolves #29053
Resolves #33298

For reference, the diffs for merging Konstantin's changes into my
original PR are here: #33390

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.

## Testing

- [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)
- [x] QA'd all new/changed functionality manually

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

## Summary by CodeRabbit

- Bug Fixes
- Fixed duplicate macOS software entries caused by users renaming apps,
ensuring accurate, consolidated inventory.

- Documentation
- Documented improved software ingestion performance by pre-inserting
data in smaller batches to reduce database lock times during host
check-ins.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

(cherry picked from commit 1ae9597)
mostlikelee added a commit that referenced this pull request Sep 27, 2025
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.

Database - Long lock times and degraded performance during software ingestion. 🪲Existing macOS software names aren't fixed on software ingestion

5 participants